ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/3.0/FB30Attachment.pas
Revision: 390
Committed: Sat Jan 22 16:15:12 2022 UTC (2 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 16490 byte(s)
Log Message:
In Firebird 3 and later API: the status vector is now a thread var

File Contents

# Content
1 (*
2 * Firebird Interface (fbintf). The fbintf components provide a set of
3 * Pascal language bindings for the Firebird API.
4 *
5 * The contents of this file are subject to the Initial Developer's
6 * Public License Version 1.0 (the "License"); you may not use this
7 * file except in compliance with the License. You may obtain a copy
8 * of the License here:
9 *
10 * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11 *
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing rights
15 * and limitations under the License.
16 *
17 * The Initial Developer of the Original Code is Tony Whyman.
18 *
19 * The Original Code is (C) 2016 Tony Whyman, MWA Software
20 * (http://www.mwasoftware.co.uk).
21 *
22 * All Rights Reserved.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 *)
27 unit FB30Attachment;
28 {$IFDEF MSWINDOWS}
29 {$DEFINE WINDOWS}
30 {$ENDIF}
31
32 {$IFDEF FPC}
33 {$mode delphi}
34 {$interfaces COM}
35 {$ENDIF}
36
37 interface
38
39 uses
40 Classes, SysUtils, FBAttachment, FBClientAPI, FB30ClientAPI, Firebird, IB,
41 FBActivityMonitor, FBParamBlock;
42
43 type
44
45 { TFB30Attachment }
46
47 TFB30Attachment = class(TFBAttachment,IAttachment, IActivityMonitor)
48 private
49 FAttachmentIntf: Firebird.IAttachment;
50 FFirebird30ClientAPI: TFB30ClientAPI;
51 FTimeZoneServices: ITimeZoneServices;
52 FUsingRemoteICU: boolean;
53 FOwnsAttachmentHandle: boolean;
54 procedure SetAttachmentIntf(AValue: Firebird.IAttachment);
55 procedure SetUseRemoteICU(aValue: boolean);
56 protected
57 procedure CheckHandle; override;
58 function GetAttachment: IAttachment; override;
59 public
60 constructor Create(api: TFB30ClientAPI; DatabaseName: AnsiString; aDPB: IDPB;
61 RaiseExceptionOnConnectError: boolean); overload;
62 constructor Create(api: TFB30ClientAPI;
63 attachment: Firebird.IAttachment; aDatabaseName: AnsiString); overload;
64 constructor CreateDatabase(api: TFB30ClientAPI; DatabaseName: AnsiString; aDPB: IDPB; RaiseExceptionOnError: boolean); overload;
65 constructor CreateDatabase(api: TFB30ClientAPI; sql: AnsiString; aSQLDialect: integer;
66 RaiseExceptionOnError: boolean); overload;
67 function GetDBInfo(ReqBuffer: PByte; ReqBufLen: integer): IDBInformation;
68 override;
69 property AttachmentIntf: Firebird.IAttachment read FAttachmentIntf write SetAttachmentIntf;
70 property Firebird30ClientAPI: TFB30ClientAPI read FFirebird30ClientAPI;
71
72 public
73 {IAttachment}
74 procedure Connect;
75 procedure Disconnect(Force: boolean=false); override;
76 function IsConnected: boolean; override;
77 procedure DropDatabase;
78 function StartTransaction(TPB: array of byte; DefaultCompletion: TTransactionCompletion; aName: AnsiString=''): ITransaction; override;
79 function StartTransaction(TPB: ITPB; DefaultCompletion: TTransactionCompletion; aName: AnsiString=''): ITransaction; override;
80 procedure ExecImmediate(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer); override;
81 function Prepare(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer; CursorName: AnsiString=''): IStatement; override;
82 function PrepareWithNamedParameters(transaction: ITransaction; sql: AnsiString;
83 aSQLDialect: integer; GenerateParamNames: boolean=false;
84 CaseSensitiveParams: boolean=false; CursorName: AnsiString=''): IStatement; override;
85
86 {Events}
87 function GetEventHandler(Events: TStrings): IEvents; override;
88
89 {Blob - may use to open existing Blobs. However, ISQLData.AsBlob is preferred}
90
91 function CreateBlob(transaction: ITransaction; BlobMetaData: IBlobMetaData; BPB: IBPB=nil): IBlob; overload; override;
92 function CreateBlob(transaction: ITransaction; SubType: integer; aCharSetID: cardinal=0; BPB: IBPB=nil): IBlob; overload;
93 function OpenBlob(transaction: ITransaction; BlobMetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB=nil): IBlob; overload; override;
94
95 {Array}
96 function OpenArray(transaction: ITransaction; ArrayMetaData: IArrayMetaData; ArrayID: TISC_QUAD): IArray; overload; override;
97 function CreateArray(transaction: ITransaction; ArrayMetaData: IArrayMetaData): IArray; overload; override;
98 function CreateArrayMetaData(SQLType: cardinal; tableName: AnsiString;
99 columnName: AnsiString; Scale: integer; size: cardinal; aCharSetID: cardinal;
100 dimensions: cardinal; bounds: TArrayBounds): IArrayMetaData;
101
102
103 {Database Information}
104 function GetBlobMetaData(Transaction: ITransaction; tableName, columnName: AnsiString): IBlobMetaData; override;
105 function GetArrayMetaData(Transaction: ITransaction; tableName, columnName: AnsiString): IArrayMetaData; override;
106 procedure getFBVersion(version: TStrings);
107 function HasDecFloatSupport: boolean; override;
108 function HasBatchMode: boolean; override;
109 function HasScollableCursors: boolean;
110
111 {Time Zone Support}
112 function GetTimeZoneServices: ITimeZoneServices; override;
113 function HasTimeZoneSupport: boolean; override;
114 end;
115
116 implementation
117
118 uses FB30Transaction, FB30Statement, FB30Array, FB30Blob, FBMessages,
119 FBOutputBlock, FB30Events, IBUtils, FB30TimeZoneServices;
120
121 type
122 { TVersionCallback }
123
124 TVersionCallback = class(Firebird.IVersionCallbackImpl)
125 private
126 FOutput: TStrings;
127 FFirebirdClientAPI: TFBClientAPI;
128 public
129 constructor Create(FirebirdClientAPI: TFBClientAPI; output: TStrings);
130 procedure callback(status: Firebird.IStatus; text: PAnsiChar); override;
131 end;
132
133 { TVersionCallback }
134
135 constructor TVersionCallback.Create(FirebirdClientAPI: TFBClientAPI;
136 output: TStrings);
137 begin
138 inherited Create;
139 FFirebirdClientAPI := FirebirdClientAPI;
140 FOutput := output;
141 end;
142
143 procedure TVersionCallback.callback(status: Firebird.IStatus; text: PAnsiChar);
144 var aStatus: IStatus;
145 begin
146 aStatus := TFB30Status.Create(FFirebirdClientAPI,status);
147 if aStatus.InErrorState then
148 raise EIBInterBaseError.Create(aStatus);
149 FOutput.Add(text);
150 end;
151
152
153 { TFB30Attachment }
154
155 procedure TFB30Attachment.SetUseRemoteICU(aValue: boolean);
156 begin
157 if (FUsingRemoteICU <> aValue) and (GetODSMajorVersion >= 13) then
158 begin
159 if aValue then
160 ExecImmediate([isc_tpb_write,isc_tpb_wait,isc_tpb_concurrency],'SET BIND OF TIME ZONE TO EXTENDED')
161 else
162 ExecImmediate([isc_tpb_write,isc_tpb_wait,isc_tpb_concurrency],'SET BIND OF TIME ZONE TO NATIVE');
163 FUsingRemoteICU := aValue;
164 end;
165 end;
166
167 procedure TFB30Attachment.SetAttachmentIntf(AValue: Firebird.IAttachment);
168 begin
169 if FAttachmentIntf = AValue then Exit;
170 if FAttachmentIntf <> nil then
171 try
172 FAttachmentIntf.release;
173 except {ignore - forced release}
174 end;
175 FOwnsAttachmentHandle := false;
176 ClearCachedInfo;
177 FTimeZoneServices := nil;
178 FAttachmentIntf := AValue;
179 if FAttachmentIntf <> nil then
180 FAttachmentIntf.AddRef;
181 end;
182
183 procedure TFB30Attachment.CheckHandle;
184 begin
185 if FAttachmentIntf = nil then
186 IBError(ibxeDatabaseClosed,[nil]);
187 end;
188
189 function TFB30Attachment.GetAttachment: IAttachment;
190 begin
191 Result := self;
192 end;
193
194 constructor TFB30Attachment.Create(api: TFB30ClientAPI; DatabaseName: AnsiString; aDPB: IDPB;
195 RaiseExceptionOnConnectError: boolean);
196 begin
197 FFirebird30ClientAPI := api;
198 if aDPB = nil then
199 begin
200 if RaiseExceptionOnConnectError then
201 IBError(ibxeNoDPB,[nil]);
202 Exit;
203 end;
204 inherited Create(api,DatabaseName,aDPB,RaiseExceptionOnConnectError);
205 Connect;
206 end;
207
208 constructor TFB30Attachment.CreateDatabase(api: TFB30ClientAPI; DatabaseName: AnsiString; aDPB: IDPB;
209 RaiseExceptionOnError: boolean);
210 var Param: IDPBItem;
211 sql: AnsiString;
212 IsCreateDB: boolean;
213 Intf: Firebird.IAttachment;
214 begin
215 inherited Create(api,DatabaseName,aDPB,RaiseExceptionOnError);
216 FFirebird30ClientAPI := api;
217 IsCreateDB := true;
218 if aDPB <> nil then
219 begin
220 Param := aDPB.Find(isc_dpb_set_db_SQL_dialect);
221 if Param <> nil then
222 SetSQLDialect(Param.AsByte);
223 end;
224 sql := GenerateCreateDatabaseSQL(DatabaseName,aDPB);
225 with FFirebird30ClientAPI do
226 begin
227 Intf := UtilIntf.executeCreateDatabase(StatusIntf,Length(sql),
228 PAnsiChar(sql),SQLDialect,@IsCreateDB);
229 if FRaiseExceptionOnConnectError then Check4DataBaseError;
230 if not InErrorState then
231 begin
232 if aDPB <> nil then
233 {Connect using known parameters}
234 begin
235 Intf.Detach(StatusIntf); {releases interface}
236 Check4DataBaseError;
237 Connect;
238 end
239 else
240 AttachmentIntf := Intf;
241 FOwnsAttachmentHandle:= true;
242 end;
243 end;
244 end;
245
246 constructor TFB30Attachment.CreateDatabase(api: TFB30ClientAPI; sql: AnsiString; aSQLDialect: integer;
247 RaiseExceptionOnError: boolean);
248 var IsCreateDB: boolean;
249 Intf: Firebird.IAttachment;
250 begin
251 inherited Create(api,'',nil,RaiseExceptionOnError);
252 FFirebird30ClientAPI := api;
253 SetSQLDialect(aSQLDialect);
254 with FFirebird30ClientAPI do
255 begin
256 Intf := UtilIntf.executeCreateDatabase(StatusIntf,Length(sql),
257 PAnsiChar(sql),aSQLDialect,@IsCreateDB);
258 if FRaiseExceptionOnConnectError then Check4DataBaseError;
259 if InErrorState then
260 Exit;
261 end;
262 AttachmentIntf := Intf;
263 FOwnsAttachmentHandle:= true;
264 ExtractConnectString(sql,FDatabaseName);
265 DPBFromCreateSQL(sql);
266 end;
267
268 constructor TFB30Attachment.Create(api: TFB30ClientAPI;
269 attachment: Firebird.IAttachment; aDatabaseName: AnsiString);
270 begin
271 inherited Create(api,aDatabaseName,nil,false);
272 FFirebird30ClientAPI := api;
273 AttachmentIntf := attachment;
274 end;
275
276 function TFB30Attachment.GetDBInfo(ReqBuffer: PByte; ReqBufLen: integer): IDBInformation;
277 begin
278 Result := TDBInformation.Create(Firebird30ClientAPI);
279 with FFirebird30ClientAPI, Result as TDBInformation do
280 begin
281 FAttachmentIntf.getInfo(StatusIntf, ReqBufLen, BytePtr(ReqBuffer),
282 getBufSize, BytePtr(Buffer));
283 Check4DataBaseError;
284 end
285 end;
286
287 procedure TFB30Attachment.Connect;
288 var Intf: Firebird.IAttachment;
289 begin
290 with FFirebird30ClientAPI do
291 begin
292 Intf := ProviderIntf.attachDatabase(StatusIntf,PAnsiChar(FDatabaseName),
293 (DPB as TDPB).getDataLength,
294 BytePtr((DPB as TDPB).getBuffer));
295 if FRaiseExceptionOnConnectError then Check4DataBaseError;
296 if not InErrorState then
297 begin
298 AttachmentIntf := Intf;
299 FOwnsAttachmentHandle := true;
300 end;
301 end;
302 end;
303
304 procedure TFB30Attachment.Disconnect(Force: boolean);
305 begin
306 if IsConnected then
307 begin
308 EndAllTransactions;
309 if FOwnsAttachmentHandle then
310 with FFirebird30ClientAPI do
311 begin
312 FAttachmentIntf.Detach(StatusIntf);
313 if not Force and InErrorState then
314 IBDataBaseError;
315 end;
316 AttachmentIntf := nil;
317 end;
318 inherited Disconnect(Force);
319 end;
320
321 function TFB30Attachment.IsConnected: boolean;
322 begin
323 Result := FAttachmentIntf <> nil;
324 end;
325
326 procedure TFB30Attachment.DropDatabase;
327 begin
328 if IsConnected then
329 begin
330 if not FOwnsAttachmentHandle then
331 IBError(ibxeCantDropAcquiredDB,[nil]);
332 with FFirebird30ClientAPI do
333 begin
334 EndAllTransactions;
335 EndSession(false);
336 FAttachmentIntf.dropDatabase(StatusIntf);
337 Check4DataBaseError;
338 end;
339 AttachmentIntf := nil;
340 end;
341 end;
342
343 function TFB30Attachment.StartTransaction(TPB: array of byte;
344 DefaultCompletion: TTransactionCompletion; aName: AnsiString): ITransaction;
345 begin
346 CheckHandle;
347 Result := TFB30Transaction.Create(FFirebird30ClientAPI,self,TPB,DefaultCompletion, aName);
348 end;
349
350 function TFB30Attachment.StartTransaction(TPB: ITPB;
351 DefaultCompletion: TTransactionCompletion; aName: AnsiString): ITransaction;
352 begin
353 CheckHandle;
354 Result := TFB30Transaction.Create(FFirebird30ClientAPI,self,TPB,DefaultCompletion,aName);
355 end;
356
357 procedure TFB30Attachment.ExecImmediate(transaction: ITransaction; sql: AnsiString;
358 aSQLDialect: integer);
359 begin
360 CheckHandle;
361 with FFirebird30ClientAPI do
362 try
363 FAttachmentIntf.execute(StatusIntf,(transaction as TFB30Transaction).TransactionIntf,
364 Length(sql),PAnsiChar(sql),aSQLDialect,nil,nil,nil,nil);
365 Check4DataBaseError;
366 finally
367 if JournalingActive and
368 ((joReadOnlyQueries in GetJournalOptions) or
369 (joModifyQueries in GetJournalOptions)) then
370 ExecImmediateJnl(sql,transaction);
371 end;
372 end;
373
374 function TFB30Attachment.Prepare(transaction: ITransaction; sql: AnsiString;
375 aSQLDialect: integer; CursorName: AnsiString): IStatement;
376 begin
377 CheckHandle;
378 Result := TFB30Statement.Create(self,transaction,sql,aSQLDialect,CursorName);
379 end;
380
381 function TFB30Attachment.PrepareWithNamedParameters(transaction: ITransaction;
382 sql: AnsiString; aSQLDialect: integer; GenerateParamNames: boolean;
383 CaseSensitiveParams: boolean; CursorName: AnsiString): IStatement;
384 begin
385 CheckHandle;
386 Result := TFB30Statement.CreateWithParameterNames(self,transaction,sql,aSQLDialect,
387 GenerateParamNames,CaseSensitiveParams,CursorName);
388 end;
389
390 function TFB30Attachment.GetEventHandler(Events: TStrings): IEvents;
391 begin
392 CheckHandle;
393 Result := TFB30Events.Create(self,Events);
394 end;
395
396 function TFB30Attachment.CreateBlob(transaction: ITransaction;
397 BlobMetaData: IBlobMetaData; BPB: IBPB): IBlob;
398 begin
399 CheckHandle;
400 Result := TFB30Blob.Create(self,transaction as TFB30Transaction, BlobMetaData,BPB);
401 end;
402
403 function TFB30Attachment.CreateBlob(transaction: ITransaction;
404 SubType: integer; aCharSetID: cardinal; BPB: IBPB): IBlob;
405 begin
406 CheckHandle;
407 Result := TFB30Blob.Create(self,transaction as TFB30Transaction, SubType,aCharSetID,BPB);
408 end;
409
410 function TFB30Attachment.OpenBlob(transaction: ITransaction;
411 BlobMetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB): IBlob;
412 begin
413 CheckHandle;
414 Result := TFB30Blob.Create(self,transaction as TFB30transaction,BlobMetaData,BlobID,BPB);
415 end;
416
417 function TFB30Attachment.OpenArray(transaction: ITransaction;
418 ArrayMetaData: IArrayMetaData; ArrayID: TISC_QUAD): IArray;
419 begin
420 CheckHandle;
421 Result := TFB30Array.Create(self,transaction as TFB30Transaction,
422 ArrayMetaData,ArrayID);
423 end;
424
425 function TFB30Attachment.CreateArray(transaction: ITransaction;
426 ArrayMetaData: IArrayMetaData): IArray;
427 begin
428 CheckHandle;
429 Result := TFB30Array.Create(self,transaction as TFB30Transaction,ArrayMetaData);
430 end;
431
432 function TFB30Attachment.CreateArrayMetaData(SQLType: cardinal; tableName: AnsiString; columnName: AnsiString;
433 Scale: integer; size: cardinal; aCharSetID: cardinal; dimensions: cardinal;
434 bounds: TArrayBounds): IArrayMetaData;
435 begin
436 Result := TFB30ArrayMetaData.Create(self,SQLType,tableName,ColumnName,Scale,size,aCharSetID, dimensions,bounds);
437 end;
438
439 function TFB30Attachment.GetBlobMetaData(Transaction: ITransaction; tableName,
440 columnName: AnsiString): IBlobMetaData;
441 begin
442 CheckHandle;
443 Result := TFB30BlobMetaData.Create(self,Transaction as TFB30Transaction,tableName,columnName);
444 end;
445
446 function TFB30Attachment.GetArrayMetaData(Transaction: ITransaction; tableName,
447 columnName: AnsiString): IArrayMetaData;
448 begin
449 CheckHandle;
450 Result := TFB30ArrayMetaData.Create(self,Transaction as TFB30Transaction,tableName,columnName);
451 end;
452
453 procedure TFB30Attachment.getFBVersion(version: TStrings);
454 var bufferObj: TVersionCallback;
455 begin
456 version.Clear;
457 bufferObj := TVersionCallback.Create(Firebird30ClientAPI,version);
458 try
459 with FFirebird30ClientAPI do
460 begin
461 UtilIntf.getFbVersion(StatusIntf,FAttachmentIntf,bufferObj);
462 Check4DataBaseError;
463 end;
464 finally
465 bufferObj.Free;
466 end;
467 end;
468
469 function TFB30Attachment.HasDecFloatSupport: boolean;
470 begin
471 Result := (FFirebird30ClientAPI.GetClientMajor >= 4) and
472 (GetODSMajorVersion >= 13);
473 end;
474
475 function TFB30Attachment.HasBatchMode: boolean;
476 begin
477 Result := FFirebird30ClientAPI.Firebird4orLater and
478 (GetODSMajorVersion >= 13);
479 end;
480
481 function TFB30Attachment.HasScollableCursors: boolean;
482 begin
483 Result := (GetODSMajorVersion >= 12);
484 end;
485
486 function TFB30Attachment.GetTimeZoneServices: ITimeZoneServices;
487 begin
488 if not HasTimeZoneSupport then
489 IBError(ibxeNotSupported,[]);
490
491 if FTimeZoneServices = nil then
492 FTimeZoneServices := TFB30TimeZoneServices.Create(self);
493 Result := FTimeZoneServices;
494 end;
495
496 function TFB30Attachment.HasTimeZoneSupport: boolean;
497 begin
498 Result := (FFirebird30ClientAPI.GetClientMajor >= 4) and
499 (GetODSMajorVersion >= 13);
500 end;
501
502 end.
503

Properties

Name Value
svn:eol-style native