ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBStatement.pas
Revision: 359
Committed: Tue Dec 7 09:37:32 2021 UTC (3 years ago) by tony
Content type: text/x-pascal
File size: 14777 byte(s)
Log Message:
Fixes 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 tony 359 function GetFlags: TStatementFlags; virtual;
116 tony 45
117     {GetDSQLInfo only supports isc_info_sql_stmt_type, isc_info_sql_get_plan, isc_info_sql_records}
118 tony 350 procedure Prepare(aTransaction: ITransaction=nil); overload;
119     procedure Prepare(CursorName: AnsiString; aTransaction: ITransaction=nil); overload; virtual;
120 tony 45 function Execute(aTransaction: ITransaction=nil): IResults;
121 tony 350 function OpenCursor(aTransaction: ITransaction=nil): IResultSet; overload;
122     function OpenCursor(Scrollable: boolean; aTransaction: ITransaction=nil): IResultSet; overload;
123 tony 56 function CreateBlob(paramName: AnsiString): IBlob; overload;
124 tony 45 function CreateBlob(index: integer): IBlob; overload;
125     function CreateBlob(column: TColumnMetaData): IBlob; overload; virtual; abstract;
126 tony 56 function CreateArray(paramName: AnsiString): IArray; overload;
127 tony 45 function CreateArray(index: integer): IArray; overload;
128     function CreateArray(column: TColumnMetaData): IArray; overload; virtual; abstract;
129     function GetAttachment: IAttachment;
130     function GetTransaction: ITransaction;
131     function GetDSQLInfo(Request: byte): ISQLInfoResults; overload;
132     procedure SetRetainInterfaces(aValue: boolean); virtual;
133 tony 47 procedure EnableStatistics(aValue: boolean);
134     function GetPerfStatistics(var stats: TPerfCounters): boolean;
135 tony 345 function IsInBatchMode: boolean; virtual;
136     function HasBatchMode: boolean; virtual;
137     public
138     {IBatch support}
139     procedure AddToBatch; virtual;
140     function ExecuteBatch(aTransaction: ITransaction): IBatchCompletion; virtual;
141     procedure CancelBatch; virtual;
142     function GetBatchCompletion: IBatchCompletion; virtual;
143     function GetBatchRowLimit: integer;
144     procedure SetBatchRowLimit(aLimit: integer);
145 tony 347 {Stale Reference Check}
146     procedure SetStaleReferenceChecks(Enable:boolean); {default true}
147     function GetStaleReferenceChecks: boolean;
148 tony 345 public
149 tony 45 property ChangeSeqNo: integer read FChangeSeqNo;
150     property SQLParams: ISQLParams read GetSQLParams;
151     property SQLStatementType: TIBSQLStatementTypes read GetSQLStatementType;
152     end;
153    
154     implementation
155    
156     uses FBMessages;
157    
158     { TFBStatement }
159    
160 tony 345 procedure TFBStatement.CheckChangeBatchRowLimit;
161     begin
162     //Do Nothing
163     end;
164    
165 tony 45 procedure TFBStatement.CheckTransaction(aTransaction: ITransaction);
166     begin
167     if (aTransaction = nil) then
168     IBError(ibxeTransactionNotAssigned,[]);
169    
170     if not aTransaction.InTransaction then
171     IBError(ibxeNotInTransaction,[]);
172     end;
173    
174 tony 209 function TFBStatement.TimeStampToMSecs(const TimeStamp: TTimeStamp): Int64;
175     begin
176     Result := TimeStamp.Time + Int64(timestamp.date)*msecsperday;
177     end;
178    
179 tony 45 constructor TFBStatement.Create(Attachment: IAttachment;
180 tony 56 Transaction: ITransaction; sql: AnsiString; SQLDialect: integer);
181 tony 45 begin
182     inherited Create(Transaction as TFBTransaction,2);
183     FAttachmentIntf := Attachment;
184     FTransactionIntf := Transaction;
185 tony 263 FFirebirdClientAPI := Attachment.getFirebirdAPI as TFBClientAPI;
186 tony 45 FSQLDialect := SQLDialect;
187     FSQL := sql;
188 tony 345 FBatchRowLimit := DefaultBatchRowLimit;
189 tony 347 FStaleReferenceChecks := true;
190 tony 45 end;
191    
192     constructor TFBStatement.CreateWithParameterNames(Attachment: IAttachment;
193 tony 56 Transaction: ITransaction; sql: AnsiString; SQLDialect: integer;
194 tony 270 GenerateParamNames: boolean; CaseSensitiveParams: boolean);
195 tony 45 begin
196     FHasParamNames := true;
197     FGenerateParamNames := GenerateParamNames;
198 tony 270 FCaseSensitiveParams := CaseSensitiveParams;
199 tony 45 Create(Attachment,Transaction,sql,SQLDialect);
200     end;
201    
202     destructor TFBStatement.Destroy;
203     begin
204     Close;
205     FreeHandle;
206     inherited Destroy;
207     end;
208    
209     procedure TFBStatement.Close;
210     begin
211     InternalClose(false);
212     end;
213    
214     procedure TFBStatement.TransactionEnding(aTransaction: ITransaction;
215     Force: boolean);
216     begin
217 tony 315 if FOpen and ((FExecTransactionIntf as TObject) = (aTransaction as TObject)) then
218 tony 45 InternalClose(Force);
219    
220     if FTransactionIntf = aTransaction then
221     begin
222     FreeHandle;
223     FPrepared := false;
224     end;
225     end;
226    
227     function TFBStatement.GetRowsAffected(var SelectCount, InsertCount,
228     UpdateCount, DeleteCount: integer): boolean;
229     var
230     RB: ISQLInfoResults;
231     i, j: integer;
232     begin
233     InsertCount := 0;
234     UpdateCount := 0;
235     DeleteCount := 0;
236     Result := FPrepared;
237     if not Result then Exit;
238    
239     RB := GetDsqlInfo(isc_info_sql_records);
240    
241     for i := 0 to RB.Count - 1 do
242     with RB[i] do
243     case getItemType of
244     isc_info_sql_records:
245     for j := 0 to Count -1 do
246     with Items[j] do
247     case getItemType of
248     isc_info_req_select_count:
249     SelectCount := GetAsInteger;
250     isc_info_req_insert_count:
251     InsertCount := GetAsInteger;
252     isc_info_req_update_count:
253     UpdateCount := GetAsInteger;
254     isc_info_req_delete_count:
255     DeleteCount := GetAsInteger;
256     end;
257     end;
258     end;
259    
260     function TFBStatement.GetSQLStatementType: TIBSQLStatementTypes;
261     begin
262     Result := FSQLStatementType;
263     end;
264    
265 tony 345 function TFBStatement.GetSQLStatementTypeName: AnsiString;
266     begin
267     case FSQLStatementType of
268     SQLUnknown: Result := 'SQL_Unknown';
269     SQLSelect: Result := 'SQL_Select';
270     SQLInsert: Result := 'SQL_Insert';
271     SQLUpdate: Result := 'SQL_Update';
272     SQLDelete: Result := 'SQL_Delete';
273     SQLDDL: Result := 'SQL_DDL';
274     SQLGetSegment: Result := 'SQL_GetSegment';
275     SQLPutSegment: Result := 'SQL_PutSegment';
276     SQLExecProcedure: Result := 'SQL_ExecProcedure';
277     SQLStartTransaction: Result := 'SQL_StartTransaction';
278     SQLCommit: Result := 'SQL_Commit';
279     SQLRollback: Result := 'SQL_Rollback';
280     SQLSelectForUpdate: Result := 'SQL_SelectForUpdate';
281     SQLSetGenerator: Result := 'SQL_SetGenerator';
282     SQLSavePoint: Result := 'SQL_SavePoint';
283     end;
284     end;
285    
286 tony 56 function TFBStatement.GetSQLText: AnsiString;
287 tony 45 begin
288     Result := FSQL;
289     end;
290    
291 tony 263 function TFBStatement.GetProcessedSQLText: AnsiString;
292     begin
293 tony 359 if not FHasParamNames then
294     Result := FSQL
295     else
296     begin
297     if FProcessedSQL = '' then
298     ProcessSQL(FSQL,FGenerateParamNames,FProcessedSQL);
299     Result := FProcessedSQL;
300     end;
301 tony 263 end;
302    
303 tony 45 function TFBStatement.GetSQLDialect: integer;
304     begin
305     Result := FSQLDialect;
306     end;
307    
308 tony 359 function TFBStatement.GetFlags: TStatementFlags;
309     begin
310     Result := [];
311     end;
312    
313 tony 45 procedure TFBStatement.Prepare(aTransaction: ITransaction);
314     begin
315 tony 350 Prepare('',aTransaction);
316     end;
317    
318     procedure TFBStatement.Prepare(CursorName: AnsiString;
319     aTransaction: ITransaction);
320     begin
321 tony 45 if FPrepared then FreeHandle;
322     if aTransaction <> nil then
323     begin
324     RemoveMonitor(FTransactionIntf as TFBTransaction);
325     FTransactionIntf := aTransaction;
326     AddMonitor(FTransactionIntf as TFBTransaction);
327     end;
328 tony 350 InternalPrepare(CursorName);
329 tony 45 end;
330    
331     function TFBStatement.Execute(aTransaction: ITransaction): IResults;
332     begin
333     if aTransaction = nil then
334     Result := InternalExecute(FTransactionIntf)
335     else
336     Result := InternalExecute(aTransaction);
337     end;
338    
339 tony 345 procedure TFBStatement.AddToBatch;
340     begin
341     IBError(ibxeBatchModeNotSupported,[]);
342     end;
343    
344     function TFBStatement.ExecuteBatch(aTransaction: ITransaction
345     ): IBatchCompletion;
346     begin
347     IBError(ibxeBatchModeNotSupported,[]);
348     end;
349    
350     procedure TFBStatement.CancelBatch;
351     begin
352     IBError(ibxeBatchModeNotSupported,[]);
353     end;
354    
355     function TFBStatement.GetBatchCompletion: IBatchCompletion;
356     begin
357     IBError(ibxeBatchModeNotSupported,[]);
358     end;
359    
360     function TFBStatement.GetBatchRowLimit: integer;
361     begin
362     Result := FBatchRowLimit;
363     end;
364    
365     procedure TFBStatement.SetBatchRowLimit(aLimit: integer);
366     begin
367     CheckChangeBatchRowLimit;
368     FBatchRowLimit := aLimit;
369     end;
370    
371 tony 347 procedure TFBStatement.SetStaleReferenceChecks(Enable: boolean);
372     begin
373     FStaleReferenceChecks := Enable;
374     end;
375    
376     function TFBStatement.GetStaleReferenceChecks: boolean;
377     begin
378     Result := FStaleReferenceChecks;
379     end;
380    
381 tony 45 function TFBStatement.OpenCursor(aTransaction: ITransaction): IResultSet;
382     begin
383 tony 350 Result := OpenCursor(false,aTransaction);
384     end;
385    
386     function TFBStatement.OpenCursor(Scrollable: boolean; aTransaction: ITransaction
387     ): IResultSet;
388     begin
389 tony 45 Close;
390     if aTransaction = nil then
391 tony 350 Result := InternalOpenCursor(FTransactionIntf,Scrollable)
392 tony 45 else
393 tony 350 Result := InternalOpenCursor(aTransaction,Scrollable);
394 tony 45 end;
395    
396 tony 56 function TFBStatement.CreateBlob(paramName: AnsiString): IBlob;
397 tony 45 var column: TColumnMetaData;
398     begin
399     InternalPrepare;
400     column := SQLParams.ByName(paramName) as TSQLParam;
401     if column = nil then
402     IBError(ibxeFieldNotFound,[paramName]);
403     Result := CreateBlob(column);
404     end;
405    
406     function TFBStatement.CreateBlob(index: integer): IBlob;
407     begin
408     InternalPrepare;
409     Result := CreateBlob(SQLParams[index] as TSQLParam);
410     end;
411    
412 tony 56 function TFBStatement.CreateArray(paramName: AnsiString): IArray;
413 tony 45 var column: TColumnMetaData;
414     begin
415     InternalPrepare;
416     column := SQLParams.ByName(paramName) as TSQLParam;
417     if column = nil then
418     IBError(ibxeFieldNotFound,[paramName]);
419     Result := CreateArray(column);
420     end;
421    
422     function TFBStatement.CreateArray(index: integer): IArray;
423     begin
424     InternalPrepare;
425     Result := CreateArray(SQLParams[index] as TSQLParam);
426     end;
427    
428     function TFBStatement.GetAttachment: IAttachment;
429     begin
430     Result := FAttachmentIntf;
431     end;
432    
433     function TFBStatement.GetTransaction: ITransaction;
434     begin
435     Result := FTransactionIntf
436     end;
437    
438     function TFBStatement.GetDSQLInfo(Request: byte): ISQLInfoResults;
439     begin
440 tony 263 Result := TSQLInfoResultsBuffer.Create(FFirebirdClientAPI);
441 tony 45 GetDsqlInfo(Request,Result);
442     end;
443    
444     procedure TFBStatement.SetRetainInterfaces(aValue: boolean);
445     begin
446     RetainInterfaces := aValue;
447     end;
448    
449 tony 47 procedure TFBStatement.EnableStatistics(aValue: boolean);
450     begin
451     if FCollectStatistics <> aValue then
452     begin
453     FCollectStatistics := aValue;
454     FStatisticsAvailable := false;
455     end;
456     end;
457    
458     function TFBStatement.GetPerfStatistics(var stats: TPerfCounters): boolean;
459     begin
460     Result := FStatisticsAvailable;
461     if Result then
462     begin
463     stats[psCurrentMemory] := FAfterStats[psCurrentMemory];
464     stats[psDeltaMemory] := FAfterStats[psCurrentMemory] - FBeforeStats[psCurrentMemory];
465     stats[psMaxMemory] := FAfterStats[psMaxMemory];
466     stats[psRealTime] := FAfterStats[psRealTime] - FBeforeStats[psRealTime];
467     stats[psUserTime] := FAfterStats[psUserTime] - FBeforeStats[psUserTime];
468     stats[psReads] := FAfterStats[psReads] - FBeforeStats[psReads];
469     stats[psWrites] := FAfterStats[psWrites] - FBeforeStats[psWrites];
470     stats[psFetches] := FAfterStats[psFetches] - FBeforeStats[psFetches];
471     stats[psBuffers] := FAfterStats[psBuffers];
472     end;
473     end;
474    
475 tony 345 function TFBStatement.IsInBatchMode: boolean;
476     begin
477     Result := false;
478     end;
479    
480     function TFBStatement.HasBatchMode: boolean;
481     begin
482     Result := false;
483     end;
484    
485 tony 45 end.
486