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

Comparing ibx/trunk/fbintf/client/FBClientAPI.pas (file contents):
Revision 56 by tony, Mon Mar 6 10:20:02 2017 UTC vs.
Revision 319 by tony, Thu Feb 25 12:05:40 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}
81 > {For Linux see result of GetFirebirdLibListruntime/nongui/winipc.inc method}
82   {$IFDEF DARWIN}
83   const
84   FIREBIRD_SO2 = 'libfbclient.dylib';
# 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  
238      {IFirebirdAPI}
239      function GetStatus: IStatus; virtual; abstract;
240      function IsLibraryLoaded: boolean;
241      function IsEmbeddedServer: boolean; virtual; abstract;
242 <    function GetLibraryName: string;
243 <    function GetCharsetName(CharSetID: integer): AnsiString;
244 <    function CharSetID2CodePage(CharSetID: integer; var CodePage: TSystemCodePage): boolean;
245 <    function CodePage2CharSetID(CodePage: TSystemCodePage; var CharSetID: integer): boolean;
246 <    function CharSetName2CharSetID(CharSetName: AnsiString; var CharSetID: integer): boolean;
182 <    function CharSetWidth(CharSetID: integer; var Width: integer): boolean;
183 <  end;
184 <
185 < var FirebirdClientAPI: TFBClientAPI = nil;
242 >    function GetFBLibrary: IFirebirdLibrary;
243 >    function GetImplementationVersion: AnsiString;
244 >    function GetClientMajor: integer;  virtual; abstract;
245 >    function GetClientMinor: integer;  virtual; abstract;
246 > end;
247  
248   implementation
249  
250 < uses IBUtils, Registry, {$IFDEF Unix} initc, {$ENDIF}
250 > uses IBUtils, Registry,
251 >  {$IFDEF Unix} unix, initc, dl, {$ENDIF}
252   {$IFDEF FPC}
253   {$IFDEF WINDOWS }
254   WinDirs,
# Line 202 | Line 264 | SysUtils;
264   {$I 'include/wloadlibrary.inc'}
265   {$ENDIF}
266  
267 < type
268 <  TCharsetMap = record
269 <    CharsetID: integer;
270 <    CharSetName: AnsiString;
271 <    CharSetWidth: integer;
272 <    CodePage: TSystemCodePage;
267 >
268 > { TFBLibrary }
269 >
270 > function TFBLibrary.GetOverrideLibName: string;
271 > begin
272 >  Result := FFBLibraryName;
273 >  if (Result = '') and AllowUseOfFBLIB then
274 >    Result := GetEnvironmentVariable('FBLIB');
275 >  if Result = '' then
276 >  begin
277 >    if assigned(OnGetLibraryName) then
278 >      OnGetLibraryName(Result)
279    end;
280 + end;
281  
282 < const
283 <  CharSetMap: array [0..69] of TCharsetMap = (
284 <  (CharsetID: 0; CharSetName: 'NONE'; CharSetWidth: 1; CodePage: CP_ACP),
285 <  (CharsetID: 1; CharSetName: 'OCTETS'; CharSetWidth: 1; CodePage: CP_NONE),
286 <  (CharsetID: 2; CharSetName: 'ASCII'; CharSetWidth: 1; CodePage: CP_ASCII),
287 <  (CharsetID: 3; CharSetName: 'UNICODE_FSS'; CharSetWidth: 3; CodePage: CP_UTF8),
288 <  (CharsetID: 4; CharSetName: 'UTF8'; CharSetWidth: 4; CodePage: CP_UTF8),
289 <  (CharsetID: 5; CharSetName: 'SJIS_0208'; CharSetWidth: 2; CodePage: 20932),
290 <  (CharsetID: 6; CharSetName: 'EUCJ_0208'; CharSetWidth: 2; CodePage: 20932),
291 <  (CharsetID: 7; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
292 <  (CharsetID: 8; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
293 <  (CharsetID: 9; CharSetName: 'DOS737'; CharSetWidth: 1; CodePage: 737),
294 <  (CharsetID: 10; CharSetName: 'DOS437'; CharSetWidth: 1; CodePage: 437),
295 <  (CharsetID: 11; CharSetName: 'DOS850'; CharSetWidth: 1; CodePage: 850),
296 <  (CharsetID: 12; CharSetName: 'DOS865'; CharSetWidth: 1; CodePage: 865),
297 <  (CharsetID: 13; CharSetName: 'DOS860'; CharSetWidth: 1; CodePage: 860),
298 <  (CharsetID: 14; CharSetName: 'DOS863'; CharSetWidth: 1; CodePage: 863),
299 <  (CharsetID: 15; CharSetName: 'DOS775'; CharSetWidth: 1; CodePage: 775),
300 <  (CharsetID: 16; CharSetName: 'DOS858'; CharSetWidth: 1; CodePage: 858),
301 <  (CharsetID: 17; CharSetName: 'DOS862'; CharSetWidth: 1; CodePage: 862),
302 <  (CharsetID: 18; CharSetName: 'DOS864'; CharSetWidth: 1; CodePage: 864),
303 <  (CharsetID: 19; CharSetName: 'NEXT'; CharSetWidth: 1; CodePage: CP_NONE),
304 <  (CharsetID: 20; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
305 <  (CharsetID: 21; CharSetName: 'ISO8859_1'; CharSetWidth: 1; CodePage: 28591),
306 <  (CharsetID: 22; CharSetName: 'ISO8859_2'; CharSetWidth: 1; CodePage: 28592),
307 <  (CharsetID: 23; CharSetName: 'ISO8859_3'; CharSetWidth: 1; CodePage: 28593),
308 <  (CharsetID: 24; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
309 <  (CharsetID: 25; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
241 <  (CharsetID: 26; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
242 <  (CharsetID: 27; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
243 <  (CharsetID: 28; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
244 <  (CharsetID: 29; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
245 <  (CharsetID: 30; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
246 <  (CharsetID: 31; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
247 <  (CharsetID: 32; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
248 <  (CharsetID: 33; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
249 <  (CharsetID: 34; CharSetName: 'ISO8859_4'; CharSetWidth: 1; CodePage: 28594),
250 <  (CharsetID: 35; CharSetName: 'ISO8859_5'; CharSetWidth: 1; CodePage: 28595),
251 <  (CharsetID: 36; CharSetName: 'ISO8859_6'; CharSetWidth: 1; CodePage: 28596),
252 <  (CharsetID: 37; CharSetName: 'ISO8859_7'; CharSetWidth: 1; CodePage: 28597),
253 <  (CharsetID: 38; CharSetName: 'ISO8859_8'; CharSetWidth: 1; CodePage: 28598),
254 <  (CharsetID: 39; CharSetName: 'ISO8859_9'; CharSetWidth: 1; CodePage: 28599),
255 <  (CharsetID: 40; CharSetName: 'ISO8859_13'; CharSetWidth: 1; CodePage: 28603),
256 <  (CharsetID: 41; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
257 <  (CharsetID: 42; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
258 <  (CharsetID: 43; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
259 <  (CharsetID: 44; CharSetName: 'KSC_5601'; CharSetWidth: 2; CodePage: 949),
260 <  (CharsetID: 45; CharSetName: 'DOS852'; CharSetWidth: 1; CodePage: 852),
261 <  (CharsetID: 46; CharSetName: 'DOS857'; CharSetWidth: 1; CodePage: 857),
262 <  (CharsetID: 47; CharSetName: 'DOS861'; CharSetWidth: 1; CodePage: 861),
263 <  (CharsetID: 48; CharSetName: 'DOS866'; CharSetWidth: 1; CodePage: 866),
264 <  (CharsetID: 49; CharSetName: 'DOS869'; CharSetWidth: 1; CodePage: 869),
265 <  (CharsetID: 50; CharSetName: 'CYRL'; CharSetWidth: 1; CodePage: 1251),
266 <  (CharsetID: 51; CharSetName: 'WIN1250'; CharSetWidth: 1; CodePage: 1250),
267 <  (CharsetID: 52; CharSetName: 'WIN1251'; CharSetWidth: 1; CodePage: 1251),
268 <  (CharsetID: 53; CharSetName: 'WIN1252'; CharSetWidth: 1; CodePage: 1252),
269 <  (CharsetID: 54; CharSetName: 'WIN1253'; CharSetWidth: 1; CodePage: 1253),
270 <  (CharsetID: 55; CharSetName: 'WIN1254'; CharSetWidth: 1; CodePage: 1254),
271 <  (CharsetID: 56; CharSetName: 'BIG_5'; CharSetWidth: 2; CodePage: 950),
272 <  (CharsetID: 57; CharSetName: 'GB_2312'; CharSetWidth: 2; CodePage: 936),
273 <  (CharsetID: 58; CharSetName: 'WIN1255'; CharSetWidth: 1; CodePage: 1255),
274 <  (CharsetID: 59; CharSetName: 'WIN1256'; CharSetWidth: 1; CodePage: 1256),
275 <  (CharsetID: 60; CharSetName: 'WIN1257'; CharSetWidth: 1; CodePage: 1257),
276 <  (CharsetID: 61; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
277 <  (CharsetID: 62; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
278 <  (CharsetID: 63; CharSetName: 'KOI8R'; CharSetWidth: 1; CodePage: 20866),
279 <  (CharsetID: 64; CharSetName: 'KOI8U'; CharSetWidth: 1; CodePage: 21866),
280 <  (CharsetID: 65; CharSetName: 'WIN1258'; CharSetWidth: 1; CodePage: 1258),
281 <  (CharsetID: 66; CharSetName: 'TIS620'; CharSetWidth: 1; CodePage: 874),
282 <  (CharsetID: 67; CharSetName: 'GBK'; CharSetWidth: 2; CodePage: 936),
283 <  (CharsetID: 68; CharSetName: 'CP943C'; CharSetWidth: 2; CodePage: 943),
284 <  (CharsetID: 69; CharSetName: 'GB18030'; CharSetWidth: 4; CodePage: 54936)
285 < );
286 <
287 <  {$IFDEF Unix}
288 <  {SetEnvironmentVariable doesn't exist so we have to use C Library}
289 <  function setenv(name:Pchar; value:Pchar; replace:integer):integer;cdecl;external clib name 'setenv';
290 <  function unsetenv(name:Pchar):integer;cdecl;external clib name 'unsetenv';
291 <  function SetEnvironmentVariable(name:PAnsiChar; value:PAnsiChar):boolean;
292 <  // Set environment variable; if empty string given, remove it.
282 > procedure TFBLibrary.FreeFBLibrary;
283 > begin
284 >  (FFirebirdAPI as TFBClientAPI).FBShutdown;
285 >  if FIBLibrary <> NilHandle then
286 >    FreeLibrary(FIBLibrary);
287 >  FIBLibrary := NilHandle;
288 >  FFBLibraryName := '';
289 > end;
290 >
291 > function TFBLibrary.GetLibraryName: string;
292 > begin
293 >  Result := ExtractFileName(FFBLibraryName);
294 > end;
295 >
296 > function TFBLibrary.GetFirebirdAPI: IFirebirdAPI;
297 > begin
298 >  Result := FFirebirdAPI;
299 > end;
300 >
301 > constructor TFBLibrary.Create(aLibPathName: string);
302 > begin
303 >  inherited Create;
304 >  SetupEnvironment;
305 >  FFBLibraryName := aLibPathName;
306 >  FIBLibrary := NilHandle;
307 >  FFirebirdAPI := GetFirebird3API;
308 >  FRequestedLibName := aLibPathName;
309 >  if aLibPathName <> '' then
310    begin
311 <    result:=false; //assume failure
312 <    if value = '' then
313 <    begin
314 <      // Assume user wants to remove variable.
315 <      if unsetenv(name)=0 then result:=true;
316 <    end
317 <    else
311 >    SetLength(FLibraryList,Length(FLibraryList)+1);
312 >    FLibraryList[Length(FLibraryList)-1] := self;
313 >  end;
314 >  if FFirebirdAPI <> nil then
315 >  begin
316 >    {First try Firebird 3}
317 >    if not LoadIBLibrary or not (FFirebirdAPI as TFBClientAPI).LoadInterface then
318 >      FFirebirdAPI := nil;
319 >  end;
320 >
321 >  if FFirebirdAPI = nil then
322 >  begin
323 >    {now try Firebird 2.5. Under Unix we need to reload the library in case we
324 >     are to use the embedded library}
325 >    FFirebirdAPI := GetLegacyFirebirdAPI;
326 >    if FFirebirdAPI <> nil then
327      begin
328 <      // Non empty so set the variable
329 <      if setenv(name, value, 1)=0 then result:=true;
328 >      {$IFDEF UNIX}
329 >      FreeFBLibrary;
330 >      {$ENDIF}
331 >      if not LoadIBLibrary or not (FFirebirdAPI as TFBClientAPI).LoadInterface then
332 >        FFirebirdAPI := nil;
333      end;
334    end;
335 <  {$ENDIF}
335 >  {Note: FFirebirdAPI will be set to nil if the Firebird API fails to load}
336 > end;
337  
338 < { TFBClientAPI }
338 > destructor TFBLibrary.Destroy;
339 > begin
340 >  FreeFBLibrary;
341 >  FFirebirdAPI := nil;
342 >  inherited Destroy;
343 > end;
344  
345 < constructor TFBClientAPI.Create;
345 > class function TFBLibrary.GetFBLibrary(aLibPathName: string): IFirebirdLibrary;
346 > var i: integer;
347   begin
348 <  inherited Create;
349 <  LoadIBLibrary;
314 <  if (IBLibrary <> NilHandle) then
348 >  Result := nil;
349 >  if aLibPathName <> '' then
350    begin
351 <    SetupEnvironment;
352 <    LoadInterface;
351 >    for i := 0 to Length(FLibraryList) - 1 do
352 >    begin
353 >      if (FLibraryList[i] as TFBLibrary).SameLibrary(aLibPathName) then
354 >      begin
355 >        Result := FLibraryList[i];
356 >        Exit;
357 >      end;
358 >    end;
359 >    Result := Create(aLibPathName);
360    end;
361 <  FirebirdClientAPI := self;
361 >
362   end;
363  
364 < destructor TFBClientAPI.Destroy;
364 > class procedure TFBLibrary.FreeLibraries;
365 > var i: integer;
366   begin
367 <  FirebirdClientAPI := nil;
368 <  if FOwnsIBLibrary and (IBLibrary <> NilHandle) then
369 <    FreeLibrary(IBLibrary);
370 <  IBLibrary := NilHandle;
371 <  inherited Destroy;
367 >  for i := 0 to Length(FLibraryList) - 1 do
368 >    FLibraryList[i] := nil;
369 >  SetLength(FLibraryList,0);
370 > end;
371 >
372 > function TFBLibrary.SameLibrary(aLibName: string): boolean;
373 > begin
374 >  Result := FRequestedLibName = aLibName;
375 > end;
376 >
377 > function TFBLibrary.GetHandle: TLibHandle;
378 > begin
379 >  Result := FIBLibrary;
380 > end;
381 >
382 > { TFBClientAPI }
383 >
384 > constructor TFBClientAPI.Create(aFBLibrary: TFBLibrary);
385 > begin
386 >  inherited Create;
387 >  FFBLibrary := aFBLibrary;
388 >  GetTZDataSettings;
389   end;
390  
391   procedure TFBClientAPI.IBAlloc(var P; OldSize, NewSize: Integer);
# Line 341 | Line 401 | begin
401    raise EIBInterBaseError.Create(GetStatus);
402   end;
403  
344 {Under Unixes, if using an embedded server then set up local TMP and LOCK Directories}
345
346 procedure TFBClientAPI.SetupEnvironment;
347 var TmpDir: AnsiString;
348 begin
349  {$IFDEF UNIX}
350    TmpDir := GetTempDir +
351        DirectorySeparator + 'firebird_' + sysutils.GetEnvironmentVariable('USER');
352    if sysutils.GetEnvironmentVariable('FIREBIRD_TMP') = '' then
353    begin
354      if not DirectoryExists(tmpDir) then
355        mkdir(tmpDir);
356      SetEnvironmentVariable('FIREBIRD_TMP',PAnsiChar(TmpDir));
357    end;
358    if sysutils.GetEnvironmentVariable('FIREBIRD_LOCK') = '' then
359    begin
360      if not DirectoryExists(tmpDir) then
361        mkdir(tmpDir);
362      SetEnvironmentVariable('FIREBIRD_LOCK',PAnsiChar(TmpDir));
363    end;
364  {$ENDIF}
365 end;
366
404   procedure TFBClientAPI.EncodeInteger(aValue: integer; len: integer; buffer: PByte);
405   begin
406    while len > 0 do
# Line 375 | Line 412 | begin
412    end;
413   end;
414  
415 + function TFBClientAPI.Int128ToStr(bufptr: PByte; scale: integer): AnsiString;
416 + begin
417 +  if not HasInt128Support then
418 +    IBError(ibxeNotSupported,[]);
419 + end;
420 +
421 + procedure TFBClientAPI.StrToInt128(scale: integer; aValue: AnsiString; bufptr: PByte);
422 + begin
423 +  if not HasInt128Support then
424 +    IBError(ibxeNotSupported,[]);
425 + end;
426 +
427 + procedure TFBClientAPI.SQLDecFloatEncode(aValue: tBCD; SQLType: cardinal;
428 +  bufptr: PByte);
429 + begin
430 +  if not HasDecFloatSupport then
431 +    IBError(ibxeNotSupported,[]);
432 + end;
433 +
434 + function TFBClientAPI.SQLDecFloatDecode(SQLType: cardinal; bufptr: PByte): tBCD;
435 + begin
436 +  if not HasDecFloatSupport then
437 +    IBError(ibxeNotSupported,[]);
438 + end;
439 +
440   function TFBClientAPI.IsLibraryLoaded: boolean;
441   begin
442 <  Result := IBLibrary <> NilHandle;
442 >  Result := FFBLibrary.IBLibrary <> NilHandle;
443   end;
444  
445 < function TFBClientAPI.GetProcAddr(ProcName: PAnsiChar): Pointer;
445 > function TFBClientAPI.GetFBLibrary: IFirebirdLibrary;
446   begin
447 <  Result := GetProcAddress(IBLibrary, ProcName);
386 <  if not Assigned(Result) then
387 <    raise Exception.CreateFmt(SFirebirdAPIFuncNotFound,[ProcName]);
447 >  Result := FFBLibrary;
448   end;
449  
450 < function TFBClientAPI.GetOverrideLibName: string;
450 > function TFBClientAPI.FBTimeStampToDateTime(aDate, aTime: longint): TDateTime;
451   begin
452 <  Result := '';
453 <  if AllowUseOfFBLIB then
454 <    Result := GetEnvironmentVariable('FBLIB');
455 <  if Result = '' then
452 >  {aDate/aTime are in TTimestamp format but aTime is decimilliseconds}
453 >  aDate := aDate - DateDelta;
454 >  if aDate < 0 then
455 >    Result := trunc(aDate) - abs(frac(aTime / (MSecsPerDay*10)))
456 >  else
457 >    Result := trunc(aDate) + abs(frac(aTime / (MSecsPerDay*10)));
458 > end;
459 >
460 > {$IFDEF UNIX}
461 > procedure TFBClientAPI.GetTZDataSettings;
462 > var S: TStringList;
463 > begin
464 >  FLocalTimeOffset := GetLocalTimeOffset;
465 >  FLocalTimeZoneName := strpas(tzname[tzdaylight]);
466 >  FIsDaylightSavingsTime := tzdaylight;
467 >  if FileExists(DefaultTimeZoneFile) then
468    begin
469 <    if assigned(OnGetLibraryName) then
470 <      OnGetLibraryName(Result)
469 >    S := TStringList.Create;
470 >    try
471 >      S.LoadFromFile(DefaultTimeZoneFile);
472 >      if S.Count > 0 then
473 >        FTZDataTimeZoneID := S[0];
474 >    finally
475 >      S.Free;
476 >    end;
477    end;
478   end;
479 + {$ENDIF}
480  
481 < procedure TFBClientAPI.LoadInterface;
481 > {$IFDEF WINDOWS}
482 > procedure TFBClientAPI.GetTZDataSettings;
483 > var TZInfo: TTimeZoneInformation;
484   begin
485 <  isc_sqlcode := GetProcAddr('isc_sqlcode'); {do not localize}
486 <  isc_sql_interprete := GetProcAddr('isc_sql_interprete'); {do not localize}
487 <  isc_interprete := GetProcAddr('isc_interprete'); {do not localize}
488 <  isc_event_counts := GetProcAddr('isc_event_counts'); {do not localize}
489 <  isc_event_block := GetProcAddr('isc_event_block'); {do not localize}
490 <  isc_free := GetProcAddr('isc_free'); {do not localize}
485 >  FIsDaylightSavingsTime := false;
486 >  {is there any way of working out the default TZData DB time zone ID under Windows?}
487 >  case GetTimeZoneInformation(TZInfo) of
488 >    TIME_ZONE_ID_UNKNOWN:
489 >      begin
490 >        FLocalTimeZoneName := '';
491 >        FLocalTimeOffset := 0;
492 >      end;
493 >    TIME_ZONE_ID_STANDARD:
494 >      begin
495 >        FLocalTimeZoneName := strpas(PWideChar(@TZInfo.StandardName));
496 >        FLocalTimeOffset := TZInfo.Bias;
497 >      end;
498 >    TIME_ZONE_ID_DAYLIGHT:
499 >      begin
500 >        FLocalTimeZoneName := strpas(PWideChar(@TZInfo.DaylightName));
501 >        FLocalTimeOffset := TZInfo.DayLightBias;
502 >        FIsDaylightSavingsTime := true;
503 >      end;
504 >  end;
505   end;
506 + {$ENDIF}
507  
508 < function TFBClientAPI.GetLibraryName: string;
508 > function TFBClientAPI.GetProcAddr(ProcName: PAnsiChar): Pointer;
509   begin
510 <  Result := FFBLibraryName;
510 >  Result := GetProcAddress(FFBLibrary.IBLibrary, ProcName);
511 >  if not Assigned(Result) then
512 >    raise Exception.CreateFmt(SFirebirdAPIFuncNotFound,[ProcName]);
513   end;
514  
515 < function TFBClientAPI.GetCharsetName(CharSetID: integer): AnsiString;
515 > function TFBClientAPI.HasDecFloatSupport: boolean;
516   begin
517 <  Result := '';
420 <  if (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap)) and
421 <                                  (CharSetMap[CharSetID].CharSetID = CharSetID) then
422 <    begin
423 <      Result := CharSetMap[CharSetID].CharSetName;
424 <      Exit;
425 <    end;
517 >  Result := GetClientMajor >= 4;
518   end;
519  
520 < function TFBClientAPI.CharSetID2CodePage(CharSetID: integer;
429 <  var CodePage: TSystemCodePage): boolean;
520 > function TFBClientAPI.HasInt128Support: boolean;
521   begin
522 <  Result := (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap))
432 <               and (CharSetMap[CharSetID].CharSetID = CharSetID);
433 <  if Result then
434 <    begin
435 <      CodePage := CharSetMap[CharSetID].CodePage;
436 <      Result := true;
437 <      Exit;
438 <    end;
522 >  Result := false;
523   end;
524  
525 < function TFBClientAPI.CodePage2CharSetID(CodePage: TSystemCodePage;
442 <  var CharSetID: integer): boolean;
443 < var i: integer;
525 > function TFBClientAPI.HasLocalTZDB: boolean;
526   begin
527    Result := false;
446  for i := Low(CharSetMap) to High(CharSetMap) do
447    if CharSetMap[i].CodePage = CodePage then
448    begin
449      CharSetID := CharSetMap[i].CharSetID;
450      Result := true;
451      Exit;
452    end;
528   end;
529  
530 < function TFBClientAPI.CharSetName2CharSetID(CharSetName: AnsiString;
456 <  var CharSetID: integer): boolean;
457 < var i: integer;
530 > function TFBClientAPI.HasExtendedTZSupport: boolean;
531   begin
532    Result := false;
460  for i := Low(CharSetMap) to High(CharSetMap) do
461    if AnsiCompareStr(CharSetMap[i].CharSetName, CharSetName) = 0 then
462    begin
463      CharSetID := CharSetMap[i].CharSetID;
464      Result := true;
465      Exit;
466    end;
533   end;
534  
535 < function TFBClientAPI.CharSetWidth(CharSetID: integer; var Width: integer
470 <  ): boolean;
535 > function TFBClientAPI.HasTimeZoneSupport: boolean;
536   begin
537 <  Result := (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap))
473 <               and (CharSetMap[CharSetID].CharSetID = CharSetID);
474 <  if Result then
475 <    begin
476 <      Width := CharSetMap[CharSetID].CharSetWidth;
477 <      Result := true;
478 <      Exit;
479 <    end;
537 >  Result := false;
538   end;
539  
540 < const
541 <  IBLocalBufferLength = 512;
542 <  IBBigLocalBufferLength = IBLocalBufferLength * 2;
543 <  IBHugeLocalBufferLength = IBBigLocalBufferLength * 20;
540 > function TFBClientAPI.GetImplementationVersion: AnsiString;
541 > begin
542 >  Result := Format('%d.%d',[GetClientMajor,GetClientMinor]);
543 > end;
544 >
545 > function TFBClientAPI.LoadInterface: boolean;
546 > begin
547 >  isc_sqlcode := GetProcAddr('isc_sqlcode'); {do not localize}
548 >  isc_sql_interprete := GetProcAddr('isc_sql_interprete'); {do not localize}
549 >  isc_event_counts := GetProcAddr('isc_event_counts'); {do not localize}
550 >  isc_event_block := GetProcAddr('isc_event_block'); {do not localize}
551 >  isc_free := GetProcAddr('isc_free'); {do not localize}
552 >  fb_shutdown := GetProcAddr('fb_shutdown'); {do not localize}
553 >  Result := assigned(isc_free);
554 > end;
555 >
556 > procedure TFBClientAPI.FBShutdown;
557 > begin
558 >  if assigned(fb_shutdown) then
559 >    fb_shutdown(0,fb_shutrsn_exit_called);
560 > end;
561  
562   { TFBStatus }
563  
# Line 508 | Line 583 | function TFBStatus.GetMessage: AnsiStrin
583   var local_buffer: array[0..IBHugeLocalBufferLength - 1] of AnsiChar;
584      IBDataBaseErrorMessages: TIBDataBaseErrorMessages;
585      sqlcode: Long;
511    psb: PStatusVector;
586   begin
587    Result := '';
588    IBDataBaseErrorMessages := FIBDataBaseErrorMessages;
# Line 520 | Line 594 | begin
594    if (ShowSQLMessage in IBDataBaseErrorMessages) then
595    begin
596      with FOwner do
597 <      isc_sql_interprete(sqlcode, local_buffer, IBLocalBufferLength);
597 >      isc_sql_interprete(sqlcode, local_buffer, sizeof(local_buffer));
598      if (ShowSQLCode in FIBDataBaseErrorMessages) then
599        Result := Result + CRLF;
600      Result := Result + strpas(local_buffer);
# Line 530 | Line 604 | begin
604    begin
605      if (ShowSQLCode in IBDataBaseErrorMessages) or
606         (ShowSQLMessage in IBDataBaseErrorMessages) then
607 <      Result := Result + CRLF;
608 <    psb := StatusVector;
535 <    with FOwner do
536 <    while (isc_interprete(@local_buffer, @psb) > 0) do
537 <    begin
538 <      if (Result <> '') and (Result[Length(Result)] <> LF) then
539 <        Result := Result + CRLF;
540 <      Result := Result + strpas(local_buffer);
541 <    end;
607 >      Result := Result + LineEnding;
608 >    Result := Result + FOwner.FormatStatus(self);
609    end;
610    if (Result <> '') and (Result[Length(Result)] = '.') then
611      Delete(Result, Length(Result), 1);
# Line 594 | Line 661 | begin
661      LeaveCriticalSection(TFBClientAPI.FIBCS);
662    end;
663   end;
664 +
665   initialization
666 <  TFBClientAPI.IBLibrary := NilHandle;
666 >  TFBLibrary.FEnvSetupDone := false;
667    {$IFNDEF FPC}
668    InitializeCriticalSection(TFBClientAPI.FIBCS);
669    {$ELSE}
# Line 603 | Line 671 | initialization
671    {$ENDIF}
672  
673   finalization
674 +  TFBLibrary.FreeLibraries;
675    {$IFNDEF FPC}
676    DeleteCriticalSection(TFBClientAPI.FIBCS);
677    {$ELSE}
678    DoneCriticalSection(TFBClientAPI.FIBCS);
679    {$ENDIF}
611  if TFBClientAPI.IBLibrary <> NilHandle then
612  begin
613    FreeLibrary(TFBClientAPI.IBLibrary);
614    TFBClientAPI.IBLibrary := NilHandle;
615    TFBClientAPI.FFBLibraryName := '';
616  end;
617
680   end.
681  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines