ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/journaling/fbintf/client/2.5/FB25Statement.pas
Revision: 363
Committed: Tue Dec 7 13:30:05 2021 UTC (2 years, 4 months ago) by tony
Content type: text/x-pascal
File size: 40441 byte(s)
Log Message:
add fbintf

File Contents

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