ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/3.0/FB30Statement.pas
(Generate patch)

Comparing ibx/trunk/fbintf/client/3.0/FB30Statement.pas (file contents):
Revision 349 by tony, Mon Oct 18 08:39:40 2021 UTC vs.
Revision 359 by tony, Tue Dec 7 09:37:32 2021 UTC

# Line 232 | Line 232 | type
232    private
233      FResults: TIBXOUTPUTSQLDA;
234      FCursorSeqNo: integer;
235 +    procedure RowChange;
236    public
237      constructor Create(aResults: TIBXOUTPUTSQLDA);
238      destructor Destroy; override;
239      {IResultSet}
240 <    function FetchNext: boolean;
240 >    function FetchNext: boolean; {fetch next record}
241 >    function FetchPrior: boolean; {fetch previous record}
242 >    function FetchFirst:boolean; {fetch first record}
243 >    function FetchLast: boolean; {fetch last record}
244 >    function FetchAbsolute(position: Integer): boolean; {fetch record by its absolute position in result set}
245 >    function FetchRelative(offset: Integer): boolean; {fetch record by position relative to current}
246      function GetCursorName: AnsiString;
247      function GetTransaction: ITransaction; override;
248 +    function IsBof: boolean;
249      function IsEof: boolean;
250      procedure Close;
251    end;
# Line 260 | Line 267 | type
267      function getUpdated: integer;
268    end;
269  
270 +  TFetchType = (ftNext,ftPrior,ftFirst,ftLast,ftAbsolute,ftRelative);
271 +
272    { TFB30Statement }
273  
274    TFB30Statement = class(TFBStatement,IStatement)
# Line 270 | Line 279 | type
279      FSQLRecord: TIBXOUTPUTSQLDA;
280      FResultSet: Firebird.IResultSet;
281      FCursorSeqNo: integer;
282 +    FCursor: AnsiString;
283      FBatch: Firebird.IBatch;
284      FBatchCompletion: IBatchCompletion;
285      FBatchRowCount: integer;
# Line 280 | Line 290 | type
290      procedure CheckHandle; override;
291      procedure CheckBatchModeAvailable;
292      procedure GetDSQLInfo(info_request: byte; buffer: ISQLInfoResults); override;
293 <    procedure InternalPrepare; override;
293 >    procedure InternalPrepare(CursorName: AnsiString=''); override;
294      function InternalExecute(aTransaction: ITransaction): IResults; override;
295 <    function InternalOpenCursor(aTransaction: ITransaction): IResultSet; override;
295 >    function InternalOpenCursor(aTransaction: ITransaction; Scrollable: boolean
296 >      ): IResultSet; override;
297      procedure ProcessSQL(sql: AnsiString; GenerateParamNames: boolean; var processedSQL: AnsiString); override;
298      procedure FreeHandle; override;
299      procedure InternalClose(Force: boolean); override;
300      function SavePerfStats(var Stats: TPerfStatistics): boolean;
301    public
302      constructor Create(Attachment: TFB30Attachment; Transaction: ITransaction;
303 <      sql: AnsiString; aSQLDialect: integer);
303 >      sql: AnsiString; aSQLDialect: integer; CursorName: AnsiString='');
304      constructor CreateWithParameterNames(Attachment: TFB30Attachment; Transaction: ITransaction;
305        sql: AnsiString;  aSQLDialect: integer; GenerateParamNames: boolean =false;
306 <      CaseSensitiveParams: boolean=false);
306 >      CaseSensitiveParams: boolean=false; CursorName: AnsiString='');
307      destructor Destroy; override;
308 <    function FetchNext: boolean;
308 >    function Fetch(FetchType: TFetchType; PosOrOffset: integer=0): boolean;
309      property StatementIntf: Firebird.IStatement read FStatementIntf;
310  
311    public
# Line 303 | Line 314 | type
314      function GetMetaData: IMetaData; override;
315      function GetPlan: AnsiString;
316      function IsPrepared: boolean;
317 +    function GetFlags: TStatementFlags; override;
318      function CreateBlob(column: TColumnMetaData): IBlob; override;
319      function CreateArray(column: TColumnMetaData): IArray; override;
320      procedure SetRetainInterfaces(aValue: boolean); override;
# Line 794 | Line 806 | end;
806  
807   { TResultSet }
808  
809 + procedure TResultSet.RowChange;
810 + var i: integer;
811 + begin
812 +  for i := 0 to getCount - 1 do
813 +    FResults.Column[i].RowChange;
814 + end;
815 +
816   constructor TResultSet.Create(aResults: TIBXOUTPUTSQLDA);
817   begin
818    inherited Create(aResults);
# Line 808 | Line 827 | begin
827   end;
828  
829   function TResultSet.FetchNext: boolean;
811 var i: integer;
830   begin
831    CheckActive;
832 <  Result := FResults.FStatement.FetchNext;
832 >  Result := FResults.FStatement.Fetch(ftNext);
833 >  if Result then
834 >    RowChange;
835 > end;
836 >
837 > function TResultSet.FetchPrior: boolean;
838 > begin
839 >  CheckActive;
840 >  Result := FResults.FStatement.Fetch(ftPrior);
841 >  if Result then
842 >    RowChange;
843 > end;
844 >
845 > function TResultSet.FetchFirst: boolean;
846 > begin
847 >  CheckActive;
848 >  Result := FResults.FStatement.Fetch(ftFirst);
849 >  if Result then
850 >    RowChange;
851 > end;
852 >
853 > function TResultSet.FetchLast: boolean;
854 > begin
855 >  CheckActive;
856 >  Result := FResults.FStatement.Fetch(ftLast);
857    if Result then
858 <    for i := 0 to getCount - 1 do
859 <      FResults.Column[i].RowChange;
858 >    RowChange;
859 > end;
860 >
861 > function TResultSet.FetchAbsolute(position: Integer): boolean;
862 > begin
863 >  CheckActive;
864 >  Result := FResults.FStatement.Fetch(ftAbsolute,position);
865 >  if Result then
866 >    RowChange;
867 > end;
868 >
869 > function TResultSet.FetchRelative(offset: Integer): boolean;
870 > begin
871 >  CheckActive;
872 >  Result := FResults.FStatement.Fetch(ftRelative,offset);
873 >  if Result then
874 >    RowChange;
875   end;
876  
877   function TResultSet.GetCursorName: AnsiString;
878   begin
879 <  IBError(ibxeNotSupported,[nil]);
823 <  Result := '';
879 >  Result := FResults.FStatement.FCursor;
880   end;
881  
882   function TResultSet.GetTransaction: ITransaction;
# Line 828 | Line 884 | begin
884    Result := FResults.FTransaction;
885   end;
886  
887 + function TResultSet.IsBof: boolean;
888 + begin
889 +  Result := FResults.FStatement.FBof;
890 + end;
891 +
892   function TResultSet.IsEof: boolean;
893   begin
894    Result := FResults.FStatement.FEof;
# Line 1264 | Line 1325 | begin
1325    end;
1326   end;
1327  
1328 < procedure TFB30Statement.InternalPrepare;
1328 > procedure TFB30Statement.InternalPrepare(CursorName: AnsiString);
1329 > var GUID : TGUID;
1330   begin
1331    if FPrepared then
1332      Exit;
1333 +
1334 +  FCursor := CursorName;
1335    if (FSQL = '') then
1336      IBError(ibxeEmptyQuery, [nil]);
1337    try
1338      CheckTransaction(FTransactionIntf);
1339      with FFirebird30ClientAPI do
1340      begin
1341 +      if FCursor = '' then
1342 +      begin
1343 +        CreateGuid(GUID);
1344 +        FCursor := GUIDToString(GUID);
1345 +      end;
1346 +
1347        if FHasParamNames then
1348        begin
1349          if FProcessedSQL = '' then
# Line 1296 | Line 1366 | begin
1366        FSQLStatementType := TIBSQLStatementTypes(FStatementIntf.getType(StatusIntf));
1367        Check4DataBaseError;
1368  
1369 +      if FSQLStatementType = SQLSelect then
1370 +      begin
1371 +        FStatementIntf.setCursorName(StatusIntf,PAnsiChar(FCursor));
1372 +        Check4DataBaseError;
1373 +      end;
1374        { Done getting the type }
1375        case FSQLStatementType of
1376          SQLGetSegment,
# Line 1333 | Line 1408 | begin
1408      end;
1409    end;
1410    FPrepared := true;
1411 +
1412    FSingleResults := false;
1413    if RetainInterfaces then
1414    begin
# Line 1367 | Line 1443 | function TFB30Statement.InternalExecute(
1443      end;
1444    end;
1445  
1446 + var Cursor: IResultSet;
1447  
1448   begin
1449    Result := nil;
# Line 1392 | Line 1469 | begin
1469      begin
1470        case FSQLStatementType of
1471        SQLSelect:
1472 <        IBError(ibxeIsAExecuteProcedure,[]);
1472 >       {e.g. Update...returning with a single row in Firebird 5 and later}
1473 >      begin
1474 >        Cursor := InternalOpenCursor(aTransaction,false);
1475 >        if not Cursor.IsEof then
1476 >          Cursor.FetchNext;
1477 >        Result := Cursor; {note only first row}
1478 >        FSingleResults := true;
1479 >      end;
1480  
1481        SQLExecProcedure:
1482        begin
# Line 1416 | Line 1500 | begin
1500    Inc(FChangeSeqNo);
1501   end;
1502  
1503 < function TFB30Statement.InternalOpenCursor(aTransaction: ITransaction
1504 <  ): IResultSet;
1503 > function TFB30Statement.InternalOpenCursor(aTransaction: ITransaction;
1504 >  Scrollable: boolean): IResultSet;
1505 > var flags: cardinal;
1506   begin
1507 <  if FSQLStatementType <> SQLSelect then
1507 >  flags := 0;
1508 >  if (FSQLStatementType <> SQLSelect) and not (stHasCursor in getFlags) then
1509     IBError(ibxeIsASelectStatement,[]);
1510  
1511    FBatchCompletion := nil;
# Line 1432 | Line 1518 | begin
1518    if FStaleReferenceChecks and (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB30transaction).TransactionSeqNo) then
1519      IBError(ibxeInterfaceOutofDate,[nil]);
1520  
1521 + if Scrollable then
1522 +   flags := Firebird.IStatement.CURSOR_TYPE_SCROLLABLE;
1523 +
1524   with FFirebird30ClientAPI do
1525   begin
1526     if FCollectStatistics then
# Line 1447 | Line 1536 | begin
1536                            FSQLParams.MetaData,
1537                            FSQLParams.MessageBuffer,
1538                            FSQLRecord.MetaData,
1539 <                          0);
1539 >                          flags);
1540     Check4DataBaseError;
1541  
1542     if FCollectStatistics then
# Line 1493 | Line 1582 | begin
1582      FStatementIntf := nil;
1583      FPrepared := false;
1584    end;
1585 +  FCursor := '';
1586   end;
1587  
1588   procedure TFB30Statement.InternalClose(Force: boolean);
# Line 1538 | Line 1628 | begin
1628   end;
1629  
1630   constructor TFB30Statement.Create(Attachment: TFB30Attachment;
1631 <  Transaction: ITransaction; sql: AnsiString; aSQLDialect: integer);
1631 >  Transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
1632 >  CursorName: AnsiString);
1633   begin
1634    inherited Create(Attachment,Transaction,sql,aSQLDialect);
1635    FFirebird30ClientAPI := Attachment.Firebird30ClientAPI;
1636    FSQLParams := TIBXINPUTSQLDA.Create(self);
1637    FSQLRecord := TIBXOUTPUTSQLDA.Create(self);
1638 <  InternalPrepare;
1638 >  InternalPrepare(CursorName);
1639   end;
1640  
1641   constructor TFB30Statement.CreateWithParameterNames(
1642    Attachment: TFB30Attachment; Transaction: ITransaction; sql: AnsiString;
1643    aSQLDialect: integer; GenerateParamNames: boolean;
1644 <  CaseSensitiveParams: boolean);
1644 >  CaseSensitiveParams: boolean; CursorName: AnsiString);
1645   begin
1646    inherited CreateWithParameterNames(Attachment,Transaction,sql,aSQLDialect,GenerateParamNames);
1647    FFirebird30ClientAPI := Attachment.Firebird30ClientAPI;
1648    FSQLParams := TIBXINPUTSQLDA.Create(self);
1649    FSQLParams.CaseSensitiveParams := CaseSensitiveParams;
1650    FSQLRecord := TIBXOUTPUTSQLDA.Create(self);
1651 <  InternalPrepare;
1651 >  InternalPrepare(CursorName);
1652   end;
1653  
1654   destructor TFB30Statement.Destroy;
# Line 1567 | Line 1658 | begin
1658    if assigned(FSQLRecord) then FSQLRecord.Free;
1659   end;
1660  
1661 < function TFB30Statement.FetchNext: boolean;
1661 > function TFB30Statement.Fetch(FetchType: TFetchType; PosOrOffset: integer
1662 >  ): boolean;
1663   var fetchResult: integer;
1664   begin
1665    result := false;
1666    if not FOpen then
1667      IBError(ibxeSQLClosed, [nil]);
1576  if FEOF then
1577    IBError(ibxeEOF,[nil]);
1668  
1669    with FFirebird30ClientAPI do
1670    begin
1671 <    { Go to the next record... }
1672 <    fetchResult := FResultSet.fetchNext(StatusIntf,FSQLRecord.MessageBuffer);
1673 <    if fetchResult = Firebird.IStatus.RESULT_NO_DATA then
1674 <    begin
1675 <      FBOF := false;
1676 <      FEOF := true;
1677 <      Exit; {End of File}
1678 <    end
1679 <    else
1680 <    if fetchResult <> Firebird.IStatus.RESULT_OK then
1681 <    begin
1682 <      try
1683 <        IBDataBaseError;
1594 <      except
1595 <        Close;
1596 <        raise;
1671 >    case FetchType of
1672 >    ftNext:
1673 >      begin
1674 >        if FEOF then
1675 >          IBError(ibxeEOF,[nil]);
1676 >        { Go to the next record... }
1677 >        fetchResult := FResultSet.fetchNext(StatusIntf,FSQLRecord.MessageBuffer);
1678 >        if fetchResult = Firebird.IStatus.RESULT_NO_DATA then
1679 >        begin
1680 >          FBOF := false;
1681 >          FEOF := true;
1682 >          Exit; {End of File}
1683 >        end
1684        end;
1685 <    end
1686 <    else
1687 <    begin
1688 <      FBOF := false;
1689 <      result := true;
1685 >
1686 >    ftPrior:
1687 >      begin
1688 >        if FBOF then
1689 >          IBError(ibxeBOF,[nil]);
1690 >        { Go to the next record... }
1691 >        fetchResult := FResultSet.fetchPrior(StatusIntf,FSQLRecord.MessageBuffer);
1692 >        if fetchResult = Firebird.IStatus.RESULT_NO_DATA then
1693 >        begin
1694 >          FBOF := true;
1695 >          FEOF := false;
1696 >          Exit; {Top of File}
1697 >        end
1698 >      end;
1699 >
1700 >    ftFirst:
1701 >      fetchResult := FResultSet.fetchFirst(StatusIntf,FSQLRecord.MessageBuffer);
1702 >
1703 >    ftLast:
1704 >      fetchResult := FResultSet.fetchLast(StatusIntf,FSQLRecord.MessageBuffer);
1705 >
1706 >    ftAbsolute:
1707 >      fetchResult := FResultSet.fetchAbsolute(StatusIntf,PosOrOffset,FSQLRecord.MessageBuffer);
1708 >
1709 >    ftRelative:
1710 >      fetchResult := FResultSet.fetchRelative(StatusIntf,PosOrOffset,FSQLRecord.MessageBuffer);
1711      end;
1712 +
1713 +    Check4DataBaseError;
1714 +    if fetchResult <> Firebird.IStatus.RESULT_OK then
1715 +      exit; {result = false}
1716 +
1717 +    {Result OK}
1718 +    FBOF := false;
1719 +    FEOF := false;
1720 +    result := true;
1721 +
1722      if FCollectStatistics then
1723      begin
1724        UtilIntf.getPerfCounters(StatusIntf,
# Line 1792 | Line 1910 | begin
1910    Result := FStatementIntf <> nil;
1911   end;
1912  
1913 + function TFB30Statement.GetFlags: TStatementFlags;
1914 + var flags: cardinal;
1915 + begin
1916 +  CheckHandle;
1917 +  Result := [];
1918 +  with FFirebird30ClientAPI do
1919 +  begin
1920 +    flags := FStatementIntf.getFlags(StatusIntf);
1921 +    Check4DataBaseError;
1922 +  end;
1923 +  if flags and Firebird.IStatement.FLAG_HAS_CURSOR <> 0 then
1924 +    Result := Result + [stHasCursor];
1925 +  if flags and Firebird.IStatement.FLAG_REPEAT_EXECUTE <> 0 then
1926 +    Result := Result + [stRepeatExecute];
1927 +  if flags and Firebird.IStatement.CURSOR_TYPE_SCROLLABLE <> 0 then
1928 +    Result := Result + [stScrollable];
1929 + end;
1930 +
1931   end.
1932  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines