ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBClientAPI.pas
Revision: 263
Committed: Thu Dec 6 15:55:01 2018 UTC (5 years, 11 months ago) by tony
Content type: text/x-pascal
Original Path: ibx/trunk/fbintf/client/FBClientAPI.pas
File size: 15359 byte(s)
Log Message:
Release 2.3.2 committed

File Contents

# Content
1 (*
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 FBClientAPI;
63 {$IFDEF MSWINDOWS}
64 {$DEFINE WINDOWS}
65 {$ENDIF}
66
67 {$IFDEF FPC}
68 {$mode delphi}
69 {$codepage UTF8}
70 {$interfaces COM}
71 {$ENDIF}
72
73 interface
74
75 uses
76 Classes,
77 {$IFDEF WINDOWS}Windows, {$ENDIF}
78 {$IFDEF FPC} Dynlibs, {$ENDIF}
79 IB, IBHeader, FBActivityMonitor, FBMessages, IBExternals;
80
81 {For Linux see result of GetFirebirdLibList method}
82 {$IFDEF DARWIN}
83 const
84 FIREBIRD_SO2 = 'libfbclient.dylib';
85 {$ENDIF}
86 {$IFDEF WINDOWS}
87 const
88 IBASE_DLL = 'gds32.dll';
89 FIREBIRD_CLIENT = 'fbclient.dll'; {do not localize}
90 FIREBIRD_EMBEDDED = 'fbembed.dll';
91 {$ENDIF}
92
93 type
94 TStatusVector = array[0..19] of NativeInt;
95 PStatusVector = ^TStatusVector;
96
97 TFBClientAPI = class;
98
99 { TFBStatus }
100
101 TFBStatus = class(TFBInterfacedObject)
102 private
103 FIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
104 protected
105 FOwner: TFBClientAPI;
106 public
107 constructor Create(aOwner: TFBClientAPI);
108 function StatusVector: PStatusVector; virtual; abstract;
109
110 {IStatus}
111 function GetIBErrorCode: Long;
112 function Getsqlcode: Long;
113 function GetMessage: AnsiString;
114 function CheckStatusVector(ErrorCodes: array of TFBStatusCode): Boolean;
115 function GetIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
116 procedure SetIBDataBaseErrorMessages(Value: TIBDataBaseErrorMessages);
117 end;
118
119 { TFBLibrary }
120
121 TFBLibrary = class(TFBInterfacedObject,IFirebirdLibrary)
122 private
123 class var FEnvSetupDone: boolean;
124 class var FLibraryList: array of IFirebirdLibrary;
125 FFirebirdAPI: IFirebirdAPI;
126 FRequestedLibName: string;
127 function LoadIBLibrary: boolean;
128 protected
129 FFBLibraryName: string;
130 FIBLibrary: TLibHandle;
131 procedure FreeFBLibrary;
132 function GetOverrideLibName: string;
133 class procedure SetupEnvironment;
134 protected
135 function GetFirebird3API: IFirebirdAPI; virtual; abstract;
136 function GetLegacyFirebirdAPI: IFirebirdAPI; virtual; abstract;
137 public
138 constructor Create(aLibPathName: string='');
139 destructor Destroy; override;
140 class function GetFBLibrary(aLibPathName: string): IFirebirdLibrary;
141 class procedure FreeLibraries;
142
143 {IFirebirdLibrary}
144 function GetHandle: TLibHandle;
145 function GetLibraryName: string;
146 function GetLibraryFilePath: string;
147 function GetFirebirdAPI: IFirebirdAPI;
148 property IBLibrary: TLibHandle read FIBLibrary;
149 end;
150
151 { TFBClientAPI }
152
153 TFBClientAPI = class(TFBInterfacedObject)
154 private
155 class var FIBCS: TRTLCriticalSection;
156 protected
157 FFBLibrary: TFBLibrary;
158 function GetProcAddr(ProcName: PAnsiChar): Pointer;
159 public
160 {Taken from legacy API}
161 isc_sqlcode: Tisc_sqlcode;
162 isc_sql_interprete: Tisc_sql_interprete;
163 isc_interprete: Tisc_interprete;
164 isc_event_counts: Tisc_event_counts;
165 isc_event_block: Tisc_event_block;
166 isc_free: Tisc_free;
167
168 constructor Create(aFBLibrary: TFBLibrary);
169 procedure IBAlloc(var P; OldSize, NewSize: Integer);
170 procedure IBDataBaseError;
171 function LoadInterface: boolean; virtual;
172 function GetAPI: IFirebirdAPI; virtual; abstract;
173 {$IFDEF UNIX}
174 function GetFirebirdLibList: string; virtual; abstract;
175 {$ENDIF}
176
177 {Encode/Decode}
178 procedure EncodeInteger(aValue: integer; len: integer; buffer: PByte);
179 function DecodeInteger(bufptr: PByte; len: short): integer; virtual; abstract;
180 procedure SQLEncodeDate(aDate: TDateTime; bufptr: PByte); virtual; abstract;
181 function SQLDecodeDate(byfptr: PByte): TDateTime; virtual; abstract;
182 procedure SQLEncodeTime(aTime: TDateTime; bufptr: PByte); virtual; abstract;
183 function SQLDecodeTime(bufptr: PByte): TDateTime; virtual; abstract;
184 procedure SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte); virtual; abstract;
185 function SQLDecodeDateTime(bufptr: PByte): TDateTime; virtual; abstract;
186
187
188 {IFirebirdAPI}
189 function GetStatus: IStatus; virtual; abstract;
190 function IsLibraryLoaded: boolean;
191 function IsEmbeddedServer: boolean; virtual; abstract;
192 function GetFBLibrary: IFirebirdLibrary;
193 end;
194
195 implementation
196
197 uses IBUtils, Registry,
198 {$IFDEF Unix} initc, dl, {$ENDIF}
199 {$IFDEF FPC}
200 {$IFDEF WINDOWS }
201 WinDirs,
202 {$ENDIF}
203 {$ELSE}
204 ShlObj,
205 {$ENDIF}
206 SysUtils;
207
208 const
209 IBLocalBufferLength = 512;
210 IBBigLocalBufferLength = IBLocalBufferLength * 2;
211 IBHugeLocalBufferLength = IBBigLocalBufferLength * 20;
212
213 {$IFDEF UNIX}
214 {$I 'include/uloadlibrary.inc'}
215 {$ELSE}
216 {$I 'include/wloadlibrary.inc'}
217 {$ENDIF}
218
219
220 { TFBLibrary }
221
222 function TFBLibrary.GetOverrideLibName: string;
223 begin
224 Result := FFBLibraryName;
225 if (Result = '') and AllowUseOfFBLIB then
226 Result := GetEnvironmentVariable('FBLIB');
227 if Result = '' then
228 begin
229 if assigned(OnGetLibraryName) then
230 OnGetLibraryName(Result)
231 end;
232 end;
233
234 procedure TFBLibrary.FreeFBLibrary;
235 begin
236 if FIBLibrary <> NilHandle then
237 FreeLibrary(FIBLibrary);
238 FIBLibrary := NilHandle;
239 end;
240
241 function TFBLibrary.GetLibraryName: string;
242 begin
243 Result := ExtractFileName(FFBLibraryName);
244 end;
245
246 function TFBLibrary.GetFirebirdAPI: IFirebirdAPI;
247 begin
248 Result := FFirebirdAPI;
249 end;
250
251 constructor TFBLibrary.Create(aLibPathName: string);
252 begin
253 inherited Create;
254 SetupEnvironment;
255 FFBLibraryName := aLibPathName;
256 FIBLibrary := NilHandle;
257 FFirebirdAPI := GetFirebird3API;
258 FRequestedLibName := aLibPathName;
259 if aLibPathName <> '' then
260 begin
261 SetLength(FLibraryList,Length(FLibraryList)+1);
262 FLibraryList[Length(FLibraryList)-1] := self;
263 end;
264 if FFirebirdAPI <> nil then
265 begin
266 {First try Firebird 3}
267 if not LoadIBLibrary or not (FFirebirdAPI as TFBClientAPI).LoadInterface then
268 FFirebirdAPI := nil;
269 end;
270
271 if FFirebirdAPI = nil then
272 begin
273 {now try Firebird 2.5. Under Unix we need to reload the library in case we
274 are to use the embedded library}
275 FFirebirdAPI := GetLegacyFirebirdAPI;
276 if FFirebirdAPI <> nil then
277 begin
278 {$IFDEF UNIX}
279 FreeFBLibrary;
280 {$ENDIF}
281 if not LoadIBLibrary or not (FFirebirdAPI as TFBClientAPI).LoadInterface then
282 FFirebirdAPI := nil;
283 end;
284 end;
285 {Note: FFirebirdAPI will be set to nil if the Firebird API fails to load}
286 end;
287
288 destructor TFBLibrary.Destroy;
289 begin
290 FFirebirdAPI := nil;
291 FreeFBLibrary;
292 inherited Destroy;
293 end;
294
295 class function TFBLibrary.GetFBLibrary(aLibPathName: string): IFirebirdLibrary;
296 var i: integer;
297 begin
298 Result := nil;
299 if aLibPathName <> '' then
300 begin
301 for i := 0 to Length(FLibraryList) - 1 do
302 if (FLibraryList[i] as TFBLibrary).FRequestedLibName = aLibPathName then
303 begin
304 Result := FLibraryList[i];
305 Exit;
306 end;
307 Result := Create(aLibPathName);
308 end;
309
310 end;
311
312 class procedure TFBLibrary.FreeLibraries;
313 var i: integer;
314 begin
315 for i := 0 to Length(FLibraryList) - 1 do
316 FLibraryList[i] := nil;
317 SetLength(FLibraryList,0);
318 end;
319
320 function TFBLibrary.GetHandle: TLibHandle;
321 begin
322 Result := FIBLibrary;
323 end;
324
325 { TFBClientAPI }
326
327 constructor TFBClientAPI.Create(aFBLibrary: TFBLibrary);
328 begin
329 inherited Create;
330 FFBLibrary := aFBLibrary;
331 end;
332
333 procedure TFBClientAPI.IBAlloc(var P; OldSize, NewSize: Integer);
334 var
335 i: Integer;
336 begin
337 ReallocMem(Pointer(P), NewSize);
338 for i := OldSize to NewSize - 1 do PAnsiChar(P)[i] := #0;
339 end;
340
341 procedure TFBClientAPI.IBDataBaseError;
342 begin
343 raise EIBInterBaseError.Create(GetStatus);
344 end;
345
346 {Under Unixes, if using an embedded server then set up local TMP and LOCK Directories}
347
348 procedure TFBClientAPI.EncodeInteger(aValue: integer; len: integer; buffer: PByte);
349 begin
350 while len > 0 do
351 begin
352 buffer^ := aValue and $FF;
353 Inc(buffer);
354 Dec(len);
355 aValue := aValue shr 8;
356 end;
357 end;
358
359 function TFBClientAPI.IsLibraryLoaded: boolean;
360 begin
361 Result := FFBLibrary.IBLibrary <> NilHandle;
362 end;
363
364 function TFBClientAPI.GetFBLibrary: IFirebirdLibrary;
365 begin
366 Result := FFBLibrary;
367 end;
368
369 function TFBClientAPI.GetProcAddr(ProcName: PAnsiChar): Pointer;
370 begin
371 Result := GetProcAddress(FFBLibrary.IBLibrary, ProcName);
372 if not Assigned(Result) then
373 raise Exception.CreateFmt(SFirebirdAPIFuncNotFound,[ProcName]);
374 end;
375
376 function TFBClientAPI.LoadInterface: boolean;
377 begin
378 isc_sqlcode := GetProcAddr('isc_sqlcode'); {do not localize}
379 isc_sql_interprete := GetProcAddr('isc_sql_interprete'); {do not localize}
380 isc_interprete := GetProcAddr('isc_interprete'); {do not localize}
381 isc_event_counts := GetProcAddr('isc_event_counts'); {do not localize}
382 isc_event_block := GetProcAddr('isc_event_block'); {do not localize}
383 isc_free := GetProcAddr('isc_free'); {do not localize}
384 Result := assigned(isc_free);
385 end;
386
387 { TFBStatus }
388
389 constructor TFBStatus.Create(aOwner: TFBClientAPI);
390 begin
391 inherited Create;
392 FOwner := aOwner;
393 FIBDataBaseErrorMessages := [ShowSQLMessage, ShowIBMessage];
394 end;
395
396 function TFBStatus.GetIBErrorCode: Long;
397 begin
398 Result := StatusVector^[1];
399 end;
400
401 function TFBStatus.Getsqlcode: Long;
402 begin
403 with FOwner do
404 Result := isc_sqlcode(PISC_STATUS(StatusVector));
405 end;
406
407 function TFBStatus.GetMessage: AnsiString;
408 var local_buffer: array[0..IBHugeLocalBufferLength - 1] of AnsiChar;
409 IBDataBaseErrorMessages: TIBDataBaseErrorMessages;
410 sqlcode: Long;
411 psb: PStatusVector;
412 begin
413 Result := '';
414 IBDataBaseErrorMessages := FIBDataBaseErrorMessages;
415 sqlcode := Getsqlcode;
416 if (ShowSQLCode in IBDataBaseErrorMessages) then
417 Result := Result + 'SQLCODE: ' + IntToStr(sqlcode); {do not localize}
418
419 Exclude(IBDataBaseErrorMessages, ShowSQLMessage);
420 if (ShowSQLMessage in IBDataBaseErrorMessages) then
421 begin
422 with FOwner do
423 isc_sql_interprete(sqlcode, local_buffer, IBLocalBufferLength);
424 if (ShowSQLCode in FIBDataBaseErrorMessages) then
425 Result := Result + CRLF;
426 Result := Result + strpas(local_buffer);
427 end;
428
429 if (ShowIBMessage in IBDataBaseErrorMessages) then
430 begin
431 if (ShowSQLCode in IBDataBaseErrorMessages) or
432 (ShowSQLMessage in IBDataBaseErrorMessages) then
433 Result := Result + CRLF;
434 psb := StatusVector;
435 with FOwner do
436 while (isc_interprete(@local_buffer, @psb) > 0) do
437 begin
438 if (Result <> '') and (Result[Length(Result)] <> LF) then
439 Result := Result + CRLF;
440 Result := Result + strpas(local_buffer);
441 end;
442 end;
443 if (Result <> '') and (Result[Length(Result)] = '.') then
444 Delete(Result, Length(Result), 1);
445 end;
446
447 function TFBStatus.CheckStatusVector(ErrorCodes: array of TFBStatusCode
448 ): Boolean;
449 var
450 p: PISC_STATUS;
451 i: Integer;
452 procedure NextP(i: Integer);
453 begin
454 p := PISC_STATUS(PAnsiChar(p) + (i * SizeOf(ISC_STATUS)));
455 end;
456 begin
457 p := PISC_STATUS(StatusVector);
458 result := False;
459 while (p^ <> 0) and (not result) do
460 case p^ of
461 3: NextP(3);
462 1, 4:
463 begin
464 NextP(1);
465 i := 0;
466 while (i <= High(ErrorCodes)) and (not result) do
467 begin
468 result := p^ = ErrorCodes[i];
469 Inc(i);
470 end;
471 NextP(1);
472 end;
473 else
474 NextP(2);
475 end;
476 end;
477
478 function TFBStatus.GetIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
479 begin
480 EnterCriticalSection(TFBClientAPI.FIBCS);
481 try
482 result := FIBDataBaseErrorMessages;
483 finally
484 LeaveCriticalSection(TFBClientAPI.FIBCS);
485 end;
486 end;
487
488 procedure TFBStatus.SetIBDataBaseErrorMessages(Value: TIBDataBaseErrorMessages);
489 begin
490 EnterCriticalSection(TFBClientAPI.FIBCS);
491 try
492 FIBDataBaseErrorMessages := Value;
493 finally
494 LeaveCriticalSection(TFBClientAPI.FIBCS);
495 end;
496 end;
497
498 initialization
499 TFBLibrary.FEnvSetupDone := false;
500 {$IFNDEF FPC}
501 InitializeCriticalSection(TFBClientAPI.FIBCS);
502 {$ELSE}
503 InitCriticalSection(TFBClientAPI.FIBCS);
504 {$ENDIF}
505
506 finalization
507 TFBLibrary.FreeLibraries;
508 {$IFNDEF FPC}
509 DeleteCriticalSection(TFBClientAPI.FIBCS);
510 {$ELSE}
511 DoneCriticalSection(TFBClientAPI.FIBCS);
512 {$ENDIF}
513 end.
514