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 47 by tony, Mon Jan 9 15:31:51 2017 UTC vs.
ibx/branches/udr/client/FBClientAPI.pas (file contents), Revision 386 by tony, Tue Jan 18 12:05:35 2022 UTC

# Line 60 | Line 60
60   {                                                                        }
61   {************************************************************************}
62   unit FBClientAPI;
63 + {$IFDEF MSWINDOWS}
64 + {$DEFINE WINDOWS}
65 + {$ENDIF}
66  
67   {$IFDEF FPC}
68   {$mode delphi}
# Line 70 | Line 73 | unit FBClientAPI;
73   interface
74  
75   uses
76 <  Classes,  Dynlibs, IB, IBHeader, FBActivityMonitor, FBMessages, IBExternals;
76 >  Classes,
77 >    {$IFDEF WINDOWS}Windows, {$ENDIF}
78 >    {$IFDEF FPC} Dynlibs, {$ENDIF}
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 84 | Line 90 | FIREBIRD_CLIENT = 'fbclient.dll'; {do no
90   FIREBIRD_EMBEDDED = 'fbembed.dll';
91   {$ENDIF}
92  
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 +    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;
112    PStatusVector              = ^TStatusVector;
# Line 92 | Line 115 | type
115  
116    { TFBStatus }
117  
118 <  TFBStatus = class(TFBInterfacedObject)
118 >  TFBStatus = class(TFBInterfacedObject, IStatus)
119    private
97    FIBCS: TRTLCriticalSection; static;
120      FIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
121 +    FPrefix: AnsiString;
122 +    function SQLCodeSupported: boolean;
123    protected
124      FOwner: TFBClientAPI;
125 +    function GetIBMessage: Ansistring; virtual; abstract;
126 +    function GetSQLMessage: Ansistring;
127    public
128 <    constructor Create(aOwner: TFBClientAPI);
128 >    constructor Create(aOwner: TFBClientAPI; prefix: AnsiString='');
129      function StatusVector: PStatusVector; virtual; abstract;
130 +    procedure Assign(src: TFBStatus); virtual;
131 +    function Clone: IStatus; virtual; abstract;
132  
133      {IStatus}
134 <    function GetIBErrorCode: Long;
135 <    function Getsqlcode: Long;
136 <    function GetMessage: string;
134 >    function GetIBErrorCode: TStatusCode;
135 >    function Getsqlcode: TStatusCode;
136 >    function GetMessage: AnsiString;
137      function CheckStatusVector(ErrorCodes: array of TFBStatusCode): Boolean;
138      function GetIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
139      procedure SetIBDataBaseErrorMessages(Value: TIBDataBaseErrorMessages);
140    end;
141  
142 +  { TFBLibrary }
143 +
144 +  TFBLibrary = class(TFBInterfacedObject,IFirebirdLibrary)
145 +  private
146 +    class var FEnvSetupDone: boolean;
147 +    class var FLibraryList: array of IFirebirdLibrary;
148 +  private
149 +    FFirebirdAPI: IFirebirdAPI;
150 +    FRequestedLibName: string;
151 +    function LoadIBLibrary: boolean;
152 +  protected
153 +    FFBLibraryName: string;
154 +    FIBLibrary: TLibHandle;
155 +    procedure FreeFBLibrary;
156 +    function GetOverrideLibName: string;
157 +    class procedure SetupEnvironment;
158 +  protected
159 +    function GetFirebird3API: IFirebirdAPI; virtual; abstract;
160 +    function GetLegacyFirebirdAPI: IFirebirdAPI; virtual; abstract;
161 +  public
162 +    constructor Create(aLibPathName: string='');
163 +    destructor Destroy; override;
164 +    class function GetFBLibrary(aLibPathName: string): IFirebirdLibrary;
165 +    class procedure FreeLibraries;
166 +    function SameLibrary(aLibName: string): boolean;
167 +
168 +  public
169 +    {IFirebirdLibrary}
170 +    function GetHandle: TLibHandle;
171 +    function GetLibraryName: string;
172 +    function GetLibraryFilePath: string;
173 +    function GetFirebirdAPI: IFirebirdAPI;
174 +    property IBLibrary: TLibHandle read FIBLibrary;
175 +  end;
176 +
177    { TFBClientAPI }
178  
179    TFBClientAPI = class(TFBInterfacedObject)
180    private
181 <    FOwnsIBLibrary: boolean;
182 <    procedure LoadIBLibrary;
181 >    FLocalTimeZoneName: AnsiString; {Informal Time Zone Name from tzname e.g. GMT or BST}
182 >    FTZDataTimeZoneID: AnsiString; {TZData DB ID e.g. Europe/London}
183 >    FLocalTimeOffset: integer;
184 >    FIsDaylightSavingsTime: boolean;
185 >    class var FIBCS: TRTLCriticalSection;
186 >    function FBTimeStampToDateTime(aDate, aTime: longint): TDateTime;
187 >    procedure GetTZDataSettings;
188    protected
189 <    FFBLibraryName: string; static;
190 <    FFBLibraryPath: string; static;
191 <    IBLibrary: TLibHandle; static;
192 <    function GetProcAddr(ProcName: PChar): Pointer;
193 <    function GetOverrideLibName: string;
194 <    {$IFDEF UNIX}
195 <    function GetFirebirdLibList: string; virtual; abstract;
196 <    {$ENDIF}
197 <    procedure LoadInterface; virtual;
189 >    FFBLibrary: TFBLibrary;
190 >    function GetProcAddr(ProcName: PAnsiChar): Pointer;
191 >
192 >  protected type
193 >    Tfb_shutdown = function (timeout: uint;
194 >                                 const reason: int): int;
195 >                   {$IFDEF WINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
196 >  protected
197 >    {FB Shutdown API}
198 >    fb_shutdown: Tfb_shutdown;
199 >
200    public
201      {Taken from legacy API}
132    isc_sqlcode: Tisc_sqlcode;
202      isc_sql_interprete: Tisc_sql_interprete;
203 <    isc_interprete: Tisc_interprete;
135 <    isc_event_counts: Tisc_event_counts;
136 <    isc_event_block: Tisc_event_block;
137 <    isc_free: Tisc_free;
203 >    isc_sqlcode: Tisc_sqlcode;
204  
205 <    constructor Create;
140 <    destructor Destroy; override;
205 >    constructor Create(aFBLibrary: TFBLibrary);
206      procedure IBAlloc(var P; OldSize, NewSize: Integer);
207      procedure IBDataBaseError;
208 <    procedure SetupEnvironment;
208 >    function LoadInterface: boolean; virtual;
209 >    procedure FBShutdown; virtual;
210 >    function GetAPI: IFirebirdAPI; virtual; abstract;
211 >    {$IFDEF UNIX}
212 >    function GetFirebirdLibList: string; virtual; abstract;
213 >    {$ENDIF}
214 >    function HasDecFloatSupport: boolean;
215 >    function HasInt128Support: boolean; virtual;
216 >    function HasLocalTZDB: boolean; virtual;
217 >    function HasExtendedTZSupport: boolean; virtual;
218 >    function HasTimeZoneSupport: boolean; virtual;
219  
220 +  public
221 +    property LocalTimeZoneName: AnsiString read FLocalTimeZoneName;
222 +    property TZDataTimeZoneID: AnsiString read FTZDataTimeZoneID;
223 +    property LocalTimeOffset: integer read FLocalTimeOffset;
224 +  public
225      {Encode/Decode}
226 <    procedure EncodeInteger(aValue: integer; len: integer; buffer: PChar);
227 <    function DecodeInteger(bufptr: PChar; len: short): integer; virtual; abstract;
228 <    procedure SQLEncodeDate(aDate: TDateTime; bufptr: PChar); virtual; abstract;
229 <    function SQLDecodeDate(byfptr: PChar): TDateTime; virtual; abstract;
230 <    procedure SQLEncodeTime(aTime: TDateTime; bufptr: PChar); virtual; abstract;
231 <    function SQLDecodeTime(bufptr: PChar): TDateTime;  virtual; abstract;
232 <    procedure SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PChar); virtual; abstract;
233 <    function SQLDecodeDateTime(bufptr: PChar): TDateTime; virtual; abstract;
234 <
226 >    procedure EncodeInteger(aValue: int64; len: integer; buffer: PByte);
227 >    function DecodeInteger(bufptr: PByte; len: short): int64;
228 >    procedure SQLEncodeDate(aDate: TDateTime; bufptr: PByte);  virtual; abstract;
229 >    function SQLDecodeDate(byfptr: PByte): TDateTime;  virtual; abstract;
230 >    procedure SQLEncodeTime(aTime: TDateTime; bufptr: PByte);  virtual; abstract;
231 >    function SQLDecodeTime(bufptr: PByte): TDateTime;  virtual; abstract;
232 >    procedure SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte); virtual; abstract;
233 >    function  SQLDecodeDateTime(bufptr: PByte): TDateTime; virtual; abstract;
234 >    function Int128ToStr(bufptr: PByte; scale: integer): AnsiString; virtual;
235 >    procedure StrToInt128(scale: integer; aValue: AnsiString; bufptr: PByte);
236 >      virtual;
237 >    procedure SQLDecFloatEncode(aValue: tBCD; SQLType: cardinal; bufptr: PByte); virtual;
238 >    function SQLDecFloatDecode(SQLType: cardinal;  bufptr: PByte): tBCD; virtual;
239  
240      {IFirebirdAPI}
241      function GetStatus: IStatus; virtual; abstract;
242      function IsLibraryLoaded: boolean;
243      function IsEmbeddedServer: boolean; virtual; abstract;
244 <    function GetLibraryName: string;
245 <    function GetCharsetName(CharSetID: integer): string;
246 <    function CharSetID2CodePage(CharSetID: integer; var CodePage: TSystemCodePage): boolean;
247 <    function CodePage2CharSetID(CodePage: TSystemCodePage; var CharSetID: integer): boolean;
164 <    function CharSetName2CharSetID(CharSetName: string; var CharSetID: integer): boolean;
165 <    function CharSetWidth(CharSetID: integer; var Width: integer): boolean;
244 >    function GetFBLibrary: IFirebirdLibrary;
245 >    function GetImplementationVersion: AnsiString;
246 >    function GetClientMajor: integer;  virtual; abstract;
247 >    function GetClientMinor: integer;  virtual; abstract;
248    end;
249  
250 < const FirebirdClientAPI: TFBClientAPI = nil;
250 >    IJournallingHook = interface
251 >      ['{7d3e45e0-3628-416a-9e22-c20474825031}']
252 >      procedure TransactionStart(Tr: ITransaction);
253 >      function TransactionEnd(TransactionID: integer; Action: TTransactionAction): boolean;
254 >      procedure TransactionRetained(Tr: ITransaction; OldTransactionID: integer; Action: TTransactionAction);
255 >      procedure ExecQuery(Stmt: IStatement);
256 >    end;
257  
258   implementation
259  
260 < uses IBUtils, {$IFDEF Unix} initc, {$ENDIF}
260 > uses IBUtils, Registry,
261 >  {$IFDEF Unix} unix, initc, dl, {$ENDIF}
262 > {$IFDEF FPC}
263   {$IFDEF WINDOWS }
264 < Windows,Registry, WinDirs,
264 > WinDirs,
265 > {$ENDIF}
266 > {$ELSE}
267 > ShlObj,
268   {$ENDIF}
269   SysUtils;
270  
271   {$IFDEF UNIX}
272 < {$I uloadlibrary.inc}
272 > {$I 'include/uloadlibrary.inc'}
273   {$ELSE}
274 < {$I wloadlibrary.inc}
274 > {$I 'include/wloadlibrary.inc'}
275   {$ENDIF}
276  
277 < type
278 <  TCharsetMap = record
279 <    CharsetID: integer;
280 <    CharSetName: string;
281 <    CharSetWidth: integer;
282 <    CodePage: TSystemCodePage;
277 >
278 > { TFBLibrary }
279 >
280 > function TFBLibrary.GetOverrideLibName: string;
281 > begin
282 >  Result := FFBLibraryName;
283 >  if (Result = '') and AllowUseOfFBLIB then
284 >    Result := GetEnvironmentVariable('FBLIB');
285 >  if Result = '' then
286 >  begin
287 >    if assigned(OnGetLibraryName) then
288 >      OnGetLibraryName(Result)
289    end;
290 + end;
291  
292 < const
293 <  CharSetMap: array [0..69] of TCharsetMap = (
294 <  (CharsetID: 0; CharSetName: 'NONE'; CharSetWidth: 1; CodePage: CP_ACP),
295 <  (CharsetID: 1; CharSetName: 'OCTETS'; CharSetWidth: 1; CodePage: CP_NONE),
296 <  (CharsetID: 2; CharSetName: 'ASCII'; CharSetWidth: 1; CodePage: CP_ASCII),
297 <  (CharsetID: 3; CharSetName: 'UNICODE_FSS'; CharSetWidth: 3; CodePage: CP_UTF8),
298 <  (CharsetID: 4; CharSetName: 'UTF8'; CharSetWidth: 4; CodePage: CP_UTF8),
299 <  (CharsetID: 5; CharSetName: 'SJIS_0208'; CharSetWidth: 2; CodePage: 20932),
300 <  (CharsetID: 6; CharSetName: 'EUCJ_0208'; CharSetWidth: 2; CodePage: 20932),
301 <  (CharsetID: 7; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
302 <  (CharsetID: 8; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
303 <  (CharsetID: 9; CharSetName: 'DOS737'; CharSetWidth: 1; CodePage: 737),
304 <  (CharsetID: 10; CharSetName: 'DOS437'; CharSetWidth: 1; CodePage: 437),
305 <  (CharsetID: 11; CharSetName: 'DOS850'; CharSetWidth: 1; CodePage: 850),
306 <  (CharsetID: 12; CharSetName: 'DOS865'; CharSetWidth: 1; CodePage: 865),
307 <  (CharsetID: 13; CharSetName: 'DOS860'; CharSetWidth: 1; CodePage: 860),
308 <  (CharsetID: 14; CharSetName: 'DOS863'; CharSetWidth: 1; CodePage: 863),
309 <  (CharsetID: 15; CharSetName: 'DOS775'; CharSetWidth: 1; CodePage: 775),
310 <  (CharsetID: 16; CharSetName: 'DOS858'; CharSetWidth: 1; CodePage: 858),
311 <  (CharsetID: 17; CharSetName: 'DOS862'; CharSetWidth: 1; CodePage: 862),
312 <  (CharsetID: 18; CharSetName: 'DOS864'; CharSetWidth: 1; CodePage: 864),
313 <  (CharsetID: 19; CharSetName: 'NEXT'; CharSetWidth: 1; CodePage: CP_NONE),
314 <  (CharsetID: 20; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
315 <  (CharsetID: 21; CharSetName: 'ISO8859_1'; CharSetWidth: 1; CodePage: 28591),
316 <  (CharsetID: 22; CharSetName: 'ISO8859_2'; CharSetWidth: 1; CodePage: 28592),
317 <  (CharsetID: 23; CharSetName: 'ISO8859_3'; CharSetWidth: 1; CodePage: 28593),
318 <  (CharsetID: 24; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
319 <  (CharsetID: 25; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
220 <  (CharsetID: 26; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
221 <  (CharsetID: 27; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
222 <  (CharsetID: 28; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
223 <  (CharsetID: 29; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
224 <  (CharsetID: 30; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
225 <  (CharsetID: 31; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
226 <  (CharsetID: 32; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
227 <  (CharsetID: 33; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
228 <  (CharsetID: 34; CharSetName: 'ISO8859_4'; CharSetWidth: 1; CodePage: 28594),
229 <  (CharsetID: 35; CharSetName: 'ISO8859_5'; CharSetWidth: 1; CodePage: 28595),
230 <  (CharsetID: 36; CharSetName: 'ISO8859_6'; CharSetWidth: 1; CodePage: 28596),
231 <  (CharsetID: 37; CharSetName: 'ISO8859_7'; CharSetWidth: 1; CodePage: 28597),
232 <  (CharsetID: 38; CharSetName: 'ISO8859_8'; CharSetWidth: 1; CodePage: 28598),
233 <  (CharsetID: 39; CharSetName: 'ISO8859_9'; CharSetWidth: 1; CodePage: 28599),
234 <  (CharsetID: 40; CharSetName: 'ISO8859_13'; CharSetWidth: 1; CodePage: 28603),
235 <  (CharsetID: 41; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
236 <  (CharsetID: 42; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
237 <  (CharsetID: 43; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
238 <  (CharsetID: 44; CharSetName: 'KSC_5601'; CharSetWidth: 2; CodePage: 949),
239 <  (CharsetID: 45; CharSetName: 'DOS852'; CharSetWidth: 1; CodePage: 852),
240 <  (CharsetID: 46; CharSetName: 'DOS857'; CharSetWidth: 1; CodePage: 857),
241 <  (CharsetID: 47; CharSetName: 'DOS861'; CharSetWidth: 1; CodePage: 861),
242 <  (CharsetID: 48; CharSetName: 'DOS866'; CharSetWidth: 1; CodePage: 866),
243 <  (CharsetID: 49; CharSetName: 'DOS869'; CharSetWidth: 1; CodePage: 869),
244 <  (CharsetID: 50; CharSetName: 'CYRL'; CharSetWidth: 1; CodePage: 1251),
245 <  (CharsetID: 51; CharSetName: 'WIN1250'; CharSetWidth: 1; CodePage: 1250),
246 <  (CharsetID: 52; CharSetName: 'WIN1251'; CharSetWidth: 1; CodePage: 1251),
247 <  (CharsetID: 53; CharSetName: 'WIN1252'; CharSetWidth: 1; CodePage: 1252),
248 <  (CharsetID: 54; CharSetName: 'WIN1253'; CharSetWidth: 1; CodePage: 1253),
249 <  (CharsetID: 55; CharSetName: 'WIN1254'; CharSetWidth: 1; CodePage: 1254),
250 <  (CharsetID: 56; CharSetName: 'BIG_5'; CharSetWidth: 2; CodePage: 950),
251 <  (CharsetID: 57; CharSetName: 'GB_2312'; CharSetWidth: 2; CodePage: 936),
252 <  (CharsetID: 58; CharSetName: 'WIN1255'; CharSetWidth: 1; CodePage: 1255),
253 <  (CharsetID: 59; CharSetName: 'WIN1256'; CharSetWidth: 1; CodePage: 1256),
254 <  (CharsetID: 60; CharSetName: 'WIN1257'; CharSetWidth: 1; CodePage: 1257),
255 <  (CharsetID: 61; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
256 <  (CharsetID: 62; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
257 <  (CharsetID: 63; CharSetName: 'KOI8R'; CharSetWidth: 1; CodePage: 20866),
258 <  (CharsetID: 64; CharSetName: 'KOI8U'; CharSetWidth: 1; CodePage: 21866),
259 <  (CharsetID: 65; CharSetName: 'WIN1258'; CharSetWidth: 1; CodePage: 1258),
260 <  (CharsetID: 66; CharSetName: 'TIS620'; CharSetWidth: 1; CodePage: 874),
261 <  (CharsetID: 67; CharSetName: 'GBK'; CharSetWidth: 2; CodePage: 936),
262 <  (CharsetID: 68; CharSetName: 'CP943C'; CharSetWidth: 2; CodePage: 943),
263 <  (CharsetID: 69; CharSetName: 'GB18030'; CharSetWidth: 4; CodePage: 54936)
264 < );
265 <
266 <  {$IFDEF Unix}
267 <  {SetEnvironmentVariable doesn't exist so we have to use C Library}
268 <  function setenv(name:Pchar; value:Pchar; replace:integer):integer;cdecl;external clib name 'setenv';
269 <  function unsetenv(name:Pchar):integer;cdecl;external clib name 'unsetenv';
270 <  function SetEnvironmentVariable(name:PChar; value:PChar):boolean;
271 <  // Set environment variable; if empty string given, remove it.
292 > procedure TFBLibrary.FreeFBLibrary;
293 > begin
294 >  (FFirebirdAPI as TFBClientAPI).FBShutdown;
295 >  if FIBLibrary <> NilHandle then
296 >    FreeLibrary(FIBLibrary);
297 >  FIBLibrary := NilHandle;
298 >  FFBLibraryName := '';
299 > end;
300 >
301 > function TFBLibrary.GetLibraryName: string;
302 > begin
303 >  Result := ExtractFileName(FFBLibraryName);
304 > end;
305 >
306 > function TFBLibrary.GetFirebirdAPI: IFirebirdAPI;
307 > begin
308 >  Result := FFirebirdAPI;
309 > end;
310 >
311 > constructor TFBLibrary.Create(aLibPathName: string);
312 > begin
313 >  inherited Create;
314 >  SetupEnvironment;
315 >  FFBLibraryName := aLibPathName;
316 >  FIBLibrary := NilHandle;
317 >  FFirebirdAPI := GetFirebird3API;
318 >  FRequestedLibName := aLibPathName;
319 >  if aLibPathName <> '' then
320    begin
321 <    result:=false; //assume failure
322 <    if value = '' then
323 <    begin
324 <      // Assume user wants to remove variable.
325 <      if unsetenv(name)=0 then result:=true;
326 <    end
327 <    else
321 >    SetLength(FLibraryList,Length(FLibraryList)+1);
322 >    FLibraryList[Length(FLibraryList)-1] := self;
323 >  end;
324 >  if FFirebirdAPI <> nil then
325 >  begin
326 >    {First try Firebird 3}
327 >    if not LoadIBLibrary or not (FFirebirdAPI as TFBClientAPI).LoadInterface then
328 >      FFirebirdAPI := nil;
329 >  end;
330 >
331 >  if FFirebirdAPI = nil then
332 >  begin
333 >    {now try Firebird 2.5. Under Unix we need to reload the library in case we
334 >     are to use the embedded library}
335 >    FFirebirdAPI := GetLegacyFirebirdAPI;
336 >    if FFirebirdAPI <> nil then
337      begin
338 <      // Non empty so set the variable
339 <      if setenv(name, value, 1)=0 then result:=true;
338 >      {$IFDEF UNIX}
339 >      FreeFBLibrary;
340 >      {$ENDIF}
341 >      if not LoadIBLibrary or not (FFirebirdAPI as TFBClientAPI).LoadInterface then
342 >        FFirebirdAPI := nil;
343      end;
344    end;
345 <  {$ENDIF}
345 >  {Note: FFirebirdAPI will be set to nil if the Firebird API fails to load}
346 > end;
347  
348 < { TFBClientAPI }
348 > destructor TFBLibrary.Destroy;
349 > begin
350 >  FreeFBLibrary;
351 >  FFirebirdAPI := nil;
352 >  inherited Destroy;
353 > end;
354  
355 < constructor TFBClientAPI.Create;
355 > class function TFBLibrary.GetFBLibrary(aLibPathName: string): IFirebirdLibrary;
356 > var i: integer;
357   begin
358 <  inherited Create;
359 <  LoadIBLibrary;
293 <  if (IBLibrary <> NilHandle) then
358 >  Result := nil;
359 >  if aLibPathName <> '' then
360    begin
361 <    SetupEnvironment;
362 <    LoadInterface;
361 >    for i := 0 to Length(FLibraryList) - 1 do
362 >    begin
363 >      if (FLibraryList[i] as TFBLibrary).SameLibrary(aLibPathName) then
364 >      begin
365 >        Result := FLibraryList[i];
366 >        Exit;
367 >      end;
368 >    end;
369 >    Result := Create(aLibPathName);
370    end;
371 <  FirebirdClientAPI := self;
371 >
372   end;
373  
374 < destructor TFBClientAPI.Destroy;
374 > class procedure TFBLibrary.FreeLibraries;
375 > var i: integer;
376   begin
377 <  FirebirdClientAPI := nil;
378 <  if FOwnsIBLibrary and (IBLibrary <> NilHandle) then
379 <    UnloadLibrary(IBLibrary);
380 <  IBLibrary := NilHandle;
381 <  inherited Destroy;
377 >  for i := 0 to Length(FLibraryList) - 1 do
378 >    FLibraryList[i] := nil;
379 >  SetLength(FLibraryList,0);
380 > end;
381 >
382 > function TFBLibrary.SameLibrary(aLibName: string): boolean;
383 > begin
384 >  Result := FRequestedLibName = aLibName;
385 > end;
386 >
387 > function TFBLibrary.GetHandle: TLibHandle;
388 > begin
389 >  Result := FIBLibrary;
390 > end;
391 >
392 > { TFBClientAPI }
393 >
394 > constructor TFBClientAPI.Create(aFBLibrary: TFBLibrary);
395 > begin
396 >  inherited Create;
397 >  FFBLibrary := aFBLibrary;
398 >  GetTZDataSettings;
399   end;
400  
401   procedure TFBClientAPI.IBAlloc(var P; OldSize, NewSize: Integer);
# Line 312 | Line 403 | var
403    i: Integer;
404   begin
405    ReallocMem(Pointer(P), NewSize);
406 <  for i := OldSize to NewSize - 1 do PChar(P)[i] := #0;
406 >  for i := OldSize to NewSize - 1 do PAnsiChar(P)[i] := #0;
407   end;
408  
409   procedure TFBClientAPI.IBDataBaseError;
# Line 320 | Line 411 | begin
411    raise EIBInterBaseError.Create(GetStatus);
412   end;
413  
414 < {Under Unixes, if using an embedded server then set up local TMP and LOCK Directories}
324 <
325 < procedure TFBClientAPI.SetupEnvironment;
326 < var TmpDir: string;
327 < begin
328 <  {$IFDEF UNIX}
329 <    TmpDir := GetTempDir +
330 <        DirectorySeparator + 'firebird_' + sysutils.GetEnvironmentVariable('USER');
331 <    if sysutils.GetEnvironmentVariable('FIREBIRD_TMP') = '' then
332 <    begin
333 <      if not DirectoryExists(tmpDir) then
334 <        mkdir(tmpDir);
335 <      SetEnvironmentVariable('FIREBIRD_TMP',PChar(TmpDir));
336 <    end;
337 <    if sysutils.GetEnvironmentVariable('FIREBIRD_LOCK') = '' then
338 <    begin
339 <      if not DirectoryExists(tmpDir) then
340 <        mkdir(tmpDir);
341 <      SetEnvironmentVariable('FIREBIRD_LOCK',PChar(TmpDir));
342 <    end;
343 <  {$ENDIF}
344 < end;
345 <
346 < procedure TFBClientAPI.EncodeInteger(aValue: integer; len: integer; buffer: PChar);
414 > procedure TFBClientAPI.EncodeInteger(aValue: int64; len: integer; buffer: PByte);
415   begin
416    while len > 0 do
417    begin
418 <    buffer^ := char(aValue and $FF);
418 >    buffer^ := aValue and $FF;
419      Inc(buffer);
420      Dec(len);
421      aValue := aValue shr 8;
422    end;
423   end;
424  
425 + (*
426 +  DecodeInteger is Translated from
427 +
428 + SINT64 API_ROUTINE isc_portable_integer(const UCHAR* ptr, SSHORT length)
429 + if (!ptr || length <= 0 || length > 8)
430 +        return 0;
431 +
432 + SINT64 value = 0;
433 + int shift = 0;
434 +
435 + while (--length > 0)
436 + {
437 +        value += ((SINT64) *ptr++) << shift;
438 +        shift += 8;
439 + }
440 +
441 + value += ((SINT64)(SCHAR) *ptr) << shift;
442 +
443 + return value;
444 + *)
445 +
446 + function TFBClientAPI.DecodeInteger(bufptr: PByte; len: short): int64;
447 + var shift: integer;
448 + begin
449 +  Result := 0;
450 +  if (BufPtr = nil) or (len <= 0) or (len > 8) then
451 +    Exit;
452 +
453 +  shift := 0;
454 +  dec(len);
455 +  while len > 0 do
456 +  begin
457 +    Result := Result + (int64(bufptr^) shl shift);
458 +    Inc(bufptr);
459 +    shift := shift + 8;
460 +    dec(len);
461 +  end;
462 +  Result := Result + (int64(bufptr^) shl shift);
463 + end;
464 +
465 + function TFBClientAPI.Int128ToStr(bufptr: PByte; scale: integer): AnsiString;
466 + begin
467 +  if not HasInt128Support then
468 +    IBError(ibxeNotSupported,[]);
469 + end;
470 +
471 + procedure TFBClientAPI.StrToInt128(scale: integer; aValue: AnsiString; bufptr: PByte);
472 + begin
473 +  if not HasInt128Support then
474 +    IBError(ibxeNotSupported,[]);
475 + end;
476 +
477 + procedure TFBClientAPI.SQLDecFloatEncode(aValue: tBCD; SQLType: cardinal;
478 +  bufptr: PByte);
479 + begin
480 +  if not HasDecFloatSupport then
481 +    IBError(ibxeNotSupported,[]);
482 + end;
483 +
484 + function TFBClientAPI.SQLDecFloatDecode(SQLType: cardinal; bufptr: PByte): tBCD;
485 + begin
486 +  if not HasDecFloatSupport then
487 +    IBError(ibxeNotSupported,[]);
488 + end;
489 +
490   function TFBClientAPI.IsLibraryLoaded: boolean;
491   begin
492 <  Result := IBLibrary <> NilHandle;
492 >  Result := FFBLibrary.IBLibrary <> NilHandle;
493   end;
494  
495 < function TFBClientAPI.GetProcAddr(ProcName: PChar): Pointer;
495 > function TFBClientAPI.GetFBLibrary: IFirebirdLibrary;
496   begin
497 <  Result := GetProcAddress(IBLibrary, ProcName);
365 <  if not Assigned(Result) then
366 <    raise Exception.CreateFmt(SFirebirdAPIFuncNotFound,[ProcName]);
497 >  Result := FFBLibrary;
498   end;
499  
500 < function TFBClientAPI.GetOverrideLibName: string;
500 > function TFBClientAPI.FBTimeStampToDateTime(aDate, aTime: longint): TDateTime;
501   begin
502 <  Result := '';
503 <  if AllowUseOfFBLIB then
504 <    Result := GetEnvironmentVariable('FBLIB');
505 <  if Result = '' then
502 >  {aDate/aTime are in TTimestamp format but aTime is decimilliseconds}
503 >  aDate := aDate - DateDelta;
504 >  if aDate < 0 then
505 >    Result := trunc(aDate) - abs(frac(aTime / (MSecsPerDay*10)))
506 >  else
507 >    Result := trunc(aDate) + abs(frac(aTime / (MSecsPerDay*10)));
508 > end;
509 >
510 > {$IFDEF UNIX}
511 >
512 > procedure TFBClientAPI.GetTZDataSettings;
513 > var S: TStringList;
514 > begin
515 >  FLocalTimeOffset := GetLocalTimeOffset;
516 >  {$if declared(Gettzname)}
517 >  FLocalTimeZoneName := Gettzname(tzdaylight);
518 >  {$else}
519 >  FLocalTimeZoneName := tzname[tzdaylight];
520 >  {$ifend}
521 >  FIsDaylightSavingsTime := tzdaylight;
522 >  if FileExists(DefaultTimeZoneFile) then
523    begin
524 <    if assigned(OnGetLibraryName) then
525 <      OnGetLibraryName(Result)
524 >    S := TStringList.Create;
525 >    try
526 >      S.LoadFromFile(DefaultTimeZoneFile);
527 >      if S.Count > 0 then
528 >        FTZDataTimeZoneID := S[0];
529 >    finally
530 >      S.Free;
531 >    end;
532    end;
533   end;
534 + {$ENDIF}
535  
536 < procedure TFBClientAPI.LoadInterface;
536 > {$IFDEF WINDOWS}
537 > procedure TFBClientAPI.GetTZDataSettings;
538 > var TZInfo: TTimeZoneInformation;
539   begin
540 <  isc_sqlcode := GetProcAddr('isc_sqlcode'); {do not localize}
541 <  isc_sql_interprete := GetProcAddr('isc_sql_interprete'); {do not localize}
542 <  isc_interprete := GetProcAddr('isc_interprete'); {do not localize}
543 <  isc_event_counts := GetProcAddr('isc_event_counts'); {do not localize}
544 <  isc_event_block := GetProcAddr('isc_event_block'); {do not localize}
545 <  isc_free := GetProcAddr('isc_free'); {do not localize}
540 >  FIsDaylightSavingsTime := false;
541 >  {is there any way of working out the default TZData DB time zone ID under Windows?}
542 >  case GetTimeZoneInformation(TZInfo) of
543 >    TIME_ZONE_ID_UNKNOWN:
544 >      begin
545 >        FLocalTimeZoneName := '';
546 >        FLocalTimeOffset := 0;
547 >      end;
548 >    TIME_ZONE_ID_STANDARD:
549 >      begin
550 >        FLocalTimeZoneName := strpas(PWideChar(@TZInfo.StandardName));
551 >        FLocalTimeOffset := TZInfo.Bias;
552 >      end;
553 >    TIME_ZONE_ID_DAYLIGHT:
554 >      begin
555 >        FLocalTimeZoneName := strpas(PWideChar(@TZInfo.DaylightName));
556 >        FLocalTimeOffset := TZInfo.DayLightBias;
557 >        FIsDaylightSavingsTime := true;
558 >      end;
559 >  end;
560   end;
561 + {$ENDIF}
562  
563 < function TFBClientAPI.GetLibraryName: string;
563 > function TFBClientAPI.GetProcAddr(ProcName: PAnsiChar): Pointer;
564   begin
565 <  Result := FFBLibraryName;
565 >  Result := nil;
566 >  if assigned(FFBLibrary) and (FFBLibrary.IBLibrary <> NilHandle) then
567 >    Result := GetProcAddress(FFBLibrary.IBLibrary, ProcName);
568 >  if not Assigned(Result) then
569 >    raise Exception.CreateFmt(SFirebirdAPIFuncNotFound,[ProcName]);
570   end;
571  
572 < function TFBClientAPI.GetCharsetName(CharSetID: integer): string;
572 > function TFBClientAPI.HasDecFloatSupport: boolean;
573   begin
574 <  Result := '';
399 <  if (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap)) and
400 <                                  (CharSetMap[CharSetID].CharSetID = CharSetID) then
401 <    begin
402 <      Result := CharSetMap[CharSetID].CharSetName;
403 <      Exit;
404 <    end;
574 >  Result := GetClientMajor >= 4;
575   end;
576  
577 < function TFBClientAPI.CharSetID2CodePage(CharSetID: integer;
408 <  var CodePage: TSystemCodePage): boolean;
577 > function TFBClientAPI.HasInt128Support: boolean;
578   begin
579 <  Result := (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap))
411 <               and (CharSetMap[CharSetID].CharSetID = CharSetID);
412 <  if Result then
413 <    begin
414 <      CodePage := CharSetMap[CharSetID].CodePage;
415 <      Result := true;
416 <      Exit;
417 <    end;
579 >  Result := false;
580   end;
581  
582 < function TFBClientAPI.CodePage2CharSetID(CodePage: TSystemCodePage;
421 <  var CharSetID: integer): boolean;
422 < var i: integer;
582 > function TFBClientAPI.HasLocalTZDB: boolean;
583   begin
584    Result := false;
425  for i := Low(CharSetMap) to High(CharSetMap) do
426    if CharSetMap[i].CodePage = CodePage then
427    begin
428      CharSetID := CharSetMap[i].CharSetID;
429      Result := true;
430      Exit;
431    end;
585   end;
586  
587 < function TFBClientAPI.CharSetName2CharSetID(CharSetName: string;
435 <  var CharSetID: integer): boolean;
436 < var i: integer;
587 > function TFBClientAPI.HasExtendedTZSupport: boolean;
588   begin
589    Result := false;
439  for i := Low(CharSetMap) to High(CharSetMap) do
440    if CompareStr(CharSetMap[i].CharSetName, CharSetName) = 0 then
441    begin
442      CharSetID := CharSetMap[i].CharSetID;
443      Result := true;
444      Exit;
445    end;
590   end;
591  
592 < function TFBClientAPI.CharSetWidth(CharSetID: integer; var Width: integer
449 <  ): boolean;
592 > function TFBClientAPI.HasTimeZoneSupport: boolean;
593   begin
594 <  Result := (CharSetID >= Low(CharSetMap)) and (CharSetID <= High(CharSetMap))
452 <               and (CharSetMap[CharSetID].CharSetID = CharSetID);
453 <  if Result then
454 <    begin
455 <      Width := CharSetMap[CharSetID].CharSetWidth;
456 <      Result := true;
457 <      Exit;
458 <    end;
594 >  Result := false;
595   end;
596  
597 < const
598 <  IBLocalBufferLength = 512;
599 <  IBBigLocalBufferLength = IBLocalBufferLength * 2;
600 <  IBHugeLocalBufferLength = IBBigLocalBufferLength * 20;
597 > function TFBClientAPI.GetImplementationVersion: AnsiString;
598 > begin
599 >  Result := Format('%d.%d',[GetClientMajor,GetClientMinor]);
600 > end;
601 >
602 > function TFBClientAPI.LoadInterface: boolean;
603 > begin
604 >  isc_sqlcode := GetProcAddr('isc_sqlcode'); {do not localize}
605 >  isc_sql_interprete := GetProcAddr('isc_sql_interprete'); {do not localize}
606 >  fb_shutdown := GetProcAddr('fb_shutdown'); {do not localize}
607 >  Result := true; {don't case if these fail to load}
608 > end;
609 >
610 > procedure TFBClientAPI.FBShutdown;
611 > begin
612 >  if assigned(fb_shutdown) then
613 >    fb_shutdown(0,fb_shutrsn_exit_called);
614 > end;
615  
616   { TFBStatus }
617  
618 < constructor TFBStatus.Create(aOwner: TFBClientAPI);
618 > function TFBStatus.SQLCodeSupported: boolean;
619 > begin
620 >  Result:= (FOwner <> nil) and assigned(FOwner.isc_sqlcode) and  assigned(FOwner.isc_sql_interprete);
621 > end;
622 >
623 > function TFBStatus.GetSQLMessage: Ansistring;
624 > var local_buffer: array[0..IBHugeLocalBufferLength - 1] of AnsiChar;
625 > begin
626 >  Result := '';
627 >  if (FOwner <> nil) and assigned(FOwner.isc_sql_interprete) then
628 >  begin
629 >     FOwner.isc_sql_interprete(Getsqlcode, local_buffer, sizeof(local_buffer));
630 >     Result := strpas(local_buffer);
631 >  end;
632 > end;
633 >
634 > constructor TFBStatus.Create(aOwner: TFBClientAPI; prefix: AnsiString);
635   begin
636    inherited Create;
637    FOwner := aOwner;
638 <  FIBDataBaseErrorMessages := [ShowSQLMessage, ShowIBMessage];
638 >  FPrefix := prefix;
639 >  FIBDataBaseErrorMessages := [ShowIBMessage];
640 > end;
641 >
642 > procedure TFBStatus.Assign(src: TFBStatus);
643 > begin
644 >  FOwner := src.FOwner;
645 >  FPrefix := src.FPrefix;
646 >  SetIBDataBaseErrorMessages(src.GetIBDataBaseErrorMessages);
647   end;
648  
649 < function TFBStatus.GetIBErrorCode: Long;
649 > function TFBStatus.GetIBErrorCode: TStatusCode;
650   begin
651    Result := StatusVector^[1];
652   end;
653  
654 < function TFBStatus.Getsqlcode: Long;
654 > function TFBStatus.Getsqlcode: TStatusCode;
655   begin
656 <  with FOwner do
657 <    Result := isc_sqlcode(PISC_STATUS(StatusVector));
656 >  if (FOwner <> nil) and assigned(FOwner.isc_sqlcode) then
657 >    Result := FOwner.isc_sqlcode(PISC_STATUS(StatusVector))
658 >  else
659 >    Result := -999; {generic SQL Code}
660   end;
661  
662 < function TFBStatus.GetMessage: string;
663 < var local_buffer: array[0..IBHugeLocalBufferLength - 1] of char;
488 <    IBDataBaseErrorMessages: TIBDataBaseErrorMessages;
489 <    sqlcode: Long;
490 <    psb: PStatusVector;
662 > function TFBStatus.GetMessage: AnsiString;
663 > var IBDataBaseErrorMessages: TIBDataBaseErrorMessages;
664   begin
665 <  Result := '';
665 >  Result := FPrefix;
666    IBDataBaseErrorMessages := FIBDataBaseErrorMessages;
667 <  sqlcode := Getsqlcode;
668 <  if (ShowSQLCode in IBDataBaseErrorMessages) then
669 <    Result := Result + 'SQLCODE: ' + IntToStr(sqlcode); {do not localize}
670 <
671 <  Exclude(IBDataBaseErrorMessages, ShowSQLMessage);
672 <  if (ShowSQLMessage in IBDataBaseErrorMessages) then
673 <  begin
674 <    with FOwner do
675 <      isc_sql_interprete(sqlcode, local_buffer, IBLocalBufferLength);
676 <    if (ShowSQLCode in FIBDataBaseErrorMessages) then
677 <      Result := Result + CRLF;
505 <    Result := Result + strpas(local_buffer);
667 >  if SQLCodeSupported then
668 >  begin
669 >    if (ShowSQLCode in IBDataBaseErrorMessages) then
670 >      Result := Result + 'SQLCODE: ' + IntToStr(Getsqlcode); {do not localize}
671 >
672 >    if (ShowSQLMessage in IBDataBaseErrorMessages) then
673 >    begin
674 >      if ShowSQLCode in IBDataBaseErrorMessages then
675 >        Result := Result + LineEnding;
676 >      Result := Result + GetSQLMessage;
677 >    end;
678    end;
679  
680    if (ShowIBMessage in IBDataBaseErrorMessages) then
681    begin
682 <    if (ShowSQLCode in IBDataBaseErrorMessages) or
683 <       (ShowSQLMessage in IBDataBaseErrorMessages) then
684 <      Result := Result + CRLF;
513 <    psb := StatusVector;
514 <    with FOwner do
515 <    while (isc_interprete(@local_buffer, @psb) > 0) do
516 <    begin
517 <      if (Result <> '') and (Result[Length(Result)] <> LF) then
518 <        Result := Result + CRLF;
519 <      Result := Result + strpas(local_buffer);
520 <    end;
682 >    if Result <> FPrefix then
683 >      Result := Result + LineEnding;
684 >    Result := Result + 'Engine Code: ' + IntToStr(GetIBErrorCode) + LineEnding + GetIBMessage;
685    end;
686    if (Result <> '') and (Result[Length(Result)] = '.') then
687      Delete(Result, Length(Result), 1);
# Line 530 | Line 694 | var
694    i: Integer;
695    procedure NextP(i: Integer);
696    begin
697 <    p := PISC_STATUS(PChar(p) + (i * SizeOf(ISC_STATUS)));
697 >    p := PISC_STATUS(PAnsiChar(p) + (i * SizeOf(ISC_STATUS)));
698    end;
699   begin
700    p := PISC_STATUS(StatusVector);
# Line 556 | Line 720 | end;
720  
721   function TFBStatus.GetIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
722   begin
723 <  EnterCriticalSection(FIBCS);
723 >  EnterCriticalSection(TFBClientAPI.FIBCS);
724    try
725      result := FIBDataBaseErrorMessages;
726    finally
727 <    LeaveCriticalSection(FIBCS);
727 >    LeaveCriticalSection(TFBClientAPI.FIBCS);
728    end;
729   end;
730  
731   procedure TFBStatus.SetIBDataBaseErrorMessages(Value: TIBDataBaseErrorMessages);
732   begin
733 <  EnterCriticalSection(FIBCS);
733 >  EnterCriticalSection(TFBClientAPI.FIBCS);
734    try
735      FIBDataBaseErrorMessages := Value;
736    finally
737 <    LeaveCriticalSection(FIBCS);
737 >    LeaveCriticalSection(TFBClientAPI.FIBCS);
738    end;
739   end;
740 +
741   initialization
742 <  TFBClientAPI.IBLibrary := NilHandle;
743 <  InitCriticalSection(TFBStatus.FIBCS);
742 >  TFBLibrary.FEnvSetupDone := false;
743 >  {$IFNDEF FPC}
744 >  InitializeCriticalSection(TFBClientAPI.FIBCS);
745 >  {$ELSE}
746 >  InitCriticalSection(TFBClientAPI.FIBCS);
747 >  {$ENDIF}
748  
749   finalization
750 <  DoneCriticalSection(TFBStatus.FIBCS);
751 <  if TFBClientAPI.IBLibrary <> NilHandle then
752 <  begin
753 <    FreeLibrary(TFBClientAPI.IBLibrary);
754 <    TFBClientAPI.IBLibrary := NilHandle;
755 <    TFBClientAPI.FFBLibraryName := '';
587 <  end;
588 <
750 >  TFBLibrary.FreeLibraries;
751 >  {$IFNDEF FPC}
752 >  DeleteCriticalSection(TFBClientAPI.FIBCS);
753 >  {$ELSE}
754 >  DoneCriticalSection(TFBClientAPI.FIBCS);
755 >  {$ENDIF}
756   end.
757  

Comparing:
ibx/trunk/fbintf/client/FBClientAPI.pas (property svn:eol-style), Revision 47 by tony, Mon Jan 9 15:31:51 2017 UTC vs.
ibx/branches/udr/client/FBClientAPI.pas (property svn:eol-style), Revision 386 by tony, Tue Jan 18 12:05:35 2022 UTC

# Line 0 | Line 1
1 + native

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines