ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBStatement.pas
Revision: 345
Committed: Mon Aug 23 14:22:29 2021 UTC (2 years, 7 months ago) by tony
Content type: text/x-pascal
File size: 13573 byte(s)
Log Message:
Merged into public release

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