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 60 by tony, Mon Mar 27 15:21:02 2017 UTC vs.
Revision 349 by tony, Mon Oct 18 08:39:40 2021 UTC

# Line 78 | Line 78 | uses
78    FB30Attachment,IBExternals, FBSQLData, FBOutputBlock, FBActivityMonitor;
79  
80   type
81
81    TFB30Statement = class;
82    TIBXSQLDA = class;
83  
# Line 87 | Line 86 | type
86    TIBXSQLVAR = class(TSQLVarData)
87    private
88      FStatement: TFB30Statement;
89 +    FFirebird30ClientAPI: TFB30ClientAPI;
90      FBlob: IBlob;             {Cache references}
91      FArray: IArray;
92      FNullIndicator: short;
# Line 100 | Line 100 | type
100      FSQLData: PByte; {Address of SQL Data in Message Buffer}
101      FSQLNullIndicator: PShort; {Address of null indicator}
102      FDataLength: integer;
103 +    FMetadataSize: integer;
104      FNullable: boolean;
105      FScale: integer;
106      FCharSetID: cardinal;
# Line 107 | Line 108 | type
108      FFieldName: AnsiString;
109  
110      protected
111 +     function CanChangeSQLType: boolean;
112       function GetSQLType: cardinal; override;
113       function GetSubtype: integer; override;
114       function GetAliasName: AnsiString;  override;
# Line 116 | Line 118 | type
118       function GetScale: integer; override;
119       function GetCharSetID: cardinal; override;
120       function GetCodePage: TSystemCodePage; override;
121 +     function GetCharSetWidth: integer; override;
122       function GetIsNull: Boolean;   override;
123       function GetIsNullable: boolean; override;
124       function GetSQLData: PByte;  override;
125       function GetDataLength: cardinal; override;
126 +     function GetSize: cardinal; override;
127 +     function GetAttachment: IAttachment; override;
128 +     function GetDefaultTextSQLType: cardinal; override;
129       procedure SetIsNull(Value: Boolean); override;
130       procedure SetIsNullable(Value: Boolean);  override;
131       procedure SetSQLData(AValue: PByte; len: cardinal); override;
# Line 127 | Line 133 | type
133       procedure SetDataLength(len: cardinal); override;
134       procedure SetSQLType(aValue: cardinal); override;
135       procedure SetCharSetID(aValue: cardinal); override;
136 <
136 >     procedure SetMetaSize(aValue: cardinal); override;
137    public
138      constructor Create(aParent: TIBXSQLDA; aIndex: integer);
139      procedure Changed; override;
140 +    procedure InitColumnMetaData(aMetaData: Firebird.IMessageMetadata);
141 +    procedure ColumnSQLDataInit;
142      procedure RowChange; override;
143      procedure FreeSQLData;
144      function GetAsArray(Array_ID: TISC_QUAD): IArray; override;
# Line 148 | Line 156 | type
156      FSize: Integer;  {Number of TIBXSQLVARs in column list}
157      FMetaData: Firebird.IMessageMetadata;
158      FTransactionSeqNo: integer;
159 <  protected
159 > protected
160      FStatement: TFB30Statement;
161 +    FFirebird30ClientAPI: TFB30ClientAPI;
162      function GetTransactionSeqNo: integer; override;
163      procedure FreeXSQLDA; virtual;
164      function GetStatement: IStatement; override;
# Line 164 | Line 173 | type
173      function GetTransaction: TFB30Transaction; virtual;
174      procedure Initialize; override;
175      function StateChanged(var ChangeSeqNo: integer): boolean; override;
176 +    function CanChangeMetaData: boolean; override;
177      property MetaData: Firebird.IMessageMetadata read FMetaData;
178      property Count: Integer read FCount write SetCount;
179      property Statement: TFB30Statement read FStatement;
# Line 177 | Line 187 | type
187      FMsgLength: integer; {Message Buffer length}
188      FCurMetaData: Firebird.IMessageMetadata;
189      procedure FreeMessageBuffer;
190 +    procedure FreeCurMetaData;
191      function GetMessageBuffer: PByte;
192      function GetMetaData: Firebird.IMessageMetadata;
193      function GetModified: Boolean;
194      function GetMsgLength: integer;
195 +    procedure BuildMetadata;
196      procedure PackBuffer;
197    protected
198      procedure FreeXSQLDA; override;
# Line 189 | Line 201 | type
201      destructor Destroy; override;
202      procedure Bind(aMetaData: Firebird.IMessageMetadata);
203      procedure Changed; override;
204 +    procedure ReInitialise;
205      function IsInputDataArea: boolean; override;
206      property MetaData: Firebird.IMessageMetadata read GetMetaData;
207      property MessageBuffer: PByte read GetMessageBuffer;
# Line 230 | Line 243 | type
243      procedure Close;
244    end;
245  
246 +  { TBatchCompletion }
247 +
248 +  TBatchCompletion = class(TInterfaceOwner,IBatchCompletion)
249 +  private
250 +    FCompletionState: Firebird.IBatchCompletionState;
251 +    FFirebird30ClientAPI: TFB30ClientAPI;
252 +  public
253 +    constructor Create(api: TFB30ClientAPI; cs: IBatchCompletionState);
254 +    destructor Destroy; override;
255 +    {IBatchCompletion}
256 +    function getErrorStatus(var RowNo: integer; var status: IStatus): boolean;
257 +    function getTotalProcessed: cardinal;
258 +    function getState(updateNo: cardinal): TBatchCompletionState;
259 +    function getStatusMessage(updateNo: cardinal): AnsiString;
260 +    function getUpdated: integer;
261 +  end;
262 +
263    { TFB30Statement }
264  
265    TFB30Statement = class(TFBStatement,IStatement)
266    private
267      FStatementIntf: Firebird.IStatement;
268 +    FFirebird30ClientAPI: TFB30ClientAPI;
269      FSQLParams: TIBXINPUTSQLDA;
270      FSQLRecord: TIBXOUTPUTSQLDA;
271      FResultSet: Firebird.IResultSet;
272      FCursorSeqNo: integer;
273 +    FBatch: Firebird.IBatch;
274 +    FBatchCompletion: IBatchCompletion;
275 +    FBatchRowCount: integer;
276 +    FBatchBufferSize: integer;
277 +    FBatchBufferUsed: integer;
278    protected
279 +    procedure CheckChangeBatchRowLimit; override;
280      procedure CheckHandle; override;
281 +    procedure CheckBatchModeAvailable;
282      procedure GetDSQLInfo(info_request: byte; buffer: ISQLInfoResults); override;
283      procedure InternalPrepare; override;
284      function InternalExecute(aTransaction: ITransaction): IResults; override;
285      function InternalOpenCursor(aTransaction: ITransaction): IResultSet; override;
286 +    procedure ProcessSQL(sql: AnsiString; GenerateParamNames: boolean; var processedSQL: AnsiString); override;
287      procedure FreeHandle; override;
288      procedure InternalClose(Force: boolean); override;
289 +    function SavePerfStats(var Stats: TPerfStatistics): boolean;
290    public
291      constructor Create(Attachment: TFB30Attachment; Transaction: ITransaction;
292        sql: AnsiString; aSQLDialect: integer);
293      constructor CreateWithParameterNames(Attachment: TFB30Attachment; Transaction: ITransaction;
294 <      sql: AnsiString;  aSQLDialect: integer; GenerateParamNames: boolean =false);
294 >      sql: AnsiString;  aSQLDialect: integer; GenerateParamNames: boolean =false;
295 >      CaseSensitiveParams: boolean=false);
296      destructor Destroy; override;
297      function FetchNext: boolean;
298      property StatementIntf: Firebird.IStatement read FStatementIntf;
# Line 265 | Line 306 | type
306      function CreateBlob(column: TColumnMetaData): IBlob; override;
307      function CreateArray(column: TColumnMetaData): IArray; override;
308      procedure SetRetainInterfaces(aValue: boolean); override;
309 <
309 >    function IsInBatchMode: boolean; override;
310 >    function HasBatchMode: boolean; override;
311 >    procedure AddToBatch; override;
312 >    function ExecuteBatch(aTransaction: ITransaction
313 >      ): IBatchCompletion; override;
314 >    procedure CancelBatch; override;
315 >    function GetBatchCompletion: IBatchCompletion; override;
316   end;
317  
318   implementation
319  
320 < uses IBUtils, FBMessages, FBBLob, FB30Blob, variants,  FBArray, FB30Array;
320 > uses IBUtils, FBMessages, FBBlob, FB30Blob, variants,  FBArray, FB30Array;
321  
322   const
323    ISQL_COUNTERS = 'CurrentMemory, MaxMemory, RealTime, UserTime, Buffers, Reads, Writes, Fetches';
324  
325 + { EIBBatchCompletionError }
326 +
327 + { TBatchCompletion }
328 +
329 + constructor TBatchCompletion.Create(api: TFB30ClientAPI;
330 +  cs: IBatchCompletionState);
331 + begin
332 +  inherited Create;
333 +  FFirebird30ClientAPI := api;
334 +  FCompletionState := cs;
335 + end;
336 +
337 + destructor TBatchCompletion.Destroy;
338 + begin
339 +  if FCompletionState <> nil then
340 +  begin
341 +    FCompletionState.dispose;
342 +    FCompletionState := nil;
343 +  end;
344 +  inherited Destroy;
345 + end;
346 +
347 + function TBatchCompletion.getErrorStatus(var RowNo: integer; var status: IStatus
348 +  ): boolean;
349 + var i: integer;
350 +  upcount: cardinal;
351 +  state: integer;
352 +  FBStatus: Firebird.IStatus;
353 + begin
354 +  Result := false;
355 +  RowNo := -1;
356 +  FBStatus := nil;
357 +  with FFirebird30ClientAPI do
358 +  begin
359 +    upcount := FCompletionState.getSize(StatusIntf);
360 +    Check4DataBaseError;
361 +    for i := 0 to upcount - 1 do
362 +    begin
363 +      state := FCompletionState.getState(StatusIntf,i);
364 +      if state = Firebird.IBatchCompletionState.EXECUTE_FAILED then
365 +      begin
366 +        RowNo := i+1;
367 +        FBStatus := MasterIntf.getStatus;
368 +        try
369 +          FCompletionState.getStatus(StatusIntf,FBStatus,i);
370 +          Check4DataBaseError;
371 +        except
372 +          FBStatus.dispose;
373 +          raise
374 +        end;
375 +        status := TFB30StatusObject.Create(FFirebird30ClientAPI,FBStatus,
376 +                      Format(SBatchCompletionError,[RowNo]));
377 +        status.SetIBDataBaseErrorMessages(GetStatus.GetIBDataBaseErrorMessages);
378 +        Result := true;
379 +        break;
380 +      end;
381 +    end;
382 +  end;
383 + end;
384 +
385 + function TBatchCompletion.getTotalProcessed: cardinal;
386 + begin
387 +  with FFirebird30ClientAPI do
388 +  begin
389 +    Result := FCompletionState.getsize(StatusIntf);
390 +    Check4DataBaseError;
391 +  end;
392 + end;
393 +
394 + function TBatchCompletion.getState(updateNo: cardinal): TBatchCompletionState;
395 + var state: integer;
396 + begin
397 +  with FFirebird30ClientAPI do
398 +  begin
399 +    state := FCompletionState.getState(StatusIntf,updateNo);
400 +    Check4DataBaseError;
401 +    case state of
402 +      Firebird.IBatchCompletionState.EXECUTE_FAILED:
403 +        Result := bcExecuteFailed;
404 +
405 +      Firebird.IBatchCompletionState.SUCCESS_NO_INFO:
406 +        Result := bcSuccessNoInfo;
407 +
408 +     else
409 +        Result := bcNoMoreErrors;
410 +    end;
411 +  end;
412 + end;
413 +
414 + function TBatchCompletion.getStatusMessage(updateNo: cardinal): AnsiString;
415 + var status: Firebird.IStatus;
416 + begin
417 +  with FFirebird30ClientAPI do
418 +  begin
419 +    status := MasterIntf.getStatus;
420 +    FCompletionState.getStatus(StatusIntf,status,updateNo);
421 +    Check4DataBaseError;
422 +    Result := FormatFBStatus(status);
423 +  end;
424 + end;
425 +
426 + function TBatchCompletion.getUpdated: integer;
427 + var i: integer;
428 +    upcount: cardinal;
429 +    state: integer;
430 + begin
431 +  Result := 0;
432 +  with FFirebird30ClientAPI do
433 +  begin
434 +    upcount := FCompletionState.getSize(StatusIntf);
435 +    Check4DataBaseError;
436 +    for i := 0 to upcount -1  do
437 +    begin
438 +      state := FCompletionState.getState(StatusIntf,i);
439 +      if state = Firebird.IBatchCompletionState.EXECUTE_FAILED then
440 +          break;
441 +      Inc(Result);
442 +    end;
443 +  end;
444 + end;
445 +
446   { TIBXSQLVAR }
447  
448   procedure TIBXSQLVAR.Changed;
# Line 283 | Line 451 | begin
451    TIBXSQLDA(Parent).Changed;
452   end;
453  
454 + procedure TIBXSQLVAR.InitColumnMetaData(aMetaData: Firebird.IMessageMetadata);
455 + begin
456 +  with FFirebird30ClientAPI do
457 +  begin
458 +    FSQLType := aMetaData.getType(StatusIntf,Index);
459 +    Check4DataBaseError;
460 +    if FSQLType = SQL_BLOB then
461 +    begin
462 +      FSQLSubType := aMetaData.getSubType(StatusIntf,Index);
463 +      Check4DataBaseError;
464 +    end
465 +    else
466 +      FSQLSubType := 0;
467 +    FDataLength := aMetaData.getLength(StatusIntf,Index);
468 +    Check4DataBaseError;
469 +    FMetadataSize := FDataLength;
470 +    FRelationName := strpas(aMetaData.getRelation(StatusIntf,Index));
471 +    Check4DataBaseError;
472 +    FFieldName := strpas(aMetaData.getField(StatusIntf,Index));
473 +    Check4DataBaseError;
474 +    FNullable := aMetaData.isNullable(StatusIntf,Index);
475 +    Check4DataBaseError;
476 +    FScale := aMetaData.getScale(StatusIntf,Index);
477 +    Check4DataBaseError;
478 +    FCharSetID :=  aMetaData.getCharSet(StatusIntf,Index) and $FF;
479 +    Check4DataBaseError;
480 +  end;
481 + end;
482 +
483 + procedure TIBXSQLVAR.ColumnSQLDataInit;
484 + begin
485 +  FreeSQLData;
486 +  with FFirebird30ClientAPI do
487 +  begin
488 +    case SQLType of
489 +      SQL_TEXT, SQL_TYPE_DATE, SQL_TYPE_TIME, SQL_TIMESTAMP,
490 +      SQL_BLOB, SQL_ARRAY, SQL_QUAD, SQL_SHORT, SQL_BOOLEAN,
491 +      SQL_LONG, SQL_INT64, SQL_INT128, SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT,
492 +      SQL_TIMESTAMP_TZ, SQL_TIME_TZ, SQL_DEC_FIXED, SQL_DEC16, SQL_DEC34,
493 +      SQL_TIMESTAMP_TZ_EX, SQL_TIME_TZ_EX:
494 +      begin
495 +        if (FDataLength = 0) then
496 +          { Make sure you get a valid pointer anyway
497 +           select '' from foo }
498 +          IBAlloc(FSQLData, 0, 1)
499 +        else
500 +          IBAlloc(FSQLData, 0, FDataLength)
501 +      end;
502 +      SQL_VARYING:
503 +        IBAlloc(FSQLData, 0, FDataLength + 2);
504 +     else
505 +        IBError(ibxeUnknownSQLDataType, [SQLType and (not 1)])
506 +    end;
507 +    FOwnsSQLData := true;
508 +    FNullIndicator := -1;
509 +  end;
510 + end;
511 +
512 + function TIBXSQLVAR.CanChangeSQLType: boolean;
513 + begin
514 +  Result := Parent.CanChangeMetaData;
515 + end;
516 +
517   function TIBXSQLVAR.GetSQLType: cardinal;
518   begin
519    Result := FSQLType;
# Line 295 | Line 526 | end;
526  
527   function TIBXSQLVAR.GetAliasName: AnsiString;
528   begin
529 <  with Firebird30ClientAPI do
529 >  with FFirebird30ClientAPI do
530    begin
531      result := strpas(TIBXSQLDA(Parent).MetaData.getAlias(StatusIntf,Index));
532      Check4DataBaseError;
# Line 309 | Line 540 | end;
540  
541   function TIBXSQLVAR.GetOwnerName: AnsiString;
542   begin
543 <  with Firebird30ClientAPI do
543 >  with FFirebird30ClientAPI do
544    begin
545      result := strpas(TIBXSQLDA(Parent).MetaData.getOwner(StatusIntf,Index));
546      Check4DataBaseError;
# Line 328 | Line 559 | end;
559  
560   function TIBXSQLVAR.GetCharSetID: cardinal;
561   begin
562 <  result := 0;
562 >  result := 0; {NONE}
563    case SQLType of
564    SQL_VARYING, SQL_TEXT:
565        result := FCharSetID;
566  
567    SQL_BLOB:
568      if (SQLSubType = 1) then
569 <      result := FCharSetID;
569 >      result := FCharSetID
570 >    else
571 >      result := 1; {OCTETS}
572  
573    SQL_ARRAY:
574      if (FRelationName <> '') and (FFieldName <> '') then
# Line 343 | Line 576 | begin
576      else
577        result := FCharSetID;
578    end;
346  result := result;
579   end;
580  
581   function TIBXSQLVAR.GetCodePage: TSystemCodePage;
# Line 353 | Line 585 | begin
585       CharSetID2CodePage(GetCharSetID,result);
586   end;
587  
588 + function TIBXSQLVAR.GetCharSetWidth: integer;
589 + begin
590 +  result := 1;
591 +  with Statement.GetAttachment DO
592 +    CharSetWidth(GetCharSetID,result);
593 + end;
594 +
595   function TIBXSQLVAR.GetIsNull: Boolean;
596   begin
597    Result := IsNullable and (FSQLNullIndicator^ = -1);
# Line 373 | Line 612 | begin
612    Result := FDataLength;
613   end;
614  
615 + function TIBXSQLVAR.GetSize: cardinal;
616 + begin
617 +  Result := FMetadataSize;
618 + end;
619 +
620 + function TIBXSQLVAR.GetAttachment: IAttachment;
621 + begin
622 +  Result := FStatement.GetAttachment;
623 + end;
624 +
625   function TIBXSQLVAR.GetArrayMetaData: IArrayMetaData;
626   begin
627    if GetSQLType <> SQL_ARRAY then
# Line 422 | Line 671 | begin
671    end
672    else
673      FSQLNullIndicator := nil;
674 +  Changed;
675   end;
676  
677   procedure TIBXSQLVAR.SetSQLData(AValue: PByte; len: cardinal);
# Line 431 | Line 681 | begin
681    FSQLData := AValue;
682    FDataLength := len;
683    FOwnsSQLData := false;
684 +  Changed;
685   end;
686  
687   procedure TIBXSQLVAR.SetScale(aValue: integer);
688   begin
689    FScale := aValue;
690 +  Changed;
691   end;
692  
693   procedure TIBXSQLVAR.SetDataLength(len: cardinal);
# Line 443 | Line 695 | begin
695    if not FOwnsSQLData then
696      FSQLData := nil;
697    FDataLength := len;
698 <  with Firebird30ClientAPI do
698 >  with FFirebird30ClientAPI do
699      IBAlloc(FSQLData, 0, FDataLength);
700    FOwnsSQLData := true;
701 +  Changed;
702   end;
703  
704   procedure TIBXSQLVAR.SetSQLType(aValue: cardinal);
705   begin
706 +  if (FSQLType <> aValue) and not CanChangeSQLType then
707 +    IBError(ibxeSQLTypeUnchangeable,[TSQLDataItem.GetSQLTypeName(FSQLType),TSQLDataItem.GetSQLTypeName(aValue)]);
708    FSQLType := aValue;
709 +  Changed;
710   end;
711  
712   procedure TIBXSQLVAR.SetCharSetID(aValue: cardinal);
713   begin
714    FCharSetID := aValue;
715 +  Changed;
716 + end;
717 +
718 + procedure TIBXSQLVAR.SetMetaSize(aValue: cardinal);
719 + begin
720 +  if (aValue > FMetaDataSize) and not CanChangeSQLType then
721 +    IBError(ibxeCannotIncreaseMetadatasize,[FMetaDataSize,aValue]);
722 +  FMetaDataSize := aValue;
723 + end;
724 +
725 + function TIBXSQLVAR.GetDefaultTextSQLType: cardinal;
726 + begin
727 +  Result := SQL_VARYING;
728   end;
729  
730   constructor TIBXSQLVAR.Create(aParent: TIBXSQLDA; aIndex: integer);
731   begin
732    inherited Create(aParent,aIndex);
733    FStatement := aParent.Statement;
734 +  FFirebird30ClientAPI := aParent.FFirebird30ClientAPI;
735   end;
736  
737   procedure TIBXSQLVAR.RowChange;
# Line 586 | Line 856 | end;
856  
857   procedure TIBXINPUTSQLDA.FreeMessageBuffer;
858   begin
589  if FCurMetaData <> nil then
590  begin
591    FCurMetaData.release;
592    FCurMetaData := nil;
593  end;
859    if FMessageBuffer <> nil then
860    begin
861      FreeMem(FMessageBuffer);
# Line 599 | Line 864 | begin
864    FMsgLength := 0;
865   end;
866  
867 + procedure TIBXINPUTSQLDA.FreeCurMetaData;
868 + begin
869 +  if FCurMetaData <> nil then
870 +  begin
871 +    FCurMetaData.release;
872 +    FCurMetaData := nil;
873 +  end;
874 + end;
875 +
876   function TIBXINPUTSQLDA.GetMessageBuffer: PByte;
877   begin
878    PackBuffer;
# Line 607 | Line 881 | end;
881  
882   function TIBXINPUTSQLDA.GetMetaData: Firebird.IMessageMetadata;
883   begin
884 <  PackBuffer;
884 >  BuildMetadata;
885    Result := FCurMetaData;
886   end;
887  
# Line 617 | Line 891 | begin
891    Result := FMsgLength;
892   end;
893  
894 < procedure TIBXINPUTSQLDA.PackBuffer;
894 > procedure TIBXINPUTSQLDA.BuildMetadata;
895   var Builder: Firebird.IMetadataBuilder;
896      i: integer;
897   begin
898 <  if FMsgLength > 0 then Exit;
899 <
626 <  with Firebird30ClientAPI do
898 >  if (FCurMetaData = nil) and (Count > 0) then
899 >  with FFirebird30ClientAPI do
900    begin
901 <    Builder := inherited MetaData.getBuilder(StatusIntf);
901 >    Builder := FFirebird30ClientAPI.MasterIntf.getMetadataBuilder(StatusIntf,Count);
902      Check4DataBaseError;
903      try
904        for i := 0 to Count - 1 do
905        with TIBXSQLVar(Column[i]) do
906        begin
907 <        Builder.setType(StatusIntf,i,FSQLType);
907 >        Builder.setType(StatusIntf,i,FSQLType+1);
908          Check4DataBaseError;
909          Builder.setSubType(StatusIntf,i,FSQLSubType);
910          Check4DataBaseError;
911 <        Builder.setLength(StatusIntf,i,FDataLength);
911 > //        writeln('Column ',Name,' Type = ',TSQLDataItem.GetSQLTypeName(FSQLType),' Size = ',GetSize,' DataLength = ',GetDataLength);
912 >        if FSQLType = SQL_VARYING then
913 >        begin
914 >          {The datalength can be greater than the metadata size when SQLType has been overridden to text}
915 >          if (GetDataLength > GetSize) and CanChangeMetaData then
916 >            Builder.setLength(StatusIntf,i,GetDataLength)
917 >          else
918 >            Builder.setLength(StatusIntf,i,GetSize)
919 >        end
920 >        else
921 >          Builder.setLength(StatusIntf,i,GetDataLength);
922          Check4DataBaseError;
923          Builder.setCharSet(StatusIntf,i,GetCharSetID);
924          Check4DataBaseError;
# Line 647 | Line 930 | begin
930      finally
931        Builder.release;
932      end;
933 +  end;
934 + end;
935  
936 + procedure TIBXINPUTSQLDA.PackBuffer;
937 + var i: integer;
938 +    P: PByte;
939 + begin
940 +  BuildMetadata;
941 +
942 +  if (FMsgLength = 0) and (FCurMetaData <> nil) then
943 +  with FFirebird30ClientAPI do
944 +  begin
945      FMsgLength := FCurMetaData.getMessageLength(StatusIntf);
946      Check4DataBaseError;
947  
# Line 656 | Line 950 | begin
950      for i := 0 to Count - 1 do
951      with TIBXSQLVar(Column[i]) do
952      begin
953 +      P := FMessageBuffer + FCurMetaData.getOffset(StatusIntf,i);
954 + //     writeln('Packbuffer: Column ',Name,' Type = ',TSQLDataItem.GetSQLTypeName(FSQLType),' Size = ',GetSize,' DataLength = ',GetDataLength);
955 +      if not Modified then
956 +        IBError(ibxeUninitializedInputParameter,[i,Name]);
957        if IsNull then
958 <        FillChar((FMessageBuffer + FCurMetaData.getOffset(StatusIntf,i))^,FDataLength,0)
958 >        FillChar(P^,FDataLength,0)
959        else
960 <        Move(FSQLData^,(FMessageBuffer + FCurMetaData.getOffset(StatusIntf,i))^,FDataLength);
961 <      Check4DataBaseError;
960 >      if FSQLData <> nil then
961 >      begin
962 >        if SQLType = SQL_VARYING then
963 >        begin
964 >            EncodeInteger(FDataLength,2,P);
965 >            Inc(P,2);
966 >        end
967 >        else
968 >        if (SQLType = SQL_BLOB) and (FStatement.FBatch <> nil) then
969 >        begin
970 >          FStatement.FBatch.registerBlob(Statusintf,ISC_QUADPtr(FSQLData),ISC_QUADPtr(FSQLData));
971 >          Check4DatabaseError;
972 >        end;
973 >        Move(FSQLData^,P^,FDataLength);
974 >      end;
975        if IsNullable then
976        begin
977          Move(FNullIndicator,(FMessageBuffer + FCurMetaData.getNullOffset(StatusIntf,i))^,sizeof(FNullIndicator));
# Line 673 | Line 984 | end;
984   procedure TIBXINPUTSQLDA.FreeXSQLDA;
985   begin
986    inherited FreeXSQLDA;
987 +  FreeCurMetaData;
988    FreeMessageBuffer;
989   end;
990  
# Line 684 | Line 996 | end;
996  
997   destructor TIBXINPUTSQLDA.Destroy;
998   begin
999 <  FreeMessageBuffer;
999 >  FreeXSQLDA;
1000    inherited Destroy;
1001   end;
1002  
# Line 692 | Line 1004 | procedure TIBXINPUTSQLDA.Bind(aMetaData:
1004   var i: integer;
1005   begin
1006    FMetaData := aMetaData;
1007 <  with Firebird30ClientAPI do
1007 >  with FFirebird30ClientAPI do
1008    begin
1009 <    Count := metadata.getCount(StatusIntf);
1009 >    Count := aMetadata.getCount(StatusIntf);
1010      Check4DataBaseError;
1011      Initialize;
1012  
1013      for i := 0 to Count - 1 do
1014      with TIBXSQLVar(Column[i]) do
1015      begin
1016 <      FSQLType := aMetaData.getType(StatusIntf,i);
1017 <      Check4DataBaseError;
706 <      if FSQLType = SQL_BLOB then
707 <      begin
708 <        FSQLSubType := aMetaData.getSubType(StatusIntf,i);
709 <        Check4DataBaseError;
710 <      end
711 <      else
712 <        FSQLSubType := 0;
713 <      FDataLength := aMetaData.getLength(StatusIntf,i);
714 <      Check4DataBaseError;
715 <      case SQLType of
716 <        SQL_TEXT, SQL_TYPE_DATE, SQL_TYPE_TIME, SQL_TIMESTAMP,
717 <        SQL_BLOB, SQL_ARRAY, SQL_QUAD, SQL_SHORT, SQL_BOOLEAN,
718 <        SQL_LONG, SQL_INT64, SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
719 <        begin
720 <          if (FDataLength = 0) then
721 <            { Make sure you get a valid pointer anyway
722 <             select '' from foo }
723 <            IBAlloc(FSQLData, 0, 1)
724 <          else
725 <            IBAlloc(FSQLData, 0, FDataLength)
726 <        end;
727 <        SQL_VARYING:
728 <          IBAlloc(FSQLData, 0, FDataLength + 2);
729 <       else
730 <          IBError(ibxeUnknownSQLDataType, [sqltype and (not 1)])
731 <      end;
732 <      FNullable := aMetaData.isNullable(StatusIntf,i);
733 <      FOwnsSQLData := true;
734 <      Check4DataBaseError;
735 <      FNullIndicator := -1;
1016 >      InitColumnMetaData(aMetaData);
1017 >      SaveMetaData;
1018        if FNullable then
1019          FSQLNullIndicator := @FNullIndicator
1020        else
1021          FSQLNullIndicator := nil;
1022 <      FScale := aMetaData.getScale(StatusIntf,i);
741 <      Check4DataBaseError;
742 <      FCharSetID :=  aMetaData.getCharSet(StatusIntf,i) and $FF;
743 <      Check4DataBaseError;
1022 >      ColumnSQLDataInit;
1023      end;
1024    end;
1025   end;
# Line 748 | Line 1027 | end;
1027   procedure TIBXINPUTSQLDA.Changed;
1028   begin
1029    inherited Changed;
1030 +  FreeCurMetaData;
1031 +  FreeMessageBuffer;
1032 + end;
1033 +
1034 + procedure TIBXINPUTSQLDA.ReInitialise;
1035 + var i: integer;
1036 + begin
1037    FreeMessageBuffer;
1038 +  for i := 0 to Count - 1 do
1039 +    TIBXSQLVar(Column[i]).ColumnSQLDataInit;
1040   end;
1041  
1042   function TIBXINPUTSQLDA.IsInputDataArea: boolean;
# Line 770 | Line 1058 | procedure TIBXOUTPUTSQLDA.Bind(aMetaData
1058   var i: integer;
1059   begin
1060    FMetaData := aMetaData;
1061 <  with Firebird30ClientAPI do
1061 >  with FFirebird30ClientAPI do
1062    begin
1063      Count := metadata.getCount(StatusIntf);
1064      Check4DataBaseError;
# Line 783 | Line 1071 | begin
1071      for i := 0 to Count - 1 do
1072      with TIBXSQLVar(Column[i]) do
1073      begin
1074 <      FSQLType := aMetaData.getType(StatusIntf,i);
787 <      Check4DataBaseError;
788 <      if FSQLType = SQL_BLOB then
789 <      begin
790 <        FSQLSubType := aMetaData.getSubType(StatusIntf,i);
791 <        Check4DataBaseError;
792 <      end
793 <      else
794 <        FSQLSubType := 0;
795 <      FBlob := nil;
796 <      FArray := nil;
1074 >      InitColumnMetaData(aMetaData);
1075        FSQLData := FMessageBuffer + metaData.getOffset(StatusIntf,i);
1076        Check4DataBaseError;
799      FDataLength := aMetaData.getLength(StatusIntf,i);
800      Check4DataBaseError;
801      FRelationName := strpas(aMetaData.getRelation(StatusIntf,i));
802      Check4DataBaseError;
803      FFieldName := strpas(aMetaData.getField(StatusIntf,i));
804      Check4DataBaseError;
805      FNullable := aMetaData.isNullable(StatusIntf,i);
806      Check4DataBaseError;
1077        if FNullable then
1078        begin
1079          FSQLNullIndicator := PShort(FMessageBuffer + aMetaData.getNullOffset(StatusIntf,i));
# Line 811 | Line 1081 | begin
1081        end
1082        else
1083          FSQLNullIndicator := nil;
1084 <      FScale := aMetaData.getScale(StatusIntf,i);
1085 <      Check4DataBaseError;
816 <      FCharSetID :=  aMetaData.getCharSet(StatusIntf,i) and $FF;
817 <      Check4DataBaseError;
1084 >      FBlob := nil;
1085 >      FArray := nil;
1086      end;
1087    end;
1088    SetUniqueRelationName;
# Line 830 | Line 1098 | begin
1098      len := FDataLength;
1099      if not IsNull and (FSQLType = SQL_VARYING) then
1100      begin
1101 <      with Firebird30ClientAPI do
1101 >      with FFirebird30ClientAPI do
1102          len := DecodeInteger(data,2);
1103        Inc(Data,2);
1104      end;
# Line 847 | Line 1115 | constructor TIBXSQLDA.Create(aStatement:
1115   begin
1116    inherited Create;
1117    FStatement := aStatement;
1118 +  FFirebird30ClientAPI := aStatement.FFirebird30ClientAPI;
1119    FSize := 0;
1120   //  writeln('Creating ',ClassName);
1121   end;
# Line 907 | Line 1176 | begin
1176      ChangeSeqNo := FStatement.ChangeSeqNo;
1177   end;
1178  
1179 + function TIBXSQLDA.CanChangeMetaData: boolean;
1180 + begin
1181 +  Result := FStatement.FBatch = nil;
1182 + end;
1183 +
1184   procedure TIBXSQLDA.SetCount(Value: Integer);
1185   var
1186    i: Integer;
# Line 938 | Line 1212 | begin
1212      TIBXSQLVAR(Column[i]).FreeSQLData;
1213    for i := 0 to FSize - 1  do
1214      TIBXSQLVAR(Column[i]).Free;
1215 +  FCount := 0;
1216    SetLength(FColumnList,0);
1217    FSize := 0;
1218   end;
# Line 954 | Line 1229 | end;
1229  
1230   { TFB30Statement }
1231  
1232 + procedure TFB30Statement.CheckChangeBatchRowLimit;
1233 + begin
1234 +  if IsInBatchMode then
1235 +    IBError(ibxeInBatchMode,[nil]);
1236 + end;
1237 +
1238   procedure TFB30Statement.CheckHandle;
1239   begin
1240    if FStatementIntf = nil then
1241      IBError(ibxeInvalidStatementHandle,[nil]);
1242   end;
1243  
1244 + procedure TFB30Statement.CheckBatchModeAvailable;
1245 + begin
1246 +  if not HasBatchMode then
1247 +    IBError(ibxeBatchModeNotSupported,[nil]);
1248 +  case SQLStatementType of
1249 +  SQLInsert,
1250 +  SQLUpdate: {OK};
1251 +  else
1252 +     IBError(ibxeInvalidBatchQuery,[GetSQLStatementTypeName]);
1253 +  end;
1254 + end;
1255 +
1256   procedure TFB30Statement.GetDSQLInfo(info_request: byte; buffer: ISQLInfoResults
1257    );
1258   begin
1259 <  with Firebird30ClientAPI, buffer as TSQLInfoResultsBuffer do
1259 >  with FFirebird30ClientAPI, buffer as TSQLInfoResultsBuffer do
1260    begin
1261      StatementIntf.getInfo(StatusIntf,1,BytePtr(@info_request),
1262                       GetBufSize, BytePtr(Buffer));
# Line 979 | Line 1272 | begin
1272      IBError(ibxeEmptyQuery, [nil]);
1273    try
1274      CheckTransaction(FTransactionIntf);
1275 <    with Firebird30ClientAPI do
1275 >    with FFirebird30ClientAPI do
1276      begin
1277        if FHasParamNames then
1278        begin
1279          if FProcessedSQL = '' then
1280 <          FSQLParams.PreprocessSQL(FSQL,FGenerateParamNames,FProcessedSQL);
1280 >          ProcessSQL(FSQL,FGenerateParamNames,FProcessedSQL);
1281          FStatementIntf := (GetAttachment as TFB30Attachment).AttachmentIntf.prepare(StatusIntf,
1282                              (FTransactionIntf as TFB30Transaction).TransactionIntf,
1283                              Length(FProcessedSQL),
# Line 1035 | Line 1328 | begin
1328        if (FStatementIntf <> nil) then
1329          FreeHandle;
1330        if E is EIBInterBaseError then
1331 <        raise EIBInterBaseError.Create(EIBInterBaseError(E).SQLCode,
1332 <                                       EIBInterBaseError(E).IBErrorCode,
1040 <                                       EIBInterBaseError(E).Message +
1041 <                                       sSQLErrorSeparator + FSQL)
1042 <      else
1043 <        raise;
1331 >        E.Message := E.Message + sSQLErrorSeparator + FSQL;
1332 >      raise;
1333      end;
1334    end;
1335    FPrepared := true;
# Line 1061 | Line 1350 | begin
1350   end;
1351  
1352   function TFB30Statement.InternalExecute(aTransaction: ITransaction): IResults;
1353 +
1354 +  procedure ExecuteQuery(outMetaData: Firebird.IMessageMetaData=nil; outBuffer: pointer=nil);
1355 +  begin
1356 +    with FFirebird30ClientAPI do
1357 +    begin
1358 +      SavePerfStats(FBeforeStats);
1359 +      FStatementIntf.execute(StatusIntf,
1360 +                             (aTransaction as TFB30Transaction).TransactionIntf,
1361 +                             FSQLParams.MetaData,
1362 +                             FSQLParams.MessageBuffer,
1363 +                             outMetaData,
1364 +                             outBuffer);
1365 +      Check4DataBaseError;
1366 +      FStatisticsAvailable := SavePerfStats(FAfterStats);
1367 +    end;
1368 +  end;
1369 +
1370 +
1371   begin
1372    Result := nil;
1373 +  FBatchCompletion := nil;
1374    FBOF := false;
1375    FEOF := false;
1376    FSingleResults := false;
1377 +  FStatisticsAvailable := false;
1378 +  if IsInBatchMode then
1379 +    IBerror(ibxeInBatchMode,[]);
1380    CheckTransaction(aTransaction);
1381    if not FPrepared then
1382      InternalPrepare;
1383    CheckHandle;
1384    if aTransaction <> FTransactionIntf then
1385      AddMonitor(aTransaction as TFB30Transaction);
1386 <  if (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB30transaction).TransactionSeqNo) then
1386 >  if FStaleReferenceChecks and (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB30transaction).TransactionSeqNo) then
1387      IBError(ibxeInterfaceOutofDate,[nil]);
1388  
1389 +
1390    try
1391 <    with Firebird30ClientAPI do
1391 >    with FFirebird30ClientAPI do
1392      begin
1081      if FCollectStatistics then
1082      begin
1083        UtilIntf.getPerfCounters(StatusIntf,
1084                      (GetAttachment as TFB30Attachment).AttachmentIntf,
1085                      ISQL_COUNTERS,@FBeforeStats);
1086        Check4DataBaseError;
1087      end;
1088
1393        case FSQLStatementType of
1394        SQLSelect:
1395          IBError(ibxeIsAExecuteProcedure,[]);
1396  
1397        SQLExecProcedure:
1398        begin
1399 <        FStatementIntf.execute(StatusIntf,
1096 <                               (aTransaction as TFB30Transaction).TransactionIntf,
1097 <                               FSQLParams.MetaData,
1098 <                               FSQLParams.MessageBuffer,
1099 <                               FSQLRecord.MetaData,
1100 <                               FSQLRecord.MessageBuffer);
1101 <        Check4DataBaseError;
1102 <
1399 >        ExecuteQuery(FSQLRecord.MetaData,FSQLRecord.MessageBuffer);
1400          Result := TResults.Create(FSQLRecord);
1401          FSingleResults := true;
1105      end
1106      else
1107        FStatementIntf.execute(StatusIntf,
1108                               (aTransaction as TFB30Transaction).TransactionIntf,
1109                               FSQLParams.MetaData,
1110                               FSQLParams.MessageBuffer,
1111                               nil,
1112                               nil);
1113        Check4DataBaseError;
1402        end;
1403 <      if FCollectStatistics then
1404 <      begin
1405 <        UtilIntf.getPerfCounters(StatusIntf,
1118 <                  (GetAttachment as TFB30Attachment).AttachmentIntf,
1119 <                  ISQL_COUNTERS, @FAfterStats);
1120 <        Check4DataBaseError;
1121 <        FStatisticsAvailable := true;
1403 >
1404 >      else
1405 >        ExecuteQuery;
1406        end;
1407      end;
1408    finally
# Line 1126 | Line 1410 | begin
1410         RemoveMonitor(aTransaction as TFB30Transaction);
1411    end;
1412    FExecTransactionIntf := aTransaction;
1413 +  FSQLRecord.FTransaction := (aTransaction as TFB30Transaction);
1414 +  FSQLRecord.FTransactionSeqNo := FSQLRecord.FTransaction.TransactionSeqNo;
1415    SignalActivity;
1416    Inc(FChangeSeqNo);
1417   end;
# Line 1136 | Line 1422 | begin
1422    if FSQLStatementType <> SQLSelect then
1423     IBError(ibxeIsASelectStatement,[]);
1424  
1425 < CheckTransaction(aTransaction);
1425 >  FBatchCompletion := nil;
1426 >  CheckTransaction(aTransaction);
1427    if not FPrepared then
1428      InternalPrepare;
1429    CheckHandle;
1430    if aTransaction <> FTransactionIntf then
1431      AddMonitor(aTransaction as TFB30Transaction);
1432 <  if (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB30transaction).TransactionSeqNo) then
1432 >  if FStaleReferenceChecks and (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB30transaction).TransactionSeqNo) then
1433      IBError(ibxeInterfaceOutofDate,[nil]);
1434  
1435 < with Firebird30ClientAPI do
1435 > with FFirebird30ClientAPI do
1436   begin
1437     if FCollectStatistics then
1438     begin
# Line 1185 | Line 1472 | begin
1472   Inc(FChangeSeqNo);
1473   end;
1474  
1475 + procedure TFB30Statement.ProcessSQL(sql: AnsiString; GenerateParamNames: boolean;
1476 +  var processedSQL: AnsiString);
1477 + begin
1478 +  FSQLParams.PreprocessSQL(sql,GenerateParamNames,processedSQL);
1479 + end;
1480 +
1481   procedure TFB30Statement.FreeHandle;
1482   begin
1483    Close;
1484    ReleaseInterfaces;
1485 +  if FBatch <> nil then
1486 +  begin
1487 +    FBatch.release;
1488 +    FBatch := nil;
1489 +  end;
1490    if FStatementIntf <> nil then
1491    begin
1492      FStatementIntf.release;
# Line 1201 | Line 1499 | procedure TFB30Statement.InternalClose(F
1499   begin
1500    if (FStatementIntf <> nil) and (SQLStatementType = SQLSelect) and FOpen then
1501    try
1502 <    with Firebird30ClientAPI do
1502 >    with FFirebird30ClientAPI do
1503      begin
1504        if FResultSet <> nil then
1505        begin
# Line 1225 | Line 1523 | begin
1523    Inc(FChangeSeqNo);
1524   end;
1525  
1526 + function TFB30Statement.SavePerfStats(var Stats: TPerfStatistics): boolean;
1527 + begin
1528 +  Result := false;
1529 +  if FCollectStatistics then
1530 +  with FFirebird30ClientAPI do
1531 +  begin
1532 +    UtilIntf.getPerfCounters(StatusIntf,
1533 +              (GetAttachment as TFB30Attachment).AttachmentIntf,
1534 +              ISQL_COUNTERS, @Stats);
1535 +    Check4DataBaseError;
1536 +    Result := true;
1537 +  end;
1538 + end;
1539 +
1540   constructor TFB30Statement.Create(Attachment: TFB30Attachment;
1541    Transaction: ITransaction; sql: AnsiString; aSQLDialect: integer);
1542   begin
1543    inherited Create(Attachment,Transaction,sql,aSQLDialect);
1544 +  FFirebird30ClientAPI := Attachment.Firebird30ClientAPI;
1545    FSQLParams := TIBXINPUTSQLDA.Create(self);
1546    FSQLRecord := TIBXOUTPUTSQLDA.Create(self);
1547    InternalPrepare;
# Line 1236 | Line 1549 | end;
1549  
1550   constructor TFB30Statement.CreateWithParameterNames(
1551    Attachment: TFB30Attachment; Transaction: ITransaction; sql: AnsiString;
1552 <  aSQLDialect: integer; GenerateParamNames: boolean);
1552 >  aSQLDialect: integer; GenerateParamNames: boolean;
1553 >  CaseSensitiveParams: boolean);
1554   begin
1555    inherited CreateWithParameterNames(Attachment,Transaction,sql,aSQLDialect,GenerateParamNames);
1556 +  FFirebird30ClientAPI := Attachment.Firebird30ClientAPI;
1557    FSQLParams := TIBXINPUTSQLDA.Create(self);
1558 +  FSQLParams.CaseSensitiveParams := CaseSensitiveParams;
1559    FSQLRecord := TIBXOUTPUTSQLDA.Create(self);
1560    InternalPrepare;
1561   end;
# Line 1260 | Line 1576 | begin
1576    if FEOF then
1577      IBError(ibxeEOF,[nil]);
1578  
1579 <  with Firebird30ClientAPI do
1579 >  with FFirebird30ClientAPI do
1580    begin
1581      { Go to the next record... }
1582      fetchResult := FResultSet.fetchNext(StatusIntf,FSQLRecord.MessageBuffer);
# Line 1285 | Line 1601 | begin
1601        FBOF := false;
1602        result := true;
1603      end;
1604 +    if FCollectStatistics then
1605 +    begin
1606 +      UtilIntf.getPerfCounters(StatusIntf,
1607 +                              (GetAttachment as TFB30Attachment).AttachmentIntf,
1608 +                              ISQL_COUNTERS,@FAfterStats);
1609 +      Check4DataBaseError;
1610 +      FStatisticsAvailable := true;
1611 +    end;
1612    end;
1613    FSQLRecord.RowChange;
1614    SignalActivity;
# Line 1316 | Line 1640 | begin
1640         SQLUpdate, SQLDelete])) then
1641      result := ''
1642    else
1643 <  with Firebird30ClientAPI do
1643 >  with FFirebird30ClientAPI do
1644    begin
1645      Result := FStatementIntf.getPlan(StatusIntf,true);
1646      Check4DataBaseError;
# Line 1350 | Line 1674 | begin
1674      TSQLParams(GetInterface(0)).RetainInterfaces := aValue;
1675   end;
1676  
1677 + function TFB30Statement.IsInBatchMode: boolean;
1678 + begin
1679 +  Result := FBatch <> nil;
1680 + end;
1681 +
1682 + function TFB30Statement.HasBatchMode: boolean;
1683 + begin
1684 +  Result := GetAttachment.HasBatchMode;
1685 + end;
1686 +
1687 + procedure TFB30Statement.AddToBatch;
1688 + var BatchPB: TXPBParameterBlock;
1689 +
1690 + const SixteenMB = 16 * 1024 * 1024;
1691 + begin
1692 +  FBatchCompletion := nil;
1693 +  if not FPrepared then
1694 +    InternalPrepare;
1695 +  CheckHandle;
1696 +  CheckBatchModeAvailable;
1697 +  with FFirebird30ClientAPI do
1698 +  begin
1699 +    if FBatch = nil then
1700 +    begin
1701 +      {Start Batch}
1702 +      BatchPB := TXPBParameterBlock.Create(FFirebird30ClientAPI,Firebird.IXpbBuilder.BATCH);
1703 +      with FFirebird30ClientAPI do
1704 +      try
1705 +        FBatchBufferSize := FBatchRowLimit * FSQLParams.MetaData.getAlignedLength(StatusIntf);
1706 +        Check4DatabaseError;
1707 +        if FBatchBufferSize < SixteenMB then
1708 +          FBatchBufferSize := SixteenMB;
1709 +        if FBatchBufferSize > 256 * 1024 *1024 {assumed limit} then
1710 +          IBError(ibxeBatchBufferSizeTooBig,[FBatchBufferSize]);
1711 +
1712 +        BatchPB.insertInt(Firebird.IBatch.TAG_RECORD_COUNTS,1);
1713 +        BatchPB.insertInt(Firebird.IBatch.TAG_BUFFER_BYTES_SIZE,FBatchBufferSize);
1714 +        FBatch := FStatementIntf.createBatch(StatusIntf,
1715 +                                             FSQLParams.MetaData,
1716 +                                             BatchPB.getDataLength,
1717 +                                             BatchPB.getBuffer);
1718 +        Check4DataBaseError;
1719 +
1720 +      finally
1721 +        BatchPB.Free;
1722 +      end;
1723 +      FBatchRowCount := 0;
1724 +      FBatchBufferUsed := 0;
1725 +    end;
1726 +
1727 +    Inc(FBatchRowCount);
1728 +    Inc(FBatchBufferUsed,FSQLParams.MetaData.getAlignedLength(StatusIntf));
1729 +    Check4DataBaseError;
1730 +    if FBatchBufferUsed > FBatchBufferSize then
1731 +      raise EIBBatchBufferOverflow.Create(Ord(ibxeBatchRowBufferOverflow),
1732 +                              Format(GetErrorMessage(ibxeBatchRowBufferOverflow),
1733 +                              [FBatchRowCount,FBatchBufferSize]));
1734 +
1735 +    FBatch.Add(StatusIntf,1,FSQLParams.GetMessageBuffer);
1736 +      Check4DataBaseError
1737 +  end;
1738 + end;
1739 +
1740 + function TFB30Statement.ExecuteBatch(aTransaction: ITransaction
1741 +  ): IBatchCompletion;
1742 +
1743 + procedure Check4BatchCompletionError(bc: IBatchCompletion);
1744 + var status: IStatus;
1745 +    RowNo: integer;
1746 + begin
1747 +  status := nil;
1748 +  {Raise an exception if there was an error reported in the BatchCompletion}
1749 +  if (bc <> nil) and bc.getErrorStatus(RowNo,status) then
1750 +    raise EIBInterbaseError.Create(status);
1751 + end;
1752 +
1753 + var cs: Firebird.IBatchCompletionState;
1754 +
1755 + begin
1756 +  Result := nil;
1757 +  if FBatch = nil then
1758 +    IBError(ibxeNotInBatchMode,[]);
1759 +
1760 +  with FFirebird30ClientAPI do
1761 +  begin
1762 +    SavePerfStats(FBeforeStats);
1763 +    if aTransaction = nil then
1764 +      cs := FBatch.execute(StatusIntf,(FTransactionIntf as TFB30Transaction).TransactionIntf)
1765 +    else
1766 +      cs := FBatch.execute(StatusIntf,(aTransaction as TFB30Transaction).TransactionIntf);
1767 +    Check4DataBaseError;
1768 +    FBatchCompletion := TBatchCompletion.Create(FFirebird30ClientAPI,cs);
1769 +    FStatisticsAvailable := SavePerfStats(FAfterStats);
1770 +    FBatch.release;
1771 +    FBatch := nil;
1772 +    Check4BatchCompletionError(FBatchCompletion);
1773 +    Result := FBatchCompletion;
1774 +  end;
1775 + end;
1776 +
1777 + procedure TFB30Statement.CancelBatch;
1778 + begin
1779 +  if FBatch = nil then
1780 +    IBError(ibxeNotInBatchMode,[]);
1781 +  FBatch.release;
1782 +  FBatch := nil;
1783 + end;
1784 +
1785 + function TFB30Statement.GetBatchCompletion: IBatchCompletion;
1786 + begin
1787 +  Result := FBatchCompletion;
1788 + end;
1789 +
1790   function TFB30Statement.IsPrepared: boolean;
1791   begin
1792    Result := FStatementIntf <> nil;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines