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 (2 years, 11 months ago) by tony
Content type: text/x-pascal
File size: 14777 byte(s)
Log Message:
Fixes Merged

File Contents

# Content
1 (*
2 * Firebird Interface (fbintf). The fbintf components provide a set of
3 * Pascal language bindings for the Firebird API. Although predominantly
4 * a new development they include source code taken from IBX and may be
5 * considered a derived product. This software thus also includes the copyright
6 * notice and license conditions from IBX.
7 *
8 * Except for those parts dervied from IBX, contents of this file are subject
9 * to the Initial Developer's Public License Version 1.0 (the "License"); you
10 * may not use this file except in compliance with the License. You may obtain a
11 * copy of the License here:
12 *
13 * http://www.firebirdsql.org/index.php?op=doc&id=idpl
14 *
15 * Software distributed under the License is distributed on an "AS
16 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17 * implied. See the License for the specific language governing rights
18 * and limitations under the License.
19 *
20 * The Initial Developer of the Original Code is Tony Whyman.
21 *
22 * The Original Code is (C) 2016 Tony Whyman, MWA Software
23 * (http://www.mwasoftware.co.uk).
24 *
25 * All Rights Reserved.
26 *
27 * Contributor(s): ______________________________________.
28 *
29 *)
30 unit FBStatement;
31 {$IFDEF MSWINDOWS}
32 {$DEFINE WINDOWS}
33 {$ENDIF}
34
35 {$IFDEF FPC}
36 {$mode delphi}
37 {$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 const
48 DefaultBatchRowLimit = 1000;
49
50 type
51 TPerfStatistics = array[psCurrentMemory..psFetches] of Int64;
52
53 { TFBStatement }
54
55 TFBStatement = class(TActivityReporter,ITransactionUser)
56 private
57 FAttachmentIntf: IAttachment;
58 FFirebirdClientAPI: TFBClientAPI;
59 protected
60 FTransactionIntf: ITransaction;
61 FExecTransactionIntf: ITransaction;
62 FStaleReferenceChecks: boolean;
63 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 FSQL: AnsiString;
69 FProcessedSQL: AnsiString;
70 FHasParamNames: boolean;
71 FBOF: boolean;
72 FEOF: boolean;
73 FSingleResults: boolean;
74 FGenerateParamNames: boolean;
75 FChangeSeqNo: integer;
76 FCollectStatistics: boolean;
77 FStatisticsAvailable: boolean;
78 FBeforeStats: TPerfStatistics;
79 FAfterStats: TPerfStatistics;
80 FCaseSensitiveParams: boolean;
81 FBatchRowLimit: integer;
82 procedure CheckChangeBatchRowLimit; virtual;
83 procedure CheckHandle; virtual; abstract;
84 procedure CheckTransaction(aTransaction: ITransaction);
85 procedure GetDsqlInfo(info_request: byte; buffer: ISQLInfoResults); overload; virtual; abstract;
86 procedure InternalPrepare(CursorName: AnsiString=''); virtual; abstract;
87 function InternalExecute(Transaction: ITransaction): IResults; virtual; abstract;
88 function InternalOpenCursor(aTransaction: ITransaction; Scrollable: boolean): IResultSet; virtual; abstract;
89 procedure ProcessSQL(sql: AnsiString; GenerateParamNames: boolean; var processedSQL: AnsiString); virtual; abstract;
90 procedure FreeHandle; virtual; abstract;
91 procedure InternalClose(Force: boolean); virtual; abstract;
92 function TimeStampToMSecs(const TimeStamp: TTimeStamp): Int64;
93 public
94 constructor Create(Attachment: IAttachment; Transaction: ITransaction;
95 sql: AnsiString; SQLDialect: integer);
96 constructor CreateWithParameterNames(Attachment: IAttachment; Transaction: ITransaction;
97 sql: AnsiString; SQLDialect: integer; GenerateParamNames: boolean =false;
98 CaseSensitiveParams: boolean = false);
99 destructor Destroy; override;
100 procedure Close;
101 procedure TransactionEnding(aTransaction: ITransaction; Force: boolean);
102 property SQLDialect: integer read FSQLDialect;
103 property FirebirdClientAPI: TFBClientAPI read FFirebirdClientAPI;
104
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 function GetSQLStatementTypeName: AnsiString;
112 function GetSQLText: AnsiString;
113 function GetProcessedSQLText: AnsiString;
114 function GetSQLDialect: integer;
115 function GetFlags: TStatementFlags; virtual;
116
117 {GetDSQLInfo only supports isc_info_sql_stmt_type, isc_info_sql_get_plan, isc_info_sql_records}
118 procedure Prepare(aTransaction: ITransaction=nil); overload;
119 procedure Prepare(CursorName: AnsiString; aTransaction: ITransaction=nil); overload; virtual;
120 function Execute(aTransaction: ITransaction=nil): IResults;
121 function OpenCursor(aTransaction: ITransaction=nil): IResultSet; overload;
122 function OpenCursor(Scrollable: boolean; aTransaction: ITransaction=nil): IResultSet; overload;
123 function CreateBlob(paramName: AnsiString): IBlob; overload;
124 function CreateBlob(index: integer): IBlob; overload;
125 function CreateBlob(column: TColumnMetaData): IBlob; overload; virtual; abstract;
126 function CreateArray(paramName: AnsiString): IArray; overload;
127 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 procedure EnableStatistics(aValue: boolean);
134 function GetPerfStatistics(var stats: TPerfCounters): boolean;
135 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 {Stale Reference Check}
146 procedure SetStaleReferenceChecks(Enable:boolean); {default true}
147 function GetStaleReferenceChecks: boolean;
148 public
149 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 procedure TFBStatement.CheckChangeBatchRowLimit;
161 begin
162 //Do Nothing
163 end;
164
165 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 function TFBStatement.TimeStampToMSecs(const TimeStamp: TTimeStamp): Int64;
175 begin
176 Result := TimeStamp.Time + Int64(timestamp.date)*msecsperday;
177 end;
178
179 constructor TFBStatement.Create(Attachment: IAttachment;
180 Transaction: ITransaction; sql: AnsiString; SQLDialect: integer);
181 begin
182 inherited Create(Transaction as TFBTransaction,2);
183 FAttachmentIntf := Attachment;
184 FTransactionIntf := Transaction;
185 FFirebirdClientAPI := Attachment.getFirebirdAPI as TFBClientAPI;
186 FSQLDialect := SQLDialect;
187 FSQL := sql;
188 FBatchRowLimit := DefaultBatchRowLimit;
189 FStaleReferenceChecks := true;
190 end;
191
192 constructor TFBStatement.CreateWithParameterNames(Attachment: IAttachment;
193 Transaction: ITransaction; sql: AnsiString; SQLDialect: integer;
194 GenerateParamNames: boolean; CaseSensitiveParams: boolean);
195 begin
196 FHasParamNames := true;
197 FGenerateParamNames := GenerateParamNames;
198 FCaseSensitiveParams := CaseSensitiveParams;
199 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 if FOpen and ((FExecTransactionIntf as TObject) = (aTransaction as TObject)) then
218 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 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 function TFBStatement.GetSQLText: AnsiString;
287 begin
288 Result := FSQL;
289 end;
290
291 function TFBStatement.GetProcessedSQLText: AnsiString;
292 begin
293 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 end;
302
303 function TFBStatement.GetSQLDialect: integer;
304 begin
305 Result := FSQLDialect;
306 end;
307
308 function TFBStatement.GetFlags: TStatementFlags;
309 begin
310 Result := [];
311 end;
312
313 procedure TFBStatement.Prepare(aTransaction: ITransaction);
314 begin
315 Prepare('',aTransaction);
316 end;
317
318 procedure TFBStatement.Prepare(CursorName: AnsiString;
319 aTransaction: ITransaction);
320 begin
321 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 InternalPrepare(CursorName);
329 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 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 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 function TFBStatement.OpenCursor(aTransaction: ITransaction): IResultSet;
382 begin
383 Result := OpenCursor(false,aTransaction);
384 end;
385
386 function TFBStatement.OpenCursor(Scrollable: boolean; aTransaction: ITransaction
387 ): IResultSet;
388 begin
389 Close;
390 if aTransaction = nil then
391 Result := InternalOpenCursor(FTransactionIntf,Scrollable)
392 else
393 Result := InternalOpenCursor(aTransaction,Scrollable);
394 end;
395
396 function TFBStatement.CreateBlob(paramName: AnsiString): IBlob;
397 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 function TFBStatement.CreateArray(paramName: AnsiString): IArray;
413 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 Result := TSQLInfoResultsBuffer.Create(FFirebirdClientAPI);
441 GetDsqlInfo(Request,Result);
442 end;
443
444 procedure TFBStatement.SetRetainInterfaces(aValue: boolean);
445 begin
446 RetainInterfaces := aValue;
447 end;
448
449 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 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 end.
486