Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Midas/TProvider    [ Add a report in this area ]  
Report #:  3515   Status: Closed
PacketRecords with params will fail if recordcount > packetrecords number.
Project:  Delphi Build #:  4.453
Version:    7.0 Submitted By:   Michael JEWEL
Report Type:  Basic functionality failure Date Reported:  2/11/2003 5:37:05 AM
Severity:    Commonly encountered problem Last Updated: 10/6/2006 6:50:54 AM
Platform:    All platforms Internal Tracking #:   157503
Resolution: Fixed (Resolution Comments) Resolved in Build: : 7.0.8.1
Duplicate of:  None
Voting and Rating
Overall Rating: (7 Total Ratings)
4.57 out of 5
Total Votes: 5
Description
If there is a parameter and the recordcount is greater than the packetrecords, the clientdataset never reaches the EOF and receices always and always the same packet that make all the application looping!

The problem was not present with Delphi 6, only appears in Delphi 7.

Dave Rowntree's coment:
"This is a D7 MIDAS bug. It only affects Delphi's default
incremental fetching where the CDS (and DSP.DataSet) have Params.

The code

>    if VarIsEmpty(Params) and (Self.Params.Count > 0) then
>      Params := PackageParams(Self.Params);


was added to D7 DoGetRecords to force CDS.Refresh to honour the CDS params
(which D<7 does not do).

The trouble is, it also affects CDS.FetchMoreData and CDS.GetNextPacket, which are used for automatic and manual control of incremental fetching.
This code causes the DSP.DataSet to be closed when the DSP.DataSet Params are set, thereby loosing the incremental fetching position, so the *first* CDS.PacketRecords number of records are returned every time by CDS.FetchMoreData and CDS.GetNextPacket."
Steps to Reproduce:
You can do a very simple test to reproduce the situation: (Delphi 7)
    Projet, new app:
- Drop a Database connection  and a query returing many rows (ex: 50) with a dummy parameter (BDE, ADO or DBX change nothing, as you prefer)
- drop a DataSetprovider and a ClientDataSet
- Link these components between them.
- Set Packetrecords to the clientdataset to a value smaller than the total recordcount of the rows (ex: 10)
- Drop a button, and on the OnClik event just make a simple loop:

    ClientDataSet1.close;
    ClientDataSet1.FetchParams;
    ClientDataSet1.Params.ParamByName('paramdummy').AsString := '...';
    ClientDataSet1.open;
    ClientDataSet1.first;
    while not ClientDataSet1.eof do
    begin
      ClientDataSet1.next;
    end;
    showmessage('done');

- you can add a DataSource and a dBgrid to see exactly what append...
- Then run and click: The Showmessage(done') never appears because the clientdataset never reachs the eof value.
Workarounds
PROVIDER.PAS
(**)(* Delphi 7.0 - 7.1 *)
(* fix for QC3515. Allows incremental fetching to be used with CDS Params *)
(* Dave Rowntree 03/12/2003 *)
function TDataSetProvider.InternalGetRecords(Count: Integer; out RecsOut: Integer;
  Options: TGetRecordOptions; const CommandText: WideString;
  var Params: OleVariant): OleVariant;
begin
  try
    if grReset in Options then
    begin
      Reset;
      { When doing only a reset and not getting more data then exit }
      if Count = 0 then Exit;
    end;
    if not DataSet.Active then
    begin
      DataSet.Open;
      FDataSetOpened := True;
      if FRecordsSent > 0 then DataSet.MoveBy(FRecordsSent);(**)(* add this line *)
    end;
    if (Count = 0) or (grMetaData in Options) then


---------

(**)(* QC#8128 fix - Loss of DSP.DataSet.Param value causing zero records to be returned *)
(* D7.1 *)
(* Mark Eddington 18 May 2004 *)
procedure TDataSetProvider.SetParams(Values: OleVariant);
var
  DataSetParams: TParams;
begin
  if VarIsClear(Values) then Exit;
  CheckDataSet;
  DataSetParams := IProviderSupport(DataSet).PSGetParams;
  if not Assigned(FParams) then
    FParams := TParams.Create;
  FParams.Clear;
  UnpackParams(Values, FParams);
  if not (Assigned(DataSetParams) and DataSetParams.IsEqual(FParams)) then
    IProviderSupport(DataSet).PSSetParams(FParams);
end;
Attachment
3515.zip
Comments

Jan Bia at 11/18/2003 1:24:03 AM -
after fix

  cds.Close;
  cds.Params[0].Value := NewValue;
  cds.Open;

returns wrong records
  - cds.Open probably fetchs records with old fetching position

Dave Rowntree at 2/3/2004 1:50:13 AM -
No, it doesn't return the wrong records, it works ok.

The only way what you describe is likely to happen is if you have set the TDataSetProvider.Option poNoReset to True. This you should never do if you are using MIDAS default incremental fetching (CDS.PacketRecords > 0).

Petr Bejlek at 3/10/2004 2:15:31 AM -
It seems to be the same problem as reported in reports # 5664, 4498

Dave Rowntree at 5/26/2004 1:44:37 AM -
Workaround fix ...

There are two VCL fixes in the Workaround tab.

Please remove the fix provided in the TDataSetProvider.InternalGetRecords procedure from your provider.pas.

Please use the replacement TDataSetProvider.SetParams procedure as a fix for this problem.

Thank you.

Exonet New Zealand Limited Developer at 8/23/2004 5:39:28 PM -
HI

My problem is very similar... its on MSSQL database.

I think the problem lies in the providers.pas DataSetProvider.SetParams routine and the line where DatasetParams.Isequal (FParams) is tested.

On the client side when the CLientDataset SQL is parsed and a parameter is found it creates a parameter of Paramtype of ptUnknown.

On the Server side when ADO Parameter is set to the TParam properties it
does a paramtype check which is in the routine

AODB.TParameter.Assign(Source: TPersistent);

  procedure AssignParam(Param: TParam);
  begin
    if Param.ParamType = ptUnknown then
      Direction := pdInput else
      Direction := TParameterDirection(Param.ParamType);

   /// IT CHANGES THE PARAMTYPE TO INPUT
  end;

So the paramtype is NOT exactly mirrored which means that the result of type TParams of the line DataSetParams := IProviderSupport(DataSet).PSGetParams in the provider.pas TDataSetProvider.SetParams routine will pass back parameters of paramtype ptInput whereas the client has the paramtype of ptunkown and therefore the DB.IsEqual routine will return false and PSSetParams gets called and the dataset is closed..

so the workaround for my problem i see as commenting the lines ( as suggested before) in the DBClient.pas unit or doctoring the DB.Isequal routine or change the DB.ParseSQL routine and default the paramtype to ptinput..

Maybe somebody with a better understand of the MIDAS architecture can recommned what solution is more correct / recommended.

Thanks

Edwin Das

Server Response from: CODE1