ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/2.5/FB25Statement.pas
Revision: 421
Committed: Sat Oct 21 14:22:28 2023 UTC (13 months, 4 weeks ago) by tony
Content type: text/x-pascal
File size: 40855 byte(s)
Log Message:
Release 2.6.3 Merged

File Contents

# Content
1 (*
2 * Firebird Interface (fbintf). The fbintf components provide a set of
3 * Pascal language bindings for the Firebird API. Although predominantly
4 * a new development they include source code taken from IBX and may be
5 * considered a derived product. This software thus also includes the copyright
6 * notice and license conditions from IBX.
7 *
8 * Except for those parts dervied from IBX, contents of this file are subject
9 * to the Initial Developer's Public License Version 1.0 (the "License"); you
10 * may not use this file except in compliance with the License. You may obtain a
11 * copy of the License here:
12 *
13 * http://www.firebirdsql.org/index.php?op=doc&id=idpl
14 *
15 * Software distributed under the License is distributed on an "AS
16 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17 * implied. See the License for the specific language governing rights
18 * and limitations under the License.
19 *
20 * The Initial Developer of the Original Code is Tony Whyman.
21 *
22 * The Original Code is (C) 2016 Tony Whyman, MWA Software
23 * (http://www.mwasoftware.co.uk).
24 *
25 * All Rights Reserved.
26 *
27 * Contributor(s): ______________________________________.
28 *
29 *)
30 {************************************************************************}
31 { }
32 { Borland Delphi Visual Component Library }
33 { InterBase Express core components }
34 { }
35 { Copyright (c) 1998-2000 Inprise Corporation }
36 { }
37 { InterBase Express is based in part on the product }
38 { Free IB Components, written by Gregory H. Deatz for }
39 { Hoagland, Longo, Moran, Dunst & Doukas Company. }
40 { Free IB Components is used under license. }
41 { }
42 { The contents of this file are subject to the InterBase }
43 { Public License Version 1.0 (the "License"); you may not }
44 { use this file except in compliance with the License. You }
45 { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
46 { Software distributed under the License is distributed on }
47 { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
48 { express or implied. See the License for the specific language }
49 { governing rights and limitations under the License. }
50 { The Original Code was created by InterBase Software Corporation }
51 { and its successors. }
52 { Portions created by Inprise Corporation are Copyright (C) Inprise }
53 { Corporation. All Rights Reserved. }
54 { Contributor(s): Jeff Overcash }
55 { }
56 { IBX For Lazarus (Firebird Express) }
57 { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
58 { Portions created by MWA Software are copyright McCallum Whyman }
59 { Associates Ltd 2011 - 2015 }
60 { }
61 {************************************************************************}
62 unit FB25Statement;
63 {$IFDEF MSWINDOWS}
64 {$DEFINE WINDOWS}
65 {$ENDIF}
66
67 {$IFDEF FPC}
68 {$mode delphi}
69 {$codepage UTF8}
70 {$interfaces COM}
71 {$ENDIF}
72
73 {This unit is hacked from IBSQL and contains the code for managing an XSQLDA and
74 SQLVars, along with statement preparation, execution and cursor management.
75 Most of the SQLVar code has been moved to unit FBSQLData. Client access is
76 provided through interface rather than direct access to the XSQLDA and XSQLVar
77 objects.}
78
79 {
80 Note on reference counted interfaces.
81 ------------------------------------
82
83 TFB25Statement manages both an input and an output SQLDA through the TIBXINPUTSQLDA
84 and TIBXOUTPUTSQLDA objects. As pure objects, these are explicitly destroyed
85 when the statement is destroyed.
86
87 However, IResultSet is an interface and is returned when a cursor is opened and
88 has a reference for the TIBXOUTPUTSQLDA. The user may discard their reference
89 to the IStatement while still using the IResultSet. This would be a problem if t
90 he underlying TFB25Statement object and its TIBXOUTPUTSQLDA is destroyed while
91 still leaving the TIBXResultSet object in place. Calls to (e.g.) FetchNext would fail.
92
93 To avoid this problem, TResultsSet objects have a reference to the IStatement
94 interface of the TFB25Statement object. Thus, as long as these "copies" exist,
95 the owning statement is not destroyed even if the user discards their reference
96 to the statement. Note: the TFB25Statement does not have a reference to the TIBXResultSet
97 interface. This way circular references are avoided.
98
99 To avoid an IResultSet interface being kept too long and no longer synchronised
100 with the query, each statement includes a prepare sequence number, incremented
101 each time the query is prepared. When the IResultSet interface is created, it
102 noted the current prepare sequence number. Whe an IResult interface is accessed
103 it checks this number against the statement's current prepare sequence number.
104 If not the same, an error is raised.
105
106 A similar strategy is used for the IMetaData, IResults and ISQLParams interfaces.
107 }
108
109 interface
110
111 uses
112 Classes, SysUtils, IB, FBClientAPI, FB25ClientAPI, FB25Transaction, FB25Attachment,
113 IBHeader, IBExternals, FBSQLData, FBOutputBlock, FBStatement, FBActivityMonitor;
114
115 type
116 TFB25Statement = class;
117 TIBXSQLDA = class;
118
119 { TIBXSQLVAR }
120
121 TIBXSQLVAR = class(TSQLVarData)
122 private
123 FStatement: TFB25Statement;
124 FFirebird25ClientAPI: TFB25ClientAPI;
125 FBlob: IBlob; {Cache references}
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 CanChangeSQLType: boolean;
134 function GetSQLType: cardinal; override;
135 function GetSubtype: integer; override;
136 function GetAliasName: AnsiString; override;
137 function GetFieldName: AnsiString; override;
138 function GetOwnerName: AnsiString; override;
139 function GetRelationName: AnsiString; override;
140 function GetScale: integer; override;
141 function GetCharSetID: cardinal; override;
142 function GetIsNull: Boolean; override;
143 function GetIsNullable: boolean; override;
144 function GetSQLData: PByte; override;
145 function GetDataLength: cardinal; override;
146 function GetSize: cardinal; override;
147 function GetDefaultTextSQLType: cardinal; override;
148 procedure SetIsNull(Value: Boolean); override;
149 procedure SetMetaSize(aValue: cardinal); override;
150 procedure SetIsNullable(Value: Boolean); override;
151 procedure SetSQLData(AValue: PByte; len: cardinal); override;
152 procedure InternalSetScale(aValue: integer); override;
153 procedure InternalSetDataLength(len: cardinal); override;
154 procedure InternalSetSQLType(aValue: cardinal); override;
155 procedure SetCharSetID(aValue: cardinal); override;
156 public
157 constructor Create(aParent: TIBXSQLDA; aIndex: integer);
158 procedure FreeSQLData;
159 procedure RowChange; override;
160 function GetAsArray: IArray; override;
161 function GetAsBlob(Blob_ID: TISC_QUAD; BPB: IBPB): IBlob; override;
162 function GetArrayMetaData: IArrayMetaData; override;
163 function GetBlobMetaData: IBlobMetaData; override;
164 function CreateBlob: IBlob; override;
165 procedure Initialize; override;
166
167 property Statement: TFB25Statement read FStatement;
168 property SQLType: cardinal read GetSQLType write SetSQLType;
169 end;
170
171 TIBXINPUTSQLDA = class;
172
173 { TIBXSQLDA }
174
175 TIBXSQLDA = class(TSQLDataArea)
176 private
177 FCount: Integer; {Columns in use - may be less than inherited columns}
178 FSize: Integer; {Number of TIBXSQLVARs in column list}
179 FXSQLDA: PXSQLDA;
180 FTransactionSeqNo: integer;
181 function GetRecordSize: Integer;
182 function GetXSQLDA: PXSQLDA;
183 protected
184 FStatement: TFB25Statement;
185 FFirebird25ClientAPI: TFB25ClientAPI;
186 function GetTransactionSeqNo: integer; override;
187 procedure FreeXSQLDA;
188 function GetStatement: IStatement; override;
189 function GetPrepareSeqNo: integer; override;
190 procedure SetCount(Value: Integer); override;
191 public
192 constructor Create(aStatement: TFB25Statement);
193 destructor Destroy; override;
194 function CanChangeMetaData: boolean; override;
195 function CheckStatementStatus(Request: TStatementStatus): boolean; override;
196 function ColumnsInUseCount: integer; override;
197 function GetTransaction: TFB25Transaction; virtual;
198 procedure Initialize; override;
199 function StateChanged(var ChangeSeqNo: integer): boolean; override;
200 property AsXSQLDA: PXSQLDA read GetXSQLDA;
201 property Count: Integer read FCount write SetCount;
202 property RecordSize: Integer read GetRecordSize;
203 property Statement: TFB25Statement read FStatement;
204 end;
205
206 { TIBXINPUTSQLDA }
207
208 TIBXINPUTSQLDA = class(TIBXSQLDA)
209 public
210 procedure Bind;
211 function IsInputDataArea: boolean; override;
212 end;
213
214
215 { TIBXOUTPUTSQLDA }
216
217 TIBXOUTPUTSQLDA = class(TIBXSQLDA)
218 private
219 FTransaction: TFB25Transaction; {transaction used to execute the statement}
220 public
221 procedure Bind;
222 function GetTransaction: TFB25Transaction; override;
223 procedure GetData(index: integer; var aIsNull: boolean; var len: short;
224 var data: PByte); override;
225 function IsInputDataArea: boolean; override;
226 end;
227
228 { TResultSet }
229
230 TResultSet = class(TResults,IResultSet)
231 private
232 FResults: TIBXOUTPUTSQLDA;
233 FCursorSeqNo: integer;
234 public
235 constructor Create(aResults: TIBXOUTPUTSQLDA);
236 destructor Destroy; override;
237 {IResultSet}
238 function FetchNext: boolean; {fetch next record}
239 function FetchPrior: boolean; {fetch previous record}
240 function FetchFirst:boolean; {fetch first record}
241 function FetchLast: boolean; {fetch last record}
242 function FetchAbsolute(position: Integer): boolean; {fetch record by its absolute position in result set}
243 function FetchRelative(offset: Integer): boolean; {fetch record by position relative to current}
244 function GetCursorName: AnsiString;
245 function IsEof: boolean;
246 function IsBof: boolean;
247 procedure Close;
248 end;
249
250 { TFB25Statement }
251
252 TFB25Statement = class(TFBStatement,IStatement)
253 private
254 FDBHandle: TISC_DB_HANDLE;
255 FHandle: TISC_STMT_HANDLE;
256 FFirebird25ClientAPI: TFB25ClientAPI;
257 FSQLParams: TIBXINPUTSQLDA;
258 FSQLRecord: TIBXOUTPUTSQLDA;
259 FCursor: AnsiString; { Cursor name...}
260 FCursorSeqNo: integer;
261 procedure GetPerfCounters(var counters: TPerfStatistics);
262 protected
263 procedure CheckHandle; override;
264 procedure GetDsqlInfo(info_request: byte; buffer: ISQLInfoResults); override;
265 function GetStatementIntf: IStatement; override;
266 procedure InternalPrepare(CursorName: AnsiString=''); override;
267 function InternalExecute(aTransaction: ITransaction): IResults; override;
268 function InternalOpenCursor(aTransaction: ITransaction; Scrollable: boolean): IResultSet; override;
269 procedure ProcessSQL(sql: AnsiString; GenerateParamNames: boolean; var processedSQL: AnsiString); override;
270 procedure FreeHandle; override;
271 procedure InternalClose(Force: boolean); override;
272 public
273 constructor Create(Attachment: TFB25Attachment; Transaction: ITransaction;
274 sql: AnsiString; aSQLDialect: integer; CursorName: AnsiString='');
275 constructor CreateWithParameterNames(Attachment: TFB25Attachment;
276 Transaction: ITransaction; sql: AnsiString; aSQLDialect: integer; GenerateParamNames: boolean;
277 CaseSensitiveParams: boolean=false; CursorName: AnsiString='');
278 destructor Destroy; override;
279 function FetchNext: boolean;
280
281 public
282 {IStatement}
283 function GetSQLParams: ISQLParams; override;
284 function GetMetaData: IMetaData; override;
285 function GetPlan: AnsiString;
286 function IsPrepared: boolean;
287 function CreateBlob(column: TColumnMetaData): IBlob; override;
288 function CreateArray(column: TColumnMetaData): IArray; override;
289 procedure SetRetainInterfaces(aValue: boolean); override;
290 property Handle: TISC_STMT_HANDLE read FHandle;
291
292 end;
293
294 implementation
295
296 uses IBUtils, FBMessages, FBBlob, FB25Blob, variants, IBErrorCodes, FBArray, FB25Array
297 {$IFDEF UNIX}, BaseUnix {$ENDIF}{$ifdef WINDOWS}, Windows{$endif};
298
299
300 { TIBXSQLVAR }
301
302 function TIBXSQLVAR.CanChangeSQLType: boolean;
303 begin
304 Result := Parent.CanChangeMetaData;
305 end;
306
307 function TIBXSQLVAR.GetSQLType: cardinal;
308 begin
309 result := FXSQLVAR^.sqltype and (not 1);
310 end;
311
312 function TIBXSQLVAR.GetSubtype: integer;
313 begin
314 if GetSQLType = SQL_BLOB then
315 result := FXSQLVAR^.sqlsubtype
316 else
317 result := 0;
318 end;
319
320 function TIBXSQLVAR.GetAliasName: AnsiString;
321 begin
322 result := strpas(FXSQLVAR^.aliasname);
323 end;
324
325 function TIBXSQLVAR.GetFieldName: AnsiString;
326 begin
327 result := strpas(FXSQLVAR^.sqlname);
328 end;
329
330 function TIBXSQLVAR.GetOwnerName: AnsiString;
331 begin
332 result := strpas(FXSQLVAR^.ownname);
333 end;
334
335 function TIBXSQLVAR.GetRelationName: AnsiString;
336 begin
337 result := strpas(FXSQLVAR^.relname);
338 end;
339
340 function TIBXSQLVAR.GetScale: integer;
341 begin
342 if GetSQLType = SQL_BLOB then
343 result := 0
344 else
345 result := FXSQLVAR^.sqlscale;
346 end;
347
348 function TIBXSQLVAR.GetCharSetID: cardinal;
349 begin
350 result := 0;
351 case SQLType of
352 SQL_VARYING, SQL_TEXT:
353 {see http://firebirdsql.org/rlsnotesh/rlsnotes210.html}
354 result := FXSQLVAR^.sqlsubtype and $FF;
355
356 SQL_BLOB:
357 if (SQLSubType = 1) then
358 {see http://firebirdsql.org/rlsnotesh/rlsnotes210.html}
359 result := FXSQLVAR^.sqlscale and $FF;
360
361 SQL_ARRAY:
362 if (GetRelationName <> '') and (GetFieldName <> '') then
363 result := GetArrayMetaData.GetCharSetID;
364 end;
365 end;
366
367 function TIBXSQLVAR.GetIsNull: Boolean;
368 begin
369 result := IsNullable and (FNullIndicator = -1);
370 end;
371
372 function TIBXSQLVAR.GetIsNullable: boolean;
373 begin
374 result := (FXSQLVAR^.sqltype and 1 = 1);
375 end;
376
377 function TIBXSQLVAR.GetSQLData: PByte;
378 begin
379 Result := FXSQLVAR^.sqldata;
380 end;
381
382 function TIBXSQLVAR.GetDataLength: cardinal;
383 begin
384 Result := FXSQLVAR^.sqllen;
385 end;
386
387 function TIBXSQLVAR.GetSize: cardinal;
388 begin
389 Result := FMetadataSize;
390 end;
391
392 function TIBXSQLVAR.GetArrayMetaData: IArrayMetaData;
393 begin
394 if GetSQLType <> SQL_ARRAY then
395 IBError(ibxeInvalidDataConversion,[nil]);
396
397 if FArrayMetaData = nil then
398 FArrayMetaData := TFB25ArrayMetaData.Create(FStatement.GetAttachment as TFB25Attachment,
399 FStatement.GetTransaction as TFB25Transaction,
400 GetRelationName,GetFieldName);
401 Result := FArrayMetaData;
402 end;
403
404 function TIBXSQLVAR.GetBlobMetaData: IBlobMetaData;
405 begin
406 if GetSQLType <> SQL_BLOB then
407 IBError(ibxeInvalidDataConversion,[nil]);
408
409 if FBlobMetaData = nil then
410 FBlobMetaData := TFB25BlobMetaData.Create(FStatement.GetAttachment as TFB25Attachment,
411 FStatement.GetTransaction as TFB25Transaction,
412 GetRelationName,GetFieldName,GetSubType);
413 (FBlobMetaData as TFBBlobMetaData).SetCharSetID(GetCharSetID);
414 Result := FBlobMetaData;
415 end;
416
417 function TIBXSQLVAR.GetAsArray: IArray;
418 begin
419 if SQLType <> SQL_ARRAY then
420 IBError(ibxeInvalidDataConversion,[nil]);
421
422 if IsNull then
423 Result := nil
424 else
425 begin
426 if FArrayIntf = nil then
427 FArrayIntf := TFB25Array.Create(FStatement.GetAttachment as TFB25Attachment,
428 TIBXSQLDA(Parent).GetTransaction,
429 GetArrayMetaData,PISC_QUAD(SQLData)^);
430 Result := FArrayIntf;
431 end;
432 end;
433
434 function TIBXSQLVAR.GetAsBlob(Blob_ID: TISC_QUAD; BPB: IBPB): IBlob;
435 begin
436 if FBlob <> nil then
437 Result := FBlob
438 else
439 begin
440 if SQLType <> SQL_BLOB then
441 IBError(ibxeInvalidDataConversion, [nil]);
442 if IsNull then
443 Result := nil
444 else
445 Result := TFB25Blob.Create(FStatement.GetAttachment as TFB25Attachment,
446 TIBXSQLDA(Parent).GetTransaction,
447 GetBlobMetaData,
448 Blob_ID,BPB);
449 FBlob := Result;
450 end;
451 end;
452
453 function TIBXSQLVAR.CreateBlob: IBlob;
454 begin
455 Result := TFB25Blob.Create(FStatement.GetAttachment as TFB25Attachment,
456 FStatement.GetTransaction as TFB25Transaction,GetSubType,GetCharSetID,nil);
457 end;
458
459 procedure TIBXSQLVAR.Initialize;
460 begin
461 inherited Initialize;
462 FOwnsSQLData := true;
463 with FFirebird25ClientAPI, FXSQLVar^ do
464 begin
465 FMetadataSize := sqllen;
466 case sqltype and (not 1) of
467 SQL_TEXT, SQL_TYPE_DATE, SQL_TYPE_TIME, SQL_TIMESTAMP,
468 SQL_BLOB, SQL_ARRAY, SQL_QUAD, SQL_SHORT, SQL_BOOLEAN,
469 SQL_LONG, SQL_INT64, SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: begin
470 if (sqllen = 0) then
471 { Make sure you get a valid pointer anyway
472 select '' from foo }
473 IBAlloc(sqldata, 0, 1)
474 else
475 IBAlloc(sqldata, 0, sqllen)
476 end;
477 SQL_VARYING: begin
478 IBAlloc(sqldata, 0, sqllen + 2);
479 end;
480 else
481 IBError(ibxeUnknownSQLDataType, [sqltype and (not 1)])
482 end;
483 if (sqltype and 1 = 1) then
484 begin
485 sqlInd := @FNullIndicator;
486 FNullIndicator := -1;
487 end
488 else
489 sqlInd := nil;
490 end;
491 SaveMetaData;
492 end;
493
494 procedure TIBXSQLVAR.SetIsNull(Value: Boolean);
495 begin
496 if Value then
497 begin
498 IsNullable := true;
499 FNullIndicator := -1;
500 Changed;
501 end
502 else
503 if ((not Value) and IsNullable) then
504 begin
505 FNullIndicator := 0;
506 Changed;
507 end;
508 end;
509
510 procedure TIBXSQLVAR.SetMetaSize(aValue: cardinal);
511 begin
512 if (aValue > FMetaDataSize) and not CanChangeSQLType then
513 IBError(ibxeCannotIncreaseMetadatasize,[FMetaDataSize,aValue]);
514 FMetaDataSize := aValue;
515 end;
516
517 procedure TIBXSQLVAR.SetIsNullable(Value: Boolean);
518 begin
519 if (Value <> IsNullable) then
520 begin
521 if Value then
522 begin
523 FXSQLVAR^.sqltype := FXSQLVAR^.sqltype or 1;
524 FNullIndicator := 0;
525 FXSQLVAR^.sqlInd := @FNullIndicator;
526 end
527 else
528 begin
529 FXSQLVAR^.sqltype := FXSQLVAR^.sqltype and (not 1);
530 FXSQLVAR^.sqlind := nil;
531 end;
532 end;
533 Changed;
534 end;
535
536 procedure TIBXSQLVAR.SetSQLData(AValue: PByte; len: cardinal);
537 begin
538 if FOwnsSQLData then
539 FreeMem(FXSQLVAR^.sqldata);
540 FXSQLVAR^.sqldata := AValue;
541 FXSQLVAR^.sqllen := len;
542 FOwnsSQLData := false;
543 Changed;
544 end;
545
546 procedure TIBXSQLVAR.InternalSetScale(aValue: integer);
547 begin
548 FXSQLVAR^.sqlscale := aValue;
549 Changed;
550 end;
551
552 procedure TIBXSQLVAR.InternalSetDataLength(len: cardinal);
553 begin
554 if not FOwnsSQLData then
555 FXSQLVAR^.sqldata := nil;
556 FXSQLVAR^.sqllen := len;
557 with FFirebird25ClientAPI do
558 IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
559 FOwnsSQLData := true;
560 Changed;
561 end;
562
563 procedure TIBXSQLVAR.InternalSetSQLType(aValue: cardinal);
564 var tmpCharSetID: cardinal;
565 begin
566 tmpCharSetID := GetCharSetID;
567 FXSQLVAR^.sqltype := aValue or (FXSQLVAR^.sqltype and 1);
568 SetCharSetID(tmpCharSetID); {Needed when changing Blob to SQL_VARYING/SQL_TEXT}
569 Changed;
570 end;
571
572 procedure TIBXSQLVAR.SetCharSetID(aValue: cardinal);
573 begin
574 if aValue <> GetCharSetID then
575 begin
576 case SQLType of
577 SQL_VARYING, SQL_TEXT:
578 FXSQLVAR^.sqlsubtype := (aValue and $FF) or (FXSQLVAR^.sqlsubtype and not $FF);
579
580 SQL_BLOB,
581 SQL_ARRAY:
582 IBError(ibxeInvalidDataConversion,[nil]);
583 end;
584 Changed;
585 end;
586 end;
587
588 function TIBXSQLVAR.GetDefaultTextSQLType: cardinal;
589 begin
590 Result := SQL_TEXT;
591 end;
592
593 constructor TIBXSQLVAR.Create(aParent: TIBXSQLDA; aIndex: integer);
594 begin
595 inherited Create(aParent,aIndex);
596 FStatement := aParent.Statement;
597 FFirebird25ClientAPI := aParent.FFirebird25ClientAPI;
598 end;
599
600 procedure TIBXSQLVAR.FreeSQLData;
601 begin
602 if FOwnsSQLData then
603 FreeMem(FXSQLVAR^.sqldata);
604 FXSQLVAR^.sqldata := nil;
605 FOwnsSQLData := true;
606 end;
607
608 procedure TIBXSQLVAR.RowChange;
609 begin
610 inherited RowChange;
611 FBlob := nil;
612 end;
613
614
615 { TResultSet }
616
617 constructor TResultSet.Create(aResults: TIBXOUTPUTSQLDA);
618 begin
619 inherited Create(aResults);
620 FResults := aResults;
621 FCursorSeqNo := aResults.FStatement.FCursorSeqNo;
622 end;
623
624 destructor TResultSet.Destroy;
625 begin
626 Close;
627 inherited Destroy;
628 end;
629
630 function TResultSet.FetchNext: boolean;
631 var i: integer;
632 begin
633 CheckActive;
634 Result := FResults.FStatement.FetchNext;
635 if Result then
636 for i := 0 to getCount - 1 do
637 FResults.Column[i].RowChange;
638 end;
639
640 function TResultSet.FetchPrior: boolean;
641 begin
642 IBError(ibxeNoScrollableCursors,[]);
643 end;
644
645 function TResultSet.FetchFirst: boolean;
646 begin
647 IBError(ibxeNoScrollableCursors,[]);
648 end;
649
650 function TResultSet.FetchLast: boolean;
651 begin
652 IBError(ibxeNoScrollableCursors,[]);
653 end;
654
655 function TResultSet.FetchAbsolute(position: Integer): boolean;
656 begin
657 IBError(ibxeNoScrollableCursors,[]);
658 end;
659
660 function TResultSet.FetchRelative(offset: Integer): boolean;
661 begin
662 IBError(ibxeNoScrollableCursors,[]);
663 end;
664
665 function TResultSet.GetCursorName: AnsiString;
666 begin
667 Result := FResults.FStatement.FCursor;
668 end;
669
670 function TResultSet.IsEof: boolean;
671 begin
672 Result := FResults.FStatement.FEof;
673 end;
674
675 function TResultSet.IsBof: boolean;
676 begin
677 Result := FResults.FStatement.FBof;
678 end;
679
680 procedure TResultSet.Close;
681 begin
682 if FCursorSeqNo = FResults.FStatement.FCursorSeqNo then
683 FResults.FStatement.Close;
684 end;
685
686 { TIBXINPUTSQLDA }
687
688 procedure TIBXINPUTSQLDA.Bind;
689 begin
690 if Count = 0 then
691 Count := 1;
692 with FFirebird25ClientAPI do
693 begin
694 if (FXSQLDA <> nil) then
695 if isc_dsql_describe_bind(StatusVector, @(FStatement.Handle), FStatement.SQLDialect,
696 FXSQLDA) > 0 then
697 raise EIBInterBaseError.Create(GetStatus,GetAttachment.GetCodePage);
698
699 if FXSQLDA^.sqld > FXSQLDA^.sqln then
700 begin
701 Count := FXSQLDA^.sqld;
702 if isc_dsql_describe_bind(StatusVector, @(FStatement.Handle), FStatement.SQLDialect,
703 FXSQLDA) > 0 then
704 raise EIBInterBaseError.Create(GetStatus,GetAttachment.GetCodePage);
705 ;
706 end
707 else
708 if FXSQLDA^.sqld = 0 then
709 Count := 0;
710 end;
711 Initialize;
712 end;
713
714 function TIBXINPUTSQLDA.IsInputDataArea: boolean;
715 begin
716 Result := true;
717 end;
718
719 { TIBXOUTPUTSQLDA }
720
721 procedure TIBXOUTPUTSQLDA.Bind;
722 begin
723 { Allocate an initial output descriptor (with one column) }
724 Count := 1;
725 with FFirebird25ClientAPI do
726 begin
727 { Using isc_dsql_describe, get the right size for the columns... }
728 if isc_dsql_describe(StatusVector, @(FStatement.Handle), FStatement.SQLDialect, FXSQLDA) > 0 then
729 raise EIBInterBaseError.Create(GetStatus,GetAttachment.GetCodePage);
730 ;
731
732 if FXSQLDA^.sqld > FXSQLDA^.sqln then
733 begin
734 Count := FXSQLDA^.sqld;
735 if isc_dsql_describe(StatusVector, @(FStatement.Handle), FStatement.SQLDialect, FXSQLDA) > 0 then
736 raise EIBInterBaseError.Create(GetStatus,GetAttachment.GetCodePage);
737 ;
738 end
739 else
740 if FXSQLDA^.sqld = 0 then
741 Count := 0;
742 end;
743 Initialize;
744 SetUniqueRelationName;
745 end;
746
747 function TIBXOUTPUTSQLDA.GetTransaction: TFB25Transaction;
748 begin
749 if FTransaction <> nil then
750 Result := FTransaction
751 else
752 Result := inherited GetTransaction;
753 end;
754
755 procedure TIBXOUTPUTSQLDA.GetData(index: integer; var aIsNull:boolean; var len: short;
756 var data: PByte);
757 begin
758 with TIBXSQLVAR(Column[index]), FXSQLVAR^ do
759 begin
760 aIsNull := (sqltype and 1 = 1) and (FNullIndicator = -1);
761 data := sqldata;
762 len := sqllen;
763 if not IsNull and ((sqltype and (not 1)) = SQL_VARYING) then
764 begin
765 with FFirebird25ClientAPI do
766 len := DecodeInteger(data,2);
767 Inc(data,2);
768 end;
769 end;
770 end;
771
772 function TIBXOUTPUTSQLDA.IsInputDataArea: boolean;
773 begin
774 Result := false;
775 end;
776
777 { TIBXSQLDA }
778 constructor TIBXSQLDA.Create(aStatement: TFB25Statement);
779 begin
780 inherited Create;
781 FStatement := aStatement;
782 FFirebird25ClientAPI := aStatement.FFirebird25ClientAPI;
783 FSize := 0;
784 // writeln('Creating ',ClassName);
785 end;
786
787 destructor TIBXSQLDA.Destroy;
788 begin
789 FreeXSQLDA;
790 // writeln('Destroying ',ClassName);
791 inherited Destroy;
792 end;
793
794 function TIBXSQLDA.CanChangeMetaData: boolean;
795 begin
796 Result := true;
797 end;
798
799 function TIBXSQLDA.CheckStatementStatus(Request: TStatementStatus): boolean;
800 begin
801 Result := false;
802 case Request of
803 ssPrepared:
804 Result := FStatement.IsPrepared;
805
806 ssExecuteResults:
807 Result :=FStatement.FSingleResults;
808
809 ssCursorOpen:
810 Result := FStatement.FOpen;
811
812 ssBOF:
813 Result := FStatement.FBOF;
814
815 ssEOF:
816 Result := FStatement.FEOF;
817 end;
818 end;
819
820 function TIBXSQLDA.ColumnsInUseCount: integer;
821 begin
822 Result := FCount;
823 end;
824
825 function TIBXSQLDA.GetRecordSize: Integer;
826 begin
827 result := SizeOf(TIBXSQLDA) + XSQLDA_LENGTH(FSize);
828 end;
829
830 function TIBXSQLDA.GetXSQLDA: PXSQLDA;
831 begin
832 result := FXSQLDA;
833 end;
834
835 function TIBXSQLDA.GetTransactionSeqNo: integer;
836 begin
837 Result := FTransactionSeqNo;
838 end;
839
840 procedure TIBXSQLDA.Initialize;
841 begin
842 if FXSQLDA <> nil then
843 inherited Initialize;
844 end;
845
846 function TIBXSQLDA.StateChanged(var ChangeSeqNo: integer): boolean;
847 begin
848 Result := FStatement.ChangeSeqNo <> ChangeSeqNo;
849 if Result then
850 ChangeSeqNo := FStatement.ChangeSeqNo;
851 end;
852
853 function TIBXSQLDA.GetTransaction: TFB25Transaction;
854 begin
855 Result := FStatement.GetTransaction as TFB25Transaction;
856 end;
857
858 procedure TIBXSQLDA.SetCount(Value: Integer);
859 var
860 i, OldSize: Integer;
861 p : PXSQLVAR;
862 begin
863 FCount := Value;
864 if FCount = 0 then
865 FUniqueRelationName := ''
866 else
867 begin
868 if FSize > 0 then
869 OldSize := XSQLDA_LENGTH(FSize)
870 else
871 OldSize := 0;
872 if Count > FSize then
873 begin
874 FFirebird25ClientAPI.IBAlloc(FXSQLDA, OldSize, XSQLDA_LENGTH(Count));
875 SetLength(FColumnList, FCount);
876 FXSQLDA^.version := SQLDA_VERSION1;
877 p := @FXSQLDA^.sqlvar[0];
878 for i := 0 to Count - 1 do
879 begin
880 if i >= FSize then
881 FColumnList[i] := TIBXSQLVAR.Create(self,i);
882 TIBXSQLVAR(Column[i]).FXSQLVAR := p;
883 p := Pointer(PAnsiChar(p) + sizeof(FXSQLDA^.sqlvar));
884 end;
885 FSize := inherited Count;
886 end;
887 if FSize > 0 then
888 begin
889 FXSQLDA^.sqln := Value;
890 FXSQLDA^.sqld := Value;
891 end;
892 end;
893 end;
894
895 procedure TIBXSQLDA.FreeXSQLDA;
896 var i: integer;
897 begin
898 if FXSQLDA <> nil then
899 begin
900 // writeln('SQLDA Cleanup');
901 for i := 0 to Count - 1 do
902 TIBXSQLVAR(Column[i]).FreeSQLData;
903 FreeMem(FXSQLDA);
904 FXSQLDA := nil;
905 end;
906 for i := 0 to FSize - 1 do
907 TIBXSQLVAR(Column[i]).Free;
908 SetLength(FColumnList,0);
909 FSize := 0;
910 end;
911
912 function TIBXSQLDA.GetStatement: IStatement;
913 begin
914 Result := FStatement;
915 end;
916
917 function TIBXSQLDA.GetPrepareSeqNo: integer;
918 begin
919 Result := FStatement.FPrepareSeqNo;
920 end;
921
922 { TFB25Statement }
923
924 procedure TFB25Statement.GetPerfCounters(var counters: TPerfStatistics);
925 var DBInfo: IDBInformation;
926 i: integer;
927 {$IFDEF UNIX}
928 times: tms;
929 {$ENDIF}
930 begin
931 {$IFDEF UNIX}
932 FpTimes(times);
933 counters[psUserTime] := times.tms_utime;
934 {$ELSE}
935 counters[psUserTime] := 0;
936 {$ENDIF}
937 counters[psRealTime] := TimeStampToMSecs(DateTimeToTimeStamp(Now));
938
939 DBInfo := GetAttachment.GetDBInformation([isc_info_reads,isc_info_writes,
940 isc_info_fetches, isc_info_num_buffers, isc_info_current_memory,
941 isc_info_max_memory]);
942 if DBInfo <> nil then
943 begin
944 for i := 0 to DBInfo.Count - 1 do
945 with DBInfo[i] do
946 case getItemType of
947 isc_info_reads:
948 counters[psReads] := AsInteger;
949 isc_info_writes:
950 counters[psWrites] := AsInteger;
951 isc_info_fetches:
952 counters[psFetches] := AsInteger;
953 isc_info_num_buffers:
954 counters[psBuffers] := AsInteger;
955 isc_info_current_memory:
956 counters[psCurrentMemory] := AsInteger;
957 isc_info_max_memory:
958 counters[psMaxMemory] := AsInteger;
959 end;
960 end;
961 end;
962
963 procedure TFB25Statement.CheckHandle;
964 begin
965 if FHandle = nil then
966 IBError(ibxeInvalidStatementHandle,[nil]);
967 end;
968
969 procedure TFB25Statement.GetDsqlInfo(info_request: byte; buffer: ISQLInfoResults
970 );
971 begin
972 with FFirebird25ClientAPI, buffer as TSQLInfoResultsBuffer do
973 if isc_dsql_sql_info(StatusVector, @(FHandle), 1, @info_request,
974 GetBufSize, Buffer) > 0 then
975 raise EIBInterBaseError.Create(GetStatus,ConnectionCodePage);
976 end;
977
978 function TFB25Statement.GetStatementIntf: IStatement;
979 begin
980 Result := self;
981 end;
982
983 procedure TFB25Statement.InternalPrepare(CursorName: AnsiString);
984 var
985 GUID: TGUID;
986 RB: ISQLInfoResults;
987 TRHandle: TISC_TR_HANDLE;
988 sql: AnsiString;
989 begin
990 if FPrepared then
991 Exit;
992
993 if (FSQL = '') then
994 IBError(ibxeEmptyQuery, [nil]);
995
996 FCursor := CursorName;
997 if FCursor = '' then
998 begin
999 CreateGuid(GUID);
1000 FCursor := GUIDToString(GUID);
1001 end;
1002
1003 try
1004 CheckTransaction(FTransactionIntf);
1005 with FFirebird25ClientAPI do
1006 begin
1007 Call(isc_dsql_alloc_statement2(StatusVector, @(FDBHandle),
1008 @FHandle), True);
1009 TRHandle := (FTransactionIntf as TFB25Transaction).Handle;
1010 if FHasParamNames then
1011 begin
1012 if FProcessedSQL = '' then
1013 ProcessSQL(FSQL,FGenerateParamNames,FProcessedSQL);
1014 sql := FProcessedSQL;
1015 end
1016 else
1017 sql := FSQL;
1018
1019 if StringCodePage(sql) <> CP_NONE then
1020 sql := TransliterateToCodePage(sql,ConnectionCodePage);
1021
1022 Call(isc_dsql_prepare(StatusVector, @(TRHandle), @FHandle, 0,
1023 PAnsiChar(sql), 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 }
1029 RB := GetDsqlInfo(isc_info_sql_stmt_type);
1030 if RB.Count > 0 then
1031 FSQLStatementType := TIBSQLStatementTypes(RB[0].GetAsInteger)
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,
1044 SQLStartTransaction: begin
1045 FreeHandle;
1046 IBError(ibxeNotPermitted, [nil]);
1047 end;
1048 SQLCommit,
1049 SQLRollback,
1050 SQLDDL, SQLSetGenerator,
1051 SQLInsert, SQLUpdate, SQLDelete, SQLSelect, SQLSelectForUpdate,
1052 SQLExecProcedure:
1053 begin
1054 {set up input sqlda}
1055 FSQLParams.Bind;
1056
1057 {setup output sqlda}
1058 if FSQLStatementType in [SQLSelect, SQLSelectForUpdate,
1059 SQLExecProcedure] then
1060 FSQLRecord.Bind;
1061 end;
1062 end;
1063 except
1064 on E: Exception do begin
1065 if (FHandle <> nil) then
1066 FreeHandle;
1067 if E is EIBInterBaseError then
1068 E.Message := E.Message + sSQLErrorSeparator + FSQL;
1069 raise;
1070 end;
1071 end;
1072 FPrepared := true;
1073 FSingleResults := false;
1074 if RetainInterfaces then
1075 begin
1076 SetRetainInterfaces(false);
1077 SetRetainInterfaces(true);
1078 end;
1079 Inc(FPrepareSeqNo);
1080 Inc(FChangeSeqNo);
1081 with FTransactionIntf as TFB25Transaction do
1082 begin
1083 FSQLParams.FTransactionSeqNo := TransactionSeqNo;
1084 FSQLRecord.FTransactionSeqNo := TransactionSeqNo;
1085 end;
1086 end;
1087
1088 function TFB25Statement.InternalExecute(aTransaction: ITransaction): IResults;
1089 var TRHandle: TISC_TR_HANDLE;
1090 begin
1091 Result := nil;
1092 FBOF := false;
1093 FEOF := false;
1094 FSingleResults := false;
1095 CheckTransaction(aTransaction);
1096 if not FPrepared then
1097 InternalPrepare;
1098 CheckHandle;
1099 if aTransaction <> FTransactionIntf then
1100 AddMonitor(aTransaction as TFB25Transaction);
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 FFirebird25ClientAPI do
1107 begin
1108 if FCollectStatistics then
1109 GetPerfCounters(FBeforeStats);
1110
1111 case FSQLStatementType of
1112 SQLSelect:
1113 IBError(ibxeIsAExecuteProcedure,[]);
1114
1115 SQLExecProcedure:
1116 begin
1117 Call(isc_dsql_execute2(StatusVector,
1118 @(TRHandle),
1119 @FHandle,
1120 SQLDialect,
1121 FSQLParams.AsXSQLDA,
1122 FSQLRecord.AsXSQLDA), True);
1123 Result := TResults.Create(FSQLRecord);
1124 FSingleResults := true;
1125 end
1126 else
1127 Call(isc_dsql_execute(StatusVector,
1128 @(TRHandle),
1129 @FHandle,
1130 SQLDialect,
1131 FSQLParams.AsXSQLDA), True);
1132
1133 end;
1134 if FCollectStatistics then
1135 begin
1136 GetPerfCounters(FAfterStats);
1137 FStatisticsAvailable := true;
1138 end;
1139 end;
1140 finally
1141 if aTransaction <> FTransactionIntf then
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 Scrollable: boolean): IResultSet;
1152 var TRHandle: TISC_TR_HANDLE;
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 FStaleReferenceChecks and (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB25transaction).TransactionSeqNo) then
1167 IBError(ibxeInterfaceOutofDate,[nil]);
1168
1169 with FFirebird25ClientAPI do
1170 begin
1171 if FCollectStatistics then
1172 GetPerfCounters(FBeforeStats);
1173
1174 TRHandle := (aTransaction as TFB25Transaction).Handle;
1175 Call(isc_dsql_execute2(StatusVector,
1176 @(TRHandle),
1177 @FHandle,
1178 SQLDialect,
1179 FSQLParams.AsXSQLDA,
1180 nil), True);
1181
1182 if FCollectStatistics then
1183 begin
1184 GetPerfCounters(FAfterStats);
1185 FStatisticsAvailable := true;
1186 end;
1187 end;
1188 Inc(FCursorSeqNo);
1189 FSingleResults := false;
1190 FOpen := True;
1191 FExecTransactionIntf := aTransaction;
1192 FBOF := true;
1193 FEOF := false;
1194 FSQLRecord.FTransaction := aTransaction as TFB25Transaction;
1195 FSQLRecord.FTransactionSeqNo := FSQLRecord.FTransaction.TransactionSeqNo;
1196 Result := TResultSet.Create(FSQLRecord);
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;
1209 begin
1210 Close;
1211 ReleaseInterfaces;
1212 try
1213 if FHandle <> nil then
1214 with FFirebird25ClientAPI do
1215 begin
1216 isc_res :=
1217 Call(isc_dsql_free_statement(StatusVector, @FHandle, DSQL_drop), False);
1218 if (StatusVector^ = 1) and (isc_res > 0) and (isc_res <> isc_bad_stmt_handle) then
1219 raise EIBInterBaseError.Create(GetStatus,ConnectionCodePage);
1220 end;
1221 finally
1222 FHandle := nil;
1223 FCursor := '';
1224 FPrepared := false;
1225 end;
1226 end;
1227
1228 procedure TFB25Statement.InternalClose(Force: boolean);
1229 var
1230 isc_res: ISC_STATUS;
1231 begin
1232 if (FHandle <> nil) and (SQLStatementType = SQLSelect) and FOpen then
1233 try
1234 with FFirebird25ClientAPI do
1235 begin
1236 isc_res := Call(
1237 isc_dsql_free_statement(StatusVector, @FHandle, DSQL_close),
1238 False);
1239 if not Force and (StatusVector^ = 1) and (isc_res > 0) and
1240 not getStatus.CheckStatusVector(
1241 [isc_bad_stmt_handle, isc_dsql_cursor_close_err]) then
1242 raise EIBInterBaseError.Create(GetStatus,ConnectionCodePage);
1243 end;
1244 finally
1245 if (FSQLRecord.FTransaction <> nil) and (FSQLRecord.FTransaction <> (FTransactionIntf as TFB25Transaction)) then
1246 RemoveMonitor(FSQLRecord.FTransaction);
1247 FOpen := False;
1248 FExecTransactionIntf := nil;
1249 FSQLRecord.FTransaction := nil;
1250 Inc(FChangeSeqNo);
1251 end;
1252 end;
1253
1254 constructor TFB25Statement.Create(Attachment: TFB25Attachment;
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 := Attachment.IBDataBaseError;
1262 FSQLParams := TIBXINPUTSQLDA.Create(self);
1263 FSQLRecord := TIBXOUTPUTSQLDA.Create(self);
1264 InternalPrepare(CursorName);
1265 end;
1266
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 := Attachment.IBDataBaseError;
1276 FSQLParams := TIBXINPUTSQLDA.Create(self);
1277 FSQLParams.CaseSensitiveParams := CaseSensitiveParams;
1278 FSQLRecord := TIBXOUTPUTSQLDA.Create(self);
1279 InternalPrepare(CursorName);
1280 end;
1281
1282 destructor TFB25Statement.Destroy;
1283 begin
1284 inherited Destroy;
1285 if assigned(FSQLParams) then FSQLParams.Free;
1286 if assigned(FSQLRecord) then FSQLRecord.Free;
1287 end;
1288
1289 function TFB25Statement.FetchNext: boolean;
1290 var
1291 fetch_res: ISC_STATUS;
1292 begin
1293 result := false;
1294 if not FOpen then
1295 IBError(ibxeSQLClosed, [nil]);
1296 if FEOF then
1297 IBError(ibxeEOF,[nil]);
1298
1299 with FFirebird25ClientAPI do
1300 begin
1301 { Go to the next record... }
1302 fetch_res :=
1303 Call(isc_dsql_fetch(StatusVector, @FHandle, SQLDialect, FSQLRecord.AsXSQLDA), False);
1304 if (fetch_res = 100) or (getStatus.CheckStatusVector([isc_dsql_cursor_err])) then
1305 begin
1306 FBOF := false;
1307 FEOF := true;
1308 Exit; {End of File}
1309 end
1310 else
1311 if (fetch_res > 0) then
1312 begin
1313 try
1314 raise EIBInterBaseError.Create(GetStatus,ConnectionCodePage);
1315 except
1316 Close;
1317 raise;
1318 end;
1319 end
1320 else
1321 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
1333 Inc(FChangeSeqNo);
1334 end;
1335
1336 function TFB25Statement.GetSQLParams: ISQLParams;
1337 begin
1338 CheckHandle;
1339 if not HasInterface(0) then
1340 AddInterface(0,TSQLParams.Create(FSQLParams));
1341 Result := TSQLParams(GetInterface(0));
1342 end;
1343
1344 function TFB25Statement.GetMetaData: IMetaData;
1345 begin
1346 CheckHandle;
1347 if not HasInterface(1) then
1348 AddInterface(1, TMetaData.Create(FSQLRecord));
1349 Result := TMetaData(GetInterface(1));
1350 end;
1351
1352 function TFB25Statement.GetPlan: AnsiString;
1353 var
1354 RB: ISQLInfoResults;
1355 begin
1356 if (not (FSQLStatementType in [SQLSelect, SQLSelectForUpdate,
1357 {TODO: SQLExecProcedure, }
1358 SQLUpdate, SQLDelete])) then
1359 result := ''
1360 else
1361 begin
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;
1366 end;
1367 end;
1368
1369 function TFB25Statement.CreateBlob(column: TColumnMetaData): IBlob;
1370 begin
1371 if assigned(column) and (column.SQLType <> SQL_Blob) then
1372 IBError(ibxeNotABlob,[nil]);
1373 Result := TFB25Blob.Create(GetAttachment as TFB25Attachment,FExecTransactionIntf as TFB25Transaction,
1374 column.GetBlobMetaData,nil);
1375 end;
1376
1377 function TFB25Statement.CreateArray(column: TColumnMetaData): IArray;
1378 begin
1379 if assigned(column) and (column.SQLType <> SQL_ARRAY) then
1380 IBError(ibxeNotAnArray,[nil]);
1381 Result := TFB25Array.Create(GetAttachment as TFB25Attachment,FExecTransactionIntf as TFB25Transaction,
1382 column.GetArrayMetaData);
1383 end;
1384
1385 procedure TFB25Statement.SetRetainInterfaces(aValue: boolean);
1386 begin
1387 inherited SetRetainInterfaces(aValue);
1388 if HasInterface(1) then
1389 TMetaData(GetInterface(1)).RetainInterfaces := aValue;
1390 if HasInterface(0) then
1391 TSQLParams(GetInterface(0)).RetainInterfaces := aValue;
1392 end;
1393
1394 function TFB25Statement.IsPrepared: boolean;
1395 begin
1396 Result := FHandle <> nil;
1397 end;
1398
1399 end.
1400

Properties

Name Value
svn:eol-style native