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 FB30ClientAPI; |
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, FBClientAPI, Firebird, IB, IBExternals; |
41 |
|
42 |
type |
43 |
|
44 |
{ TFB30Status } |
45 |
|
46 |
TFB30Status = class(TFBStatus,IStatus) |
47 |
private |
48 |
FStatus: Firebird.IStatus; |
49 |
public |
50 |
procedure Init; |
51 |
function InErrorState: boolean; |
52 |
function GetStatus: Firebird.IStatus; |
53 |
function StatusVector: PStatusVector; override; |
54 |
end; |
55 |
|
56 |
Tfb_get_master_interface = function: IMaster; |
57 |
{$IFDEF WINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF} |
58 |
|
59 |
{ TFB30ClientAPI } |
60 |
|
61 |
TFB30ClientAPI = class(TFBClientAPI,IFirebirdAPI) |
62 |
private |
63 |
FMaster: Firebird.IMaster; |
64 |
FUtil: Firebird.IUtil; |
65 |
FProvider: Firebird.IProvider; |
66 |
FConfigManager: Firebird.IConfigManager; |
67 |
FStatus: TFB30Status; |
68 |
FIsEmbeddedServer: boolean; |
69 |
FStatusIntf: IStatus; {Keep a reference to the interface - automatic destroy |
70 |
when this class is freed and last reference to IStatus |
71 |
goes out of scope.} |
72 |
procedure CheckPlugins; |
73 |
protected |
74 |
{$IFDEF UNIX} |
75 |
function GetFirebirdLibList: string; override; |
76 |
{$ENDIF} |
77 |
procedure LoadInterface; override; |
78 |
public |
79 |
constructor Create; |
80 |
destructor Destroy; override; |
81 |
|
82 |
function StatusIntf: Firebird.IStatus; |
83 |
procedure Check4DataBaseError; |
84 |
function InErrorState: boolean; |
85 |
|
86 |
public |
87 |
{IFirebirdAPI} |
88 |
function GetStatus: IStatus; override; |
89 |
function AllocateDPB: IDPB; |
90 |
function AllocateTPB: ITPB; |
91 |
|
92 |
{Database connections} |
93 |
function OpenDatabase(DatabaseName: AnsiString; DPB: IDPB; RaiseExceptionOnConnectError: boolean=true): IAttachment; |
94 |
function CreateDatabase(DatabaseName: AnsiString; DPB: IDPB; RaiseExceptionOnError: boolean=true): IAttachment; overload; |
95 |
function CreateDatabase(sql: AnsiString; aSQLDialect: integer; RaiseExceptionOnError: boolean=true): IAttachment; overload; |
96 |
{Start Transaction against multiple databases} |
97 |
function StartTransaction(Attachments: array of IAttachment; |
98 |
TPB: array of byte; DefaultCompletion: TTransactionCompletion): ITransaction; overload; |
99 |
function StartTransaction(Attachments: array of IAttachment; |
100 |
TPB: ITPB; DefaultCompletion: TTransactionCompletion): ITransaction; overload; |
101 |
|
102 |
{Service Manager} |
103 |
function AllocateSPB: ISPB; |
104 |
function GetServiceManager(ServerName: AnsiString; Protocol: TProtocol; SPB: ISPB): IServiceManager; |
105 |
|
106 |
{Information} |
107 |
function HasServiceAPI: boolean; |
108 |
function HasRollbackRetaining: boolean; |
109 |
function IsEmbeddedServer: boolean; override; |
110 |
function GetImplementationVersion: AnsiString; |
111 |
|
112 |
{Firebird 3 API} |
113 |
function HasMasterIntf: boolean; |
114 |
function GetIMaster: TObject; |
115 |
|
116 |
{Encode/Decode} |
117 |
function DecodeInteger(bufptr: PByte; len: short): integer; override; |
118 |
procedure SQLEncodeDate(aDate: TDateTime; bufptr: PByte); override; |
119 |
function SQLDecodeDate(bufptr: PByte): TDateTime; override; |
120 |
procedure SQLEncodeTime(aTime: TDateTime; bufptr: PByte); override; |
121 |
function SQLDecodeTime(bufptr: PByte): TDateTime; override; |
122 |
procedure SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte); override; |
123 |
function SQLDecodeDateTime(bufptr: PByte): TDateTime; override; |
124 |
|
125 |
{Firebird Interfaces} |
126 |
property MasterIntf: Firebird.IMaster read FMaster; |
127 |
property UtilIntf: Firebird.IUtil read FUtil; |
128 |
property ProviderIntf: Firebird.IProvider read FProvider; |
129 |
end; |
130 |
|
131 |
var Firebird30ClientAPI: TFB30ClientAPI; |
132 |
|
133 |
implementation |
134 |
|
135 |
uses FBParamBlock, FB30Attachment, {$IFDEF FPC}dynlibs{$ELSE} windows{$ENDIF}, |
136 |
FBMessages, FB30Services, FB30Transaction; |
137 |
|
138 |
type |
139 |
PISC_DATE = ^ISC_DATE; |
140 |
PISC_TIME = ^ISC_TIME; |
141 |
|
142 |
{ TFB30Status } |
143 |
|
144 |
procedure TFB30Status.Init; |
145 |
begin |
146 |
if assigned(FStatus) then |
147 |
FStatus.Init; |
148 |
end; |
149 |
|
150 |
function TFB30Status.InErrorState: boolean; |
151 |
begin |
152 |
with GetStatus do |
153 |
Result := ((getState and STATE_ERRORS) <> 0); |
154 |
end; |
155 |
|
156 |
function TFB30Status.GetStatus: Firebird.IStatus; |
157 |
begin |
158 |
if FStatus = nil then |
159 |
with FOwner do |
160 |
FStatus := (FOwner as TFB30ClientAPI).MasterIntf.GetStatus; |
161 |
Result := FStatus; |
162 |
end; |
163 |
|
164 |
function TFB30Status.StatusVector: PStatusVector; |
165 |
begin |
166 |
Result := PStatusVector(GetStatus.getErrors); |
167 |
end; |
168 |
|
169 |
{ TFB30ClientAPI } |
170 |
|
171 |
procedure TFB30ClientAPI.CheckPlugins; |
172 |
var FBConf: Firebird.IFirebirdConf; |
173 |
Plugins: AnsiString; |
174 |
PluginsList: TStringList; |
175 |
begin |
176 |
FIsEmbeddedServer := false; |
177 |
FBConf := FConfigManager.getFirebirdConf; |
178 |
try |
179 |
Plugins := FBConf.asString(FBConf.getKey('Providers')); |
180 |
finally |
181 |
FBConf.release; |
182 |
end; |
183 |
if Plugins = '' then Exit; |
184 |
|
185 |
PluginsList := TStringList.Create; |
186 |
try |
187 |
PluginsList.CommaText := Plugins; |
188 |
FIsEmbeddedServer := PluginsList.IndexOf('Engine12') <> -1; |
189 |
finally |
190 |
PluginsList.Free; |
191 |
end; |
192 |
end; |
193 |
|
194 |
{$IFDEF UNIX} |
195 |
function TFB30ClientAPI.GetFirebirdLibList: string; |
196 |
begin |
197 |
Result := 'libfbclient.so:libfbclient.so.2'; |
198 |
end; |
199 |
{$ENDIF} |
200 |
|
201 |
procedure TFB30ClientAPI.LoadInterface; |
202 |
var |
203 |
fb_get_master_interface: Tfb_get_master_interface; |
204 |
begin |
205 |
inherited LoadInterface; |
206 |
fb_get_master_interface := GetProcAddress(IBLibrary, 'fb_get_master_interface'); {do not localize} |
207 |
if assigned(fb_get_master_interface) then |
208 |
begin |
209 |
FMaster := fb_get_master_interface; |
210 |
FUtil := FMaster.getUtilInterface; |
211 |
FProvider := FMaster.getDispatcher; |
212 |
FConfigManager := FMaster.getConfigManager; |
213 |
CheckPlugins; |
214 |
end; |
215 |
end; |
216 |
|
217 |
constructor TFB30ClientAPI.Create; |
218 |
begin |
219 |
inherited; |
220 |
FStatus := TFB30Status.Create(self); |
221 |
FStatusIntf := FStatus; |
222 |
Firebird30ClientAPI := self; |
223 |
end; |
224 |
|
225 |
destructor TFB30ClientAPI.Destroy; |
226 |
begin |
227 |
if assigned(FProvider) then |
228 |
FProvider.release; |
229 |
inherited Destroy; |
230 |
end; |
231 |
|
232 |
function TFB30ClientAPI.StatusIntf: Firebird.IStatus; |
233 |
begin |
234 |
Result := FStatus.GetStatus; |
235 |
Result.Init; |
236 |
end; |
237 |
|
238 |
procedure TFB30ClientAPI.Check4DataBaseError; |
239 |
begin |
240 |
if FStatus.InErrorState then |
241 |
IBDataBaseError; |
242 |
end; |
243 |
|
244 |
function TFB30ClientAPI.InErrorState: boolean; |
245 |
begin |
246 |
Result := FStatus.InErrorState; |
247 |
end; |
248 |
|
249 |
function TFB30ClientAPI.GetStatus: IStatus; |
250 |
begin |
251 |
Result := FStatusIntf; |
252 |
end; |
253 |
|
254 |
function TFB30ClientAPI.AllocateDPB: IDPB; |
255 |
begin |
256 |
Result := TDPB.Create; |
257 |
end; |
258 |
|
259 |
function TFB30ClientAPI.AllocateTPB: ITPB; |
260 |
begin |
261 |
Result := TTPB.Create; |
262 |
end; |
263 |
|
264 |
function TFB30ClientAPI.OpenDatabase(DatabaseName: AnsiString; DPB: IDPB; |
265 |
RaiseExceptionOnConnectError: boolean): IAttachment; |
266 |
begin |
267 |
Result := TFB30Attachment.Create(DatabaseName, DPB, RaiseExceptionOnConnectError); |
268 |
if not Result.IsConnected then |
269 |
Result := nil; |
270 |
end; |
271 |
|
272 |
function TFB30ClientAPI.CreateDatabase(DatabaseName: AnsiString; DPB: IDPB; |
273 |
RaiseExceptionOnError: boolean): IAttachment; |
274 |
begin |
275 |
Result := TFB30Attachment.CreateDatabase(DatabaseName,DPB, RaiseExceptionOnError); |
276 |
if not Result.IsConnected then |
277 |
Result := nil; |
278 |
end; |
279 |
|
280 |
function TFB30ClientAPI.CreateDatabase(sql: AnsiString; aSQLDialect: integer; |
281 |
RaiseExceptionOnError: boolean): IAttachment; |
282 |
begin |
283 |
Result := TFB30Attachment.CreateDatabase(sql,aSQLDialect, RaiseExceptionOnError); |
284 |
if not Result.IsConnected then |
285 |
Result := nil; |
286 |
end; |
287 |
|
288 |
function TFB30ClientAPI.StartTransaction(Attachments: array of IAttachment; |
289 |
TPB: array of byte; DefaultCompletion: TTransactionCompletion): ITransaction; |
290 |
begin |
291 |
Result := TFB30Transaction.Create(Attachments,TPB,DefaultCompletion); |
292 |
end; |
293 |
|
294 |
function TFB30ClientAPI.StartTransaction(Attachments: array of IAttachment; |
295 |
TPB: ITPB; DefaultCompletion: TTransactionCompletion): ITransaction; |
296 |
begin |
297 |
Result := TFB30Transaction.Create(Attachments,TPB,DefaultCompletion); |
298 |
end; |
299 |
|
300 |
function TFB30ClientAPI.AllocateSPB: ISPB; |
301 |
begin |
302 |
Result := TSPB.Create; |
303 |
end; |
304 |
|
305 |
function TFB30ClientAPI.GetServiceManager(ServerName: AnsiString; |
306 |
Protocol: TProtocol; SPB: ISPB): IServiceManager; |
307 |
begin |
308 |
Result := TFB30ServiceManager.Create(ServerName,Protocol,SPB); |
309 |
end; |
310 |
|
311 |
function TFB30ClientAPI.HasServiceAPI: boolean; |
312 |
begin |
313 |
Result := true; |
314 |
end; |
315 |
|
316 |
function TFB30ClientAPI.HasMasterIntf: boolean; |
317 |
begin |
318 |
Result := MasterIntf <> nil; |
319 |
end; |
320 |
|
321 |
function TFB30ClientAPI.GetIMaster: TObject; |
322 |
begin |
323 |
Result := FMaster; |
324 |
end; |
325 |
|
326 |
function TFB30ClientAPI.HasRollbackRetaining: boolean; |
327 |
begin |
328 |
Result := true; |
329 |
end; |
330 |
|
331 |
function TFB30ClientAPI.IsEmbeddedServer: boolean; |
332 |
begin |
333 |
Result := FIsEmbeddedServer; |
334 |
end; |
335 |
|
336 |
function TFB30ClientAPI.GetImplementationVersion: AnsiString; |
337 |
begin |
338 |
Result := Format('3.%d',[UtilIntf.GetClientVersion]); |
339 |
end; |
340 |
|
341 |
function TFB30ClientAPI.DecodeInteger(bufptr: PByte; len: short): integer; |
342 |
var P: PByte; |
343 |
begin |
344 |
Result := 0; |
345 |
P := Bufptr + len - 1; |
346 |
while P >= bufptr do |
347 |
begin |
348 |
Result := (Result shl 8 ) or P^; |
349 |
Dec(P); |
350 |
end; |
351 |
end; |
352 |
|
353 |
procedure TFB30ClientAPI.SQLEncodeDate(aDate: TDateTime; bufptr: PByte); |
354 |
var |
355 |
Yr, Mn, Dy: Word; |
356 |
begin |
357 |
DecodeDate(aDate, Yr, Mn, Dy); |
358 |
PISC_Date(Bufptr)^ := UtilIntf.encodeDate(Yr, Mn, Dy); |
359 |
end; |
360 |
|
361 |
function TFB30ClientAPI.SQLDecodeDate(bufptr: PByte): TDateTime; |
362 |
var |
363 |
Yr, Mn, Dy: cardinal; |
364 |
begin |
365 |
UtilIntf.decodeDate(PISC_DATE(bufptr)^,@Yr, @Mn, @Dy); |
366 |
try |
367 |
result := EncodeDate(Yr, Mn,Dy); |
368 |
except |
369 |
on E: EConvertError do begin |
370 |
IBError(ibxeInvalidDataConversion, [nil]); |
371 |
end; |
372 |
end; |
373 |
end; |
374 |
|
375 |
procedure TFB30ClientAPI.SQLEncodeTime(aTime: TDateTime; bufptr: PByte); |
376 |
var |
377 |
Hr, Mt, S, Ms: Word; |
378 |
begin |
379 |
DecodeTime(aTime, Hr, Mt, S, Ms); |
380 |
PISC_TIME(bufptr)^ := UtilIntf.encodeTime(Hr, Mt, S, Ms*10); |
381 |
end; |
382 |
|
383 |
function TFB30ClientAPI.SQLDecodeTime(bufptr: PByte): TDateTime; |
384 |
var |
385 |
Hr, Mt, S, Ms: cardinal; |
386 |
begin |
387 |
UtilIntf.decodeTime(PISC_TIME(bufptr)^,@Hr, @Mt, @S, @Ms); |
388 |
try |
389 |
Result := EncodeTime(Hr, Mt, S, Ms div 10); |
390 |
except |
391 |
on E: EConvertError do begin |
392 |
IBError(ibxeInvalidDataConversion, [nil]); |
393 |
end; |
394 |
end; |
395 |
end; |
396 |
|
397 |
procedure TFB30ClientAPI.SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte); |
398 |
begin |
399 |
SQLEncodeDate(aDateTime,bufPtr); |
400 |
Inc(bufptr,sizeof(ISC_DATE)); |
401 |
SQLEncodeTime(aDateTime,bufPtr); |
402 |
end; |
403 |
|
404 |
function TFB30ClientAPI.SQLDecodeDateTime(bufptr: PByte): TDateTime; |
405 |
begin |
406 |
Result := SQLDecodeDate(bufPtr); |
407 |
Inc(bufptr,sizeof(ISC_DATE)); |
408 |
Result := Result + SQLDecodeTime(bufPtr); |
409 |
end; |
410 |
|
411 |
end. |
412 |
|
413 |
|