ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/journaling/fbintf/client/FBClientAPI.pas
(Generate patch)

Comparing ibx/trunk/fbintf/client/FBClientAPI.pas (file contents):
Revision 60 by tony, Mon Mar 27 15:21:02 2017 UTC vs.
Revision 315 by tony, Thu Feb 25 11:56:36 2021 UTC

# Line 76 | Line 76 | uses
76    Classes,
77      {$IFDEF WINDOWS}Windows, {$ENDIF}
78      {$IFDEF FPC} Dynlibs, {$ENDIF}
79 <   IB, IBHeader, FBActivityMonitor, FBMessages, IBExternals;
79 >   IB, IBHeader, FBActivityMonitor, FBMessages, IBExternals, FmtBCD;
80  
81   {For Linux see result of GetFirebirdLibList method}
82   {$IFDEF DARWIN}
# Line 90 | Line 90 | FIREBIRD_CLIENT = 'fbclient.dll'; {do no
90   FIREBIRD_EMBEDDED = 'fbembed.dll';
91   {$ENDIF}
92  
93 < {$IFNDEF FPC}
94 < type
95 <  TLibHandle = THandle;
93 > const
94 >  {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 <  NilHandle = 0;
104 <  DirectorySeparator = '\';
105 < {$ENDIF}
103 >    DefaultTimeZoneFile = '/etc/timezone';
104 >
105 > const
106 >  IBLocalBufferLength = 512;
107 >  IBBigLocalBufferLength = IBLocalBufferLength * 2;
108 >  IBHugeLocalBufferLength = IBBigLocalBufferLength * 20;
109  
110   type
111    TStatusVector              = array[0..19] of NativeInt;
# Line 125 | Line 133 | type
133      procedure SetIBDataBaseErrorMessages(Value: TIBDataBaseErrorMessages);
134    end;
135  
136 +  { TFBLibrary }
137 +
138 +  TFBLibrary = class(TFBInterfacedObject,IFirebirdLibrary)
139 +  private
140 +    class var FEnvSetupDone: boolean;
141 +    class var FLibraryList: array of IFirebirdLibrary;
142 +  private
143 +    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 +    function SameLibrary(aLibName: string): boolean;
161 +
162 +  public
163 +    {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    { TFBClientAPI }
172  
173    TFBClientAPI = class(TFBInterfacedObject)
174    private
175 <    FOwnsIBLibrary: boolean;
175 >    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      class var FIBCS: TRTLCriticalSection;
180 <    procedure LoadIBLibrary;
180 >    function FBTimeStampToDateTime(aDate, aTime: longint): TDateTime;
181 >    procedure GetTZDataSettings;
182    protected
183 <    class var FFBLibraryName: string;
137 <    class var IBLibrary: TLibHandle;
138 <    {$IFDEF WINDOWS}
139 <    class var FFBLibraryPath: string;
140 <    {$ENDIF}
183 >    FFBLibrary: TFBLibrary;
184      function GetProcAddr(ProcName: PAnsiChar): Pointer;
185 <    function GetOverrideLibName: string;
186 <    {$IFDEF UNIX}
187 <    function GetFirebirdLibList: string; virtual; abstract;
188 <    {$ENDIF}
189 <    procedure LoadInterface; virtual;
185 >
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    public
195      {Taken from legacy API}
196      isc_sqlcode: Tisc_sqlcode;
197      isc_sql_interprete: Tisc_sql_interprete;
151    isc_interprete: Tisc_interprete;
198      isc_event_counts: Tisc_event_counts;
199      isc_event_block: Tisc_event_block;
200      isc_free: Tisc_free;
201  
202 <    constructor Create;
157 <    destructor Destroy; override;
202 >    constructor Create(aFBLibrary: TFBLibrary);
203      procedure IBAlloc(var P; OldSize, NewSize: Integer);
204      procedure IBDataBaseError;
205 <    procedure SetupEnvironment;
205 >    function LoadInterface: boolean; virtual;
206 >    procedure FBShutdown; virtual;
207 >    function GetAPI: IFirebirdAPI; virtual; abstract;
208 >    {$IFDEF UNIX}
209 >    function GetFirebirdLibList: string; virtual; abstract;
210 >    {$ENDIF}
211 >    function HasDecFloatSupport: boolean;
212 >    function HasInt128Support: boolean; virtual;
213 >    function HasLocalTZDB: boolean; virtual;
214 >    function HasExtendedTZSupport: boolean; virtual;
215 >    function HasTimeZoneSupport: boolean; virtual;
216  
217 +  public
218 +    property LocalTimeZoneName: AnsiString read FLocalTimeZoneName;
219 +    property TZDataTimeZoneID: AnsiString read FTZDataTimeZoneID;
220 +    property LocalTimeOffset: integer read FLocalTimeOffset;
221 +  public
222      {Encode/Decode}
223      procedure EncodeInteger(aValue: integer; len: integer; buffer: PByte);
224      function DecodeInteger(bufptr: PByte; len: short): integer; virtual; abstract;
225 <    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;
225 >    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      function SQLDecodeTime(bufptr: PByte): TDateTime;  virtual; abstract;
229      procedure SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte); virtual; abstract;
230 <    function SQLDecodeDateTime(bufptr: PByte): TDateTime; virtual; abstract;
231 <
230 >    function  SQLDecodeDateTime(bufptr: PByte): TDateTime; virtual; abstract;
231 >    function FormatStatus(Status: TFBStatus): AnsiString; virtual; abstract;
232 >    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  
239      {IFirebirdAPI}
240      function GetStatus: IStatus; virtual; abstract;
241      function IsLibraryLoaded: boolean;
242      function IsEmbeddedServer: boolean; virtual; abstract;
243 <    function GetLibraryName: string;
243 >    function GetFBLibrary: IFirebirdLibrary;
244 >    function GetImplementationVersion: AnsiString;
245 >    function GetClientMajor: integer;  virtual; abstract;
246 >    function GetClientMinor: integer;  virtual; abstract;
247   end;
248  
180 var FirebirdClientAPI: TFBClientAPI = nil;
181
249   implementation
250  
251 < uses IBUtils, Registry, {$IFDEF Unix} initc, {$ENDIF}
251 > uses IBUtils, Registry,
252 >  {$IFDEF Unix} unix, initc, dl, {$ENDIF}
253   {$IFDEF FPC}
254   {$IFDEF WINDOWS }
255   WinDirs,
# Line 197 | Line 265 | SysUtils;
265   {$I 'include/wloadlibrary.inc'}
266   {$ENDIF}
267  
268 <  {$IFDEF Unix}
269 <  {SetEnvironmentVariable doesn't exist so we have to use C Library}
270 <  function setenv(name:Pchar; value:Pchar; replace:integer):integer;cdecl;external clib name 'setenv';
271 <  function unsetenv(name:Pchar):integer;cdecl;external clib name 'unsetenv';
272 <  function SetEnvironmentVariable(name:PAnsiChar; value:PAnsiChar):boolean;
273 <  // Set environment variable; if empty string given, remove it.
268 >
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    begin
278 <    result:=false; //assume failure
279 <    if value = '' then
209 <    begin
210 <      // Assume user wants to remove variable.
211 <      if unsetenv(name)=0 then result:=true;
212 <    end
213 <    else
214 <    begin
215 <      // Non empty so set the variable
216 <      if setenv(name, value, 1)=0 then result:=true;
217 <    end;
278 >    if assigned(OnGetLibraryName) then
279 >      OnGetLibraryName(Result)
280    end;
281 <  {$ENDIF}
281 > end;
282  
283 < { TFBClientAPI }
283 > procedure TFBLibrary.FreeFBLibrary;
284 > begin
285 >  (FFirebirdAPI as TFBClientAPI).FBShutdown;
286 >  if FIBLibrary <> NilHandle then
287 >    FreeLibrary(FIBLibrary);
288 >  FIBLibrary := NilHandle;
289 >  FFBLibraryName := '';
290 > end;
291 >
292 > function TFBLibrary.GetLibraryName: string;
293 > begin
294 >  Result := ExtractFileName(FFBLibraryName);
295 > end;
296 >
297 > function TFBLibrary.GetFirebirdAPI: IFirebirdAPI;
298 > begin
299 >  Result := FFirebirdAPI;
300 > end;
301  
302 < constructor TFBClientAPI.Create;
302 > constructor TFBLibrary.Create(aLibPathName: string);
303   begin
304    inherited Create;
305 <  LoadIBLibrary;
306 <  if (IBLibrary <> NilHandle) then
305 >  SetupEnvironment;
306 >  FFBLibraryName := aLibPathName;
307 >  FIBLibrary := NilHandle;
308 >  FFirebirdAPI := GetFirebird3API;
309 >  FRequestedLibName := aLibPathName;
310 >  if aLibPathName <> '' then
311    begin
312 <    SetupEnvironment;
313 <    LoadInterface;
312 >    SetLength(FLibraryList,Length(FLibraryList)+1);
313 >    FLibraryList[Length(FLibraryList)-1] := self;
314    end;
315 <  FirebirdClientAPI := self;
315 >  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   end;
338  
339 < destructor TFBClientAPI.Destroy;
339 > destructor TFBLibrary.Destroy;
340   begin
341 <  FirebirdClientAPI := nil;
342 <  if FOwnsIBLibrary and (IBLibrary <> NilHandle) then
239 <    FreeLibrary(IBLibrary);
240 <  IBLibrary := NilHandle;
341 >  FreeFBLibrary;
342 >  FFirebirdAPI := nil;
343    inherited Destroy;
344   end;
345  
346 + 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 +    begin
354 +      if (FLibraryList[i] as TFBLibrary).SameLibrary(aLibPathName) then
355 +      begin
356 +        Result := FLibraryList[i];
357 +        Exit;
358 +      end;
359 +    end;
360 +    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 + function TFBLibrary.SameLibrary(aLibName: string): boolean;
374 + begin
375 +  Result := FRequestedLibName = aLibName;
376 + end;
377 +
378 + 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 +  GetTZDataSettings;
390 + end;
391 +
392   procedure TFBClientAPI.IBAlloc(var P; OldSize, NewSize: Integer);
393   var
394    i: Integer;
# Line 254 | Line 402 | begin
402    raise EIBInterBaseError.Create(GetStatus);
403   end;
404  
257 {Under Unixes, if using an embedded server then set up local TMP and LOCK Directories}
258
259 procedure TFBClientAPI.SetupEnvironment;
260 var TmpDir: AnsiString;
261 begin
262  {$IFDEF UNIX}
263    TmpDir := GetTempDir +
264        DirectorySeparator + 'firebird_' + sysutils.GetEnvironmentVariable('USER');
265    if sysutils.GetEnvironmentVariable('FIREBIRD_TMP') = '' then
266    begin
267      if not DirectoryExists(tmpDir) then
268        mkdir(tmpDir);
269      SetEnvironmentVariable('FIREBIRD_TMP',PAnsiChar(TmpDir));
270    end;
271    if sysutils.GetEnvironmentVariable('FIREBIRD_LOCK') = '' then
272    begin
273      if not DirectoryExists(tmpDir) then
274        mkdir(tmpDir);
275      SetEnvironmentVariable('FIREBIRD_LOCK',PAnsiChar(TmpDir));
276    end;
277  {$ENDIF}
278 end;
279
405   procedure TFBClientAPI.EncodeInteger(aValue: integer; len: integer; buffer: PByte);
406   begin
407    while len > 0 do
# Line 288 | Line 413 | begin
413    end;
414   end;
415  
416 + 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   function TFBClientAPI.IsLibraryLoaded: boolean;
442   begin
443 <  Result := IBLibrary <> NilHandle;
443 >  Result := FFBLibrary.IBLibrary <> NilHandle;
444 > end;
445 >
446 > function TFBClientAPI.GetFBLibrary: IFirebirdLibrary;
447 > begin
448 >  Result := FFBLibrary;
449 > end;
450 >
451 > function TFBClientAPI.FBTimeStampToDateTime(aDate, aTime: longint): TDateTime;
452 > begin
453 >  {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 > end;
460 >
461 > {$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   function TFBClientAPI.GetProcAddr(ProcName: PAnsiChar): Pointer;
510   begin
511 <  Result := GetProcAddress(IBLibrary, ProcName);
511 >  Result := GetProcAddress(FFBLibrary.IBLibrary, ProcName);
512    if not Assigned(Result) then
513      raise Exception.CreateFmt(SFirebirdAPIFuncNotFound,[ProcName]);
514   end;
515  
516 < function TFBClientAPI.GetOverrideLibName: string;
516 > function TFBClientAPI.HasDecFloatSupport: boolean;
517   begin
518 <  Result := '';
306 <  if AllowUseOfFBLIB then
307 <    Result := GetEnvironmentVariable('FBLIB');
308 <  if Result = '' then
309 <  begin
310 <    if assigned(OnGetLibraryName) then
311 <      OnGetLibraryName(Result)
312 <  end;
518 >  Result := GetClientMajor >= 4;
519   end;
520  
521 < procedure TFBClientAPI.LoadInterface;
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 > function TFBClientAPI.LoadInterface: boolean;
547   begin
548    isc_sqlcode := GetProcAddr('isc_sqlcode'); {do not localize}
549    isc_sql_interprete := GetProcAddr('isc_sql_interprete'); {do not localize}
319  isc_interprete := GetProcAddr('isc_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 +  fb_shutdown := GetProcAddr('fb_shutdown'); {do not localize}
554 +  Result := assigned(isc_free);
555   end;
556  
557 < function TFBClientAPI.GetLibraryName: string;
557 > procedure TFBClientAPI.FBShutdown;
558   begin
559 <  Result := FFBLibraryName;
559 >  if assigned(fb_shutdown) then
560 >    fb_shutdown(0,fb_shutrsn_exit_called);
561   end;
562  
330 const
331  IBLocalBufferLength = 512;
332  IBBigLocalBufferLength = IBLocalBufferLength * 2;
333  IBHugeLocalBufferLength = IBBigLocalBufferLength * 20;
334
563   { TFBStatus }
564  
565   constructor TFBStatus.Create(aOwner: TFBClientAPI);
# Line 356 | Line 584 | function TFBStatus.GetMessage: AnsiStrin
584   var local_buffer: array[0..IBHugeLocalBufferLength - 1] of AnsiChar;
585      IBDataBaseErrorMessages: TIBDataBaseErrorMessages;
586      sqlcode: Long;
359    psb: PStatusVector;
587   begin
588    Result := '';
589    IBDataBaseErrorMessages := FIBDataBaseErrorMessages;
# Line 368 | Line 595 | begin
595    if (ShowSQLMessage in IBDataBaseErrorMessages) then
596    begin
597      with FOwner do
598 <      isc_sql_interprete(sqlcode, local_buffer, IBLocalBufferLength);
598 >      isc_sql_interprete(sqlcode, local_buffer, sizeof(local_buffer));
599      if (ShowSQLCode in FIBDataBaseErrorMessages) then
600        Result := Result + CRLF;
601      Result := Result + strpas(local_buffer);
# Line 378 | Line 605 | begin
605    begin
606      if (ShowSQLCode in IBDataBaseErrorMessages) or
607         (ShowSQLMessage in IBDataBaseErrorMessages) then
608 <      Result := Result + CRLF;
609 <    psb := StatusVector;
383 <    with FOwner do
384 <    while (isc_interprete(@local_buffer, @psb) > 0) do
385 <    begin
386 <      if (Result <> '') and (Result[Length(Result)] <> LF) then
387 <        Result := Result + CRLF;
388 <      Result := Result + strpas(local_buffer);
389 <    end;
608 >      Result := Result + LineEnding;
609 >    Result := Result + FOwner.FormatStatus(self);
610    end;
611    if (Result <> '') and (Result[Length(Result)] = '.') then
612      Delete(Result, Length(Result), 1);
# Line 444 | Line 664 | begin
664   end;
665  
666   initialization
667 <  TFBClientAPI.IBLibrary := NilHandle;
667 >  TFBLibrary.FEnvSetupDone := false;
668    {$IFNDEF FPC}
669    InitializeCriticalSection(TFBClientAPI.FIBCS);
670    {$ELSE}
# Line 452 | Line 672 | initialization
672    {$ENDIF}
673  
674   finalization
675 +  TFBLibrary.FreeLibraries;
676    {$IFNDEF FPC}
677    DeleteCriticalSection(TFBClientAPI.FIBCS);
678    {$ELSE}
679    DoneCriticalSection(TFBClientAPI.FIBCS);
680    {$ENDIF}
460  if TFBClientAPI.IBLibrary <> NilHandle then
461  begin
462    FreeLibrary(TFBClientAPI.IBLibrary);
463    TFBClientAPI.IBLibrary := NilHandle;
464    TFBClientAPI.FFBLibraryName := '';
465  end;
466
681   end.
682  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines