60 |
|
{ } |
61 |
|
{************************************************************************} |
62 |
|
unit FBTransaction; |
63 |
+ |
{$IFDEF MSWINDOWS} |
64 |
+ |
{$DEFINE WINDOWS} |
65 |
+ |
{$ENDIF} |
66 |
|
|
67 |
|
{$IFDEF FPC} |
68 |
< |
{$mode objfpc}{$H+} |
68 |
> |
{$mode delphi} |
69 |
|
{$interfaces COM} |
70 |
|
{$ENDIF} |
71 |
|
|
72 |
|
interface |
73 |
|
|
74 |
|
uses |
75 |
< |
Classes, SysUtils, IB, FBParamBlock, FBActivityMonitor; |
75 |
> |
Classes, SysUtils, IB, FBParamBlock, FBActivityMonitor, FBClientAPI; |
76 |
|
|
77 |
|
type |
78 |
|
{ TFBTransaction } |
79 |
|
|
80 |
|
TFBTransaction = class(TActivityReporter, IActivityMonitor,ITransaction) |
81 |
|
private |
82 |
+ |
FFirebirdAPI: TFBClientAPI; |
83 |
|
function GenerateTPB(sl: array of byte): ITPB; |
84 |
|
protected |
85 |
|
FTPB: ITPB; |
88 |
|
FAttachments: array of IAttachment; {Keep reference to attachment - ensures |
89 |
|
attachment cannot be freed before transaction} |
90 |
|
function GetActivityIntf(att: IAttachment): IActivityMonitor; virtual; abstract; |
91 |
+ |
procedure SetInterface(api: TFBClientAPI); virtual; |
92 |
|
public |
93 |
< |
constructor Create(Attachments: array of IAttachment; Params: array of byte; DefaultCompletion: TTransactionAction); overload; |
94 |
< |
constructor Create(Attachments: array of IAttachment; TPB: ITPB; DefaultCompletion: TTransactionAction); overload; |
95 |
< |
constructor Create(Attachment: IAttachment; Params: array of byte; DefaultCompletion: TTransactionAction); overload; |
96 |
< |
constructor Create(Attachment: IAttachment; TPB: ITPB; DefaultCompletion: TTransactionAction); overload; |
93 |
> |
constructor Create(api: TFBClientAPI; Attachments: array of IAttachment; Params: array of byte; DefaultCompletion: TTransactionAction); overload; |
94 |
> |
constructor Create(api: TFBClientAPI; Attachments: array of IAttachment; TPB: ITPB; DefaultCompletion: TTransactionAction); overload; |
95 |
> |
constructor Create(api: TFBClientAPI; Attachment: IAttachment; Params: array of byte; DefaultCompletion: TTransactionAction); overload; |
96 |
> |
constructor Create(api: TFBClientAPI; Attachment: IAttachment; TPB: ITPB; DefaultCompletion: TTransactionAction); overload; |
97 |
|
destructor Destroy; override; |
98 |
|
procedure DoDefaultTransactionEnd(Force: boolean); |
99 |
+ |
property FirebirdAPI: TFBClientAPI read FFirebirdAPI; |
100 |
|
|
101 |
|
public |
102 |
|
{ITransaction} |
116 |
|
property TransactionSeqNo: integer read FSeqNo; |
117 |
|
end; |
118 |
|
|
119 |
+ |
{The transaction user interface is used to force an action on the end of the |
120 |
+ |
transaction.} |
121 |
+ |
|
122 |
+ |
ITransactionUser = interface |
123 |
+ |
['{156fcdc9-a326-44b3-a82d-f23c6fb9f97c}'] |
124 |
+ |
procedure TransactionEnding(aTransaction: ITransaction; Force: boolean); |
125 |
+ |
end; |
126 |
+ |
|
127 |
+ |
{ TTPBItem } |
128 |
+ |
|
129 |
+ |
TTPBItem = class(TParamBlockItem,ITPBItem) |
130 |
+ |
public |
131 |
+ |
function getParamTypeName: AnsiString; override; |
132 |
+ |
end; |
133 |
+ |
|
134 |
+ |
{ TTPB } |
135 |
+ |
|
136 |
+ |
TTPB = class (TCustomParamBlock<TTPBItem,ITPBItem>, ITPB) |
137 |
+ |
protected |
138 |
+ |
function LookupItemType(ParamTypeName: AnsiString): byte; override; |
139 |
+ |
public |
140 |
+ |
constructor Create(api: TFBClientAPI); |
141 |
+ |
function GetDPBParamTypeName(ParamType: byte): Ansistring; |
142 |
+ |
end; |
143 |
+ |
|
144 |
|
implementation |
145 |
|
|
146 |
< |
uses FBMessages, FBStatement; |
146 |
> |
uses FBMessages; |
147 |
> |
|
148 |
> |
const |
149 |
> |
isc_tpb_last_tpb_constant = isc_tpb_at_snapshot_number; |
150 |
> |
|
151 |
> |
TPBConstantNames: array[1..isc_tpb_last_tpb_constant] of string = ( |
152 |
> |
'consistency', |
153 |
> |
'concurrency', |
154 |
> |
'shared', |
155 |
> |
'protected', |
156 |
> |
'exclusive', |
157 |
> |
'wait', |
158 |
> |
'nowait', |
159 |
> |
'read', |
160 |
> |
'write', |
161 |
> |
'lock_read', |
162 |
> |
'lock_write', |
163 |
> |
'verb_time', |
164 |
> |
'commit_time', |
165 |
> |
'ignore_limbo', |
166 |
> |
'read_committed', |
167 |
> |
'autocommit', |
168 |
> |
'rec_version', |
169 |
> |
'no_rec_version', |
170 |
> |
'restart_requests', |
171 |
> |
'no_auto_undo', |
172 |
> |
'lock_timeout', |
173 |
> |
'read_consistency', |
174 |
> |
'at_snapshot_number' |
175 |
> |
); |
176 |
|
|
177 |
|
{ TFBTransaction } |
178 |
|
|
180 |
|
var |
181 |
|
i: Integer; |
182 |
|
begin |
183 |
< |
Result := TTPB.Create; |
183 |
> |
Result := TTPB.Create(FFirebirdAPI); |
184 |
|
for i := 0 to Length(sl) - 1 do |
185 |
|
Result.Add(sl[i]); |
186 |
|
end; |
187 |
|
|
188 |
< |
constructor TFBTransaction.Create(Attachments: array of IAttachment; |
188 |
> |
procedure TFBTransaction.SetInterface(api: TFBClientAPI); |
189 |
> |
begin |
190 |
> |
FFirebirdAPI := api; |
191 |
> |
end; |
192 |
> |
|
193 |
> |
constructor TFBTransaction.Create(api: TFBClientAPI; Attachments: array of IAttachment; |
194 |
|
Params: array of byte; DefaultCompletion: TTransactionAction); |
195 |
|
begin |
196 |
< |
Create(Attachments,GenerateTPB(Params), DefaultCompletion); |
196 |
> |
Create(api, Attachments,GenerateTPB(Params), DefaultCompletion); |
197 |
|
end; |
198 |
|
|
199 |
< |
constructor TFBTransaction.Create(Attachments: array of IAttachment; TPB: ITPB; |
199 |
> |
constructor TFBTransaction.Create(api: TFBClientAPI; Attachments: array of IAttachment; TPB: ITPB; |
200 |
|
DefaultCompletion: TTransactionAction); |
201 |
|
var |
202 |
|
i: Integer; |
203 |
|
begin |
204 |
|
inherited Create(nil); |
205 |
+ |
SetInterface(api); |
206 |
|
if Length(Attachments) = 0 then |
207 |
|
IBError(ibxeEmptyAttachmentsList,[nil]); |
208 |
|
|
209 |
+ |
{make sure all attachments use same Firebird API} |
210 |
+ |
for i := 0 to Length(Attachments) - 1 do |
211 |
+ |
if Attachments[i].getFirebirdAPI.GetFBLibrary.GetHandle <> FFirebirdAPI.GetFBLibrary.GetHandle then |
212 |
+ |
IBError(ibxeDifferentAPIs,[nil]); |
213 |
+ |
|
214 |
|
SetLength(FAttachments,Length(Attachments)); |
215 |
|
for i := 0 to Length(Attachments) - 1 do |
216 |
|
begin |
221 |
|
Start(DefaultCompletion); |
222 |
|
end; |
223 |
|
|
224 |
< |
constructor TFBTransaction.Create(Attachment: IAttachment; |
224 |
> |
constructor TFBTransaction.Create(api: TFBClientAPI; Attachment: IAttachment; |
225 |
|
Params: array of byte; DefaultCompletion: TTransactionAction); |
226 |
|
begin |
227 |
< |
Create(Attachment,GenerateTPB(Params),DefaultCompletion); |
227 |
> |
Create(api,Attachment,GenerateTPB(Params),DefaultCompletion); |
228 |
|
end; |
229 |
|
|
230 |
< |
constructor TFBTransaction.Create(Attachment: IAttachment; TPB: ITPB; |
230 |
> |
constructor TFBTransaction.Create(api: TFBClientAPI; Attachment: IAttachment; TPB: ITPB; |
231 |
|
DefaultCompletion: TTransactionAction); |
232 |
|
begin |
233 |
|
inherited Create(nil); |
234 |
+ |
SetInterface(api); |
235 |
|
AddMonitor(GetActivityIntf(Attachment)); |
236 |
|
SetLength(FAttachments,1); |
237 |
|
FAttachments[0] := Attachment; |
247 |
|
|
248 |
|
procedure TFBTransaction.DoDefaultTransactionEnd(Force: boolean); |
249 |
|
var i: integer; |
250 |
< |
intf: TInterfacedObject; |
250 |
> |
intf: IUnknown; |
251 |
> |
user: ITransactionUser; |
252 |
|
begin |
253 |
|
if InTransaction then |
254 |
|
begin |
255 |
|
for i := 0 to InterfaceCount - 1 do |
256 |
|
begin |
257 |
|
intf := GetInterface(i); |
258 |
< |
if (intf <> nil) and (intf is TFBStatement) then |
259 |
< |
TFBStatement(intf).TransactionEnding(self,Force); |
258 |
> |
if (intf <> nil) and (intf.QueryInterface(ITransactionUser,user) = S_OK) then |
259 |
> |
user.TransactionEnding(self,Force); |
260 |
|
end; |
261 |
|
case FDefaultCompletion of |
262 |
|
taRollback: |
292 |
|
Start(DefaultCompletion); |
293 |
|
end; |
294 |
|
|
295 |
+ |
{ TTPBItem } |
296 |
+ |
|
297 |
+ |
function TTPBItem.getParamTypeName: AnsiString; |
298 |
+ |
begin |
299 |
+ |
Result := TPBPrefix + TPBConstantNames[getParamType]; |
300 |
+ |
end; |
301 |
+ |
|
302 |
+ |
|
303 |
+ |
{TTPB} |
304 |
+ |
|
305 |
+ |
constructor TTPB.Create(api: TFBClientAPI); |
306 |
+ |
begin |
307 |
+ |
inherited Create(api); |
308 |
+ |
FDataLength := 1; |
309 |
+ |
FBuffer^ := isc_tpb_version3; |
310 |
+ |
end; |
311 |
+ |
|
312 |
+ |
function TTPB.GetDPBParamTypeName(ParamType: byte): Ansistring; |
313 |
+ |
begin |
314 |
+ |
if ParamType <= isc_tpb_last_tpb_constant then |
315 |
+ |
Result := TPBConstantNames[ParamType] |
316 |
+ |
else |
317 |
+ |
Result := ''; |
318 |
+ |
end; |
319 |
+ |
|
320 |
+ |
function TTPB.LookupItemType(ParamTypeName: AnsiString): byte; |
321 |
+ |
var i: byte; |
322 |
+ |
begin |
323 |
+ |
Result := 0; |
324 |
+ |
ParamTypeName := LowerCase(ParamTypeName); |
325 |
+ |
if (Pos(TPBPrefix, ParamTypeName) = 1) then |
326 |
+ |
Delete(ParamTypeName, 1, Length(TPBPrefix)); |
327 |
+ |
|
328 |
+ |
for i := 1 to isc_tpb_last_tpb_constant do |
329 |
+ |
if (ParamTypeName = TPBConstantNames[i]) then |
330 |
+ |
begin |
331 |
+ |
Result := i; |
332 |
+ |
break; |
333 |
+ |
end; |
334 |
+ |
end; |
335 |
+ |
|
336 |
|
end. |
337 |
|
|