ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBStatement.pas
Revision: 350
Committed: Wed Oct 20 14:58:56 2021 UTC (3 years, 1 month ago) by tony
Content type: text/x-pascal
File size: 14574 byte(s)
Log Message:
Fixed Merged

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     unit FBStatement;
31 tony 56 {$IFDEF MSWINDOWS}
32     {$DEFINE WINDOWS}
33     {$ENDIF}
34 tony 45
35     {$IFDEF FPC}
36 tony 56 {$mode delphi}
37 tony 45 {$codepage UTF8}
38     {$interfaces COM}
39     {$ENDIF}
40    
41     interface
42    
43     uses
44     Classes, SysUtils, IB, FBClientAPI, FBSQLData, FBOutputBlock, FBActivityMonitor,
45     FBTransaction;
46    
47 tony 345 const
48     DefaultBatchRowLimit = 1000;
49    
50 tony 45 type
51 tony 209 TPerfStatistics = array[psCurrentMemory..psFetches] of Int64;
52 tony 45
53     { TFBStatement }
54    
55 tony 315 TFBStatement = class(TActivityReporter,ITransactionUser)
56 tony 45 private
57     FAttachmentIntf: IAttachment;
58 tony 263 FFirebirdClientAPI: TFBClientAPI;
59 tony 45 protected
60     FTransactionIntf: ITransaction;
61     FExecTransactionIntf: ITransaction;
62 tony 347 FStaleReferenceChecks: boolean;
63 tony 45 FSQLStatementType: TIBSQLStatementTypes; { Select, update, delete, insert, create, alter, etc...}
64     FSQLDialect: integer;
65     FOpen: boolean;
66     FPrepared: boolean;
67     FPrepareSeqNo: integer; {used to check for out of date references from interfaces}
68 tony 56 FSQL: AnsiString;
69     FProcessedSQL: AnsiString;
70 tony 45 FHasParamNames: boolean;
71     FBOF: boolean;
72     FEOF: boolean;
73     FSingleResults: boolean;
74     FGenerateParamNames: boolean;
75     FChangeSeqNo: integer;
76 tony 47 FCollectStatistics: boolean;
77     FStatisticsAvailable: boolean;
78     FBeforeStats: TPerfStatistics;
79     FAfterStats: TPerfStatistics;
80 tony 270 FCaseSensitiveParams: boolean;
81 tony 345 FBatchRowLimit: integer;
82     procedure CheckChangeBatchRowLimit; virtual;
83 tony 45 procedure CheckHandle; virtual; abstract;
84     procedure CheckTransaction(aTransaction: ITransaction);
85     procedure GetDsqlInfo(info_request: byte; buffer: ISQLInfoResults); overload; virtual; abstract;
86 tony 350 procedure InternalPrepare(CursorName: AnsiString=''); virtual; abstract;
87 tony 345 function InternalExecute(Transaction: ITransaction): IResults; virtual; abstract;
88 tony 350 function InternalOpenCursor(aTransaction: ITransaction; Scrollable: boolean): IResultSet; virtual; abstract;
89 tony 263 procedure ProcessSQL(sql: AnsiString; GenerateParamNames: boolean; var processedSQL: AnsiString); virtual; abstract;
90 tony 45 procedure FreeHandle; virtual; abstract;
91     procedure InternalClose(Force: boolean); virtual; abstract;
92 tony 209 function TimeStampToMSecs(const TimeStamp: TTimeStamp): Int64;
93 tony 45 public
94     constructor Create(Attachment: IAttachment; Transaction: ITransaction;
95 tony 56 sql: AnsiString; SQLDialect: integer);
96 tony 45 constructor CreateWithParameterNames(Attachment: IAttachment; Transaction: ITransaction;
97 tony 270 sql: AnsiString; SQLDialect: integer; GenerateParamNames: boolean =false;
98     CaseSensitiveParams: boolean = false);
99 tony 45 destructor Destroy; override;
100     procedure Close;
101     procedure TransactionEnding(aTransaction: ITransaction; Force: boolean);
102     property SQLDialect: integer read FSQLDialect;
103 tony 263 property FirebirdClientAPI: TFBClientAPI read FFirebirdClientAPI;
104 tony 45
105     public
106     function GetSQLParams: ISQLParams; virtual; abstract;
107     function GetMetaData: IMetaData; virtual; abstract;
108     function GetRowsAffected(var SelectCount, InsertCount, UpdateCount,
109     DeleteCount: integer): boolean;
110     function GetSQLStatementType: TIBSQLStatementTypes;
111 tony 345 function GetSQLStatementTypeName: AnsiString;
112 tony 56 function GetSQLText: AnsiString;
113 tony 263 function GetProcessedSQLText: AnsiString;
114 tony 45 function GetSQLDialect: integer;
115    
116     {GetDSQLInfo only supports isc_info_sql_stmt_type, isc_info_sql_get_plan, isc_info_sql_records}
117 tony 350 procedure Prepare(aTransaction: ITransaction=nil); overload;
118     procedure Prepare(CursorName: AnsiString; aTransaction: ITransaction=nil); overload; virtual;
119 tony 45 function Execute(aTransaction: ITransaction=nil): IResults;
120 tony 350 function OpenCursor(aTransaction: ITransaction=nil): IResultSet; overload;
121     function OpenCursor(Scrollable: boolean; aTransaction: ITransaction=nil): IResultSet; overload;
122 tony 56 function CreateBlob(paramName: AnsiString): IBlob; overload;
123 tony 45 function CreateBlob(index: integer): IBlob; overload;
124     function CreateBlob(column: TColumnMetaData): IBlob; overload; virtual; abstract;
125 tony 56 function CreateArray(paramName: AnsiString): IArray; overload;
126 tony 45 function CreateArray(index: integer): IArray; overload;
127     function CreateArray(column: TColumnMetaData): IArray; overload; virtual; abstract;
128     function GetAttachment: IAttachment;
129     function GetTransaction: ITransaction;
130     function GetDSQLInfo(Request: byte): ISQLInfoResults; overload;
131     procedure SetRetainInterfaces(aValue: boolean); virtual;
132 tony 47 procedure EnableStatistics(aValue: boolean);
133     function GetPerfStatistics(var stats: TPerfCounters): boolean;
134 tony 345 function IsInBatchMode: boolean; virtual;
135     function HasBatchMode: boolean; virtual;
136     public
137     {IBatch support}
138     procedure AddToBatch; virtual;
139     function ExecuteBatch(aTransaction: ITransaction): IBatchCompletion; virtual;
140     procedure CancelBatch; virtual;
141     function GetBatchCompletion: IBatchCompletion; virtual;
142     function GetBatchRowLimit: integer;
143     procedure SetBatchRowLimit(aLimit: integer);
144 tony 347 {Stale Reference Check}
145     procedure SetStaleReferenceChecks(Enable:boolean); {default true}
146     function GetStaleReferenceChecks: boolean;
147 tony 345 public
148 tony 45 property ChangeSeqNo: integer read FChangeSeqNo;
149     property SQLParams: ISQLParams read GetSQLParams;
150     property SQLStatementType: TIBSQLStatementTypes read GetSQLStatementType;
151     end;
152    
153     implementation
154    
155     uses FBMessages;
156    
157     { TFBStatement }
158    
159 tony 345 procedure TFBStatement.CheckChangeBatchRowLimit;
160     begin
161     //Do Nothing
162     end;
163    
164 tony 45 procedure TFBStatement.CheckTransaction(aTransaction: ITransaction);
165     begin
166     if (aTransaction = nil) then
167     IBError(ibxeTransactionNotAssigned,[]);
168    
169     if not aTransaction.InTransaction then
170     IBError(ibxeNotInTransaction,[]);
171     end;
172    
173 tony 209 function TFBStatement.TimeStampToMSecs(const TimeStamp: TTimeStamp): Int64;
174     begin
175     Result := TimeStamp.Time + Int64(timestamp.date)*msecsperday;
176     end;
177    
178 tony 45 constructor TFBStatement.Create(Attachment: IAttachment;
179 tony 56 Transaction: ITransaction; sql: AnsiString; SQLDialect: integer);
180 tony 45 begin
181     inherited Create(Transaction as TFBTransaction,2);
182     FAttachmentIntf := Attachment;
183     FTransactionIntf := Transaction;
184 tony 263 FFirebirdClientAPI := Attachment.getFirebirdAPI as TFBClientAPI;
185 tony 45 FSQLDialect := SQLDialect;
186     FSQL := sql;
187 tony 345 FBatchRowLimit := DefaultBatchRowLimit;
188 tony 347 FStaleReferenceChecks := true;
189 tony 45 end;
190    
191     constructor TFBStatement.CreateWithParameterNames(Attachment: IAttachment;
192 tony 56 Transaction: ITransaction; sql: AnsiString; SQLDialect: integer;
193 tony 270 GenerateParamNames: boolean; CaseSensitiveParams: boolean);
194 tony 45 begin
195     FHasParamNames := true;
196     FGenerateParamNames := GenerateParamNames;
197 tony 270 FCaseSensitiveParams := CaseSensitiveParams;
198 tony 45 Create(Attachment,Transaction,sql,SQLDialect);
199     end;
200    
201     destructor TFBStatement.Destroy;
202     begin
203     Close;
204     FreeHandle;
205     inherited Destroy;
206     end;
207    
208     procedure TFBStatement.Close;
209     begin
210     InternalClose(false);
211     end;
212    
213     procedure TFBStatement.TransactionEnding(aTransaction: ITransaction;
214     Force: boolean);
215     begin
216 tony 315 if FOpen and ((FExecTransactionIntf as TObject) = (aTransaction as TObject)) then
217 tony 45 InternalClose(Force);
218    
219     if FTransactionIntf = aTransaction then
220     begin
221     FreeHandle;
222     FPrepared := false;
223     end;
224     end;
225    
226     function TFBStatement.GetRowsAffected(var SelectCount, InsertCount,
227     UpdateCount, DeleteCount: integer): boolean;
228     var
229     RB: ISQLInfoResults;
230     i, j: integer;
231     begin
232     InsertCount := 0;
233     UpdateCount := 0;
234     DeleteCount := 0;
235     Result := FPrepared;
236     if not Result then Exit;
237    
238     RB := GetDsqlInfo(isc_info_sql_records);
239    
240     for i := 0 to RB.Count - 1 do
241     with RB[i] do
242     case getItemType of
243     isc_info_sql_records:
244     for j := 0 to Count -1 do
245     with Items[j] do
246     case getItemType of
247     isc_info_req_select_count:
248     SelectCount := GetAsInteger;
249     isc_info_req_insert_count:
250     InsertCount := GetAsInteger;
251     isc_info_req_update_count:
252     UpdateCount := GetAsInteger;
253     isc_info_req_delete_count:
254     DeleteCount := GetAsInteger;
255     end;
256     end;
257     end;
258    
259     function TFBStatement.GetSQLStatementType: TIBSQLStatementTypes;
260     begin
261     Result := FSQLStatementType;
262     end;
263    
264 tony 345 function TFBStatement.GetSQLStatementTypeName: AnsiString;
265     begin
266     case FSQLStatementType of
267     SQLUnknown: Result := 'SQL_Unknown';
268     SQLSelect: Result := 'SQL_Select';
269     SQLInsert: Result := 'SQL_Insert';
270     SQLUpdate: Result := 'SQL_Update';
271     SQLDelete: Result := 'SQL_Delete';
272     SQLDDL: Result := 'SQL_DDL';
273     SQLGetSegment: Result := 'SQL_GetSegment';
274     SQLPutSegment: Result := 'SQL_PutSegment';
275     SQLExecProcedure: Result := 'SQL_ExecProcedure';
276     SQLStartTransaction: Result := 'SQL_StartTransaction';
277     SQLCommit: Result := 'SQL_Commit';
278     SQLRollback: Result := 'SQL_Rollback';
279     SQLSelectForUpdate: Result := 'SQL_SelectForUpdate';
280     SQLSetGenerator: Result := 'SQL_SetGenerator';
281     SQLSavePoint: Result := 'SQL_SavePoint';
282     end;
283     end;
284    
285 tony 56 function TFBStatement.GetSQLText: AnsiString;
286 tony 45 begin
287     Result := FSQL;
288     end;
289    
290 tony 263 function TFBStatement.GetProcessedSQLText: AnsiString;
291     begin
292     if FProcessedSQL = '' then
293     ProcessSQL(FSQL,FGenerateParamNames,FProcessedSQL);
294     Result := FProcessedSQL
295     end;
296    
297 tony 45 function TFBStatement.GetSQLDialect: integer;
298     begin
299     Result := FSQLDialect;
300     end;
301    
302     procedure TFBStatement.Prepare(aTransaction: ITransaction);
303     begin
304 tony 350 Prepare('',aTransaction);
305     end;
306    
307     procedure TFBStatement.Prepare(CursorName: AnsiString;
308     aTransaction: ITransaction);
309     begin
310 tony 45 if FPrepared then FreeHandle;
311     if aTransaction <> nil then
312     begin
313     RemoveMonitor(FTransactionIntf as TFBTransaction);
314     FTransactionIntf := aTransaction;
315     AddMonitor(FTransactionIntf as TFBTransaction);
316     end;
317 tony 350 InternalPrepare(CursorName);
318 tony 45 end;
319    
320     function TFBStatement.Execute(aTransaction: ITransaction): IResults;
321     begin
322     if aTransaction = nil then
323     Result := InternalExecute(FTransactionIntf)
324     else
325     Result := InternalExecute(aTransaction);
326     end;
327    
328 tony 345 procedure TFBStatement.AddToBatch;
329     begin
330     IBError(ibxeBatchModeNotSupported,[]);
331     end;
332    
333     function TFBStatement.ExecuteBatch(aTransaction: ITransaction
334     ): IBatchCompletion;
335     begin
336     IBError(ibxeBatchModeNotSupported,[]);
337     end;
338    
339     procedure TFBStatement.CancelBatch;
340     begin
341     IBError(ibxeBatchModeNotSupported,[]);
342     end;
343    
344     function TFBStatement.GetBatchCompletion: IBatchCompletion;
345     begin
346     IBError(ibxeBatchModeNotSupported,[]);
347     end;
348    
349     function TFBStatement.GetBatchRowLimit: integer;
350     begin
351     Result := FBatchRowLimit;
352     end;
353    
354     procedure TFBStatement.SetBatchRowLimit(aLimit: integer);
355     begin
356     CheckChangeBatchRowLimit;
357     FBatchRowLimit := aLimit;
358     end;
359    
360 tony 347 procedure TFBStatement.SetStaleReferenceChecks(Enable: boolean);
361     begin
362     FStaleReferenceChecks := Enable;
363     end;
364    
365     function TFBStatement.GetStaleReferenceChecks: boolean;
366     begin
367     Result := FStaleReferenceChecks;
368     end;
369    
370 tony 45 function TFBStatement.OpenCursor(aTransaction: ITransaction): IResultSet;
371     begin
372 tony 350 Result := OpenCursor(false,aTransaction);
373     end;
374    
375     function TFBStatement.OpenCursor(Scrollable: boolean; aTransaction: ITransaction
376     ): IResultSet;
377     begin
378 tony 45 Close;
379     if aTransaction = nil then
380 tony 350 Result := InternalOpenCursor(FTransactionIntf,Scrollable)
381 tony 45 else
382 tony 350 Result := InternalOpenCursor(aTransaction,Scrollable);
383 tony 45 end;
384    
385 tony 56 function TFBStatement.CreateBlob(paramName: AnsiString): IBlob;
386 tony 45 var column: TColumnMetaData;
387     begin
388     InternalPrepare;
389     column := SQLParams.ByName(paramName) as TSQLParam;
390     if column = nil then
391     IBError(ibxeFieldNotFound,[paramName]);
392     Result := CreateBlob(column);
393     end;
394    
395     function TFBStatement.CreateBlob(index: integer): IBlob;
396     begin
397     InternalPrepare;
398     Result := CreateBlob(SQLParams[index] as TSQLParam);
399     end;
400    
401 tony 56 function TFBStatement.CreateArray(paramName: AnsiString): IArray;
402 tony 45 var column: TColumnMetaData;
403     begin
404     InternalPrepare;
405     column := SQLParams.ByName(paramName) as TSQLParam;
406     if column = nil then
407     IBError(ibxeFieldNotFound,[paramName]);
408     Result := CreateArray(column);
409     end;
410    
411     function TFBStatement.CreateArray(index: integer): IArray;
412     begin
413     InternalPrepare;
414     Result := CreateArray(SQLParams[index] as TSQLParam);
415     end;
416    
417     function TFBStatement.GetAttachment: IAttachment;
418     begin
419     Result := FAttachmentIntf;
420     end;
421    
422     function TFBStatement.GetTransaction: ITransaction;
423     begin
424     Result := FTransactionIntf
425     end;
426    
427     function TFBStatement.GetDSQLInfo(Request: byte): ISQLInfoResults;
428     begin
429 tony 263 Result := TSQLInfoResultsBuffer.Create(FFirebirdClientAPI);
430 tony 45 GetDsqlInfo(Request,Result);
431     end;
432    
433     procedure TFBStatement.SetRetainInterfaces(aValue: boolean);
434     begin
435     RetainInterfaces := aValue;
436     end;
437    
438 tony 47 procedure TFBStatement.EnableStatistics(aValue: boolean);
439     begin
440     if FCollectStatistics <> aValue then
441     begin
442     FCollectStatistics := aValue;
443     FStatisticsAvailable := false;
444     end;
445     end;
446    
447     function TFBStatement.GetPerfStatistics(var stats: TPerfCounters): boolean;
448     begin
449     Result := FStatisticsAvailable;
450     if Result then
451     begin
452     stats[psCurrentMemory] := FAfterStats[psCurrentMemory];
453     stats[psDeltaMemory] := FAfterStats[psCurrentMemory] - FBeforeStats[psCurrentMemory];
454     stats[psMaxMemory] := FAfterStats[psMaxMemory];
455     stats[psRealTime] := FAfterStats[psRealTime] - FBeforeStats[psRealTime];
456     stats[psUserTime] := FAfterStats[psUserTime] - FBeforeStats[psUserTime];
457     stats[psReads] := FAfterStats[psReads] - FBeforeStats[psReads];
458     stats[psWrites] := FAfterStats[psWrites] - FBeforeStats[psWrites];
459     stats[psFetches] := FAfterStats[psFetches] - FBeforeStats[psFetches];
460     stats[psBuffers] := FAfterStats[psBuffers];
461     end;
462     end;
463    
464 tony 345 function TFBStatement.IsInBatchMode: boolean;
465     begin
466     Result := false;
467     end;
468    
469     function TFBStatement.HasBatchMode: boolean;
470     begin
471     Result := false;
472     end;
473    
474 tony 45 end.
475