我有办法!
你应该使用 Dbiregister CallBack 回调函数,钩住 BATCH MOVE的每一次
动作,这样BATCHMOVE每动作一条记录就会调用一次你的函数,事实上
我想DBPROGRESS也是如此做的
这个例子在BORLAND 的 技术支持站里有 ,地址是
http://www.borland.com/devsupport/delphi/ti_list/TI1327D.html
不过即使在TI里,此例子也有BUG,不过原理是讲明白了
事实上捕获BATCHMOVE只是一个小CASE
捕获 SQL 的查询状态才是一个大问题,比如在执行一个长程查询的时候
漫长的等待过程有可能很让用户头疼,这时候用户需要知道查询进程执行了
多少
下面是一段我写的利用DbiRegister CallBack 的代码,在SYBASE上执行
时这段代码可以CACEL 掉查询进程, (其他Server不支持,SYBASE是异步数据库
而其他SERVER是同步查询方式)
Procedure TForm1.Button1Click(Sender : TObject);
Begin
//打开跟踪标志,注意这里将 TRACEFLAG全部选取了,参照HELP里的TRACE,可以只取
//返回信息中的一部分作记录
Query1.Database.TraceFlags := [tfQPrepare..tfDataOut];
Query1.Close;
Query1.ParamByName('param1').AsString := QueryEdit.Text;
RegisterTraceCallback;
fCancel := False;
j := 0;
Query1.Open;
UnRegisterTraceCallback;
End;
Procedure Tform1.RegisterTraceCallback;
Begin
//分配内存
GetMem(ptdInfo, sizeof(TRACEDesc) + DBIMAXTRACELEN);
//加载回调函数
Check(DbiRegisterCallBack(
Nil,
cbTRACE,
0,
sizeof(TRACEDesc) + DBIMAXTRACELEN,
ptdInfo,
@TraceCallBack));
//下面这个CALLBACK只对SYBASE有用,别的数据库现在似乎还不支持CANCELQUERY
Check(DbiRegisterCallback(
Nil,
cbCANCELQRY,
0,
0,
Nil,
@TraceCallBack));
End;
Procedure Tform1.UnregisterTraceCallback;
Begin
Check(DbiRegisterCallBack(
Nil,
cbTRACE,
0,
sizeof(TRACEDesc) + DBIMAXTRACELEN,
Nil,
Nil));
Check(DbiRegisterCallback(Nil, cbCANCELQRY, 0, 0, Nil, Nil));
FreeMem(ptdInfo);
End;
Function TraceCallBack(ecbType : CBType; iClientData : Longint; ptdInfo :
pTRACEDesc) : CBRType;
Begin
Case ecbType Of
cbTRACE :
Begin
With form1 Do
Begin
//i 记录查询了多少条记录
//我的这个查询的一条记录有6个FIELDS
If i <> 6 Then inc(i)
Else
Begin
i := 1;
inc(j);
label1.Caption := IntToStr(j);
application.ProcessMessages;
End;
//下面这句可以看到具体的SQL 调试语句,因影响速度 被忽略
//Memo1.Lines.Add(IntToStr(PBar.Position) + ': ' +PChar(@ptdInfo^.pszTrace[0]));
End;
End;
//如果是SYBASE,这个CANCEL应该能用
cbCANCELQRY : fCancel:=True;
End;
If fCancel Then
//cbrAbort退出QUERY状态
Result := cbrABORT
Else
Result := cbrUseDef;
End;
Procedure TForm1.Button2Click(Sender : TObject);
Begin
//CancelQuery标志为真,因为没有SYBASE,故无法做测试
fCancel := True;
End;