Subject Trouble using Datapump in a long delete to drive a progress bar
Author Chuck Belanger
Hello,

I'm trying to get a progress meter update for a longish DELETE command.

Since there is no OnCallBack event from ib_dsql, I thought I'd try to
use IB_Datapump and use the cursor that is used in the datapump.

My problem is that the CursorRowNum gets to about 84 for a cursor row
count of 702 in my particular test table then stops. On checking, in
fact, all 702 rows are properly deleted. Further checking showed that if
I introduced a ShowMessage() in the OnCallBack, then I would see each
cursor row. Additionally, when I actually put the src and dst SQL into
IB_SQL's datapump, it properly showed the progress bar movement and row
count in its label, albeit IB_SQL took longer to start the process. My
OnCallBack is essentially a copy from IB_SQL.

How can I get the CursorRowNum to correctly reflect the status of the
delete process?

Thank you for your help,

Chuck Belanger

p.s. I'm using IBO 4.2 Ie; I have 4.5 (as trustware), but heard about
some issues and need to get 4.6 before updating. Not sure this datapump
issue could be effected by using pre-4.5, though.


Here's my code:

//reset progress bar
fcProgressBar1.Max := 10000;
fcProgressBar1.Progress := 0;
fcProgressBar1.Update;
fcProgressBar1.Visible := true;

with ModData.crDPAnyUse do
begin
SQL.Clear;
SQL.Add('SELECT cv_id From CUSTOM_VIEW ');
SQL.Add('Where ml_id NOT IN (SELECT ml_id FROM MasterLibrary) ');
SQL.Add('ORDER BY CV_ID ');
end;

with ModData.dsqlDPAnyUse do
begin
SQL.Clear;
SQL.Add('DELETE FROM Custom_View ');
SQL.Add('Where cv_id = :cv_id ');
end;

DoDataPump(False); //allows for OnCallBack Progress

procedure DoDataPump(CallBackOff : Boolean);
begin
try
begin
ModData.IB_Connection1.BeginBusy(true);
if CallBackOff then
begin
ModData.crDPAnyUse.OnCallback := nil;
ModData.crDPAnyUse.CallbackInc := -1;
ModData.crDPAnyUse.CallbackInitInt := 3000;
ModData.crDPAnyUse.CallbackRefreshInt := 250;
end
else
begin

with ModData.crDPAnyUse do
begin
Open;
if RecordCount > 1 then
begin
OnCallback := crUpdateCallback;
CallbackInc := 1;
CallbackInitInt := 1;
CallbackRefreshInt := 1;
close; //opened just to get recordcount; if record count = 0
then
//error in _Trunc SYSTEM.pas

end
else //make sure no OnCallBack--no point anyway, if only one
rec
begin
OnCallback := nil;
CallbackInc := -1;
end;
end;

end;

ModData.dpAnyUse.DstLinks.Clear;
ModData.dpAnyUse.DstStatement.Prepared := true;
ModData.dpAnyUse.SrcDataset.Unprepare;
ModData.dpAnyUse.SrcDataset.Prepared := true;

ModData.dpAnyUse.Execute;

end;
finally
begin
ModData.dpAnyUse.DstStatement.IB_Transaction.Commit;
ModData.IB_Connection1.EndBusy;

//reset ModData.crDPAnyUse.
with ModData.crDPAnyUse do
begin
ModData.crDPAnyUse.OnCallback := nil;
//-1 would mean no callback, 5 is the property's setting and
//I don't want to mess with something that I use elsewhere
ModData.crDPAnyUse.CallbackInc := 5;
ModData.crDPAnyUse.CallbackInitInt := 3000;
ModData.crDPAnyUse.CallbackRefreshInt := 250;
end;

end;
end;
end;

procedure TfrmUpdateDlg.crUpdateCallback(IB_Dataset : TIB_Dataset;
Status : TIB_CallbackStatus; CursorRowNum : Integer; var Abort :
Boolean);
//var
// tmpCnt : Longint;
begin
if Status = csInit then
begin
with fcProgressBar1 do
begin
if IB_Dataset.Owner.Name = 'dpUpdate' then
Import.RowCount := crUpdate.RecordCount
else
if IB_Dataset.Owner.Name = 'dpAnyUse' then
Import.RowCount := ModData.crDPAnyUse.RecordCount;

Progress := 0;
end;
end;

lblProgress.Caption := IntToStr(CursorRowNum) + '/' +
IntToStr(Import.RowCount);

if Status in [csRefresh, csFinal] then
begin
with IB_Dataset do
begin
//I'm not using the Rows per second label
// tmpCnt := ( GetTickCount - CallbackInitTick ) div 1000;
// if tmpCnt = 0 then
// tmpCnt := 1;
// lbRowPerSec.Caption := IntToStr( CursorRowNum div tmpCnt );

if Import.RowCount > 0 then
fcProgressBar1.Progress :=
1 + Integer(Int64(CursorRowNum) *
Int64(10000) div Int64(Import.RowCount));

// Trunc((CursorRowNum / Import.RowCount) * 10000);
end;
end;
end;