ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/journaling/fbintf/client/FBStatement.pas
Revision: 350
Committed: Wed Oct 20 14:58:56 2021 UTC (2 years, 5 months ago) by tony
Content type: text/x-pascal
Original Path: ibx/trunk/fbintf/client/FBStatement.pas
File size: 14574 byte(s)
Log Message:
Fixed 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
116 {GetDSQLInfo only supports isc_info_sql_stmt_type, isc_info_sql_get_plan, isc_info_sql_records}
117 procedure Prepare(aTransaction: ITransaction=nil); overload;
118 procedure Prepare(CursorName: AnsiString; aTransaction: ITransaction=nil); overload; virtual;
119 function Execute(aTransaction: ITransaction=nil): IResults;
120 function OpenCursor(aTransaction: ITransaction=nil): IResultSet; overload;
121 function OpenCursor(Scrollable: boolean; aTransaction: ITransaction=nil): IResultSet; overload;
122 function CreateBlob(paramName: AnsiString): IBlob; overload;
123 function CreateBlob(index: integer): IBlob; overload;
124 function CreateBlob(column: TColumnMetaData): IBlob; overload; virtual; abstract;
125 function CreateArray(paramName: AnsiString): IArray; overload;
126 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 procedure EnableStatistics(aValue: boolean);
133 function GetPerfStatistics(var stats: TPerfCounters): boolean;
134 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 {Stale Reference Check}
145 procedure SetStaleReferenceChecks(Enable:boolean); {default true}
146 function GetStaleReferenceChecks: boolean;
147 public
148 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 procedure TFBStatement.CheckChangeBatchRowLimit;
160 begin
161 //Do Nothing
162 end;
163
164 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 function TFBStatement.TimeStampToMSecs(const TimeStamp: TTimeStamp): Int64;
174 begin
175 Result := TimeStamp.Time + Int64(timestamp.date)*msecsperday;
176 end;
177
178 constructor TFBStatement.Create(Attachment: IAttachment;
179 Transaction: ITransaction; sql: AnsiString; SQLDialect: integer);
180 begin
181 inherited Create(Transaction as TFBTransaction,2);
182 FAttachmentIntf := Attachment;
183 FTransactionIntf := Transaction;
184 FFirebirdClientAPI := Attachment.getFirebirdAPI as TFBClientAPI;
185 FSQLDialect := SQLDialect;
186 FSQL := sql;
187 FBatchRowLimit := DefaultBatchRowLimit;
188 FStaleReferenceChecks := true;
189 end;
190
191 constructor TFBStatement.CreateWithParameterNames(Attachment: IAttachment;
192 Transaction: ITransaction; sql: AnsiString; SQLDialect: integer;
193 GenerateParamNames: boolean; CaseSensitiveParams: boolean);
194 begin
195 FHasParamNames := true;
196 FGenerateParamNames := GenerateParamNames;
197 FCaseSensitiveParams := CaseSensitiveParams;
198 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 if FOpen and ((FExecTransactionIntf as TObject) = (aTransaction as TObject)) then
217 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 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 function TFBStatement.GetSQLText: AnsiString;
286 begin
287 Result := FSQL;
288 end;
289
290 function TFBStatement.GetProcessedSQLText: AnsiString;
291 begin
292 if FProcessedSQL = '' then
293 ProcessSQL(FSQL,FGenerateParamNames,FProcessedSQL);
294 Result := FProcessedSQL
295 end;
296
297 function TFBStatement.GetSQLDialect: integer;
298 begin
299 Result := FSQLDialect;
300 end;
301
302 procedure TFBStatement.Prepare(aTransaction: ITransaction);
303 begin
304 Prepare('',aTransaction);
305 end;
306
307 procedure TFBStatement.Prepare(CursorName: AnsiString;
308 aTransaction: ITransaction);
309 begin
310 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 InternalPrepare(CursorName);
318 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 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 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 function TFBStatement.OpenCursor(aTransaction: ITransaction): IResultSet;
371 begin
372 Result := OpenCursor(false,aTransaction);
373 end;
374
375 function TFBStatement.OpenCursor(Scrollable: boolean; aTransaction: ITransaction
376 ): IResultSet;
377 begin
378 Close;
379 if aTransaction = nil then
380 Result := InternalOpenCursor(FTransactionIntf,Scrollable)
381 else
382 Result := InternalOpenCursor(aTransaction,Scrollable);
383 end;
384
385 function TFBStatement.CreateBlob(paramName: AnsiString): IBlob;
386 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 function TFBStatement.CreateArray(paramName: AnsiString): IArray;
402 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 Result := TSQLInfoResultsBuffer.Create(FFirebirdClientAPI);
430 GetDsqlInfo(Request,Result);
431 end;
432
433 procedure TFBStatement.SetRetainInterfaces(aValue: boolean);
434 begin
435 RetainInterfaces := aValue;
436 end;
437
438 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 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 end.
475