ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/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
File size: 21988 byte(s)
Log Message:
Committing updates for Trunk

File Contents

# Content
1 (*
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 {$IFDEF MSWINDOWS}
64 {$DEFINE WINDOWS}
65 {$ENDIF}
66
67 {$IFDEF FPC}
68 {$mode delphi}
69 {$codepage UTF8}
70 {$interfaces COM}
71 {$ENDIF}
72
73 interface
74
75 uses
76 Classes,
77 {$IFDEF WINDOWS}Windows, {$ENDIF}
78 {$IFDEF FPC} Dynlibs, {$ENDIF}
79 IB, IBHeader, FBActivityMonitor, FBMessages, IBExternals;
80
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 {$IFNDEF FPC}
94 type
95 TLibHandle = THandle;
96
97 const
98 NilHandle = 0;
99 DirectorySeparator = '\';
100 {$ENDIF}
101
102 type
103 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 function GetMessage: AnsiString;
123 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 class var FIBCS: TRTLCriticalSection;
134 procedure LoadIBLibrary;
135 protected
136 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 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 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
172
173 {IFirebirdAPI}
174 function GetStatus: IStatus; virtual; abstract;
175 function IsLibraryLoaded: boolean;
176 function IsEmbeddedServer: boolean; virtual; abstract;
177 function GetLibraryName: string;
178 function GetCharsetName(CharSetID: integer): AnsiString;
179 function CharSetID2CodePage(CharSetID: integer; var CodePage: TSystemCodePage): boolean;
180 function CodePage2CharSetID(CodePage: TSystemCodePage; var CharSetID: integer): boolean;
181 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;
186
187 implementation
188
189 uses IBUtils, Registry, {$IFDEF Unix} initc, {$ENDIF}
190 {$IFDEF FPC}
191 {$IFDEF WINDOWS }
192 WinDirs,
193 {$ENDIF}
194 {$ELSE}
195 ShlObj,
196 {$ENDIF}
197 SysUtils;
198
199 {$IFDEF UNIX}
200 {$I 'include/uloadlibrary.inc'}
201 {$ELSE}
202 {$I 'include/wloadlibrary.inc'}
203 {$ENDIF}
204
205 type
206 TCharsetMap = record
207 CharsetID: integer;
208 CharSetName: AnsiString;
209 CharSetWidth: integer;
210 CodePage: TSystemCodePage;
211 end;
212
213 const
214 CharSetMap: array [0..69] of TCharsetMap = (
215 (CharsetID: 0; CharSetName: 'NONE'; CharSetWidth: 1; CodePage: CP_ACP),
216 (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 function SetEnvironmentVariable(name:PAnsiChar; value:PAnsiChar):boolean;
292 // 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 FreeLibrary(IBLibrary);
327 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 for i := OldSize to NewSize - 1 do PAnsiChar(P)[i] := #0;
337 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 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
367 procedure TFBClientAPI.EncodeInteger(aValue: integer; len: integer; buffer: PByte);
368 begin
369 while len > 0 do
370 begin
371 buffer^ := aValue and $FF;
372 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 function TFBClientAPI.GetProcAddr(ProcName: PAnsiChar): Pointer;
384 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 function TFBClientAPI.GetCharsetName(CharSetID: integer): AnsiString;
418 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 function TFBClientAPI.CharSetName2CharSetID(CharSetName: AnsiString;
456 var CharSetID: integer): boolean;
457 var i: integer;
458 begin
459 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;
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 function TFBStatus.GetMessage: AnsiString;
508 var local_buffer: array[0..IBHugeLocalBufferLength - 1] of AnsiChar;
509 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 p := PISC_STATUS(PAnsiChar(p) + (i * SizeOf(ISC_STATUS)));
555 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 EnterCriticalSection(TFBClientAPI.FIBCS);
581 try
582 result := FIBDataBaseErrorMessages;
583 finally
584 LeaveCriticalSection(TFBClientAPI.FIBCS);
585 end;
586 end;
587
588 procedure TFBStatus.SetIBDataBaseErrorMessages(Value: TIBDataBaseErrorMessages);
589 begin
590 EnterCriticalSection(TFBClientAPI.FIBCS);
591 try
592 FIBDataBaseErrorMessages := Value;
593 finally
594 LeaveCriticalSection(TFBClientAPI.FIBCS);
595 end;
596 end;
597 initialization
598 TFBClientAPI.IBLibrary := NilHandle;
599 {$IFNDEF FPC}
600 InitializeCriticalSection(TFBClientAPI.FIBCS);
601 {$ELSE}
602 InitCriticalSection(TFBClientAPI.FIBCS);
603 {$ENDIF}
604
605 finalization
606 {$IFNDEF FPC}
607 DeleteCriticalSection(TFBClientAPI.FIBCS);
608 {$ELSE}
609 DoneCriticalSection(TFBClientAPI.FIBCS);
610 {$ENDIF}
611 if TFBClientAPI.IBLibrary <> NilHandle then
612 begin
613 FreeLibrary(TFBClientAPI.IBLibrary);
614 TFBClientAPI.IBLibrary := NilHandle;
615 TFBClientAPI.FFBLibraryName := '';
616 end;
617
618 end.
619