ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/3.0/FB30Attachment.pas
Revision: 315
Committed: Thu Feb 25 11:56:36 2021 UTC (3 years, 1 month ago) by tony
Content type: text/x-pascal
File size: 14721 byte(s)
Log Message:
Updated for IBX 4 release

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.
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 tony 56 {$IFDEF MSWINDOWS}
29     {$DEFINE WINDOWS}
30     {$ENDIF}
31 tony 45
32     {$IFDEF FPC}
33 tony 56 {$mode delphi}
34 tony 45 {$interfaces COM}
35     {$ENDIF}
36    
37     interface
38    
39     uses
40 tony 315 Classes, SysUtils, FBAttachment, FBClientAPI, FB30ClientAPI, Firebird, IB,
41     FBActivityMonitor, FBParamBlock;
42 tony 45
43     type
44    
45     { TFB30Attachment }
46    
47     TFB30Attachment = class(TFBAttachment,IAttachment, IActivityMonitor)
48     private
49     FAttachmentIntf: Firebird.IAttachment;
50 tony 263 FFirebird30ClientAPI: TFB30ClientAPI;
51 tony 315 FTimeZoneServices: ITimeZoneServices;
52     FUsingRemoteICU: boolean;
53     procedure SetUseRemoteICU(aValue: boolean);
54 tony 45 protected
55     procedure CheckHandle; override;
56     public
57 tony 263 constructor Create(api: TFB30ClientAPI; DatabaseName: AnsiString; aDPB: IDPB;
58 tony 45 RaiseExceptionOnConnectError: boolean);
59 tony 263 constructor CreateDatabase(api: TFB30ClientAPI; DatabaseName: AnsiString; aDPB: IDPB; RaiseExceptionOnError: boolean); overload;
60     constructor CreateDatabase(api: TFB30ClientAPI; sql: AnsiString; aSQLDialect: integer;
61 tony 47 RaiseExceptionOnError: boolean); overload;
62 tony 45 destructor Destroy; override;
63 tony 143 function GetDBInfo(ReqBuffer: PByte; ReqBufLen: integer): IDBInformation;
64     override;
65 tony 45 property AttachmentIntf: Firebird.IAttachment read FAttachmentIntf;
66 tony 263 property Firebird30ClientAPI: TFB30ClientAPI read FFirebird30ClientAPI;
67 tony 45
68     public
69     {IAttachment}
70     procedure Connect;
71     procedure Disconnect(Force: boolean=false); override;
72 tony 117 function IsConnected: boolean; override;
73 tony 45 procedure DropDatabase;
74     function StartTransaction(TPB: array of byte; DefaultCompletion: TTransactionCompletion): ITransaction; override;
75     function StartTransaction(TPB: ITPB; DefaultCompletion: TTransactionCompletion): ITransaction; override;
76 tony 56 procedure ExecImmediate(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer); override;
77     function Prepare(transaction: ITransaction; sql: AnsiString; aSQLDialect: integer): IStatement; override;
78     function PrepareWithNamedParameters(transaction: ITransaction; sql: AnsiString;
79 tony 270 aSQLDialect: integer; GenerateParamNames: boolean=false;
80     CaseSensitiveParams: boolean=false): IStatement; override;
81 tony 45
82     {Events}
83     function GetEventHandler(Events: TStrings): IEvents; override;
84    
85     {Blob - may use to open existing Blobs. However, ISQLData.AsBlob is preferred}
86    
87 tony 291 function CreateBlob(transaction: ITransaction; BlobMetaData: IBlobMetaData; BPB: IBPB=nil): IBlob; overload; override;
88 tony 45 function CreateBlob(transaction: ITransaction; SubType: integer; aCharSetID: cardinal=0; BPB: IBPB=nil): IBlob; overload;
89 tony 56 function OpenBlob(transaction: ITransaction; BlobMetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB=nil): IBlob; overload; override;
90 tony 45
91     {Array}
92 tony 291 function OpenArray(transaction: ITransaction; ArrayMetaData: IArrayMetaData; ArrayID: TISC_QUAD): IArray; overload; override;
93     function CreateArray(transaction: ITransaction; ArrayMetaData: IArrayMetaData): IArray; overload; override;
94 tony 56 function CreateArrayMetaData(SQLType: cardinal; tableName: AnsiString;
95     columnName: AnsiString; Scale: integer; size: cardinal; aCharSetID: cardinal;
96 tony 263 dimensions: cardinal; bounds: TArrayBounds): IArrayMetaData;
97 tony 45
98 tony 47
99 tony 45 {Database Information}
100 tony 291 function GetBlobMetaData(Transaction: ITransaction; tableName, columnName: AnsiString): IBlobMetaData; override;
101     function GetArrayMetaData(Transaction: ITransaction; tableName, columnName: AnsiString): IArrayMetaData; override;
102 tony 266 procedure getFBVersion(version: TStrings);
103 tony 315 function HasDecFloatSupport: boolean; override;
104    
105     {Time Zone Support}
106     function GetTimeZoneServices: ITimeZoneServices; override;
107     function HasTimeZoneSupport: boolean; override;
108 tony 45 end;
109    
110     implementation
111    
112     uses FB30Transaction, FB30Statement, FB30Array, FB30Blob, FBMessages,
113 tony 315 FBOutputBlock, FB30Events, IBUtils, FB30TimeZoneServices;
114 tony 45
115 tony 266 type
116     { TVersionCallback }
117    
118     TVersionCallback = class(Firebird.IVersionCallbackImpl)
119     private
120     FOutput: TStrings;
121 tony 315 FFirebirdClientAPI: TFBClientAPI;
122 tony 266 public
123 tony 315 constructor Create(FirebirdClientAPI: TFBClientAPI; output: TStrings);
124 tony 266 procedure callback(status: Firebird.IStatus; text: PAnsiChar); override;
125     end;
126    
127     { TVersionCallback }
128    
129 tony 315 constructor TVersionCallback.Create(FirebirdClientAPI: TFBClientAPI;
130     output: TStrings);
131 tony 266 begin
132     inherited Create;
133 tony 315 FFirebirdClientAPI := FirebirdClientAPI;
134 tony 266 FOutput := output;
135     end;
136    
137     procedure TVersionCallback.callback(status: Firebird.IStatus; text: PAnsiChar);
138 tony 315 var StatusObj: TFB30StatusObject;
139 tony 266 begin
140 tony 315 if ((status.getState and status.STATE_ERRORS) <> 0) then
141     begin
142     StatusObj := TFB30StatusObject.Create(FFirebirdClientAPI,status);
143     try
144     raise EIBInterBaseError.Create(StatusObj);
145     finally
146     StatusObj.Free;
147     end;
148     end;
149 tony 266 FOutput.Add(text);
150     end;
151    
152    
153 tony 45 { TFB30Attachment }
154    
155 tony 315 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 tony 45 procedure TFB30Attachment.CheckHandle;
168     begin
169     if FAttachmentIntf = nil then
170     IBError(ibxeDatabaseClosed,[nil]);
171     end;
172    
173 tony 263 constructor TFB30Attachment.Create(api: TFB30ClientAPI; DatabaseName: AnsiString; aDPB: IDPB;
174 tony 45 RaiseExceptionOnConnectError: boolean);
175     begin
176 tony 263 FFirebird30ClientAPI := api;
177 tony 45 if aDPB = nil then
178     begin
179     if RaiseExceptionOnConnectError then
180     IBError(ibxeNoDPB,[nil]);
181     Exit;
182     end;
183 tony 263 inherited Create(api,DatabaseName,aDPB,RaiseExceptionOnConnectError);
184 tony 45 Connect;
185     end;
186    
187 tony 263 constructor TFB30Attachment.CreateDatabase(api: TFB30ClientAPI; DatabaseName: AnsiString; aDPB: IDPB;
188 tony 45 RaiseExceptionOnError: boolean);
189     var Param: IDPBItem;
190 tony 56 sql: AnsiString;
191 tony 45 IsCreateDB: boolean;
192     begin
193 tony 263 inherited Create(api,DatabaseName,aDPB,RaiseExceptionOnError);
194     FFirebird30ClientAPI := api;
195 tony 45 IsCreateDB := true;
196     if aDPB <> nil then
197     begin
198     Param := aDPB.Find(isc_dpb_set_db_SQL_dialect);
199     if Param <> nil then
200     FSQLDialect := Param.AsByte;
201     end;
202     sql := GenerateCreateDatabaseSQL(DatabaseName,aDPB);
203 tony 263 with FFirebird30ClientAPI do
204 tony 45 begin
205     FAttachmentIntf := UtilIntf.executeCreateDatabase(StatusIntf,Length(sql),
206     PAnsiChar(sql),FSQLDialect,@IsCreateDB);
207     if FRaiseExceptionOnConnectError then Check4DataBaseError;
208     if InErrorState then
209     FAttachmentIntf := nil
210     else
211     if aDPB <> nil then
212     {Connect using known parameters}
213     begin
214     Disconnect;
215     Connect;
216 tony 117 end
217     else
218     GetODSAndConnectionInfo;
219 tony 45 end;
220     end;
221    
222 tony 263 constructor TFB30Attachment.CreateDatabase(api: TFB30ClientAPI; sql: AnsiString; aSQLDialect: integer;
223 tony 47 RaiseExceptionOnError: boolean);
224     var IsCreateDB: boolean;
225     begin
226 tony 263 inherited Create(api,'',nil,RaiseExceptionOnError);
227     FFirebird30ClientAPI := api;
228 tony 47 FSQLDialect := aSQLDialect;
229 tony 263 with FFirebird30ClientAPI do
230 tony 47 begin
231     FAttachmentIntf := UtilIntf.executeCreateDatabase(StatusIntf,Length(sql),
232     PAnsiChar(sql),aSQLDialect,@IsCreateDB);
233     if FRaiseExceptionOnConnectError then Check4DataBaseError;
234     if InErrorState then
235     FAttachmentIntf := nil;
236     end;
237 tony 117 GetODSAndConnectionInfo;
238     ExtractConnectString(sql,FDatabaseName);
239     DPBFromCreateSQL(sql);
240 tony 47 end;
241    
242 tony 45 destructor TFB30Attachment.Destroy;
243     begin
244     inherited Destroy;
245     if assigned(FAttachmentIntf) then
246     FAttachmentIntf.release;
247     end;
248    
249 tony 143 function TFB30Attachment.GetDBInfo(ReqBuffer: PByte; ReqBufLen: integer): IDBInformation;
250     begin
251 tony 263 Result := TDBInformation.Create(Firebird30ClientAPI);
252     with FFirebird30ClientAPI, Result as TDBInformation do
253 tony 143 begin
254     FAttachmentIntf.getInfo(StatusIntf, ReqBufLen, BytePtr(ReqBuffer),
255     getBufSize, BytePtr(Buffer));
256     Check4DataBaseError;
257     end
258     end;
259    
260 tony 45 procedure TFB30Attachment.Connect;
261     begin
262 tony 263 with FFirebird30ClientAPI do
263 tony 45 begin
264     FAttachmentIntf := ProviderIntf.attachDatabase(StatusIntf,PAnsiChar(FDatabaseName),
265     (DPB as TDPB).getDataLength,
266     BytePtr((DPB as TDPB).getBuffer));
267     if FRaiseExceptionOnConnectError then Check4DataBaseError;
268     if InErrorState then
269     FAttachmentIntf := nil
270     else
271 tony 117 GetODSAndConnectionInfo;
272 tony 315
273 tony 45 end;
274     end;
275    
276     procedure TFB30Attachment.Disconnect(Force: boolean);
277     begin
278     if IsConnected then
279 tony 263 with FFirebird30ClientAPI do
280 tony 45 begin
281     EndAllTransactions;
282     FAttachmentIntf.Detach(StatusIntf);
283     if not Force and InErrorState then
284     IBDataBaseError;
285     FAttachmentIntf := nil;
286     FHasDefaultCharSet := false;
287     FCodePage := CP_NONE;
288     FCharSetID := 0;
289 tony 315 FTimeZoneServices := nil;
290 tony 45 end;
291     end;
292    
293     function TFB30Attachment.IsConnected: boolean;
294     begin
295     Result := FAttachmentIntf <> nil;
296     end;
297    
298     procedure TFB30Attachment.DropDatabase;
299     begin
300     if IsConnected then
301 tony 263 with FFirebird30ClientAPI do
302 tony 45 begin
303     EndAllTransactions;
304     FAttachmentIntf.dropDatabase(StatusIntf);
305     Check4DataBaseError;
306     FAttachmentIntf := nil;
307     end;
308     end;
309    
310     function TFB30Attachment.StartTransaction(TPB: array of byte;
311     DefaultCompletion: TTransactionCompletion): ITransaction;
312     begin
313     CheckHandle;
314 tony 263 Result := TFB30Transaction.Create(FFirebird30ClientAPI,self,TPB,DefaultCompletion);
315 tony 45 end;
316    
317     function TFB30Attachment.StartTransaction(TPB: ITPB;
318     DefaultCompletion: TTransactionCompletion): ITransaction;
319     begin
320     CheckHandle;
321 tony 263 Result := TFB30Transaction.Create(FFirebird30ClientAPI,self,TPB,DefaultCompletion);
322 tony 45 end;
323    
324 tony 56 procedure TFB30Attachment.ExecImmediate(transaction: ITransaction; sql: AnsiString;
325 tony 45 aSQLDialect: integer);
326     begin
327     CheckHandle;
328 tony 263 with FFirebird30ClientAPI do
329 tony 45 begin
330     FAttachmentIntf.execute(StatusIntf,(transaction as TFB30Transaction).TransactionIntf,
331 tony 56 Length(sql),PAnsiChar(sql),aSQLDialect,nil,nil,nil,nil);
332 tony 45 Check4DataBaseError;
333     end;
334     end;
335    
336 tony 56 function TFB30Attachment.Prepare(transaction: ITransaction; sql: AnsiString;
337 tony 45 aSQLDialect: integer): IStatement;
338     begin
339     CheckHandle;
340     Result := TFB30Statement.Create(self,transaction,sql,aSQLDialect);
341     end;
342    
343     function TFB30Attachment.PrepareWithNamedParameters(transaction: ITransaction;
344 tony 270 sql: AnsiString; aSQLDialect: integer; GenerateParamNames: boolean;
345     CaseSensitiveParams: boolean): IStatement;
346 tony 45 begin
347     CheckHandle;
348     Result := TFB30Statement.CreateWithParameterNames(self,transaction,sql,aSQLDialect,
349 tony 270 GenerateParamNames,CaseSensitiveParams);
350 tony 45 end;
351    
352     function TFB30Attachment.GetEventHandler(Events: TStrings): IEvents;
353     begin
354     CheckHandle;
355     Result := TFB30Events.Create(self,Events);
356     end;
357    
358     function TFB30Attachment.CreateBlob(transaction: ITransaction;
359     BlobMetaData: IBlobMetaData; BPB: IBPB): IBlob;
360     begin
361     CheckHandle;
362     Result := TFB30Blob.Create(self,transaction as TFB30Transaction, BlobMetaData,BPB);
363     end;
364    
365     function TFB30Attachment.CreateBlob(transaction: ITransaction;
366     SubType: integer; aCharSetID: cardinal; BPB: IBPB): IBlob;
367     begin
368     CheckHandle;
369     Result := TFB30Blob.Create(self,transaction as TFB30Transaction, SubType,aCharSetID,BPB);
370     end;
371    
372     function TFB30Attachment.OpenBlob(transaction: ITransaction;
373     BlobMetaData: IBlobMetaData; BlobID: TISC_QUAD; BPB: IBPB): IBlob;
374     begin
375     CheckHandle;
376     Result := TFB30Blob.Create(self,transaction as TFB30transaction,BlobMetaData,BlobID,BPB);
377     end;
378    
379 tony 291 function TFB30Attachment.OpenArray(transaction: ITransaction;
380     ArrayMetaData: IArrayMetaData; ArrayID: TISC_QUAD): IArray;
381 tony 45 begin
382     CheckHandle;
383     Result := TFB30Array.Create(self,transaction as TFB30Transaction,
384 tony 291 ArrayMetaData,ArrayID);
385 tony 45 end;
386    
387     function TFB30Attachment.CreateArray(transaction: ITransaction;
388     ArrayMetaData: IArrayMetaData): IArray;
389     begin
390     CheckHandle;
391     Result := TFB30Array.Create(self,transaction as TFB30Transaction,ArrayMetaData);
392     end;
393    
394 tony 56 function TFB30Attachment.CreateArrayMetaData(SQLType: cardinal; tableName: AnsiString; columnName: AnsiString;
395 tony 47 Scale: integer; size: cardinal; aCharSetID: cardinal; dimensions: cardinal;
396     bounds: TArrayBounds): IArrayMetaData;
397     begin
398 tony 60 Result := TFB30ArrayMetaData.Create(self,SQLType,tableName,ColumnName,Scale,size,aCharSetID, dimensions,bounds);
399 tony 47 end;
400    
401 tony 45 function TFB30Attachment.GetBlobMetaData(Transaction: ITransaction; tableName,
402 tony 56 columnName: AnsiString): IBlobMetaData;
403 tony 45 begin
404     CheckHandle;
405     Result := TFB30BlobMetaData.Create(self,Transaction as TFB30Transaction,tableName,columnName);
406     end;
407    
408     function TFB30Attachment.GetArrayMetaData(Transaction: ITransaction; tableName,
409 tony 56 columnName: AnsiString): IArrayMetaData;
410 tony 45 begin
411     CheckHandle;
412     Result := TFB30ArrayMetaData.Create(self,Transaction as TFB30Transaction,tableName,columnName);
413     end;
414    
415 tony 266 procedure TFB30Attachment.getFBVersion(version: TStrings);
416     var bufferObj: TVersionCallback;
417     begin
418 tony 267 version.Clear;
419 tony 315 bufferObj := TVersionCallback.Create(Firebird30ClientAPI,version);
420 tony 266 try
421     with FFirebird30ClientAPI do
422 tony 267 begin
423 tony 266 UtilIntf.getFbVersion(StatusIntf,FAttachmentIntf,bufferObj);
424 tony 267 Check4DataBaseError;
425     end;
426 tony 266 finally
427     bufferObj.Free;
428     end;
429     end;
430    
431 tony 315 function TFB30Attachment.HasDecFloatSupport: boolean;
432     begin
433     Result := (FFirebird30ClientAPI.GetClientMajor >= 4) and
434     (GetODSMajorVersion >= 13);
435     end;
436    
437     function TFB30Attachment.GetTimeZoneServices: ITimeZoneServices;
438     begin
439     if not HasTimeZoneSupport then
440     IBError(ibxeNotSupported,[]);
441    
442     if FTimeZoneServices = nil then
443     FTimeZoneServices := TFB30TimeZoneServices.Create(self);
444     Result := FTimeZoneServices;
445     end;
446    
447     function TFB30Attachment.HasTimeZoneSupport: boolean;
448     begin
449     Result := (FFirebird30ClientAPI.GetClientMajor >= 4) and
450     (GetODSMajorVersion >= 13);
451     end;
452    
453 tony 45 end.
454