ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/journaling/fbintf/client/2.5/FB25Statement.pas
(Generate patch)

Comparing:
ibx/trunk/fbintf/client/2.5/FB25Statement.pas (file contents), Revision 47 by tony, Mon Jan 9 15:31:51 2017 UTC vs.
ibx/branches/journaling/fbintf/client/2.5/FB25Statement.pas (file contents), Revision 363 by tony, Tue Dec 7 13:30:05 2021 UTC

# Line 60 | Line 60
60   {                                                                        }
61   {************************************************************************}
62   unit FB25Statement;
63 + {$IFDEF MSWINDOWS}
64 + {$DEFINE WINDOWS}
65 + {$ENDIF}
66  
67   {$IFDEF FPC}
68 < {$mode objfpc}{$H+}
68 > {$mode delphi}
69   {$codepage UTF8}
70   {$interfaces COM}
71   {$ENDIF}
# Line 118 | Line 121 | type
121    TIBXSQLVAR = class(TSQLVarData)
122    private
123      FStatement: TFB25Statement;
124 +    FFirebird25ClientAPI: TFB25ClientAPI;
125      FBlob: IBlob;             {Cache references}
122    FArray: IArray;
126      FNullIndicator: short;
127      FOwnsSQLData: boolean;
128      FBlobMetaData: IBlobMetaData;
129      FArrayMetaData: IArrayMetaData;
130 +    FMetadataSize: short; {size of field from metadata}
131      FXSQLVAR: PXSQLVAR;       { Points to the PXSQLVAR in the owner object }
132    protected
133      function GetSQLType: cardinal; override;
134      function GetSubtype: integer; override;
135 <    function GetAliasName: string;  override;
136 <    function GetFieldName: string; override;
137 <    function GetOwnerName: string;  override;
138 <    function GetRelationName: string;  override;
135 >    function GetAliasName: AnsiString;  override;
136 >    function GetFieldName: AnsiString; override;
137 >    function GetOwnerName: AnsiString;  override;
138 >    function GetRelationName: AnsiString;  override;
139      function GetScale: integer; override;
140      function GetCharSetID: cardinal; override;
141      function GetCodePage: TSystemCodePage; override;
142 +    function GetCharSetWidth: integer; override;
143      function GetIsNull: Boolean;   override;
144      function GetIsNullable: boolean; override;
145 <    function GetSQLData: PChar;  override;
145 >    function GetSQLData: PByte;  override;
146      function GetDataLength: cardinal; override;
147 +    function GetSize: cardinal; override;
148 +    function GetAttachment: IAttachment; override;
149 +    function GetDefaultTextSQLType: cardinal; override;
150      procedure SetIsNull(Value: Boolean); override;
151      procedure SetIsNullable(Value: Boolean);  override;
152 <    procedure SetSQLData(AValue: PChar; len: cardinal); override;
152 >    procedure SetSQLData(AValue: PByte; len: cardinal); override;
153      procedure SetScale(aValue: integer); override;
154      procedure SetDataLength(len: cardinal); override;
155      procedure SetSQLType(aValue: cardinal); override;
# Line 150 | Line 158 | type
158      constructor Create(aParent: TIBXSQLDA; aIndex: integer);
159      procedure FreeSQLData;
160      procedure RowChange; override;
161 <    function GetAsArray(Array_ID: TISC_QUAD): IArray; override;
161 >    function GetAsArray: IArray; override;
162      function GetAsBlob(Blob_ID: TISC_QUAD; BPB: IBPB): IBlob; override;
163      function GetArrayMetaData: IArrayMetaData; override;
164      function GetBlobMetaData: IBlobMetaData; override;
# Line 158 | Line 166 | type
166      procedure Initialize; override;
167  
168      property Statement: TFB25Statement read FStatement;
169 +    property SQLType: cardinal read GetSQLType write SetSQLType;
170    end;
171  
172    TIBXINPUTSQLDA = class;
# Line 174 | Line 183 | type
183      function GetXSQLDA: PXSQLDA;
184    protected
185      FStatement: TFB25Statement;
186 +    FFirebird25ClientAPI: TFB25ClientAPI;
187      function GetTransactionSeqNo: integer; override;
188      procedure FreeXSQLDA;
189      function GetStatement: IStatement; override;
# Line 182 | Line 192 | type
192    public
193      constructor Create(aStatement: TFB25Statement);
194      destructor Destroy; override;
195 +    function CanChangeMetaData: boolean; override;
196      function CheckStatementStatus(Request: TStatementStatus): boolean; override;
197      function ColumnsInUseCount: integer; override;
198      function GetTransaction: TFB25Transaction; virtual;
# Line 211 | Line 222 | type
222      procedure Bind;
223      function GetTransaction: TFB25Transaction; override;
224      procedure GetData(index: integer; var aIsNull: boolean; var len: short;
225 <      var data: PChar); override;
225 >      var data: PByte); override;
226      function IsInputDataArea: boolean; override;
227    end;
228  
# Line 225 | Line 236 | type
236      constructor Create(aResults: TIBXOUTPUTSQLDA);
237      destructor Destroy; override;
238      {IResultSet}
239 <    function FetchNext: boolean;
240 <    function GetCursorName: string;
239 >    function FetchNext: boolean; {fetch next record}
240 >    function FetchPrior: boolean; {fetch previous record}
241 >    function FetchFirst:boolean; {fetch first record}
242 >    function FetchLast: boolean; {fetch last record}
243 >    function FetchAbsolute(position: Integer): boolean; {fetch record by its absolute position in result set}
244 >    function FetchRelative(offset: Integer): boolean; {fetch record by position relative to current}
245 >    function GetCursorName: AnsiString;
246      function GetTransaction: ITransaction; override;
247      function IsEof: boolean;
248 +    function IsBof: boolean;
249      procedure Close;
250    end;
251  
# Line 238 | Line 255 | type
255    private
256      FDBHandle: TISC_DB_HANDLE;
257      FHandle: TISC_STMT_HANDLE;
258 +    FFirebird25ClientAPI: TFB25ClientAPI;
259      FSQLParams: TIBXINPUTSQLDA;
260      FSQLRecord: TIBXOUTPUTSQLDA;
261 <    FCursor: String;               { Cursor name...}
261 >    FCursor: AnsiString;               { Cursor name...}
262      FCursorSeqNo: integer;
263      procedure GetPerfCounters(var counters: TPerfStatistics);
264    protected
265      procedure CheckHandle; override;
266      procedure GetDsqlInfo(info_request: byte; buffer: ISQLInfoResults); override;
267 <    procedure InternalPrepare; override;
267 >    function GetStatementIntf: IStatement; override;
268 >    procedure InternalPrepare(CursorName: AnsiString=''); override;
269      function InternalExecute(aTransaction: ITransaction): IResults; override;
270 <    function InternalOpenCursor(aTransaction: ITransaction): IResultSet; override;
270 >    function InternalOpenCursor(aTransaction: ITransaction; Scrollable: boolean): IResultSet; override;
271 >    procedure ProcessSQL(sql: AnsiString; GenerateParamNames: boolean; var processedSQL: AnsiString); override;
272      procedure FreeHandle; override;
273      procedure InternalClose(Force: boolean); override;
274    public
275      constructor Create(Attachment: TFB25Attachment; Transaction: ITransaction;
276 <      sql: string; aSQLDialect: integer);
276 >      sql: AnsiString; aSQLDialect: integer; CursorName: AnsiString='');
277      constructor CreateWithParameterNames(Attachment: TFB25Attachment;
278 <      Transaction: ITransaction; sql: string; aSQLDialect: integer; GenerateParamNames: boolean);
278 >      Transaction: ITransaction; sql: AnsiString; aSQLDialect: integer; GenerateParamNames: boolean;
279 >      CaseSensitiveParams: boolean=false; CursorName: AnsiString='');
280      destructor Destroy; override;
281      function FetchNext: boolean;
282  
# Line 263 | Line 284 | type
284      {IStatement}
285      function GetSQLParams: ISQLParams; override;
286      function GetMetaData: IMetaData; override;
287 <    function GetPlan: String;
287 >    function GetPlan: AnsiString;
288      function IsPrepared: boolean;
289      function CreateBlob(column: TColumnMetaData): IBlob; override;
290      function CreateArray(column: TColumnMetaData): IArray; override;
# Line 293 | Line 314 | begin
314      result := 0;
315   end;
316  
317 < function TIBXSQLVAR.GetAliasName: string;
317 > function TIBXSQLVAR.GetAliasName: AnsiString;
318   begin
319    result := strpas(FXSQLVAR^.aliasname);
320   end;
321  
322 < function TIBXSQLVAR.GetFieldName: string;
322 > function TIBXSQLVAR.GetFieldName: AnsiString;
323   begin
324    result := strpas(FXSQLVAR^.sqlname);
325   end;
326  
327 < function TIBXSQLVAR.GetOwnerName: string;
327 > function TIBXSQLVAR.GetOwnerName: AnsiString;
328   begin
329    result := strpas(FXSQLVAR^.ownname);
330   end;
331  
332 < function TIBXSQLVAR.GetRelationName: string;
332 > function TIBXSQLVAR.GetRelationName: AnsiString;
333   begin
334    result := strpas(FXSQLVAR^.relname);
335   end;
# Line 332 | Line 353 | begin
353    SQL_BLOB:
354      if (SQLSubType = 1)  then
355        {see http://firebirdsql.org/rlsnotesh/rlsnotes210.html}
356 <      result := FXSQLVAR^.sqlscale;
356 >      result := FXSQLVAR^.sqlscale and $FF;
357  
358    SQL_ARRAY:
359      if (GetRelationName <> '') and (GetFieldName <> '') then
# Line 343 | Line 364 | end;
364   function TIBXSQLVAR.GetCodePage: TSystemCodePage;
365   begin
366    result := CP_NONE;
367 <  with FirebirdClientAPI do
367 >  with Statement.GetAttachment do
368       CharSetID2CodePage(GetCharSetID,result);
369   end;
370  
371 + function TIBXSQLVAR.GetCharSetWidth: integer;
372 + begin
373 +  result := 1;
374 +  with Statement.GetAttachment DO
375 +    CharSetWidth(GetCharSetID,result);
376 + end;
377 +
378   function TIBXSQLVAR.GetIsNull: Boolean;
379   begin
380    result := IsNullable and (FNullIndicator = -1);
# Line 357 | Line 385 | begin
385    result := (FXSQLVAR^.sqltype and 1 = 1);
386   end;
387  
388 < function TIBXSQLVAR.GetSQLData: PChar;
388 > function TIBXSQLVAR.GetSQLData: PByte;
389   begin
390    Result := FXSQLVAR^.sqldata;
391   end;
# Line 367 | Line 395 | begin
395    Result := FXSQLVAR^.sqllen;
396   end;
397  
398 + function TIBXSQLVAR.GetSize: cardinal;
399 + begin
400 +  Result := FMetadataSize;
401 + end;
402 +
403 + function TIBXSQLVAR.GetAttachment: IAttachment;
404 + begin
405 +  Result := FStatement.GetAttachment;
406 + end;
407 +
408   function TIBXSQLVAR.GetArrayMetaData: IArrayMetaData;
409   begin
410    if GetSQLType <> SQL_ARRAY then
# Line 392 | Line 430 | begin
430    Result := FBlobMetaData;
431   end;
432  
433 < function TIBXSQLVAR.GetAsArray(Array_ID: TISC_QUAD): IArray;
433 > function TIBXSQLVAR.GetAsArray: IArray;
434   begin
435    if SQLType <> SQL_ARRAY then
436      IBError(ibxeInvalidDataConversion,[nil]);
# Line 401 | Line 439 | begin
439      Result := nil
440    else
441    begin
442 <    if FArray = nil then
443 <      FArray := TFB25Array.Create(FStatement.GetAttachment as TFB25Attachment,
442 >    if FArrayIntf = nil then
443 >      FArrayIntf := TFB25Array.Create(FStatement.GetAttachment as TFB25Attachment,
444                                    TIBXSQLDA(Parent).GetTransaction,
445 <                                  GetArrayMetaData,Array_ID);
446 <    Result := FArray;
445 >                                  GetArrayMetaData,PISC_QUAD(SQLData)^);
446 >    Result := FArrayIntf;
447    end;
448   end;
449  
# Line 438 | Line 476 | procedure TIBXSQLVAR.Initialize;
476   begin
477    inherited Initialize;
478    FOwnsSQLData := true;
479 <  with FirebirdClientAPI, FXSQLVar^ do
479 >  with FFirebird25ClientAPI, FXSQLVar^ do
480    begin
481 +    FMetadataSize := sqllen;
482      case sqltype and (not 1) of
483        SQL_TEXT, SQL_TYPE_DATE, SQL_TYPE_TIME, SQL_TIMESTAMP,
484        SQL_BLOB, SQL_ARRAY, SQL_QUAD, SQL_SHORT, SQL_BOOLEAN,
# Line 465 | Line 504 | begin
504      else
505        sqlInd :=  nil;
506    end;
507 +  SaveMetaData;
508   end;
509  
510   procedure TIBXSQLVAR.SetIsNull(Value: Boolean);
# Line 499 | Line 539 | begin
539        FXSQLVAR^.sqlind := nil;
540      end;
541    end;
542 +  Changed;
543   end;
544  
545 < procedure TIBXSQLVAR.SetSQLData(AValue: PChar; len: cardinal);
545 > procedure TIBXSQLVAR.SetSQLData(AValue: PByte; len: cardinal);
546   begin
547    if FOwnsSQLData then
548      FreeMem(FXSQLVAR^.sqldata);
549    FXSQLVAR^.sqldata := AValue;
550    FXSQLVAR^.sqllen := len;
551    FOwnsSQLData := false;
552 +  Changed;
553   end;
554  
555   procedure TIBXSQLVAR.SetScale(aValue: integer);
556   begin
557    FXSQLVAR^.sqlscale := aValue;
558 +  Changed;
559   end;
560  
561   procedure TIBXSQLVAR.SetDataLength(len: cardinal);
# Line 520 | Line 563 | begin
563    if not FOwnsSQLData then
564      FXSQLVAR^.sqldata := nil;
565    FXSQLVAR^.sqllen := len;
566 <  with FirebirdClientAPI do
566 >  with FFirebird25ClientAPI do
567      IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
568    FOwnsSQLData := true;
569 +  Changed;
570   end;
571  
572   procedure TIBXSQLVAR.SetSQLType(aValue: cardinal);
573   begin
574    FXSQLVAR^.sqltype := aValue or (FXSQLVAR^.sqltype and 1);
575 +  Changed;
576   end;
577  
578   procedure TIBXSQLVAR.SetCharSetID(aValue: cardinal);
579   begin
580    if aValue <> GetCharSetID then
581 <  case SQLType of
582 <  SQL_VARYING, SQL_TEXT:
583 <      FXSQLVAR^.sqlsubtype := (aValue and $FF) or (FXSQLVAR^.sqlsubtype and not $FF);
584 <
585 <  SQL_BLOB,
586 <  SQL_ARRAY:
587 <    IBError(ibxeInvalidDataConversion,[nil]);
581 >  begin
582 >    case SQLType of
583 >    SQL_VARYING, SQL_TEXT:
584 >        FXSQLVAR^.sqlsubtype := (aValue and $FF) or (FXSQLVAR^.sqlsubtype and not $FF);
585 >
586 >    SQL_BLOB,
587 >    SQL_ARRAY:
588 >      IBError(ibxeInvalidDataConversion,[nil]);
589 >    end;
590 >  Changed;
591    end;
592   end;
593  
594 + function TIBXSQLVAR.GetDefaultTextSQLType: cardinal;
595 + begin
596 +  Result := SQL_TEXT;
597 + end;
598 +
599   constructor TIBXSQLVAR.Create(aParent: TIBXSQLDA; aIndex: integer);
600   begin
601    inherited Create(aParent,aIndex);
602    FStatement := aParent.Statement;
603 +  FFirebird25ClientAPI := aParent.FFirebird25ClientAPI;
604   end;
605  
606   procedure TIBXSQLVAR.FreeSQLData;
# Line 561 | Line 615 | procedure TIBXSQLVAR.RowChange;
615   begin
616    inherited RowChange;
617    FBlob := nil;
564  FArray := nil;
618   end;
619  
620  
# Line 590 | Line 643 | begin
643        FResults.Column[i].RowChange;
644   end;
645  
646 < function TResultSet.GetCursorName: string;
646 > function TResultSet.FetchPrior: boolean;
647 > begin
648 >  IBError(ibxeNoScrollableCursors,[]);
649 > end;
650 >
651 > function TResultSet.FetchFirst: boolean;
652 > begin
653 >  IBError(ibxeNoScrollableCursors,[]);
654 > end;
655 >
656 > function TResultSet.FetchLast: boolean;
657 > begin
658 >  IBError(ibxeNoScrollableCursors,[]);
659 > end;
660 >
661 > function TResultSet.FetchAbsolute(position: Integer): boolean;
662 > begin
663 >  IBError(ibxeNoScrollableCursors,[]);
664 > end;
665 >
666 > function TResultSet.FetchRelative(offset: Integer): boolean;
667 > begin
668 >  IBError(ibxeNoScrollableCursors,[]);
669 > end;
670 >
671 > function TResultSet.GetCursorName: AnsiString;
672   begin
673    Result := FResults.FStatement.FCursor;
674   end;
# Line 605 | Line 683 | begin
683    Result := FResults.FStatement.FEof;
684   end;
685  
686 + function TResultSet.IsBof: boolean;
687 + begin
688 +  Result := FResults.FStatement.FBof;
689 + end;
690 +
691   procedure TResultSet.Close;
692   begin
693    if FCursorSeqNo = FResults.FStatement.FCursorSeqNo then
# Line 617 | Line 700 | procedure TIBXINPUTSQLDA.Bind;
700   begin
701    if Count = 0 then
702      Count := 1;
703 <  with Firebird25ClientAPI do
703 >  with FFirebird25ClientAPI do
704    begin
705      if (FXSQLDA <> nil) then
706         if isc_dsql_describe_bind(StatusVector, @(FStatement.Handle), FStatement.SQLDialect,
# Line 649 | Line 732 | procedure TIBXOUTPUTSQLDA.Bind;
732   begin
733    { Allocate an initial output descriptor (with one column) }
734    Count := 1;
735 <  with Firebird25ClientAPI do
735 >  with FFirebird25ClientAPI do
736    begin
737      { Using isc_dsql_describe, get the right size for the columns... }
738      if isc_dsql_describe(StatusVector, @(FStatement.Handle), FStatement.SQLDialect, FXSQLDA) > 0 then
# Line 675 | Line 758 | begin
758   end;
759  
760   procedure TIBXOUTPUTSQLDA.GetData(index: integer; var aIsNull:boolean; var len: short;
761 <  var data: PChar);
761 >  var data: PByte);
762   begin
763    with TIBXSQLVAR(Column[index]), FXSQLVAR^ do
764    begin
# Line 684 | Line 767 | begin
767      len := sqllen;
768      if not IsNull and ((sqltype and (not 1)) = SQL_VARYING) then
769      begin
770 <      with FirebirdClientAPI do
770 >      with FFirebird25ClientAPI do
771          len := DecodeInteger(data,2);
772        Inc(data,2);
773      end;
# Line 701 | Line 784 | constructor TIBXSQLDA.Create(aStatement:
784   begin
785    inherited Create;
786    FStatement := aStatement;
787 +  FFirebird25ClientAPI := aStatement.FFirebird25ClientAPI;
788    FSize := 0;
789   //  writeln('Creating ',ClassName);
790   end;
# Line 712 | Line 796 | begin
796    inherited Destroy;
797   end;
798  
799 + function TIBXSQLDA.CanChangeMetaData: boolean;
800 + begin
801 +  Result := true;
802 + end;
803 +
804   function TIBXSQLDA.CheckStatementStatus(Request: TStatementStatus): boolean;
805   begin
806    Result := false;
# Line 787 | Line 876 | begin
876        OldSize := 0;
877      if Count > FSize then
878      begin
879 <      Firebird25ClientAPI.IBAlloc(FXSQLDA, OldSize, XSQLDA_LENGTH(Count));
879 >      FFirebird25ClientAPI.IBAlloc(FXSQLDA, OldSize, XSQLDA_LENGTH(Count));
880        SetLength(FColumnList, FCount);
881        FXSQLDA^.version := SQLDA_VERSION1;
882        p := @FXSQLDA^.sqlvar[0];
# Line 796 | Line 885 | begin
885          if i >= FSize then
886            FColumnList[i] := TIBXSQLVAR.Create(self,i);
887          TIBXSQLVAR(Column[i]).FXSQLVAR := p;
888 <        p := Pointer(PChar(p) + sizeof(FXSQLDA^.sqlvar));
888 >        p := Pointer(PAnsiChar(p) + sizeof(FXSQLDA^.sqlvar));
889        end;
890        FSize := inherited Count;
891      end;
# Line 850 | Line 939 | begin
939    {$ELSE}
940    counters[psUserTime] := 0;
941    {$ENDIF}
942 <  counters[psRealTime] := Int64(TimeStampToMSecs(DateTimeToTimeStamp(Now)));
942 >  counters[psRealTime] := TimeStampToMSecs(DateTimeToTimeStamp(Now));
943  
944    DBInfo := GetAttachment.GetDBInformation([isc_info_reads,isc_info_writes,
945           isc_info_fetches, isc_info_num_buffers, isc_info_current_memory,
# Line 885 | Line 974 | end;
974   procedure TFB25Statement.GetDsqlInfo(info_request: byte; buffer: ISQLInfoResults
975    );
976   begin
977 <  with Firebird25ClientAPI, buffer as TSQLInfoResultsBuffer do
977 >  with FFirebird25ClientAPI, buffer as TSQLInfoResultsBuffer do
978    if isc_dsql_sql_info(StatusVector, @(FHandle), 1, @info_request,
979                       GetBufSize, Buffer) > 0 then
980      IBDatabaseError;
981   end;
982  
983 < procedure TFB25Statement.InternalPrepare;
983 > function TFB25Statement.GetStatementIntf: IStatement;
984 > begin
985 >  Result := self;
986 > end;
987 >
988 > procedure TFB25Statement.InternalPrepare(CursorName: AnsiString);
989   var
990 +  GUID: TGUID;
991    RB: ISQLInfoResults;
992    TRHandle: TISC_TR_HANDLE;
993   begin
994    if FPrepared then
995      Exit;
996 +
997    if (FSQL = '') then
998      IBError(ibxeEmptyQuery, [nil]);
999 +
1000 +  FCursor := CursorName;
1001 +  if FCursor = '' then
1002 +  begin
1003 +    CreateGuid(GUID);
1004 +    FCursor := GUIDToString(GUID);
1005 +  end;
1006 +
1007    try
1008      CheckTransaction(FTransactionIntf);
1009 <    with Firebird25ClientAPI do
1009 >    with FFirebird25ClientAPI do
1010      begin
1011        Call(isc_dsql_alloc_statement2(StatusVector, @(FDBHandle),
1012                                        @FHandle), True);
# Line 910 | Line 1014 | begin
1014        if FHasParamNames then
1015        begin
1016          if FProcessedSQL = '' then
1017 <          FSQLParams.PreprocessSQL(FSQL,FGenerateParamNames,FProcessedSQL);
1017 >          ProcessSQL(FSQL,FGenerateParamNames,FProcessedSQL);
1018          Call(isc_dsql_prepare(StatusVector, @(TRHandle), @FHandle, 0,
1019 <                 PChar(FProcessedSQL), FSQLDialect, nil), True);
1019 >                 PAnsiChar(FProcessedSQL), FSQLDialect, nil), True);
1020        end
1021        else
1022          Call(isc_dsql_prepare(StatusVector, @(TRHandle), @FHandle, 0,
1023 <                 PChar(FSQL), FSQLDialect, nil), True);
1023 >                 PAnsiChar(FSQL), FSQLDialect, nil), True);
1024      end;
1025 +
1026      { After preparing the statement, query the stmt type and possibly
1027        create a FSQLRecord "holder" }
1028      { Get the type of the statement }
# Line 927 | Line 1032 | begin
1032      else
1033        FSQLStatementType := SQLUnknown;
1034  
1035 +    if FSQLStatementType = SQLSelect then
1036 +    with FFirebird25ClientAPI do
1037 +      Call(
1038 +        isc_dsql_set_cursor_name(StatusVector, @FHandle, PAnsiChar(FCursor), 0),
1039 +        True);
1040 +
1041      case FSQLStatementType of
1042        SQLGetSegment,
1043        SQLPutSegment,
# Line 954 | Line 1065 | begin
1065        if (FHandle <> nil) then
1066          FreeHandle;
1067        if E is EIBInterBaseError then
1068 <        raise EIBInterBaseError.Create(EIBInterBaseError(E).SQLCode,
1069 <                                       EIBInterBaseError(E).IBErrorCode,
959 <                                       EIBInterBaseError(E).Message +
960 <                                       sSQLErrorSeparator + FSQL)
961 <      else
962 <        raise;
1068 >        E.Message := E.Message + sSQLErrorSeparator + FSQL;
1069 >      raise;
1070      end;
1071    end;
1072    FPrepared := true;
# Line 991 | Line 1098 | begin
1098    CheckHandle;
1099    if aTransaction <> FTransactionIntf then
1100      AddMonitor(aTransaction as TFB25Transaction);
1101 <  if (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB25transaction).TransactionSeqNo) then
1101 >  if FStaleReferenceChecks and (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB25transaction).TransactionSeqNo) then
1102      IBError(ibxeInterfaceOutofDate,[nil]);
1103  
1104    try
1105      TRHandle := (aTransaction as TFB25Transaction).Handle;
1106 <    with Firebird25ClientAPI do
1106 >    with FFirebird25ClientAPI do
1107      begin
1108        if FCollectStatistics then
1109          GetPerfCounters(FBeforeStats);
# Line 1035 | Line 1142 | begin
1142         RemoveMonitor(aTransaction as TFB25Transaction);
1143    end;
1144    FExecTransactionIntf := aTransaction;
1145 +  FSQLRecord.FTransaction := aTransaction as TFB25Transaction;
1146 +  FSQLRecord.FTransactionSeqNo := FSQLRecord.FTransaction.TransactionSeqNo;
1147    Inc(FChangeSeqNo);
1148   end;
1149  
1150 < function TFB25Statement.InternalOpenCursor(aTransaction: ITransaction
1151 <  ): IResultSet;
1150 > function TFB25Statement.InternalOpenCursor(aTransaction: ITransaction;
1151 >  Scrollable: boolean): IResultSet;
1152   var TRHandle: TISC_TR_HANDLE;
1044    GUID : TGUID;
1153   begin
1154    if FSQLStatementType <> SQLSelect then
1155     IBError(ibxeIsASelectStatement,[]);
1156  
1157 +  if Scrollable then
1158 +    IBError(ibxeNoScrollableCursors,[]);
1159 +
1160   CheckTransaction(aTransaction);
1161    if not FPrepared then
1162      InternalPrepare;
1163    CheckHandle;
1164    if aTransaction <> FTransactionIntf then
1165      AddMonitor(aTransaction as TFB25Transaction);
1166 <  if (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB25transaction).TransactionSeqNo) then
1166 >  if FStaleReferenceChecks and (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB25transaction).TransactionSeqNo) then
1167      IBError(ibxeInterfaceOutofDate,[nil]);
1168  
1169 < with Firebird25ClientAPI do
1169 > with FFirebird25ClientAPI do
1170   begin
1171     if FCollectStatistics then
1172       GetPerfCounters(FBeforeStats);
# Line 1067 | Line 1178 | begin
1178                         SQLDialect,
1179                         FSQLParams.AsXSQLDA,
1180                         nil), True);
1070   if FCursor = '' then
1071   begin
1072     CreateGuid(GUID);
1073     FCursor := GUIDToString(GUID);
1074     Call(
1075       isc_dsql_set_cursor_name(StatusVector, @FHandle, PChar(FCursor), 0),
1076       True);
1077   end;
1181  
1182     if FCollectStatistics then
1183     begin
# Line 1094 | Line 1197 | begin
1197   Inc(FChangeSeqNo);
1198   end;
1199  
1200 + procedure TFB25Statement.ProcessSQL(sql: AnsiString; GenerateParamNames: boolean;
1201 +  var processedSQL: AnsiString);
1202 + begin
1203 +  FSQLParams.PreprocessSQL(sql,GenerateParamNames, processedSQL);
1204 + end;
1205 +
1206   procedure TFB25Statement.FreeHandle;
1207   var
1208    isc_res: ISC_STATUS;
# Line 1102 | Line 1211 | begin
1211    ReleaseInterfaces;
1212    try
1213      if FHandle <> nil then
1214 <    with Firebird25ClientAPI do
1214 >    with FFirebird25ClientAPI do
1215      begin
1216        isc_res :=
1217          Call(isc_dsql_free_statement(StatusVector, @FHandle, DSQL_drop), False);
# Line 1122 | Line 1231 | var
1231   begin
1232    if (FHandle <> nil) and (SQLStatementType = SQLSelect) and FOpen then
1233    try
1234 <    with Firebird25ClientAPI do
1234 >    with FFirebird25ClientAPI do
1235      begin
1236        isc_res := Call(
1237                     isc_dsql_free_statement(StatusVector, @FHandle, DSQL_close),
# Line 1133 | Line 1242 | begin
1242          IBDatabaseError;
1243      end;
1244    finally
1245 <    if (FSQLRecord.FTransaction <> nil) and (FSQLRecord.FTransaction <> FTransactionIntf) then
1245 >    if (FSQLRecord.FTransaction <> nil) and (FSQLRecord.FTransaction <> (FTransactionIntf as TFB25Transaction)) then
1246        RemoveMonitor(FSQLRecord.FTransaction);
1247      FOpen := False;
1248      FExecTransactionIntf := nil;
# Line 1143 | Line 1252 | begin
1252   end;
1253  
1254   constructor TFB25Statement.Create(Attachment: TFB25Attachment;
1255 <  Transaction: ITransaction; sql: string; aSQLDialect: integer);
1255 >  Transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
1256 >  CursorName: AnsiString);
1257   begin
1258    inherited Create(Attachment,Transaction,sql,aSQLDialect);
1259    FDBHandle := Attachment.Handle;
1260 +  FFirebird25ClientAPI := Attachment.Firebird25ClientAPI;
1261 +  OnDatabaseError := FFirebird25ClientAPI.IBDataBaseError;
1262    FSQLParams := TIBXINPUTSQLDA.Create(self);
1263    FSQLRecord := TIBXOUTPUTSQLDA.Create(self);
1264 <  InternalPrepare;
1264 >  InternalPrepare(CursorName);
1265   end;
1266  
1267 < constructor TFB25Statement.CreateWithParameterNames(Attachment: TFB25Attachment;
1268 <  Transaction: ITransaction; sql: string; aSQLDialect: integer;
1269 <  GenerateParamNames: boolean);
1267 > constructor TFB25Statement.CreateWithParameterNames(
1268 >  Attachment: TFB25Attachment; Transaction: ITransaction; sql: AnsiString;
1269 >  aSQLDialect: integer; GenerateParamNames: boolean;
1270 >  CaseSensitiveParams: boolean; CursorName: AnsiString);
1271   begin
1272    inherited CreateWithParameterNames(Attachment,Transaction,sql,aSQLDialect,GenerateParamNames);
1273    FDBHandle := Attachment.Handle;
1274 +  FFirebird25ClientAPI := Attachment.Firebird25ClientAPI;
1275 +  OnDatabaseError := FFirebird25ClientAPI.IBDataBaseError;
1276    FSQLParams := TIBXINPUTSQLDA.Create(self);
1277 +  FSQLParams.CaseSensitiveParams := CaseSensitiveParams;
1278    FSQLRecord := TIBXOUTPUTSQLDA.Create(self);
1279 <  InternalPrepare;
1279 >  InternalPrepare(CursorName);
1280   end;
1281  
1282   destructor TFB25Statement.Destroy;
# Line 1180 | Line 1296 | begin
1296    if FEOF then
1297      IBError(ibxeEOF,[nil]);
1298  
1299 <  with Firebird25ClientAPI do
1299 >  with FFirebird25ClientAPI do
1300    begin
1301      { Go to the next record... }
1302      fetch_res :=
# Line 1206 | Line 1322 | begin
1322        FBOF := false;
1323        result := true;
1324      end;
1325 +    if FCollectStatistics then
1326 +    begin
1327 +      GetPerfCounters(FAfterStats);
1328 +      FStatisticsAvailable := true;
1329 +    end;
1330    end;
1331    FSQLRecord.RowChange;
1332    if FEOF then
# Line 1228 | Line 1349 | begin
1349    Result := TMetaData(GetInterface(1));
1350   end;
1351  
1352 < function TFB25Statement.GetPlan: String;
1352 > function TFB25Statement.GetPlan: AnsiString;
1353   var
1354      RB: ISQLInfoResults;
1355   begin
# Line 1238 | Line 1359 | begin
1359      result := ''
1360    else
1361    begin
1362 <    RB := TSQLInfoResultsBuffer.Create(4*4096);
1362 >    RB := TSQLInfoResultsBuffer.Create(FFirebird25ClientAPI,4*4096);
1363      GetDsqlInfo(isc_info_sql_get_plan,RB);
1364       if RB.Count > 0 then
1365       Result := RB[0].GetAsString;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines