ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBTransaction.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: 15523 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     {************************************************************************}
31     { }
32     { Borland Delphi Visual Component Library }
33     { InterBase Express core components }
34     { }
35     { Copyright (c) 1998-2000 Inprise Corporation }
36     { }
37     { InterBase Express is based in part on the product }
38     { Free IB Components, written by Gregory H. Deatz for }
39     { Hoagland, Longo, Moran, Dunst & Doukas Company. }
40     { Free IB Components is used under license. }
41     { }
42     { The contents of this file are subject to the InterBase }
43     { Public License Version 1.0 (the "License"); you may not }
44     { use this file except in compliance with the License. You }
45     { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
46     { Software distributed under the License is distributed on }
47     { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
48     { express or implied. See the License for the specific language }
49     { governing rights and limitations under the License. }
50     { The Original Code was created by InterBase Software Corporation }
51     { and its successors. }
52     { Portions created by Inprise Corporation are Copyright (C) Inprise }
53     { Corporation. All Rights Reserved. }
54     { Contributor(s): Jeff Overcash }
55     { }
56     { IBX For Lazarus (Firebird Express) }
57     { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
58     { Portions created by MWA Software are copyright McCallum Whyman }
59     { Associates Ltd 2011 - 2015 }
60     { }
61     {************************************************************************}
62     unit FBTransaction;
63 tony 56 {$IFDEF MSWINDOWS}
64     {$DEFINE WINDOWS}
65     {$ENDIF}
66 tony 45
67     {$IFDEF FPC}
68 tony 56 {$mode delphi}
69 tony 45 {$interfaces COM}
70     {$ENDIF}
71    
72     interface
73    
74     uses
75 tony 359 Classes, SysUtils, IB, FBParamBlock, FBActivityMonitor, FBClientAPI, FBOutputBlock;
76 tony 45
77     type
78     { TFBTransaction }
79    
80     TFBTransaction = class(TActivityReporter, IActivityMonitor,ITransaction)
81     private
82 tony 263 FFirebirdAPI: TFBClientAPI;
83 tony 45 function GenerateTPB(sl: array of byte): ITPB;
84     protected
85     FTPB: ITPB;
86     FSeqNo: integer;
87     FDefaultCompletion: TTransactionAction;
88     FAttachments: array of IAttachment; {Keep reference to attachment - ensures
89     attachment cannot be freed before transaction}
90 tony 359 procedure CheckHandle;
91 tony 45 function GetActivityIntf(att: IAttachment): IActivityMonitor; virtual; abstract;
92 tony 263 procedure SetInterface(api: TFBClientAPI); virtual;
93 tony 359 function GetTrInfo(ReqBuffer: PByte; ReqBufLen: integer): ITrInformation; virtual; abstract;
94 tony 45 public
95 tony 263 constructor Create(api: TFBClientAPI; Attachments: array of IAttachment; Params: array of byte; DefaultCompletion: TTransactionAction); overload;
96     constructor Create(api: TFBClientAPI; Attachments: array of IAttachment; TPB: ITPB; DefaultCompletion: TTransactionAction); overload;
97     constructor Create(api: TFBClientAPI; Attachment: IAttachment; Params: array of byte; DefaultCompletion: TTransactionAction); overload;
98     constructor Create(api: TFBClientAPI; Attachment: IAttachment; TPB: ITPB; DefaultCompletion: TTransactionAction); overload;
99 tony 45 destructor Destroy; override;
100     procedure DoDefaultTransactionEnd(Force: boolean);
101 tony 263 property FirebirdAPI: TFBClientAPI read FFirebirdAPI;
102 tony 45
103     public
104     {ITransaction}
105     function getTPB: ITPB;
106     procedure PrepareForCommit;virtual; abstract;
107     procedure Commit(Force: boolean=false); virtual; abstract;
108     procedure CommitRetaining; virtual; abstract;
109     function GetInTransaction: boolean; virtual; abstract;
110 tony 359 function GetIsReadOnly: boolean;
111     function GetTransactionID: integer;
112 tony 45 function GetAttachmentCount: integer;
113     function GetAttachment(index: integer): IAttachment;
114     procedure Rollback(Force: boolean=false); virtual; abstract;
115     procedure RollbackRetaining; virtual; abstract;
116     procedure Start(DefaultCompletion: TTransactionCompletion=taCommit); overload; virtual; abstract;
117     procedure Start(TPB: ITPB; DefaultCompletion: TTransactionCompletion=taCommit); overload;
118 tony 359 function GetTrInformation(Requests: array of byte): ITrInformation; overload;
119     function GetTrInformation(Request: byte): ITrInformation; overload;
120 tony 45
121     property InTransaction: boolean read GetInTransaction;
122     property TransactionSeqNo: integer read FSeqNo;
123     end;
124    
125 tony 315 {The transaction user interface is used to force an action on the end of the
126     transaction.}
127    
128     ITransactionUser = interface
129     ['{156fcdc9-a326-44b3-a82d-f23c6fb9f97c}']
130     procedure TransactionEnding(aTransaction: ITransaction; Force: boolean);
131     end;
132    
133     { TTPBItem }
134    
135     TTPBItem = class(TParamBlockItem,ITPBItem)
136     public
137     function getParamTypeName: AnsiString; override;
138     end;
139    
140     { TTPB }
141    
142     TTPB = class (TCustomParamBlock<TTPBItem,ITPBItem>, ITPB)
143     protected
144     function LookupItemType(ParamTypeName: AnsiString): byte; override;
145     public
146     constructor Create(api: TFBClientAPI);
147 tony 345 function GetParamTypeName(ParamType: byte): Ansistring;
148     {$IFDEF FPC}
149     function ITPB.GetDPBParamTypeName = GetParamTypeName;
150     {$ELSE}
151 tony 315 function GetDPBParamTypeName(ParamType: byte): Ansistring;
152 tony 345 {$ENDIF}
153     end;
154 tony 315
155 tony 359 {$IFDEF FPC}
156     TTrInfoItem = class;
157    
158     { TTrInfoItem }
159    
160     TTrInfoItem = class(TOutputBlockItemGroup<TTrInfoItem,ITrInfoItem>,ITrInfoItem)
161     {$ELSE}
162     TTransInfoItem = class(TOutputBlockItemGroup<TOutputBlockItem,ITransInfoItem>,ITransInfoItem)
163     {$ENDIF}
164     public
165     procedure DecodeTraIsolation(var IsolationType, RecVersion: byte);
166     end;
167    
168     { TTrInformation }
169    
170     TTrInformation = class(TCustomOutputBlock<TTrInfoItem,ITrInfoItem>, ITrInformation)
171     protected
172     procedure DoParseBuffer; override;
173     public
174     constructor Create(api: TFBClientAPI; aSize: integer = DefaultBufferSize);
175     {$IFNDEF FPC}
176     function Find(ItemType: byte): ITransInfoItem;
177     {$ENDIF}
178     end;
179    
180 tony 45 implementation
181    
182 tony 315 uses FBMessages;
183 tony 45
184 tony 315 const
185     isc_tpb_last_tpb_constant = isc_tpb_at_snapshot_number;
186    
187     TPBConstantNames: array[1..isc_tpb_last_tpb_constant] of string = (
188     'consistency',
189     'concurrency',
190     'shared',
191     'protected',
192     'exclusive',
193     'wait',
194     'nowait',
195     'read',
196     'write',
197     'lock_read',
198     'lock_write',
199     'verb_time',
200     'commit_time',
201     'ignore_limbo',
202     'read_committed',
203     'autocommit',
204     'rec_version',
205     'no_rec_version',
206     'restart_requests',
207     'no_auto_undo',
208     'lock_timeout',
209     'read_consistency',
210     'at_snapshot_number'
211     );
212    
213 tony 45 { TFBTransaction }
214    
215     function TFBTransaction.GenerateTPB(sl: array of byte): ITPB;
216     var
217     i: Integer;
218     begin
219 tony 263 Result := TTPB.Create(FFirebirdAPI);
220 tony 45 for i := 0 to Length(sl) - 1 do
221     Result.Add(sl[i]);
222     end;
223    
224 tony 359 procedure TFBTransaction.CheckHandle;
225     begin
226     if not InTransaction then
227     IBError(ibxeNotInTransaction,[]);
228     end;
229    
230 tony 263 procedure TFBTransaction.SetInterface(api: TFBClientAPI);
231     begin
232     FFirebirdAPI := api;
233     end;
234    
235     constructor TFBTransaction.Create(api: TFBClientAPI; Attachments: array of IAttachment;
236 tony 45 Params: array of byte; DefaultCompletion: TTransactionAction);
237     begin
238 tony 263 Create(api, Attachments,GenerateTPB(Params), DefaultCompletion);
239 tony 45 end;
240    
241 tony 263 constructor TFBTransaction.Create(api: TFBClientAPI; Attachments: array of IAttachment; TPB: ITPB;
242 tony 45 DefaultCompletion: TTransactionAction);
243     var
244     i: Integer;
245     begin
246     inherited Create(nil);
247 tony 263 SetInterface(api);
248 tony 45 if Length(Attachments) = 0 then
249     IBError(ibxeEmptyAttachmentsList,[nil]);
250    
251 tony 263 {make sure all attachments use same Firebird API}
252     for i := 0 to Length(Attachments) - 1 do
253     if Attachments[i].getFirebirdAPI.GetFBLibrary.GetHandle <> FFirebirdAPI.GetFBLibrary.GetHandle then
254     IBError(ibxeDifferentAPIs,[nil]);
255    
256 tony 45 SetLength(FAttachments,Length(Attachments));
257     for i := 0 to Length(Attachments) - 1 do
258     begin
259     AddMonitor(GetActivityIntf(Attachments[i]));
260     FAttachments[i] := Attachments[i];
261     end;
262     FTPB := TPB;
263     Start(DefaultCompletion);
264     end;
265    
266 tony 263 constructor TFBTransaction.Create(api: TFBClientAPI; Attachment: IAttachment;
267 tony 45 Params: array of byte; DefaultCompletion: TTransactionAction);
268     begin
269 tony 263 Create(api,Attachment,GenerateTPB(Params),DefaultCompletion);
270 tony 45 end;
271    
272 tony 263 constructor TFBTransaction.Create(api: TFBClientAPI; Attachment: IAttachment; TPB: ITPB;
273 tony 45 DefaultCompletion: TTransactionAction);
274     begin
275     inherited Create(nil);
276 tony 263 SetInterface(api);
277 tony 45 AddMonitor(GetActivityIntf(Attachment));
278     SetLength(FAttachments,1);
279     FAttachments[0] := Attachment;
280     FTPB := TPB;
281     Start(DefaultCompletion);
282     end;
283    
284     destructor TFBTransaction.Destroy;
285     begin
286     DoDefaultTransactionEnd(false);
287     inherited Destroy;
288     end;
289    
290     procedure TFBTransaction.DoDefaultTransactionEnd(Force: boolean);
291     var i: integer;
292 tony 315 intf: IUnknown;
293     user: ITransactionUser;
294 tony 45 begin
295     if InTransaction then
296     begin
297     for i := 0 to InterfaceCount - 1 do
298     begin
299     intf := GetInterface(i);
300 tony 315 if (intf <> nil) and (intf.QueryInterface(ITransactionUser,user) = S_OK) then
301     user.TransactionEnding(self,Force);
302 tony 45 end;
303     case FDefaultCompletion of
304     taRollback:
305     Rollback(Force);
306     taCommit:
307     Commit(Force);
308     end;
309     end;
310     end;
311    
312     function TFBTransaction.getTPB: ITPB;
313     begin
314     Result := FTPB;
315     end;
316    
317 tony 359 function TFBTransaction.GetIsReadOnly: boolean;
318     var Info: ITrInformation;
319     begin
320     Info := GetTrInformation(isc_info_tra_access);
321     if (Info.Count > 0) and (Info[0].getItemType = isc_info_tra_access) then
322     Result := Info[0].getAsInteger = isc_info_tra_readonly
323     else
324     Result := false;
325     end;
326    
327     function TFBTransaction.GetTransactionID: integer;
328     var Info: ITrInformation;
329     begin
330     Result := -1;
331     Info := GetTrInformation(isc_info_tra_id);
332     if (Info.Count > 0) and (Info[0].getItemType = isc_info_tra_id) then
333     Result := Info[0].getAsInteger;
334     end;
335    
336 tony 45 function TFBTransaction.GetAttachmentCount: integer;
337     begin
338     Result := Length(FAttachments);
339     end;
340    
341     function TFBTransaction.GetAttachment(index: integer): IAttachment;
342     begin
343     if (index >= 0) and (index < Length(FAttachments)) then
344     Result := FAttachments[index]
345     else
346     IBError(ibxeAttachmentListIndexError,[index]);
347     end;
348    
349     procedure TFBTransaction.Start(TPB: ITPB; DefaultCompletion: TTransactionCompletion
350     );
351     begin
352     FTPB := TPB;
353     Start(DefaultCompletion);
354     end;
355    
356 tony 359 function TFBTransaction.GetTrInformation(Requests: array of byte
357     ): ITrInformation;
358     var ReqBuffer: PByte;
359     i: integer;
360     begin
361     CheckHandle;
362     if Length(Requests) = 1 then
363     Result := GetTrInformation(Requests[0])
364     else
365     begin
366     GetMem(ReqBuffer,Length(Requests));
367     try
368     for i := 0 to Length(Requests) - 1 do
369     ReqBuffer[i] := Requests[i];
370    
371     Result := GetTrInfo(ReqBuffer,Length(Requests));
372    
373     finally
374     FreeMem(ReqBuffer);
375     end;
376     end;
377     end;
378    
379     function TFBTransaction.GetTrInformation(Request: byte): ITrInformation;
380     begin
381     CheckHandle;
382     Result := GetTrInfo(@Request,1);
383     end;
384    
385 tony 315 { TTPBItem }
386    
387     function TTPBItem.getParamTypeName: AnsiString;
388     begin
389     Result := TPBPrefix + TPBConstantNames[getParamType];
390     end;
391    
392    
393     {TTPB}
394    
395     constructor TTPB.Create(api: TFBClientAPI);
396     begin
397     inherited Create(api);
398     FDataLength := 1;
399     FBuffer^ := isc_tpb_version3;
400     end;
401    
402 tony 345 function TTPB.GetParamTypeName(ParamType: byte): Ansistring;
403 tony 315 begin
404     if ParamType <= isc_tpb_last_tpb_constant then
405     Result := TPBConstantNames[ParamType]
406     else
407     Result := '';
408     end;
409    
410 tony 345 {$IFNDEF FPC}
411     function TTPB.GetDPBParamTypeName(ParamType: byte): Ansistring;
412     begin
413     Result := GetParamTypeName(ParamType);
414     end;
415     {$ENDIF}
416    
417    
418 tony 315 function TTPB.LookupItemType(ParamTypeName: AnsiString): byte;
419     var i: byte;
420     begin
421     Result := 0;
422     ParamTypeName := LowerCase(ParamTypeName);
423     if (Pos(TPBPrefix, ParamTypeName) = 1) then
424     Delete(ParamTypeName, 1, Length(TPBPrefix));
425    
426     for i := 1 to isc_tpb_last_tpb_constant do
427     if (ParamTypeName = TPBConstantNames[i]) then
428     begin
429     Result := i;
430     break;
431     end;
432     end;
433    
434 tony 359 { TTrInfoItem }
435    
436     procedure TTrInfoItem.DecodeTraIsolation(var IsolationType, RecVersion: byte);
437     begin
438     with FFirebirdClientAPI, ItemData^ do
439     if getItemType = isc_info_tra_isolation then
440     begin
441     if FDataLength = 1 then
442     begin
443     IsolationType := getAsInteger;
444     RecVersion := 0;
445     end
446     else
447     begin
448     IsolationType := (FBufPtr + 3)^;
449     RecVersion := (FBufPtr + 4)^;
450     end
451     end
452     else
453     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
454     end;
455    
456     { TTrInformation }
457    
458     procedure TTrInformation.DoParseBuffer;
459     var P: PByte;
460     index: integer;
461     begin
462     P := Buffer;
463     index := 0;
464     SetLength(FItems,0);
465     while (P^ <> isc_info_end) and (P < Buffer + getBufSize) do
466     begin
467     SetLength(FItems,index+1);
468     case byte(P^) of
469     isc_info_tra_id,
470     isc_info_tra_oldest_interesting,
471     isc_info_tra_oldest_active,
472     isc_info_tra_oldest_snapshot,
473     fb_info_tra_snapshot_number,
474     isc_info_tra_lock_timeout:
475     FItems[index] := AddIntegerItem(P);
476    
477     isc_info_tra_isolation,
478     {return transaction isolation mode of current transaction.
479     format of returned clumplets is following:
480    
481     isc_info_tra_isolation,
482     1, isc_info_tra_consistency | isc_info_tra_concurrency
483     |
484     2, isc_info_tra_read_committed,
485     isc_info_tra_no_rec_version | isc_info_tra_rec_version
486    
487     i.e. for read committed transactions returned 2 items while for
488     other transactions returned 1 item}
489    
490     isc_info_tra_access:
491     FItems[index] := AddIntegerItem(P);
492     fb_info_tra_dbpath:
493     FItems[index] := AddStringItem(P);
494     else
495     FItems[index] := AddItem(P);
496     end;
497     P := P + FItems[index]^.FSize;
498     Inc(index);
499     end;
500     end;
501    
502     constructor TTrInformation.Create(api: TFBClientAPI; aSize: integer);
503     begin
504     inherited Create(api,aSize);
505     FIntegerType := dtInteger;
506     end;
507    
508 tony 45 end.
509