ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBClientAPI.pas
Revision: 56
Committed: Mon Mar 6 10:20:02 2017 UTC (7 years, 8 months ago) by tony
Content type: text/x-pascal
Original Path: ibx/trunk/fbintf/client/FBClientAPI.pas
File size: 21988 byte(s)
Log Message:
Committing updates for Trunk

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     IB, IBHeader, FBActivityMonitor, FBMessages, IBExternals;
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 56 {$IFNDEF FPC}
94 tony 45 type
95 tony 56 TLibHandle = THandle;
96    
97     const
98     NilHandle = 0;
99     DirectorySeparator = '\';
100     {$ENDIF}
101    
102     type
103 tony 45 TStatusVector = array[0..19] of NativeInt;
104     PStatusVector = ^TStatusVector;
105    
106     TFBClientAPI = class;
107    
108     { TFBStatus }
109    
110     TFBStatus = class(TFBInterfacedObject)
111     private
112     FIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
113     protected
114     FOwner: TFBClientAPI;
115     public
116     constructor Create(aOwner: TFBClientAPI);
117     function StatusVector: PStatusVector; virtual; abstract;
118    
119     {IStatus}
120     function GetIBErrorCode: Long;
121     function Getsqlcode: Long;
122 tony 56 function GetMessage: AnsiString;
123 tony 45 function CheckStatusVector(ErrorCodes: array of TFBStatusCode): Boolean;
124     function GetIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
125     procedure SetIBDataBaseErrorMessages(Value: TIBDataBaseErrorMessages);
126     end;
127    
128     { TFBClientAPI }
129    
130     TFBClientAPI = class(TFBInterfacedObject)
131     private
132     FOwnsIBLibrary: boolean;
133 tony 56 class var FIBCS: TRTLCriticalSection;
134 tony 45 procedure LoadIBLibrary;
135     protected
136 tony 56 class var FFBLibraryName: string;
137     class var IBLibrary: TLibHandle;
138     {$IFDEF WINDOWS}
139     class var FFBLibraryPath: string;
140     {$ENDIF}
141     function GetProcAddr(ProcName: PAnsiChar): Pointer;
142 tony 45 function GetOverrideLibName: string;
143     {$IFDEF UNIX}
144     function GetFirebirdLibList: string; virtual; abstract;
145     {$ENDIF}
146     procedure LoadInterface; virtual;
147     public
148     {Taken from legacy API}
149     isc_sqlcode: Tisc_sqlcode;
150     isc_sql_interprete: Tisc_sql_interprete;
151     isc_interprete: Tisc_interprete;
152     isc_event_counts: Tisc_event_counts;
153     isc_event_block: Tisc_event_block;
154     isc_free: Tisc_free;
155    
156     constructor Create;
157     destructor Destroy; override;
158     procedure IBAlloc(var P; OldSize, NewSize: Integer);
159     procedure IBDataBaseError;
160     procedure SetupEnvironment;
161    
162     {Encode/Decode}
163 tony 56 procedure EncodeInteger(aValue: integer; len: integer; buffer: PByte);
164     function DecodeInteger(bufptr: PByte; len: short): integer; virtual; abstract;
165     procedure SQLEncodeDate(aDate: TDateTime; bufptr: PByte); virtual; abstract;
166     function SQLDecodeDate(byfptr: PByte): TDateTime; virtual; abstract;
167     procedure SQLEncodeTime(aTime: TDateTime; bufptr: PByte); virtual; abstract;
168     function SQLDecodeTime(bufptr: PByte): TDateTime; virtual; abstract;
169     procedure SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte); virtual; abstract;
170     function SQLDecodeDateTime(bufptr: PByte): TDateTime; virtual; abstract;
171 tony 45
172    
173     {IFirebirdAPI}
174     function GetStatus: IStatus; virtual; abstract;
175     function IsLibraryLoaded: boolean;
176     function IsEmbeddedServer: boolean; virtual; abstract;
177     function GetLibraryName: string;
178 tony 56 function GetCharsetName(CharSetID: integer): AnsiString;
179 tony 45 function CharSetID2CodePage(CharSetID: integer; var CodePage: TSystemCodePage): boolean;
180     function CodePage2CharSetID(CodePage: TSystemCodePage; var CharSetID: integer): boolean;
181 tony 56 function CharSetName2CharSetID(CharSetName: AnsiString; var CharSetID: integer): boolean;
182 tony 45 function CharSetWidth(CharSetID: integer; var Width: integer): boolean;
183     end;
184    
185 tony 56 var FirebirdClientAPI: TFBClientAPI = nil;
186 tony 45
187     implementation
188    
189 tony 56 uses IBUtils, Registry, {$IFDEF Unix} initc, {$ENDIF}
190     {$IFDEF FPC}
191 tony 45 {$IFDEF WINDOWS }
192 tony 56 WinDirs,
193 tony 45 {$ENDIF}
194 tony 56 {$ELSE}
195     ShlObj,
196     {$ENDIF}
197 tony 45 SysUtils;
198    
199     {$IFDEF UNIX}
200 tony 56 {$I 'include/uloadlibrary.inc'}
201 tony 45 {$ELSE}
202 tony 56 {$I 'include/wloadlibrary.inc'}
203 tony 45 {$ENDIF}
204    
205     type
206     TCharsetMap = record
207     CharsetID: integer;
208 tony 56 CharSetName: AnsiString;
209 tony 45 CharSetWidth: integer;
210     CodePage: TSystemCodePage;
211     end;
212    
213     const
214     CharSetMap: array [0..69] of TCharsetMap = (
215 tony 47 (CharsetID: 0; CharSetName: 'NONE'; CharSetWidth: 1; CodePage: CP_ACP),
216 tony 45 (CharsetID: 1; CharSetName: 'OCTETS'; CharSetWidth: 1; CodePage: CP_NONE),
217     (CharsetID: 2; CharSetName: 'ASCII'; CharSetWidth: 1; CodePage: CP_ASCII),
218     (CharsetID: 3; CharSetName: 'UNICODE_FSS'; CharSetWidth: 3; CodePage: CP_UTF8),
219     (CharsetID: 4; CharSetName: 'UTF8'; CharSetWidth: 4; CodePage: CP_UTF8),
220     (CharsetID: 5; CharSetName: 'SJIS_0208'; CharSetWidth: 2; CodePage: 20932),
221     (CharsetID: 6; CharSetName: 'EUCJ_0208'; CharSetWidth: 2; CodePage: 20932),
222     (CharsetID: 7; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
223     (CharsetID: 8; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
224     (CharsetID: 9; CharSetName: 'DOS737'; CharSetWidth: 1; CodePage: 737),
225     (CharsetID: 10; CharSetName: 'DOS437'; CharSetWidth: 1; CodePage: 437),
226     (CharsetID: 11; CharSetName: 'DOS850'; CharSetWidth: 1; CodePage: 850),
227     (CharsetID: 12; CharSetName: 'DOS865'; CharSetWidth: 1; CodePage: 865),
228     (CharsetID: 13; CharSetName: 'DOS860'; CharSetWidth: 1; CodePage: 860),
229     (CharsetID: 14; CharSetName: 'DOS863'; CharSetWidth: 1; CodePage: 863),
230     (CharsetID: 15; CharSetName: 'DOS775'; CharSetWidth: 1; CodePage: 775),
231     (CharsetID: 16; CharSetName: 'DOS858'; CharSetWidth: 1; CodePage: 858),
232     (CharsetID: 17; CharSetName: 'DOS862'; CharSetWidth: 1; CodePage: 862),
233     (CharsetID: 18; CharSetName: 'DOS864'; CharSetWidth: 1; CodePage: 864),
234     (CharsetID: 19; CharSetName: 'NEXT'; CharSetWidth: 1; CodePage: CP_NONE),
235     (CharsetID: 20; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
236     (CharsetID: 21; CharSetName: 'ISO8859_1'; CharSetWidth: 1; CodePage: 28591),
237     (CharsetID: 22; CharSetName: 'ISO8859_2'; CharSetWidth: 1; CodePage: 28592),
238     (CharsetID: 23; CharSetName: 'ISO8859_3'; CharSetWidth: 1; CodePage: 28593),
239     (CharsetID: 24; CharSetName: 'Unknown'; CharSetWidth: 0; CodePage: CP_NONE),
240     (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 tony 56 function SetEnvironmentVariable(name:PAnsiChar; value:PAnsiChar):boolean;
292 tony 45 // Set environment variable; if empty string given, remove it.
293     begin
294     result:=false; //assume failure
295     if value = '' then
296     begin
297     // Assume user wants to remove variable.
298     if unsetenv(name)=0 then result:=true;
299     end
300     else
301     begin
302     // Non empty so set the variable
303     if setenv(name, value, 1)=0 then result:=true;
304     end;
305     end;
306     {$ENDIF}
307    
308     { TFBClientAPI }
309    
310     constructor TFBClientAPI.Create;
311     begin
312     inherited Create;
313     LoadIBLibrary;
314     if (IBLibrary <> NilHandle) then
315     begin
316     SetupEnvironment;
317     LoadInterface;
318     end;
319     FirebirdClientAPI := self;
320     end;
321    
322     destructor TFBClientAPI.Destroy;
323     begin
324     FirebirdClientAPI := nil;
325     if FOwnsIBLibrary and (IBLibrary <> NilHandle) then
326 tony 56 FreeLibrary(IBLibrary);
327 tony 45 IBLibrary := NilHandle;
328     inherited Destroy;
329     end;
330    
331     procedure TFBClientAPI.IBAlloc(var P; OldSize, NewSize: Integer);
332     var
333     i: Integer;
334     begin
335     ReallocMem(Pointer(P), NewSize);
336 tony 56 for i := OldSize to NewSize - 1 do PAnsiChar(P)[i] := #0;
337 tony 45 end;
338    
339     procedure TFBClientAPI.IBDataBaseError;
340     begin
341     raise EIBInterBaseError.Create(GetStatus);
342     end;
343    
344     {Under Unixes, if using an embedded server then set up local TMP and LOCK Directories}
345    
346     procedure TFBClientAPI.SetupEnvironment;
347 tony 56 var TmpDir: AnsiString;
348 tony 45 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 tony 56 SetEnvironmentVariable('FIREBIRD_TMP',PAnsiChar(TmpDir));
357 tony 45 end;
358     if sysutils.GetEnvironmentVariable('FIREBIRD_LOCK') = '' then
359     begin
360     if not DirectoryExists(tmpDir) then
361     mkdir(tmpDir);
362 tony 56 SetEnvironmentVariable('FIREBIRD_LOCK',PAnsiChar(TmpDir));
363 tony 45 end;
364     {$ENDIF}
365     end;
366    
367 tony 56 procedure TFBClientAPI.EncodeInteger(aValue: integer; len: integer; buffer: PByte);
368 tony 45 begin
369     while len > 0 do
370     begin
371 tony 56 buffer^ := aValue and $FF;
372 tony 45 Inc(buffer);
373     Dec(len);
374     aValue := aValue shr 8;
375     end;
376     end;
377    
378     function TFBClientAPI.IsLibraryLoaded: boolean;
379     begin
380     Result := IBLibrary <> NilHandle;
381     end;
382    
383 tony 56 function TFBClientAPI.GetProcAddr(ProcName: PAnsiChar): Pointer;
384 tony 45 begin
385     Result := GetProcAddress(IBLibrary, ProcName);
386     if not Assigned(Result) then
387     raise Exception.CreateFmt(SFirebirdAPIFuncNotFound,[ProcName]);
388     end;
389    
390     function TFBClientAPI.GetOverrideLibName: string;
391     begin
392     Result := '';
393     if AllowUseOfFBLIB then
394     Result := GetEnvironmentVariable('FBLIB');
395     if Result = '' then
396     begin
397     if assigned(OnGetLibraryName) then
398     OnGetLibraryName(Result)
399     end;
400     end;
401    
402     procedure TFBClientAPI.LoadInterface;
403     begin
404     isc_sqlcode := GetProcAddr('isc_sqlcode'); {do not localize}
405     isc_sql_interprete := GetProcAddr('isc_sql_interprete'); {do not localize}
406     isc_interprete := GetProcAddr('isc_interprete'); {do not localize}
407     isc_event_counts := GetProcAddr('isc_event_counts'); {do not localize}
408     isc_event_block := GetProcAddr('isc_event_block'); {do not localize}
409     isc_free := GetProcAddr('isc_free'); {do not localize}
410     end;
411    
412     function TFBClientAPI.GetLibraryName: string;
413     begin
414     Result := FFBLibraryName;
415     end;
416    
417 tony 56 function TFBClientAPI.GetCharsetName(CharSetID: integer): AnsiString;
418 tony 45 begin
419     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;
426     end;
427    
428     function TFBClientAPI.CharSetID2CodePage(CharSetID: integer;
429     var CodePage: TSystemCodePage): boolean;
430     begin
431     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;
439     end;
440    
441     function TFBClientAPI.CodePage2CharSetID(CodePage: TSystemCodePage;
442     var CharSetID: integer): boolean;
443     var i: integer;
444     begin
445     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;
453     end;
454    
455 tony 56 function TFBClientAPI.CharSetName2CharSetID(CharSetName: AnsiString;
456 tony 45 var CharSetID: integer): boolean;
457     var i: integer;
458     begin
459     Result := false;
460     for i := Low(CharSetMap) to High(CharSetMap) do
461 tony 56 if AnsiCompareStr(CharSetMap[i].CharSetName, CharSetName) = 0 then
462 tony 45 begin
463     CharSetID := CharSetMap[i].CharSetID;
464     Result := true;
465     Exit;
466     end;
467     end;
468    
469     function TFBClientAPI.CharSetWidth(CharSetID: integer; var Width: integer
470     ): boolean;
471     begin
472     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;
480     end;
481    
482     const
483     IBLocalBufferLength = 512;
484     IBBigLocalBufferLength = IBLocalBufferLength * 2;
485     IBHugeLocalBufferLength = IBBigLocalBufferLength * 20;
486    
487     { TFBStatus }
488    
489     constructor TFBStatus.Create(aOwner: TFBClientAPI);
490     begin
491     inherited Create;
492     FOwner := aOwner;
493     FIBDataBaseErrorMessages := [ShowSQLMessage, ShowIBMessage];
494     end;
495    
496     function TFBStatus.GetIBErrorCode: Long;
497     begin
498     Result := StatusVector^[1];
499     end;
500    
501     function TFBStatus.Getsqlcode: Long;
502     begin
503     with FOwner do
504     Result := isc_sqlcode(PISC_STATUS(StatusVector));
505     end;
506    
507 tony 56 function TFBStatus.GetMessage: AnsiString;
508     var local_buffer: array[0..IBHugeLocalBufferLength - 1] of AnsiChar;
509 tony 45 IBDataBaseErrorMessages: TIBDataBaseErrorMessages;
510     sqlcode: Long;
511     psb: PStatusVector;
512     begin
513     Result := '';
514     IBDataBaseErrorMessages := FIBDataBaseErrorMessages;
515     sqlcode := Getsqlcode;
516     if (ShowSQLCode in IBDataBaseErrorMessages) then
517     Result := Result + 'SQLCODE: ' + IntToStr(sqlcode); {do not localize}
518    
519     Exclude(IBDataBaseErrorMessages, ShowSQLMessage);
520     if (ShowSQLMessage in IBDataBaseErrorMessages) then
521     begin
522     with FOwner do
523     isc_sql_interprete(sqlcode, local_buffer, IBLocalBufferLength);
524     if (ShowSQLCode in FIBDataBaseErrorMessages) then
525     Result := Result + CRLF;
526     Result := Result + strpas(local_buffer);
527     end;
528    
529     if (ShowIBMessage in IBDataBaseErrorMessages) then
530     begin
531     if (ShowSQLCode in IBDataBaseErrorMessages) or
532     (ShowSQLMessage in IBDataBaseErrorMessages) then
533     Result := Result + CRLF;
534     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;
542     end;
543     if (Result <> '') and (Result[Length(Result)] = '.') then
544     Delete(Result, Length(Result), 1);
545     end;
546    
547     function TFBStatus.CheckStatusVector(ErrorCodes: array of TFBStatusCode
548     ): Boolean;
549     var
550     p: PISC_STATUS;
551     i: Integer;
552     procedure NextP(i: Integer);
553     begin
554 tony 56 p := PISC_STATUS(PAnsiChar(p) + (i * SizeOf(ISC_STATUS)));
555 tony 45 end;
556     begin
557     p := PISC_STATUS(StatusVector);
558     result := False;
559     while (p^ <> 0) and (not result) do
560     case p^ of
561     3: NextP(3);
562     1, 4:
563     begin
564     NextP(1);
565     i := 0;
566     while (i <= High(ErrorCodes)) and (not result) do
567     begin
568     result := p^ = ErrorCodes[i];
569     Inc(i);
570     end;
571     NextP(1);
572     end;
573     else
574     NextP(2);
575     end;
576     end;
577    
578     function TFBStatus.GetIBDataBaseErrorMessages: TIBDataBaseErrorMessages;
579     begin
580 tony 56 EnterCriticalSection(TFBClientAPI.FIBCS);
581 tony 45 try
582     result := FIBDataBaseErrorMessages;
583     finally
584 tony 56 LeaveCriticalSection(TFBClientAPI.FIBCS);
585 tony 45 end;
586     end;
587    
588     procedure TFBStatus.SetIBDataBaseErrorMessages(Value: TIBDataBaseErrorMessages);
589     begin
590 tony 56 EnterCriticalSection(TFBClientAPI.FIBCS);
591 tony 45 try
592     FIBDataBaseErrorMessages := Value;
593     finally
594 tony 56 LeaveCriticalSection(TFBClientAPI.FIBCS);
595 tony 45 end;
596     end;
597     initialization
598     TFBClientAPI.IBLibrary := NilHandle;
599 tony 56 {$IFNDEF FPC}
600     InitializeCriticalSection(TFBClientAPI.FIBCS);
601     {$ELSE}
602     InitCriticalSection(TFBClientAPI.FIBCS);
603     {$ENDIF}
604 tony 45
605     finalization
606 tony 56 {$IFNDEF FPC}
607     DeleteCriticalSection(TFBClientAPI.FIBCS);
608     {$ELSE}
609     DoneCriticalSection(TFBClientAPI.FIBCS);
610     {$ENDIF}
611 tony 45 if TFBClientAPI.IBLibrary <> NilHandle then
612     begin
613     FreeLibrary(TFBClientAPI.IBLibrary);
614     TFBClientAPI.IBLibrary := NilHandle;
615     TFBClientAPI.FFBLibraryName := '';
616     end;
617    
618     end.
619