ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBClientAPI.pas
Revision: 315
Committed: Thu Feb 25 11:56:36 2021 UTC (3 years, 8 months ago) by tony
Content type: text/x-pascal
File size: 20229 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. 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 tony 56 {$IFDEF MSWINDOWS}
64     {$DEFINE WINDOWS}
65     {$ENDIF}
66 tony 45
67     {$IFDEF FPC}
68     {$mode delphi}
69     {$codepage UTF8}
70     {$interfaces COM}
71     {$ENDIF}
72    
73     interface
74    
75     uses
76 tony 56 Classes,
77     {$IFDEF WINDOWS}Windows, {$ENDIF}
78     {$IFDEF FPC} Dynlibs, {$ENDIF}
79 tony 315 IB, IBHeader, FBActivityMonitor, FBMessages, IBExternals, FmtBCD;
80 tony 45
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 tony 308 const
94 tony 315 {fb_shutdown reasons}
95     fb_shutrsn_svc_stopped = -1;
96     fb_shutrsn_no_connection = -2;
97     fb_shutrsn_app_stopped = -3;
98     fb_shutrsn_signal = -5;
99     fb_shutrsn_services = -6;
100     fb_shutrsn_exit_called = -7;
101    
102     const
103     DefaultTimeZoneFile = '/etc/timezone';
104    
105     const
106 tony 308 IBLocalBufferLength = 512;
107     IBBigLocalBufferLength = IBLocalBufferLength * 2;
108     IBHugeLocalBufferLength = IBBigLocalBufferLength * 20;
109    
110 tony 45 type
111     TStatusVector = array[0..19] of NativeInt;
112     PStatusVector = ^TStatusVector;
113    
114     TFBClientAPI = class;
115    
116     { TFBStatus }
117    
118     TFBStatus = class(TFBInterfacedObject)
119     private
120     FIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
121     protected
122     FOwner: TFBClientAPI;
123     public
124     constructor Create(aOwner: TFBClientAPI);
125     function StatusVector: PStatusVector; virtual; abstract;
126    
127     {IStatus}
128     function GetIBErrorCode: Long;
129     function Getsqlcode: Long;
130 tony 56 function GetMessage: AnsiString;
131 tony 45 function CheckStatusVector(ErrorCodes: array of TFBStatusCode): Boolean;
132     function GetIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
133     procedure SetIBDataBaseErrorMessages(Value: TIBDataBaseErrorMessages);
134     end;
135    
136 tony 263 { TFBLibrary }
137    
138     TFBLibrary = class(TFBInterfacedObject,IFirebirdLibrary)
139     private
140     class var FEnvSetupDone: boolean;
141     class var FLibraryList: array of IFirebirdLibrary;
142 tony 315 private
143 tony 263 FFirebirdAPI: IFirebirdAPI;
144     FRequestedLibName: string;
145     function LoadIBLibrary: boolean;
146     protected
147     FFBLibraryName: string;
148     FIBLibrary: TLibHandle;
149     procedure FreeFBLibrary;
150     function GetOverrideLibName: string;
151     class procedure SetupEnvironment;
152     protected
153     function GetFirebird3API: IFirebirdAPI; virtual; abstract;
154     function GetLegacyFirebirdAPI: IFirebirdAPI; virtual; abstract;
155     public
156     constructor Create(aLibPathName: string='');
157     destructor Destroy; override;
158     class function GetFBLibrary(aLibPathName: string): IFirebirdLibrary;
159     class procedure FreeLibraries;
160 tony 315 function SameLibrary(aLibName: string): boolean;
161 tony 263
162 tony 315 public
163 tony 263 {IFirebirdLibrary}
164     function GetHandle: TLibHandle;
165     function GetLibraryName: string;
166     function GetLibraryFilePath: string;
167     function GetFirebirdAPI: IFirebirdAPI;
168     property IBLibrary: TLibHandle read FIBLibrary;
169     end;
170    
171 tony 45 { TFBClientAPI }
172    
173     TFBClientAPI = class(TFBInterfacedObject)
174     private
175 tony 315 FLocalTimeZoneName: AnsiString; {Informal Time Zone Name from tzname e.g. GMT or BST}
176     FTZDataTimeZoneID: AnsiString; {TZData DB ID e.g. Europe/London}
177     FLocalTimeOffset: integer;
178     FIsDaylightSavingsTime: boolean;
179 tony 56 class var FIBCS: TRTLCriticalSection;
180 tony 315 function FBTimeStampToDateTime(aDate, aTime: longint): TDateTime;
181     procedure GetTZDataSettings;
182 tony 45 protected
183 tony 263 FFBLibrary: TFBLibrary;
184 tony 56 function GetProcAddr(ProcName: PAnsiChar): Pointer;
185 tony 315
186     protected type
187     Tfb_shutdown = function (timeout: uint;
188     const reason: int): int;
189     {$IFDEF WINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
190     protected
191     {FB Shutdown API}
192     fb_shutdown: Tfb_shutdown;
193    
194 tony 45 public
195     {Taken from legacy API}
196     isc_sqlcode: Tisc_sqlcode;
197     isc_sql_interprete: Tisc_sql_interprete;
198     isc_event_counts: Tisc_event_counts;
199     isc_event_block: Tisc_event_block;
200     isc_free: Tisc_free;
201    
202 tony 263 constructor Create(aFBLibrary: TFBLibrary);
203 tony 45 procedure IBAlloc(var P; OldSize, NewSize: Integer);
204     procedure IBDataBaseError;
205 tony 263 function LoadInterface: boolean; virtual;
206 tony 315 procedure FBShutdown; virtual;
207 tony 263 function GetAPI: IFirebirdAPI; virtual; abstract;
208     {$IFDEF UNIX}
209     function GetFirebirdLibList: string; virtual; abstract;
210     {$ENDIF}
211 tony 315 function HasDecFloatSupport: boolean;
212     function HasInt128Support: boolean; virtual;
213     function HasLocalTZDB: boolean; virtual;
214     function HasExtendedTZSupport: boolean; virtual;
215     function HasTimeZoneSupport: boolean; virtual;
216 tony 45
217 tony 315 public
218     property LocalTimeZoneName: AnsiString read FLocalTimeZoneName;
219     property TZDataTimeZoneID: AnsiString read FTZDataTimeZoneID;
220     property LocalTimeOffset: integer read FLocalTimeOffset;
221     public
222 tony 45 {Encode/Decode}
223 tony 56 procedure EncodeInteger(aValue: integer; len: integer; buffer: PByte);
224     function DecodeInteger(bufptr: PByte; len: short): integer; virtual; abstract;
225 tony 315 procedure SQLEncodeDate(aDate: TDateTime; bufptr: PByte); virtual; abstract;
226     function SQLDecodeDate(byfptr: PByte): TDateTime; virtual; abstract;
227     procedure SQLEncodeTime(aTime: TDateTime; bufptr: PByte); virtual; abstract;
228 tony 56 function SQLDecodeTime(bufptr: PByte): TDateTime; virtual; abstract;
229     procedure SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte); virtual; abstract;
230 tony 315 function SQLDecodeDateTime(bufptr: PByte): TDateTime; virtual; abstract;
231 tony 308 function FormatStatus(Status: TFBStatus): AnsiString; virtual; abstract;
232 tony 315 function Int128ToStr(bufptr: PByte; scale: integer): AnsiString; virtual;
233     procedure StrToInt128(scale: integer; aValue: AnsiString; bufptr: PByte);
234     virtual;
235     procedure SQLDecFloatEncode(aValue: tBCD; SQLType: cardinal; bufptr: PByte); virtual;
236     function SQLDecFloatDecode(SQLType: cardinal; bufptr: PByte): tBCD; virtual;
237     function FormatStatus(Status: TFBStatus): AnsiString; virtual; abstract;
238 tony 45
239     {IFirebirdAPI}
240     function GetStatus: IStatus; virtual; abstract;
241     function IsLibraryLoaded: boolean;
242     function IsEmbeddedServer: boolean; virtual; abstract;
243 tony 263 function GetFBLibrary: IFirebirdLibrary;
244 tony 308 function GetImplementationVersion: AnsiString;
245     function GetClientMajor: integer; virtual; abstract;
246     function GetClientMinor: integer; virtual; abstract;
247 tony 60 end;
248 tony 45
249     implementation
250    
251 tony 263 uses IBUtils, Registry,
252 tony 315 {$IFDEF Unix} unix, initc, dl, {$ENDIF}
253 tony 56 {$IFDEF FPC}
254 tony 45 {$IFDEF WINDOWS }
255 tony 56 WinDirs,
256 tony 45 {$ENDIF}
257 tony 56 {$ELSE}
258     ShlObj,
259     {$ENDIF}
260 tony 45 SysUtils;
261    
262     {$IFDEF UNIX}
263 tony 56 {$I 'include/uloadlibrary.inc'}
264 tony 45 {$ELSE}
265 tony 56 {$I 'include/wloadlibrary.inc'}
266 tony 45 {$ENDIF}
267    
268 tony 263
269     { TFBLibrary }
270    
271     function TFBLibrary.GetOverrideLibName: string;
272     begin
273     Result := FFBLibraryName;
274     if (Result = '') and AllowUseOfFBLIB then
275     Result := GetEnvironmentVariable('FBLIB');
276     if Result = '' then
277 tony 45 begin
278 tony 263 if assigned(OnGetLibraryName) then
279     OnGetLibraryName(Result)
280 tony 45 end;
281 tony 263 end;
282 tony 45
283 tony 263 procedure TFBLibrary.FreeFBLibrary;
284     begin
285 tony 315 (FFirebirdAPI as TFBClientAPI).FBShutdown;
286 tony 263 if FIBLibrary <> NilHandle then
287     FreeLibrary(FIBLibrary);
288     FIBLibrary := NilHandle;
289 tony 315 FFBLibraryName := '';
290 tony 263 end;
291 tony 45
292 tony 263 function TFBLibrary.GetLibraryName: string;
293 tony 45 begin
294 tony 263 Result := ExtractFileName(FFBLibraryName);
295     end;
296    
297     function TFBLibrary.GetFirebirdAPI: IFirebirdAPI;
298     begin
299     Result := FFirebirdAPI;
300     end;
301    
302     constructor TFBLibrary.Create(aLibPathName: string);
303     begin
304 tony 45 inherited Create;
305 tony 263 SetupEnvironment;
306     FFBLibraryName := aLibPathName;
307     FIBLibrary := NilHandle;
308     FFirebirdAPI := GetFirebird3API;
309     FRequestedLibName := aLibPathName;
310     if aLibPathName <> '' then
311 tony 45 begin
312 tony 263 SetLength(FLibraryList,Length(FLibraryList)+1);
313     FLibraryList[Length(FLibraryList)-1] := self;
314 tony 45 end;
315 tony 263 if FFirebirdAPI <> nil then
316     begin
317     {First try Firebird 3}
318     if not LoadIBLibrary or not (FFirebirdAPI as TFBClientAPI).LoadInterface then
319     FFirebirdAPI := nil;
320     end;
321    
322     if FFirebirdAPI = nil then
323     begin
324     {now try Firebird 2.5. Under Unix we need to reload the library in case we
325     are to use the embedded library}
326     FFirebirdAPI := GetLegacyFirebirdAPI;
327     if FFirebirdAPI <> nil then
328     begin
329     {$IFDEF UNIX}
330     FreeFBLibrary;
331     {$ENDIF}
332     if not LoadIBLibrary or not (FFirebirdAPI as TFBClientAPI).LoadInterface then
333     FFirebirdAPI := nil;
334     end;
335     end;
336     {Note: FFirebirdAPI will be set to nil if the Firebird API fails to load}
337 tony 45 end;
338    
339 tony 263 destructor TFBLibrary.Destroy;
340 tony 45 begin
341 tony 315 FreeFBLibrary;
342 tony 263 FFirebirdAPI := nil;
343 tony 45 inherited Destroy;
344     end;
345    
346 tony 263 class function TFBLibrary.GetFBLibrary(aLibPathName: string): IFirebirdLibrary;
347     var i: integer;
348     begin
349     Result := nil;
350     if aLibPathName <> '' then
351     begin
352     for i := 0 to Length(FLibraryList) - 1 do
353 tony 315 begin
354     if (FLibraryList[i] as TFBLibrary).SameLibrary(aLibPathName) then
355 tony 263 begin
356     Result := FLibraryList[i];
357     Exit;
358     end;
359 tony 315 end;
360 tony 263 Result := Create(aLibPathName);
361     end;
362    
363     end;
364    
365     class procedure TFBLibrary.FreeLibraries;
366     var i: integer;
367     begin
368     for i := 0 to Length(FLibraryList) - 1 do
369     FLibraryList[i] := nil;
370     SetLength(FLibraryList,0);
371     end;
372    
373 tony 315 function TFBLibrary.SameLibrary(aLibName: string): boolean;
374     begin
375     Result := FRequestedLibName = aLibName;
376     end;
377    
378 tony 263 function TFBLibrary.GetHandle: TLibHandle;
379     begin
380     Result := FIBLibrary;
381     end;
382    
383     { TFBClientAPI }
384    
385     constructor TFBClientAPI.Create(aFBLibrary: TFBLibrary);
386     begin
387     inherited Create;
388     FFBLibrary := aFBLibrary;
389 tony 315 GetTZDataSettings;
390 tony 263 end;
391    
392 tony 45 procedure TFBClientAPI.IBAlloc(var P; OldSize, NewSize: Integer);
393     var
394     i: Integer;
395     begin
396     ReallocMem(Pointer(P), NewSize);
397 tony 56 for i := OldSize to NewSize - 1 do PAnsiChar(P)[i] := #0;
398 tony 45 end;
399    
400     procedure TFBClientAPI.IBDataBaseError;
401     begin
402     raise EIBInterBaseError.Create(GetStatus);
403     end;
404    
405 tony 56 procedure TFBClientAPI.EncodeInteger(aValue: integer; len: integer; buffer: PByte);
406 tony 45 begin
407     while len > 0 do
408     begin
409 tony 56 buffer^ := aValue and $FF;
410 tony 45 Inc(buffer);
411     Dec(len);
412     aValue := aValue shr 8;
413     end;
414     end;
415    
416 tony 315 function TFBClientAPI.Int128ToStr(bufptr: PByte; scale: integer): AnsiString;
417     begin
418     if not HasInt128Support then
419     IBError(ibxeNotSupported,[]);
420     end;
421    
422     procedure TFBClientAPI.StrToInt128(scale: integer; aValue: AnsiString; bufptr: PByte);
423     begin
424     if not HasInt128Support then
425     IBError(ibxeNotSupported,[]);
426     end;
427    
428     procedure TFBClientAPI.SQLDecFloatEncode(aValue: tBCD; SQLType: cardinal;
429     bufptr: PByte);
430     begin
431     if not HasDecFloatSupport then
432     IBError(ibxeNotSupported,[]);
433     end;
434    
435     function TFBClientAPI.SQLDecFloatDecode(SQLType: cardinal; bufptr: PByte): tBCD;
436     begin
437     if not HasDecFloatSupport then
438     IBError(ibxeNotSupported,[]);
439     end;
440    
441 tony 45 function TFBClientAPI.IsLibraryLoaded: boolean;
442     begin
443 tony 263 Result := FFBLibrary.IBLibrary <> NilHandle;
444 tony 45 end;
445    
446 tony 263 function TFBClientAPI.GetFBLibrary: IFirebirdLibrary;
447     begin
448     Result := FFBLibrary;
449     end;
450    
451 tony 315 function TFBClientAPI.FBTimeStampToDateTime(aDate, aTime: longint): TDateTime;
452 tony 308 begin
453 tony 315 {aDate/aTime are in TTimestamp format but aTime is decimilliseconds}
454     aDate := aDate - DateDelta;
455     if aDate < 0 then
456     Result := trunc(aDate) - abs(frac(aTime / (MSecsPerDay*10)))
457     else
458     Result := trunc(aDate) + abs(frac(aTime / (MSecsPerDay*10)));
459 tony 308 end;
460    
461 tony 315 {$IFDEF UNIX}
462     procedure TFBClientAPI.GetTZDataSettings;
463     var S: TStringList;
464     begin
465     FLocalTimeOffset := GetLocalTimeOffset;
466     FLocalTimeZoneName := strpas(tzname[tzdaylight]);
467     FIsDaylightSavingsTime := tzdaylight;
468     if FileExists(DefaultTimeZoneFile) then
469     begin
470     S := TStringList.Create;
471     try
472     S.LoadFromFile(DefaultTimeZoneFile);
473     if S.Count > 0 then
474     FTZDataTimeZoneID := S[0];
475     finally
476     S.Free;
477     end;
478     end;
479     end;
480     {$ENDIF}
481    
482     {$IFDEF WINDOWS}
483     procedure TFBClientAPI.GetTZDataSettings;
484     var TZInfo: TTimeZoneInformation;
485     begin
486     FIsDaylightSavingsTime := false;
487     {is there any way of working out the default TZData DB time zone ID under Windows?}
488     case GetTimeZoneInformation(TZInfo) of
489     TIME_ZONE_ID_UNKNOWN:
490     begin
491     FLocalTimeZoneName := '';
492     FLocalTimeOffset := 0;
493     end;
494     TIME_ZONE_ID_STANDARD:
495     begin
496     FLocalTimeZoneName := strpas(PWideChar(@TZInfo.StandardName));
497     FLocalTimeOffset := TZInfo.Bias;
498     end;
499     TIME_ZONE_ID_DAYLIGHT:
500     begin
501     FLocalTimeZoneName := strpas(PWideChar(@TZInfo.DaylightName));
502     FLocalTimeOffset := TZInfo.DayLightBias;
503     FIsDaylightSavingsTime := true;
504     end;
505     end;
506     end;
507     {$ENDIF}
508    
509 tony 56 function TFBClientAPI.GetProcAddr(ProcName: PAnsiChar): Pointer;
510 tony 45 begin
511 tony 263 Result := GetProcAddress(FFBLibrary.IBLibrary, ProcName);
512 tony 45 if not Assigned(Result) then
513     raise Exception.CreateFmt(SFirebirdAPIFuncNotFound,[ProcName]);
514     end;
515    
516 tony 315 function TFBClientAPI.HasDecFloatSupport: boolean;
517     begin
518     Result := GetClientMajor >= 4;
519     end;
520    
521     function TFBClientAPI.HasInt128Support: boolean;
522     begin
523     Result := false;
524     end;
525    
526     function TFBClientAPI.HasLocalTZDB: boolean;
527     begin
528     Result := false;
529     end;
530    
531     function TFBClientAPI.HasExtendedTZSupport: boolean;
532     begin
533     Result := false;
534     end;
535    
536     function TFBClientAPI.HasTimeZoneSupport: boolean;
537     begin
538     Result := false;
539     end;
540    
541     function TFBClientAPI.GetImplementationVersion: AnsiString;
542     begin
543     Result := Format('%d.%d',[GetClientMajor,GetClientMinor]);
544     end;
545    
546 tony 263 function TFBClientAPI.LoadInterface: boolean;
547 tony 45 begin
548     isc_sqlcode := GetProcAddr('isc_sqlcode'); {do not localize}
549     isc_sql_interprete := GetProcAddr('isc_sql_interprete'); {do not localize}
550     isc_event_counts := GetProcAddr('isc_event_counts'); {do not localize}
551     isc_event_block := GetProcAddr('isc_event_block'); {do not localize}
552     isc_free := GetProcAddr('isc_free'); {do not localize}
553 tony 315 fb_shutdown := GetProcAddr('fb_shutdown'); {do not localize}
554 tony 263 Result := assigned(isc_free);
555 tony 45 end;
556    
557 tony 315 procedure TFBClientAPI.FBShutdown;
558     begin
559     if assigned(fb_shutdown) then
560     fb_shutdown(0,fb_shutrsn_exit_called);
561     end;
562    
563 tony 45 { TFBStatus }
564    
565     constructor TFBStatus.Create(aOwner: TFBClientAPI);
566     begin
567     inherited Create;
568     FOwner := aOwner;
569     FIBDataBaseErrorMessages := [ShowSQLMessage, ShowIBMessage];
570     end;
571    
572     function TFBStatus.GetIBErrorCode: Long;
573     begin
574     Result := StatusVector^[1];
575     end;
576    
577     function TFBStatus.Getsqlcode: Long;
578     begin
579     with FOwner do
580     Result := isc_sqlcode(PISC_STATUS(StatusVector));
581     end;
582    
583 tony 56 function TFBStatus.GetMessage: AnsiString;
584     var local_buffer: array[0..IBHugeLocalBufferLength - 1] of AnsiChar;
585 tony 45 IBDataBaseErrorMessages: TIBDataBaseErrorMessages;
586     sqlcode: Long;
587     begin
588     Result := '';
589     IBDataBaseErrorMessages := FIBDataBaseErrorMessages;
590     sqlcode := Getsqlcode;
591     if (ShowSQLCode in IBDataBaseErrorMessages) then
592     Result := Result + 'SQLCODE: ' + IntToStr(sqlcode); {do not localize}
593    
594     Exclude(IBDataBaseErrorMessages, ShowSQLMessage);
595     if (ShowSQLMessage in IBDataBaseErrorMessages) then
596     begin
597     with FOwner do
598 tony 308 isc_sql_interprete(sqlcode, local_buffer, sizeof(local_buffer));
599 tony 45 if (ShowSQLCode in FIBDataBaseErrorMessages) then
600     Result := Result + CRLF;
601     Result := Result + strpas(local_buffer);
602     end;
603    
604     if (ShowIBMessage in IBDataBaseErrorMessages) then
605     begin
606     if (ShowSQLCode in IBDataBaseErrorMessages) or
607     (ShowSQLMessage in IBDataBaseErrorMessages) then
608 tony 308 Result := Result + LineEnding;
609 tony 315 Result := Result + FOwner.FormatStatus(self);
610 tony 45 end;
611     if (Result <> '') and (Result[Length(Result)] = '.') then
612     Delete(Result, Length(Result), 1);
613     end;
614    
615     function TFBStatus.CheckStatusVector(ErrorCodes: array of TFBStatusCode
616     ): Boolean;
617     var
618     p: PISC_STATUS;
619     i: Integer;
620     procedure NextP(i: Integer);
621     begin
622 tony 56 p := PISC_STATUS(PAnsiChar(p) + (i * SizeOf(ISC_STATUS)));
623 tony 45 end;
624     begin
625     p := PISC_STATUS(StatusVector);
626     result := False;
627     while (p^ <> 0) and (not result) do
628     case p^ of
629     3: NextP(3);
630     1, 4:
631     begin
632     NextP(1);
633     i := 0;
634     while (i <= High(ErrorCodes)) and (not result) do
635     begin
636     result := p^ = ErrorCodes[i];
637     Inc(i);
638     end;
639     NextP(1);
640     end;
641     else
642     NextP(2);
643     end;
644     end;
645    
646     function TFBStatus.GetIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
647     begin
648 tony 56 EnterCriticalSection(TFBClientAPI.FIBCS);
649 tony 45 try
650     result := FIBDataBaseErrorMessages;
651     finally
652 tony 56 LeaveCriticalSection(TFBClientAPI.FIBCS);
653 tony 45 end;
654     end;
655    
656     procedure TFBStatus.SetIBDataBaseErrorMessages(Value: TIBDataBaseErrorMessages);
657     begin
658 tony 56 EnterCriticalSection(TFBClientAPI.FIBCS);
659 tony 45 try
660     FIBDataBaseErrorMessages := Value;
661     finally
662 tony 56 LeaveCriticalSection(TFBClientAPI.FIBCS);
663 tony 45 end;
664     end;
665 tony 60
666 tony 45 initialization
667 tony 263 TFBLibrary.FEnvSetupDone := false;
668 tony 56 {$IFNDEF FPC}
669     InitializeCriticalSection(TFBClientAPI.FIBCS);
670     {$ELSE}
671     InitCriticalSection(TFBClientAPI.FIBCS);
672     {$ENDIF}
673 tony 45
674     finalization
675 tony 263 TFBLibrary.FreeLibraries;
676 tony 56 {$IFNDEF FPC}
677     DeleteCriticalSection(TFBClientAPI.FIBCS);
678     {$ELSE}
679     DoneCriticalSection(TFBClientAPI.FIBCS);
680     {$ENDIF}
681 tony 45 end.
682