ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/2.5/FB25Statement.pas
Revision: 379
Committed: Mon Jan 10 10:08:03 2022 UTC (2 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 39855 byte(s)
Log Message:
set line ending property

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 GetSQLType: cardinal; override;
134 function GetSubtype: integer; 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 GetIsNull: Boolean; override;
142 function GetIsNullable: boolean; override;
143 function GetSQLData: PByte; override;
144 function GetDataLength: cardinal; override;
145 function GetSize: cardinal; override;
146 function GetDefaultTextSQLType: cardinal; override;
147 procedure SetIsNull(Value: Boolean); override;
148 procedure SetIsNullable(Value: Boolean); override;
149 procedure SetSQLData(AValue: PByte; len: cardinal); override;
150 procedure InternalSetScale(aValue: integer); override;
151 procedure InternalSetDataLength(len: cardinal); override;
152 procedure InternalSetSQLType(aValue: cardinal); override;
153 procedure SetCharSetID(aValue: cardinal); override;
154 public
155 constructor Create(aParent: TIBXSQLDA; aIndex: integer);
156 procedure FreeSQLData;
157 procedure RowChange; override;
158 function GetAsArray: IArray; override;
159 function GetAsBlob(Blob_ID: TISC_QUAD; BPB: IBPB): IBlob; override;
160 function GetArrayMetaData: IArrayMetaData; override;
161 function GetBlobMetaData: IBlobMetaData; override;
162 function CreateBlob: IBlob; override;
163 procedure Initialize; override;
164
165 property Statement: TFB25Statement read FStatement;
166 property SQLType: cardinal read GetSQLType write SetSQLType;
167 end;
168
169 TIBXINPUTSQLDA = class;
170
171 { TIBXSQLDA }
172
173 TIBXSQLDA = class(TSQLDataArea)
174 private
175 FCount: Integer; {Columns in use - may be less than inherited columns}
176 FSize: Integer; {Number of TIBXSQLVARs in column list}
177 FXSQLDA: PXSQLDA;
178 FTransactionSeqNo: integer;
179 function GetRecordSize: Integer;
180 function GetXSQLDA: PXSQLDA;
181 protected
182 FStatement: TFB25Statement;
183 FFirebird25ClientAPI: TFB25ClientAPI;
184 function GetTransactionSeqNo: integer; override;
185 procedure FreeXSQLDA;
186 function GetStatement: IStatement; override;
187 function GetPrepareSeqNo: integer; override;
188 procedure SetCount(Value: Integer); override;
189 public
190 constructor Create(aStatement: TFB25Statement);
191 destructor Destroy; override;
192 function CanChangeMetaData: boolean; override;
193 function CheckStatementStatus(Request: TStatementStatus): boolean; override;
194 function ColumnsInUseCount: integer; override;
195 function GetTransaction: TFB25Transaction; virtual;
196 procedure Initialize; override;
197 function StateChanged(var ChangeSeqNo: integer): boolean; override;
198 property AsXSQLDA: PXSQLDA read GetXSQLDA;
199 property Count: Integer read FCount write SetCount;
200 property RecordSize: Integer read GetRecordSize;
201 property Statement: TFB25Statement read FStatement;
202 end;
203
204 { TIBXINPUTSQLDA }
205
206 TIBXINPUTSQLDA = class(TIBXSQLDA)
207 public
208 procedure Bind;
209 function IsInputDataArea: boolean; override;
210 end;
211
212
213 { TIBXOUTPUTSQLDA }
214
215 TIBXOUTPUTSQLDA = class(TIBXSQLDA)
216 private
217 FTransaction: TFB25Transaction; {transaction used to execute the statement}
218 public
219 procedure Bind;
220 function GetTransaction: TFB25Transaction; override;
221 procedure GetData(index: integer; var aIsNull: boolean; var len: short;
222 var data: PByte); override;
223 function IsInputDataArea: boolean; override;
224 end;
225
226 { TResultSet }
227
228 TResultSet = class(TResults,IResultSet)
229 private
230 FResults: TIBXOUTPUTSQLDA;
231 FCursorSeqNo: integer;
232 public
233 constructor Create(aResults: TIBXOUTPUTSQLDA);
234 destructor Destroy; override;
235 {IResultSet}
236 function FetchNext: boolean; {fetch next record}
237 function FetchPrior: boolean; {fetch previous record}
238 function FetchFirst:boolean; {fetch first record}
239 function FetchLast: boolean; {fetch last record}
240 function FetchAbsolute(position: Integer): boolean; {fetch record by its absolute position in result set}
241 function FetchRelative(offset: Integer): boolean; {fetch record by position relative to current}
242 function GetCursorName: AnsiString;
243 function IsEof: boolean;
244 function IsBof: boolean;
245 procedure Close;
246 end;
247
248 { TFB25Statement }
249
250 TFB25Statement = class(TFBStatement,IStatement)
251 private
252 FDBHandle: TISC_DB_HANDLE;
253 FHandle: TISC_STMT_HANDLE;
254 FFirebird25ClientAPI: TFB25ClientAPI;
255 FSQLParams: TIBXINPUTSQLDA;
256 FSQLRecord: TIBXOUTPUTSQLDA;
257 FCursor: AnsiString; { Cursor name...}
258 FCursorSeqNo: integer;
259 procedure GetPerfCounters(var counters: TPerfStatistics);
260 protected
261 procedure CheckHandle; override;
262 procedure GetDsqlInfo(info_request: byte; buffer: ISQLInfoResults); override;
263 function GetStatementIntf: IStatement; override;
264 procedure InternalPrepare(CursorName: AnsiString=''); override;
265 function InternalExecute(aTransaction: ITransaction): IResults; override;
266 function InternalOpenCursor(aTransaction: ITransaction; Scrollable: boolean): IResultSet; override;
267 procedure ProcessSQL(sql: AnsiString; GenerateParamNames: boolean; var processedSQL: AnsiString); override;
268 procedure FreeHandle; override;
269 procedure InternalClose(Force: boolean); override;
270 public
271 constructor Create(Attachment: TFB25Attachment; Transaction: ITransaction;
272 sql: AnsiString; aSQLDialect: integer; CursorName: AnsiString='');
273 constructor CreateWithParameterNames(Attachment: TFB25Attachment;
274 Transaction: ITransaction; sql: AnsiString; aSQLDialect: integer; GenerateParamNames: boolean;
275 CaseSensitiveParams: boolean=false; CursorName: AnsiString='');
276 destructor Destroy; override;
277 function FetchNext: boolean;
278
279 public
280 {IStatement}
281 function GetSQLParams: ISQLParams; override;
282 function GetMetaData: IMetaData; override;
283 function GetPlan: AnsiString;
284 function IsPrepared: boolean;
285 function CreateBlob(column: TColumnMetaData): IBlob; override;
286 function CreateArray(column: TColumnMetaData): IArray; override;
287 procedure SetRetainInterfaces(aValue: boolean); override;
288 property Handle: TISC_STMT_HANDLE read FHandle;
289
290 end;
291
292 implementation
293
294 uses IBUtils, FBMessages, FBBlob, FB25Blob, variants, IBErrorCodes, FBArray, FB25Array
295 {$IFDEF UNIX}, BaseUnix {$ENDIF};
296
297
298 { TIBXSQLVAR }
299
300 function TIBXSQLVAR.GetSQLType: cardinal;
301 begin
302 result := FXSQLVAR^.sqltype and (not 1);
303 end;
304
305 function TIBXSQLVAR.GetSubtype: integer;
306 begin
307 if GetSQLType = SQL_BLOB then
308 result := FXSQLVAR^.sqlsubtype
309 else
310 result := 0;
311 end;
312
313 function TIBXSQLVAR.GetAliasName: AnsiString;
314 begin
315 result := strpas(FXSQLVAR^.aliasname);
316 end;
317
318 function TIBXSQLVAR.GetFieldName: AnsiString;
319 begin
320 result := strpas(FXSQLVAR^.sqlname);
321 end;
322
323 function TIBXSQLVAR.GetOwnerName: AnsiString;
324 begin
325 result := strpas(FXSQLVAR^.ownname);
326 end;
327
328 function TIBXSQLVAR.GetRelationName: AnsiString;
329 begin
330 result := strpas(FXSQLVAR^.relname);
331 end;
332
333 function TIBXSQLVAR.GetScale: integer;
334 begin
335 if GetSQLType = SQL_BLOB then
336 result := 0
337 else
338 result := FXSQLVAR^.sqlscale;
339 end;
340
341 function TIBXSQLVAR.GetCharSetID: cardinal;
342 begin
343 result := 0;
344 case SQLType of
345 SQL_VARYING, SQL_TEXT:
346 {see http://firebirdsql.org/rlsnotesh/rlsnotes210.html}
347 result := FXSQLVAR^.sqlsubtype and $FF;
348
349 SQL_BLOB:
350 if (SQLSubType = 1) then
351 {see http://firebirdsql.org/rlsnotesh/rlsnotes210.html}
352 result := FXSQLVAR^.sqlscale and $FF;
353
354 SQL_ARRAY:
355 if (GetRelationName <> '') and (GetFieldName <> '') then
356 result := GetArrayMetaData.GetCharSetID;
357 end;
358 end;
359
360 function TIBXSQLVAR.GetIsNull: Boolean;
361 begin
362 result := IsNullable and (FNullIndicator = -1);
363 end;
364
365 function TIBXSQLVAR.GetIsNullable: boolean;
366 begin
367 result := (FXSQLVAR^.sqltype and 1 = 1);
368 end;
369
370 function TIBXSQLVAR.GetSQLData: PByte;
371 begin
372 Result := FXSQLVAR^.sqldata;
373 end;
374
375 function TIBXSQLVAR.GetDataLength: cardinal;
376 begin
377 Result := FXSQLVAR^.sqllen;
378 end;
379
380 function TIBXSQLVAR.GetSize: cardinal;
381 begin
382 Result := FMetadataSize;
383 end;
384
385 function TIBXSQLVAR.GetArrayMetaData: IArrayMetaData;
386 begin
387 if GetSQLType <> SQL_ARRAY then
388 IBError(ibxeInvalidDataConversion,[nil]);
389
390 if FArrayMetaData = nil then
391 FArrayMetaData := TFB25ArrayMetaData.Create(FStatement.GetAttachment as TFB25Attachment,
392 FStatement.GetTransaction as TFB25Transaction,
393 GetRelationName,GetFieldName);
394 Result := FArrayMetaData;
395 end;
396
397 function TIBXSQLVAR.GetBlobMetaData: IBlobMetaData;
398 begin
399 if GetSQLType <> SQL_BLOB then
400 IBError(ibxeInvalidDataConversion,[nil]);
401
402 if FBlobMetaData = nil then
403 FBlobMetaData := TFB25BlobMetaData.Create(FStatement.GetAttachment as TFB25Attachment,
404 FStatement.GetTransaction as TFB25Transaction,
405 GetRelationName,GetFieldName,GetSubType);
406 (FBlobMetaData as TFBBlobMetaData).SetCharSetID(GetCharSetID);
407 Result := FBlobMetaData;
408 end;
409
410 function TIBXSQLVAR.GetAsArray: IArray;
411 begin
412 if SQLType <> SQL_ARRAY then
413 IBError(ibxeInvalidDataConversion,[nil]);
414
415 if IsNull then
416 Result := nil
417 else
418 begin
419 if FArrayIntf = nil then
420 FArrayIntf := TFB25Array.Create(FStatement.GetAttachment as TFB25Attachment,
421 TIBXSQLDA(Parent).GetTransaction,
422 GetArrayMetaData,PISC_QUAD(SQLData)^);
423 Result := FArrayIntf;
424 end;
425 end;
426
427 function TIBXSQLVAR.GetAsBlob(Blob_ID: TISC_QUAD; BPB: IBPB): IBlob;
428 begin
429 if FBlob <> nil then
430 Result := FBlob
431 else
432 begin
433 if SQLType <> SQL_BLOB then
434 IBError(ibxeInvalidDataConversion, [nil]);
435 if IsNull then
436 Result := nil
437 else
438 Result := TFB25Blob.Create(FStatement.GetAttachment as TFB25Attachment,
439 TIBXSQLDA(Parent).GetTransaction,
440 GetBlobMetaData,
441 Blob_ID,BPB);
442 FBlob := Result;
443 end;
444 end;
445
446 function TIBXSQLVAR.CreateBlob: IBlob;
447 begin
448 Result := TFB25Blob.Create(FStatement.GetAttachment as TFB25Attachment,
449 FStatement.GetTransaction as TFB25Transaction,GetSubType,GetCharSetID,nil);
450 end;
451
452 procedure TIBXSQLVAR.Initialize;
453 begin
454 inherited Initialize;
455 FOwnsSQLData := true;
456 with FFirebird25ClientAPI, FXSQLVar^ do
457 begin
458 FMetadataSize := sqllen;
459 case sqltype and (not 1) of
460 SQL_TEXT, SQL_TYPE_DATE, SQL_TYPE_TIME, SQL_TIMESTAMP,
461 SQL_BLOB, SQL_ARRAY, SQL_QUAD, SQL_SHORT, SQL_BOOLEAN,
462 SQL_LONG, SQL_INT64, SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: begin
463 if (sqllen = 0) then
464 { Make sure you get a valid pointer anyway
465 select '' from foo }
466 IBAlloc(sqldata, 0, 1)
467 else
468 IBAlloc(sqldata, 0, sqllen)
469 end;
470 SQL_VARYING: begin
471 IBAlloc(sqldata, 0, sqllen + 2);
472 end;
473 else
474 IBError(ibxeUnknownSQLDataType, [sqltype and (not 1)])
475 end;
476 if (sqltype and 1 = 1) then
477 begin
478 sqlInd := @FNullIndicator;
479 FNullIndicator := -1;
480 end
481 else
482 sqlInd := nil;
483 end;
484 SaveMetaData;
485 end;
486
487 procedure TIBXSQLVAR.SetIsNull(Value: Boolean);
488 begin
489 if Value then
490 begin
491 IsNullable := true;
492 FNullIndicator := -1;
493 Changed;
494 end
495 else
496 if ((not Value) and IsNullable) then
497 begin
498 FNullIndicator := 0;
499 Changed;
500 end;
501 end;
502
503 procedure TIBXSQLVAR.SetIsNullable(Value: Boolean);
504 begin
505 if (Value <> IsNullable) then
506 begin
507 if Value then
508 begin
509 FXSQLVAR^.sqltype := FXSQLVAR^.sqltype or 1;
510 FNullIndicator := 0;
511 FXSQLVAR^.sqlInd := @FNullIndicator;
512 end
513 else
514 begin
515 FXSQLVAR^.sqltype := FXSQLVAR^.sqltype and (not 1);
516 FXSQLVAR^.sqlind := nil;
517 end;
518 end;
519 Changed;
520 end;
521
522 procedure TIBXSQLVAR.SetSQLData(AValue: PByte; len: cardinal);
523 begin
524 if FOwnsSQLData then
525 FreeMem(FXSQLVAR^.sqldata);
526 FXSQLVAR^.sqldata := AValue;
527 FXSQLVAR^.sqllen := len;
528 FOwnsSQLData := false;
529 Changed;
530 end;
531
532 procedure TIBXSQLVAR.InternalSetScale(aValue: integer);
533 begin
534 FXSQLVAR^.sqlscale := aValue;
535 Changed;
536 end;
537
538 procedure TIBXSQLVAR.InternalSetDataLength(len: cardinal);
539 begin
540 if not FOwnsSQLData then
541 FXSQLVAR^.sqldata := nil;
542 FXSQLVAR^.sqllen := len;
543 with FFirebird25ClientAPI do
544 IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
545 FOwnsSQLData := true;
546 Changed;
547 end;
548
549 procedure TIBXSQLVAR.InternalSetSQLType(aValue: cardinal);
550 begin
551 FXSQLVAR^.sqltype := aValue or (FXSQLVAR^.sqltype and 1);
552 Changed;
553 end;
554
555 procedure TIBXSQLVAR.SetCharSetID(aValue: cardinal);
556 begin
557 if aValue <> GetCharSetID then
558 begin
559 case SQLType of
560 SQL_VARYING, SQL_TEXT:
561 FXSQLVAR^.sqlsubtype := (aValue and $FF) or (FXSQLVAR^.sqlsubtype and not $FF);
562
563 SQL_BLOB,
564 SQL_ARRAY:
565 IBError(ibxeInvalidDataConversion,[nil]);
566 end;
567 Changed;
568 end;
569 end;
570
571 function TIBXSQLVAR.GetDefaultTextSQLType: cardinal;
572 begin
573 Result := SQL_TEXT;
574 end;
575
576 constructor TIBXSQLVAR.Create(aParent: TIBXSQLDA; aIndex: integer);
577 begin
578 inherited Create(aParent,aIndex);
579 FStatement := aParent.Statement;
580 FFirebird25ClientAPI := aParent.FFirebird25ClientAPI;
581 end;
582
583 procedure TIBXSQLVAR.FreeSQLData;
584 begin
585 if FOwnsSQLData then
586 FreeMem(FXSQLVAR^.sqldata);
587 FXSQLVAR^.sqldata := nil;
588 FOwnsSQLData := true;
589 end;
590
591 procedure TIBXSQLVAR.RowChange;
592 begin
593 inherited RowChange;
594 FBlob := nil;
595 end;
596
597
598 { TResultSet }
599
600 constructor TResultSet.Create(aResults: TIBXOUTPUTSQLDA);
601 begin
602 inherited Create(aResults);
603 FResults := aResults;
604 FCursorSeqNo := aResults.FStatement.FCursorSeqNo;
605 end;
606
607 destructor TResultSet.Destroy;
608 begin
609 Close;
610 inherited Destroy;
611 end;
612
613 function TResultSet.FetchNext: boolean;
614 var i: integer;
615 begin
616 CheckActive;
617 Result := FResults.FStatement.FetchNext;
618 if Result then
619 for i := 0 to getCount - 1 do
620 FResults.Column[i].RowChange;
621 end;
622
623 function TResultSet.FetchPrior: boolean;
624 begin
625 IBError(ibxeNoScrollableCursors,[]);
626 end;
627
628 function TResultSet.FetchFirst: boolean;
629 begin
630 IBError(ibxeNoScrollableCursors,[]);
631 end;
632
633 function TResultSet.FetchLast: boolean;
634 begin
635 IBError(ibxeNoScrollableCursors,[]);
636 end;
637
638 function TResultSet.FetchAbsolute(position: Integer): boolean;
639 begin
640 IBError(ibxeNoScrollableCursors,[]);
641 end;
642
643 function TResultSet.FetchRelative(offset: Integer): boolean;
644 begin
645 IBError(ibxeNoScrollableCursors,[]);
646 end;
647
648 function TResultSet.GetCursorName: AnsiString;
649 begin
650 Result := FResults.FStatement.FCursor;
651 end;
652
653 function TResultSet.IsEof: boolean;
654 begin
655 Result := FResults.FStatement.FEof;
656 end;
657
658 function TResultSet.IsBof: boolean;
659 begin
660 Result := FResults.FStatement.FBof;
661 end;
662
663 procedure TResultSet.Close;
664 begin
665 if FCursorSeqNo = FResults.FStatement.FCursorSeqNo then
666 FResults.FStatement.Close;
667 end;
668
669 { TIBXINPUTSQLDA }
670
671 procedure TIBXINPUTSQLDA.Bind;
672 begin
673 if Count = 0 then
674 Count := 1;
675 with FFirebird25ClientAPI do
676 begin
677 if (FXSQLDA <> nil) then
678 if isc_dsql_describe_bind(StatusVector, @(FStatement.Handle), FStatement.SQLDialect,
679 FXSQLDA) > 0 then
680 IBDataBaseError;
681
682 if FXSQLDA^.sqld > FXSQLDA^.sqln then
683 begin
684 Count := FXSQLDA^.sqld;
685 if isc_dsql_describe_bind(StatusVector, @(FStatement.Handle), FStatement.SQLDialect,
686 FXSQLDA) > 0 then
687 IBDataBaseError;
688 end
689 else
690 if FXSQLDA^.sqld = 0 then
691 Count := 0;
692 end;
693 Initialize;
694 end;
695
696 function TIBXINPUTSQLDA.IsInputDataArea: boolean;
697 begin
698 Result := true;
699 end;
700
701 { TIBXOUTPUTSQLDA }
702
703 procedure TIBXOUTPUTSQLDA.Bind;
704 begin
705 { Allocate an initial output descriptor (with one column) }
706 Count := 1;
707 with FFirebird25ClientAPI do
708 begin
709 { Using isc_dsql_describe, get the right size for the columns... }
710 if isc_dsql_describe(StatusVector, @(FStatement.Handle), FStatement.SQLDialect, FXSQLDA) > 0 then
711 IBDataBaseError;
712
713 if FXSQLDA^.sqld > FXSQLDA^.sqln then
714 begin
715 Count := FXSQLDA^.sqld;
716 if isc_dsql_describe(StatusVector, @(FStatement.Handle), FStatement.SQLDialect, FXSQLDA) > 0 then
717 IBDataBaseError;
718 end
719 else
720 if FXSQLDA^.sqld = 0 then
721 Count := 0;
722 end;
723 Initialize;
724 SetUniqueRelationName;
725 end;
726
727 function TIBXOUTPUTSQLDA.GetTransaction: TFB25Transaction;
728 begin
729 if FTransaction <> nil then
730 Result := FTransaction
731 else
732 Result := inherited GetTransaction;
733 end;
734
735 procedure TIBXOUTPUTSQLDA.GetData(index: integer; var aIsNull:boolean; var len: short;
736 var data: PByte);
737 begin
738 with TIBXSQLVAR(Column[index]), FXSQLVAR^ do
739 begin
740 aIsNull := (sqltype and 1 = 1) and (FNullIndicator = -1);
741 data := sqldata;
742 len := sqllen;
743 if not IsNull and ((sqltype and (not 1)) = SQL_VARYING) then
744 begin
745 with FFirebird25ClientAPI do
746 len := DecodeInteger(data,2);
747 Inc(data,2);
748 end;
749 end;
750 end;
751
752 function TIBXOUTPUTSQLDA.IsInputDataArea: boolean;
753 begin
754 Result := false;
755 end;
756
757 { TIBXSQLDA }
758 constructor TIBXSQLDA.Create(aStatement: TFB25Statement);
759 begin
760 inherited Create;
761 FStatement := aStatement;
762 FFirebird25ClientAPI := aStatement.FFirebird25ClientAPI;
763 FSize := 0;
764 // writeln('Creating ',ClassName);
765 end;
766
767 destructor TIBXSQLDA.Destroy;
768 begin
769 FreeXSQLDA;
770 // writeln('Destroying ',ClassName);
771 inherited Destroy;
772 end;
773
774 function TIBXSQLDA.CanChangeMetaData: boolean;
775 begin
776 Result := true;
777 end;
778
779 function TIBXSQLDA.CheckStatementStatus(Request: TStatementStatus): boolean;
780 begin
781 Result := false;
782 case Request of
783 ssPrepared:
784 Result := FStatement.IsPrepared;
785
786 ssExecuteResults:
787 Result :=FStatement.FSingleResults;
788
789 ssCursorOpen:
790 Result := FStatement.FOpen;
791
792 ssBOF:
793 Result := FStatement.FBOF;
794
795 ssEOF:
796 Result := FStatement.FEOF;
797 end;
798 end;
799
800 function TIBXSQLDA.ColumnsInUseCount: integer;
801 begin
802 Result := FCount;
803 end;
804
805 function TIBXSQLDA.GetRecordSize: Integer;
806 begin
807 result := SizeOf(TIBXSQLDA) + XSQLDA_LENGTH(FSize);
808 end;
809
810 function TIBXSQLDA.GetXSQLDA: PXSQLDA;
811 begin
812 result := FXSQLDA;
813 end;
814
815 function TIBXSQLDA.GetTransactionSeqNo: integer;
816 begin
817 Result := FTransactionSeqNo;
818 end;
819
820 procedure TIBXSQLDA.Initialize;
821 begin
822 if FXSQLDA <> nil then
823 inherited Initialize;
824 end;
825
826 function TIBXSQLDA.StateChanged(var ChangeSeqNo: integer): boolean;
827 begin
828 Result := FStatement.ChangeSeqNo <> ChangeSeqNo;
829 if Result then
830 ChangeSeqNo := FStatement.ChangeSeqNo;
831 end;
832
833 function TIBXSQLDA.GetTransaction: TFB25Transaction;
834 begin
835 Result := FStatement.GetTransaction as TFB25Transaction;
836 end;
837
838 procedure TIBXSQLDA.SetCount(Value: Integer);
839 var
840 i, OldSize: Integer;
841 p : PXSQLVAR;
842 begin
843 FCount := Value;
844 if FCount = 0 then
845 FUniqueRelationName := ''
846 else
847 begin
848 if FSize > 0 then
849 OldSize := XSQLDA_LENGTH(FSize)
850 else
851 OldSize := 0;
852 if Count > FSize then
853 begin
854 FFirebird25ClientAPI.IBAlloc(FXSQLDA, OldSize, XSQLDA_LENGTH(Count));
855 SetLength(FColumnList, FCount);
856 FXSQLDA^.version := SQLDA_VERSION1;
857 p := @FXSQLDA^.sqlvar[0];
858 for i := 0 to Count - 1 do
859 begin
860 if i >= FSize then
861 FColumnList[i] := TIBXSQLVAR.Create(self,i);
862 TIBXSQLVAR(Column[i]).FXSQLVAR := p;
863 p := Pointer(PAnsiChar(p) + sizeof(FXSQLDA^.sqlvar));
864 end;
865 FSize := inherited Count;
866 end;
867 if FSize > 0 then
868 begin
869 FXSQLDA^.sqln := Value;
870 FXSQLDA^.sqld := Value;
871 end;
872 end;
873 end;
874
875 procedure TIBXSQLDA.FreeXSQLDA;
876 var i: integer;
877 begin
878 if FXSQLDA <> nil then
879 begin
880 // writeln('SQLDA Cleanup');
881 for i := 0 to Count - 1 do
882 TIBXSQLVAR(Column[i]).FreeSQLData;
883 FreeMem(FXSQLDA);
884 FXSQLDA := nil;
885 end;
886 for i := 0 to FSize - 1 do
887 TIBXSQLVAR(Column[i]).Free;
888 SetLength(FColumnList,0);
889 FSize := 0;
890 end;
891
892 function TIBXSQLDA.GetStatement: IStatement;
893 begin
894 Result := FStatement;
895 end;
896
897 function TIBXSQLDA.GetPrepareSeqNo: integer;
898 begin
899 Result := FStatement.FPrepareSeqNo;
900 end;
901
902 { TFB25Statement }
903
904 procedure TFB25Statement.GetPerfCounters(var counters: TPerfStatistics);
905 var DBInfo: IDBInformation;
906 i: integer;
907 {$IFDEF UNIX}
908 times: tms;
909 {$ENDIF}
910 begin
911 {$IFDEF UNIX}
912 FpTimes(times);
913 counters[psUserTime] := times.tms_utime;
914 {$ELSE}
915 counters[psUserTime] := 0;
916 {$ENDIF}
917 counters[psRealTime] := TimeStampToMSecs(DateTimeToTimeStamp(Now));
918
919 DBInfo := GetAttachment.GetDBInformation([isc_info_reads,isc_info_writes,
920 isc_info_fetches, isc_info_num_buffers, isc_info_current_memory,
921 isc_info_max_memory]);
922 if DBInfo <> nil then
923 begin
924 for i := 0 to DBInfo.Count - 1 do
925 with DBInfo[i] do
926 case getItemType of
927 isc_info_reads:
928 counters[psReads] := AsInteger;
929 isc_info_writes:
930 counters[psWrites] := AsInteger;
931 isc_info_fetches:
932 counters[psFetches] := AsInteger;
933 isc_info_num_buffers:
934 counters[psBuffers] := AsInteger;
935 isc_info_current_memory:
936 counters[psCurrentMemory] := AsInteger;
937 isc_info_max_memory:
938 counters[psMaxMemory] := AsInteger;
939 end;
940 end;
941 end;
942
943 procedure TFB25Statement.CheckHandle;
944 begin
945 if FHandle = nil then
946 IBError(ibxeInvalidStatementHandle,[nil]);
947 end;
948
949 procedure TFB25Statement.GetDsqlInfo(info_request: byte; buffer: ISQLInfoResults
950 );
951 begin
952 with FFirebird25ClientAPI, buffer as TSQLInfoResultsBuffer do
953 if isc_dsql_sql_info(StatusVector, @(FHandle), 1, @info_request,
954 GetBufSize, Buffer) > 0 then
955 IBDatabaseError;
956 end;
957
958 function TFB25Statement.GetStatementIntf: IStatement;
959 begin
960 Result := self;
961 end;
962
963 procedure TFB25Statement.InternalPrepare(CursorName: AnsiString);
964 var
965 GUID: TGUID;
966 RB: ISQLInfoResults;
967 TRHandle: TISC_TR_HANDLE;
968 begin
969 if FPrepared then
970 Exit;
971
972 if (FSQL = '') then
973 IBError(ibxeEmptyQuery, [nil]);
974
975 FCursor := CursorName;
976 if FCursor = '' then
977 begin
978 CreateGuid(GUID);
979 FCursor := GUIDToString(GUID);
980 end;
981
982 try
983 CheckTransaction(FTransactionIntf);
984 with FFirebird25ClientAPI do
985 begin
986 Call(isc_dsql_alloc_statement2(StatusVector, @(FDBHandle),
987 @FHandle), True);
988 TRHandle := (FTransactionIntf as TFB25Transaction).Handle;
989 if FHasParamNames then
990 begin
991 if FProcessedSQL = '' then
992 ProcessSQL(FSQL,FGenerateParamNames,FProcessedSQL);
993 Call(isc_dsql_prepare(StatusVector, @(TRHandle), @FHandle, 0,
994 PAnsiChar(FProcessedSQL), FSQLDialect, nil), True);
995 end
996 else
997 Call(isc_dsql_prepare(StatusVector, @(TRHandle), @FHandle, 0,
998 PAnsiChar(FSQL), FSQLDialect, nil), True);
999 end;
1000
1001 { After preparing the statement, query the stmt type and possibly
1002 create a FSQLRecord "holder" }
1003 { Get the type of the statement }
1004 RB := GetDsqlInfo(isc_info_sql_stmt_type);
1005 if RB.Count > 0 then
1006 FSQLStatementType := TIBSQLStatementTypes(RB[0].GetAsInteger)
1007 else
1008 FSQLStatementType := SQLUnknown;
1009
1010 if FSQLStatementType = SQLSelect then
1011 with FFirebird25ClientAPI do
1012 Call(
1013 isc_dsql_set_cursor_name(StatusVector, @FHandle, PAnsiChar(FCursor), 0),
1014 True);
1015
1016 case FSQLStatementType of
1017 SQLGetSegment,
1018 SQLPutSegment,
1019 SQLStartTransaction: begin
1020 FreeHandle;
1021 IBError(ibxeNotPermitted, [nil]);
1022 end;
1023 SQLCommit,
1024 SQLRollback,
1025 SQLDDL, SQLSetGenerator,
1026 SQLInsert, SQLUpdate, SQLDelete, SQLSelect, SQLSelectForUpdate,
1027 SQLExecProcedure:
1028 begin
1029 {set up input sqlda}
1030 FSQLParams.Bind;
1031
1032 {setup output sqlda}
1033 if FSQLStatementType in [SQLSelect, SQLSelectForUpdate,
1034 SQLExecProcedure] then
1035 FSQLRecord.Bind;
1036 end;
1037 end;
1038 except
1039 on E: Exception do begin
1040 if (FHandle <> nil) then
1041 FreeHandle;
1042 if E is EIBInterBaseError then
1043 E.Message := E.Message + sSQLErrorSeparator + FSQL;
1044 raise;
1045 end;
1046 end;
1047 FPrepared := true;
1048 FSingleResults := false;
1049 if RetainInterfaces then
1050 begin
1051 SetRetainInterfaces(false);
1052 SetRetainInterfaces(true);
1053 end;
1054 Inc(FPrepareSeqNo);
1055 Inc(FChangeSeqNo);
1056 with FTransactionIntf as TFB25Transaction do
1057 begin
1058 FSQLParams.FTransactionSeqNo := TransactionSeqNo;
1059 FSQLRecord.FTransactionSeqNo := TransactionSeqNo;
1060 end;
1061 end;
1062
1063 function TFB25Statement.InternalExecute(aTransaction: ITransaction): IResults;
1064 var TRHandle: TISC_TR_HANDLE;
1065 begin
1066 Result := nil;
1067 FBOF := false;
1068 FEOF := false;
1069 FSingleResults := false;
1070 CheckTransaction(aTransaction);
1071 if not FPrepared then
1072 InternalPrepare;
1073 CheckHandle;
1074 if aTransaction <> FTransactionIntf then
1075 AddMonitor(aTransaction as TFB25Transaction);
1076 if FStaleReferenceChecks and (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB25transaction).TransactionSeqNo) then
1077 IBError(ibxeInterfaceOutofDate,[nil]);
1078
1079 try
1080 TRHandle := (aTransaction as TFB25Transaction).Handle;
1081 with FFirebird25ClientAPI do
1082 begin
1083 if FCollectStatistics then
1084 GetPerfCounters(FBeforeStats);
1085
1086 case FSQLStatementType of
1087 SQLSelect:
1088 IBError(ibxeIsAExecuteProcedure,[]);
1089
1090 SQLExecProcedure:
1091 begin
1092 Call(isc_dsql_execute2(StatusVector,
1093 @(TRHandle),
1094 @FHandle,
1095 SQLDialect,
1096 FSQLParams.AsXSQLDA,
1097 FSQLRecord.AsXSQLDA), True);
1098 Result := TResults.Create(FSQLRecord);
1099 FSingleResults := true;
1100 end
1101 else
1102 Call(isc_dsql_execute(StatusVector,
1103 @(TRHandle),
1104 @FHandle,
1105 SQLDialect,
1106 FSQLParams.AsXSQLDA), True);
1107
1108 end;
1109 if FCollectStatistics then
1110 begin
1111 GetPerfCounters(FAfterStats);
1112 FStatisticsAvailable := true;
1113 end;
1114 end;
1115 finally
1116 if aTransaction <> FTransactionIntf then
1117 RemoveMonitor(aTransaction as TFB25Transaction);
1118 end;
1119 FExecTransactionIntf := aTransaction;
1120 FSQLRecord.FTransaction := aTransaction as TFB25Transaction;
1121 FSQLRecord.FTransactionSeqNo := FSQLRecord.FTransaction.TransactionSeqNo;
1122 Inc(FChangeSeqNo);
1123 end;
1124
1125 function TFB25Statement.InternalOpenCursor(aTransaction: ITransaction;
1126 Scrollable: boolean): IResultSet;
1127 var TRHandle: TISC_TR_HANDLE;
1128 begin
1129 if FSQLStatementType <> SQLSelect then
1130 IBError(ibxeIsASelectStatement,[]);
1131
1132 if Scrollable then
1133 IBError(ibxeNoScrollableCursors,[]);
1134
1135 CheckTransaction(aTransaction);
1136 if not FPrepared then
1137 InternalPrepare;
1138 CheckHandle;
1139 if aTransaction <> FTransactionIntf then
1140 AddMonitor(aTransaction as TFB25Transaction);
1141 if FStaleReferenceChecks and (FSQLParams.FTransactionSeqNo < (FTransactionIntf as TFB25transaction).TransactionSeqNo) then
1142 IBError(ibxeInterfaceOutofDate,[nil]);
1143
1144 with FFirebird25ClientAPI do
1145 begin
1146 if FCollectStatistics then
1147 GetPerfCounters(FBeforeStats);
1148
1149 TRHandle := (aTransaction as TFB25Transaction).Handle;
1150 Call(isc_dsql_execute2(StatusVector,
1151 @(TRHandle),
1152 @FHandle,
1153 SQLDialect,
1154 FSQLParams.AsXSQLDA,
1155 nil), True);
1156
1157 if FCollectStatistics then
1158 begin
1159 GetPerfCounters(FAfterStats);
1160 FStatisticsAvailable := true;
1161 end;
1162 end;
1163 Inc(FCursorSeqNo);
1164 FSingleResults := false;
1165 FOpen := True;
1166 FExecTransactionIntf := aTransaction;
1167 FBOF := true;
1168 FEOF := false;
1169 FSQLRecord.FTransaction := aTransaction as TFB25Transaction;
1170 FSQLRecord.FTransactionSeqNo := FSQLRecord.FTransaction.TransactionSeqNo;
1171 Result := TResultSet.Create(FSQLRecord);
1172 Inc(FChangeSeqNo);
1173 end;
1174
1175 procedure TFB25Statement.ProcessSQL(sql: AnsiString; GenerateParamNames: boolean;
1176 var processedSQL: AnsiString);
1177 begin
1178 FSQLParams.PreprocessSQL(sql,GenerateParamNames, processedSQL);
1179 end;
1180
1181 procedure TFB25Statement.FreeHandle;
1182 var
1183 isc_res: ISC_STATUS;
1184 begin
1185 Close;
1186 ReleaseInterfaces;
1187 try
1188 if FHandle <> nil then
1189 with FFirebird25ClientAPI do
1190 begin
1191 isc_res :=
1192 Call(isc_dsql_free_statement(StatusVector, @FHandle, DSQL_drop), False);
1193 if (StatusVector^ = 1) and (isc_res > 0) and (isc_res <> isc_bad_stmt_handle) then
1194 IBDataBaseError;
1195 end;
1196 finally
1197 FHandle := nil;
1198 FCursor := '';
1199 FPrepared := false;
1200 end;
1201 end;
1202
1203 procedure TFB25Statement.InternalClose(Force: boolean);
1204 var
1205 isc_res: ISC_STATUS;
1206 begin
1207 if (FHandle <> nil) and (SQLStatementType = SQLSelect) and FOpen then
1208 try
1209 with FFirebird25ClientAPI do
1210 begin
1211 isc_res := Call(
1212 isc_dsql_free_statement(StatusVector, @FHandle, DSQL_close),
1213 False);
1214 if not Force and (StatusVector^ = 1) and (isc_res > 0) and
1215 not getStatus.CheckStatusVector(
1216 [isc_bad_stmt_handle, isc_dsql_cursor_close_err]) then
1217 IBDatabaseError;
1218 end;
1219 finally
1220 if (FSQLRecord.FTransaction <> nil) and (FSQLRecord.FTransaction <> (FTransactionIntf as TFB25Transaction)) then
1221 RemoveMonitor(FSQLRecord.FTransaction);
1222 FOpen := False;
1223 FExecTransactionIntf := nil;
1224 FSQLRecord.FTransaction := nil;
1225 Inc(FChangeSeqNo);
1226 end;
1227 end;
1228
1229 constructor TFB25Statement.Create(Attachment: TFB25Attachment;
1230 Transaction: ITransaction; sql: AnsiString; aSQLDialect: integer;
1231 CursorName: AnsiString);
1232 begin
1233 inherited Create(Attachment,Transaction,sql,aSQLDialect);
1234 FDBHandle := Attachment.Handle;
1235 FFirebird25ClientAPI := Attachment.Firebird25ClientAPI;
1236 OnDatabaseError := FFirebird25ClientAPI.IBDataBaseError;
1237 FSQLParams := TIBXINPUTSQLDA.Create(self);
1238 FSQLRecord := TIBXOUTPUTSQLDA.Create(self);
1239 InternalPrepare(CursorName);
1240 end;
1241
1242 constructor TFB25Statement.CreateWithParameterNames(
1243 Attachment: TFB25Attachment; Transaction: ITransaction; sql: AnsiString;
1244 aSQLDialect: integer; GenerateParamNames: boolean;
1245 CaseSensitiveParams: boolean; CursorName: AnsiString);
1246 begin
1247 inherited CreateWithParameterNames(Attachment,Transaction,sql,aSQLDialect,GenerateParamNames);
1248 FDBHandle := Attachment.Handle;
1249 FFirebird25ClientAPI := Attachment.Firebird25ClientAPI;
1250 OnDatabaseError := FFirebird25ClientAPI.IBDataBaseError;
1251 FSQLParams := TIBXINPUTSQLDA.Create(self);
1252 FSQLParams.CaseSensitiveParams := CaseSensitiveParams;
1253 FSQLRecord := TIBXOUTPUTSQLDA.Create(self);
1254 InternalPrepare(CursorName);
1255 end;
1256
1257 destructor TFB25Statement.Destroy;
1258 begin
1259 inherited Destroy;
1260 if assigned(FSQLParams) then FSQLParams.Free;
1261 if assigned(FSQLRecord) then FSQLRecord.Free;
1262 end;
1263
1264 function TFB25Statement.FetchNext: boolean;
1265 var
1266 fetch_res: ISC_STATUS;
1267 begin
1268 result := false;
1269 if not FOpen then
1270 IBError(ibxeSQLClosed, [nil]);
1271 if FEOF then
1272 IBError(ibxeEOF,[nil]);
1273
1274 with FFirebird25ClientAPI do
1275 begin
1276 { Go to the next record... }
1277 fetch_res :=
1278 Call(isc_dsql_fetch(StatusVector, @FHandle, SQLDialect, FSQLRecord.AsXSQLDA), False);
1279 if (fetch_res = 100) or (getStatus.CheckStatusVector([isc_dsql_cursor_err])) then
1280 begin
1281 FBOF := false;
1282 FEOF := true;
1283 Exit; {End of File}
1284 end
1285 else
1286 if (fetch_res > 0) then
1287 begin
1288 try
1289 IBDataBaseError;
1290 except
1291 Close;
1292 raise;
1293 end;
1294 end
1295 else
1296 begin
1297 FBOF := false;
1298 result := true;
1299 end;
1300 if FCollectStatistics then
1301 begin
1302 GetPerfCounters(FAfterStats);
1303 FStatisticsAvailable := true;
1304 end;
1305 end;
1306 FSQLRecord.RowChange;
1307 if FEOF then
1308 Inc(FChangeSeqNo);
1309 end;
1310
1311 function TFB25Statement.GetSQLParams: ISQLParams;
1312 begin
1313 CheckHandle;
1314 if not HasInterface(0) then
1315 AddInterface(0,TSQLParams.Create(FSQLParams));
1316 Result := TSQLParams(GetInterface(0));
1317 end;
1318
1319 function TFB25Statement.GetMetaData: IMetaData;
1320 begin
1321 CheckHandle;
1322 if not HasInterface(1) then
1323 AddInterface(1, TMetaData.Create(FSQLRecord));
1324 Result := TMetaData(GetInterface(1));
1325 end;
1326
1327 function TFB25Statement.GetPlan: AnsiString;
1328 var
1329 RB: ISQLInfoResults;
1330 begin
1331 if (not (FSQLStatementType in [SQLSelect, SQLSelectForUpdate,
1332 {TODO: SQLExecProcedure, }
1333 SQLUpdate, SQLDelete])) then
1334 result := ''
1335 else
1336 begin
1337 RB := TSQLInfoResultsBuffer.Create(FFirebird25ClientAPI,4*4096);
1338 GetDsqlInfo(isc_info_sql_get_plan,RB);
1339 if RB.Count > 0 then
1340 Result := RB[0].GetAsString;
1341 end;
1342 end;
1343
1344 function TFB25Statement.CreateBlob(column: TColumnMetaData): IBlob;
1345 begin
1346 if assigned(column) and (column.SQLType <> SQL_Blob) then
1347 IBError(ibxeNotABlob,[nil]);
1348 Result := TFB25Blob.Create(GetAttachment as TFB25Attachment,FExecTransactionIntf as TFB25Transaction,
1349 column.GetBlobMetaData,nil);
1350 end;
1351
1352 function TFB25Statement.CreateArray(column: TColumnMetaData): IArray;
1353 begin
1354 if assigned(column) and (column.SQLType <> SQL_ARRAY) then
1355 IBError(ibxeNotAnArray,[nil]);
1356 Result := TFB25Array.Create(GetAttachment as TFB25Attachment,FExecTransactionIntf as TFB25Transaction,
1357 column.GetArrayMetaData);
1358 end;
1359
1360 procedure TFB25Statement.SetRetainInterfaces(aValue: boolean);
1361 begin
1362 inherited SetRetainInterfaces(aValue);
1363 if HasInterface(1) then
1364 TMetaData(GetInterface(1)).RetainInterfaces := aValue;
1365 if HasInterface(0) then
1366 TSQLParams(GetInterface(0)).RetainInterfaces := aValue;
1367 end;
1368
1369 function TFB25Statement.IsPrepared: boolean;
1370 begin
1371 Result := FHandle <> nil;
1372 end;
1373
1374 end.
1375

Properties

Name Value
svn:eol-style native