ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/3.0/FB30ClientAPI.pas
Revision: 319
Committed: Thu Feb 25 12:05:40 2021 UTC (3 years, 1 month ago) by tony
Content type: text/x-pascal
File size: 18701 byte(s)
Log Message:
Merge into public release

File Contents

# Content
1 (*
2 * Firebird Interface (fbintf). The fbintf components provide a set of
3 * Pascal language bindings for the Firebird API.
4 *
5 * The contents of this file are subject to the Initial Developer's
6 * Public License Version 1.0 (the "License"); you may not use this
7 * file except in compliance with the License. You may obtain a copy
8 * of the License here:
9 *
10 * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11 *
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing rights
15 * and limitations under the License.
16 *
17 * The Initial Developer of the Original Code is Tony Whyman.
18 *
19 * The Original Code is (C) 2016 Tony Whyman, MWA Software
20 * (http://www.mwasoftware.co.uk).
21 *
22 * All Rights Reserved.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 *)
27 unit FB30ClientAPI;
28 {$IFDEF MSWINDOWS}
29 {$DEFINE WINDOWS}
30 {$ENDIF}
31
32 {$IFDEF FPC}
33 {$mode delphi}
34 {$interfaces COM}
35 {$ENDIF}
36
37 interface
38
39 uses
40 Classes, SysUtils, FBClientAPI, Firebird, IB, IBExternals, FmtBCD, FBClientLib;
41
42 type
43
44 { TFB30Status }
45
46 TFB30Status = class(TFBStatus,IStatus)
47 private
48 FStatus: Firebird.IStatus;
49 public
50 procedure Init;
51 function InErrorState: boolean;
52 function GetStatus: Firebird.IStatus;
53 function StatusVector: PStatusVector; override;
54 end;
55
56 { TFB30StatusObject }
57
58 TFB30StatusObject = class(TFB30Status)
59 public
60 constructor Create(aOwner: TFBClientAPI; status: Firebird.IStatus);
61 end;
62
63 Tfb_get_master_interface = function: IMaster;
64 {$IFDEF WINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
65
66 { TFB30ClientAPI }
67
68 TFB30ClientAPI = class(TFBClientAPI,IFirebirdAPI,IFBIMasterProvider)
69 private
70 FMaster: Firebird.IMaster;
71 FUtil: Firebird.IUtil;
72 FProvider: Firebird.IProvider;
73 FConfigManager: Firebird.IConfigManager;
74 FStatus: TFB30Status;
75 FIsEmbeddedServer: boolean;
76 FStatusIntf: IStatus; {Keep a reference to the interface - automatic destroy
77 when this class is freed and last reference to IStatus
78 goes out of scope.}
79 procedure CheckPlugins;
80 function Firebird4orLater: boolean;
81 public
82 constructor Create(aFBLibrary: TFBLibrary);
83 destructor Destroy; override;
84
85 function StatusIntf: Firebird.IStatus;
86 procedure Check4DataBaseError;
87 function InErrorState: boolean;
88 function LoadInterface: boolean; override;
89 procedure FBShutdown; override;
90 function GetAPI: IFirebirdAPI; override;
91 {$IFDEF UNIX}
92 function GetFirebirdLibList: string; override;
93 {$ENDIF}
94
95 public
96 {IFirebirdAPI}
97 function GetStatus: IStatus; override;
98 function AllocateDPB: IDPB;
99 function AllocateTPB: ITPB;
100
101 {Database connections}
102 function OpenDatabase(DatabaseName: AnsiString; DPB: IDPB; RaiseExceptionOnConnectError: boolean=true): IAttachment;
103 function CreateDatabase(DatabaseName: AnsiString; DPB: IDPB; RaiseExceptionOnError: boolean=true): IAttachment; overload;
104 function CreateDatabase(sql: AnsiString; aSQLDialect: integer; RaiseExceptionOnError: boolean=true): IAttachment; overload;
105 {Start Transaction against multiple databases}
106 function StartTransaction(Attachments: array of IAttachment;
107 TPB: array of byte; DefaultCompletion: TTransactionCompletion): ITransaction; overload;
108 function StartTransaction(Attachments: array of IAttachment;
109 TPB: ITPB; DefaultCompletion: TTransactionCompletion): ITransaction; overload;
110
111 {Service Manager}
112 function AllocateSPB: ISPB;
113 function GetServiceManager(ServerName: AnsiString; Protocol: TProtocol; SPB: ISPB): IServiceManager; overload;
114 function GetServiceManager(ServerName: AnsiString; Port: Ansistring; Protocol: TProtocol; SPB: ISPB): IServiceManager; overload;
115
116 {Information}
117 function HasServiceAPI: boolean;
118 function HasRollbackRetaining: boolean;
119 function IsEmbeddedServer: boolean; override;
120 function GetClientMajor: integer; override;
121 function GetClientMinor: integer; override;
122 function HasLocalTZDB: boolean; override;
123 function HasTimeZoneSupport: boolean; override;
124 function HasExtendedTZSupport: boolean; override;
125 function HasInt128Support: boolean; override;
126
127 {Firebird 3 API}
128 function HasMasterIntf: boolean;
129 function GetIMaster: TObject;
130
131 {IFBIMasterProvider}
132 function GetIMasterIntf: Firebird.IMaster;
133
134 {Encode/Decode}
135 function DecodeInteger(bufptr: PByte; len: short): integer; override;
136 procedure SQLEncodeDate(aDate: TDateTime; bufptr: PByte); override;
137 function SQLDecodeDate(bufptr: PByte): TDateTime; override;
138 procedure SQLEncodeTime(aTime: TDateTime; bufptr: PByte); override;
139 function SQLDecodeTime(bufptr: PByte): TDateTime; override;
140 procedure SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte); override;
141 function SQLDecodeDateTime(bufptr: PByte): TDateTime; override;
142 function FormatStatus(Status: TFBStatus): AnsiString; override;
143
144 {Firebird 4 Extensions}
145 procedure SQLDecFloatEncode(aValue: tBCD; SQLType: cardinal; bufptr: PByte);
146 override;
147 function SQLDecFloatDecode(SQLType: cardinal; bufptr: PByte): tBCD; override;
148 function Int128ToStr(bufptr: PByte; scale: integer): AnsiString; override;
149 procedure StrToInt128(scale: integer; aValue: AnsiString; bufptr: PByte); override;
150
151 {Firebird Interfaces}
152 property MasterIntf: Firebird.IMaster read FMaster;
153 property UtilIntf: Firebird.IUtil read FUtil;
154 property ProviderIntf: Firebird.IProvider read FProvider;
155
156 end;
157
158 implementation
159
160 uses FB30Attachment, {$IFDEF FPC}dynlibs{$ELSE} windows{$ENDIF},
161 FBMessages, FB30Services, FB30Transaction, IBUtils, DateUtils,
162 FBAttachment, FBTransaction, FBServices;
163
164 type
165 PISC_DATE = ^ISC_DATE;
166 PISC_TIME = ^ISC_TIME;
167
168 { TFB30StatusObject }
169
170 constructor TFB30StatusObject.Create(aOwner: TFBClientAPI;
171 status: Firebird.IStatus);
172 begin
173 inherited Create(aOwner);
174 FStatus := status;
175 end;
176
177 { TFB30Status }
178
179 procedure TFB30Status.Init;
180 begin
181 if assigned(FStatus) then
182 FStatus.Init;
183 end;
184
185 function TFB30Status.InErrorState: boolean;
186 begin
187 with GetStatus do
188 Result := ((getState and STATE_ERRORS) <> 0);
189 end;
190
191 function TFB30Status.GetStatus: Firebird.IStatus;
192 begin
193 if FStatus = nil then
194 with FOwner do
195 FStatus := (FOwner as TFB30ClientAPI).MasterIntf.GetStatus;
196 Result := FStatus;
197 end;
198
199 function TFB30Status.StatusVector: PStatusVector;
200 begin
201 Result := PStatusVector(GetStatus.getErrors);
202 end;
203
204 { TFB30ClientAPI }
205
206 procedure TFB30ClientAPI.CheckPlugins;
207 var FBConf: Firebird.IFirebirdConf;
208 Plugins: AnsiString;
209 PluginsList: TStringList;
210 begin
211 FIsEmbeddedServer := false;
212 FBConf := FConfigManager.getFirebirdConf;
213 try
214 Plugins := FBConf.asString(FBConf.getKey('Providers'));
215 finally
216 FBConf.release;
217 end;
218 if Plugins = '' then Exit;
219
220 PluginsList := TStringList.Create;
221 try
222 PluginsList.CommaText := Plugins;
223 FIsEmbeddedServer := (PluginsList.IndexOf('Engine12') <> -1) or {Firebird 3}
224 (PluginsList.IndexOf('Engine13') <> -1); {Firebird 4}
225 finally
226 PluginsList.Free;
227 end;
228 end;
229
230 function TFB30ClientAPI.Firebird4orLater: boolean;
231 begin
232 Result := (GetClientMajor >=4) and (UtilIntf.vtable.version >= 4)
233 and (UtilIntf.vtable.version <> 21) {ignore FB4 Beta1}
234 and (UtilIntf.vtable.version <> 24) {ignore FB4 Beta2}
235 end;
236
237 {$IFDEF UNIX}
238 function TFB30ClientAPI.GetFirebirdLibList: string;
239 begin
240 Result := 'libfbclient.so:libfbclient.so.2';
241 end;
242 {$ENDIF}
243
244 function TFB30ClientAPI.LoadInterface: boolean;
245 var
246 fb_get_master_interface: Tfb_get_master_interface;
247 begin
248 Result := inherited LoadInterface;
249 fb_get_master_interface := GetProcAddress(GetFBLibrary.GetHandle, 'fb_get_master_interface'); {do not localize}
250 if assigned(fb_get_master_interface) then
251 begin
252 FMaster := fb_get_master_interface;
253 FUtil := FMaster.getUtilInterface;
254 FProvider := FMaster.getDispatcher;
255 FConfigManager := FMaster.getConfigManager;
256 CheckPlugins;
257 end;
258 Result := Result and HasMasterIntf;
259 end;
260
261 procedure TFB30ClientAPI.FBShutdown;
262 begin
263 if assigned(fb_shutdown) and assigned(FProvider) then
264 begin
265 FProvider.release;
266 FProvider := nil;
267 end;
268 inherited;
269 end;
270
271 function TFB30ClientAPI.GetAPI: IFirebirdAPI;
272 begin
273 Result := self;
274 end;
275
276 constructor TFB30ClientAPI.Create(aFBLibrary: TFBLibrary);
277 begin
278 inherited Create(aFBLibrary);
279 FStatus := TFB30Status.Create(self);
280 FStatusIntf := FStatus;
281 end;
282
283 destructor TFB30ClientAPI.Destroy;
284 begin
285 if assigned(FProvider) then
286 FProvider.release;
287 inherited Destroy;
288 end;
289
290 function TFB30ClientAPI.StatusIntf: Firebird.IStatus;
291 begin
292 Result := FStatus.GetStatus;
293 Result.Init;
294 end;
295
296 procedure TFB30ClientAPI.Check4DataBaseError;
297 begin
298 if FStatus.InErrorState then
299 IBDataBaseError;
300 end;
301
302 function TFB30ClientAPI.InErrorState: boolean;
303 begin
304 Result := FStatus.InErrorState;
305 end;
306
307 function TFB30ClientAPI.GetStatus: IStatus;
308 begin
309 Result := FStatusIntf;
310 end;
311
312 function TFB30ClientAPI.AllocateDPB: IDPB;
313 begin
314 Result := TDPB.Create(self);
315 end;
316
317 function TFB30ClientAPI.AllocateTPB: ITPB;
318 begin
319 Result := TTPB.Create(self);
320 end;
321
322 function TFB30ClientAPI.OpenDatabase(DatabaseName: AnsiString; DPB: IDPB;
323 RaiseExceptionOnConnectError: boolean): IAttachment;
324 begin
325 Result := TFB30Attachment.Create(self,DatabaseName, DPB, RaiseExceptionOnConnectError);
326 if not Result.IsConnected then
327 Result := nil;
328 end;
329
330 function TFB30ClientAPI.CreateDatabase(DatabaseName: AnsiString; DPB: IDPB;
331 RaiseExceptionOnError: boolean): IAttachment;
332 begin
333 Result := TFB30Attachment.CreateDatabase(self,DatabaseName,DPB, RaiseExceptionOnError);
334 if not Result.IsConnected then
335 Result := nil;
336 end;
337
338 function TFB30ClientAPI.CreateDatabase(sql: AnsiString; aSQLDialect: integer;
339 RaiseExceptionOnError: boolean): IAttachment;
340 begin
341 Result := TFB30Attachment.CreateDatabase(self,sql,aSQLDialect, RaiseExceptionOnError);
342 if not Result.IsConnected then
343 Result := nil;
344 end;
345
346 function TFB30ClientAPI.StartTransaction(Attachments: array of IAttachment;
347 TPB: array of byte; DefaultCompletion: TTransactionCompletion): ITransaction;
348 begin
349 Result := TFB30Transaction.Create(self,Attachments,TPB,DefaultCompletion);
350 end;
351
352 function TFB30ClientAPI.StartTransaction(Attachments: array of IAttachment;
353 TPB: ITPB; DefaultCompletion: TTransactionCompletion): ITransaction;
354 begin
355 Result := TFB30Transaction.Create(self,Attachments,TPB,DefaultCompletion);
356 end;
357
358 function TFB30ClientAPI.AllocateSPB: ISPB;
359 begin
360 Result := TSPB.Create(self);
361 end;
362
363 function TFB30ClientAPI.GetServiceManager(ServerName: AnsiString;
364 Protocol: TProtocol; SPB: ISPB): IServiceManager;
365 begin
366 Result := TFB30ServiceManager.Create(self,ServerName,Protocol,SPB);
367 end;
368
369 function TFB30ClientAPI.GetServiceManager(ServerName: AnsiString;
370 Port: Ansistring; Protocol: TProtocol; SPB: ISPB): IServiceManager;
371 begin
372 Result := TFB30ServiceManager.Create(self,ServerName,Protocol,SPB,Port);
373 end;
374
375 function TFB30ClientAPI.HasServiceAPI: boolean;
376 begin
377 Result := true;
378 end;
379
380 function TFB30ClientAPI.HasMasterIntf: boolean;
381 begin
382 Result := MasterIntf <> nil;
383 end;
384
385 function TFB30ClientAPI.GetIMaster: TObject;
386 begin
387 Result := FMaster;
388 end;
389
390 function TFB30ClientAPI.GetIMasterIntf: Firebird.IMaster;
391 begin
392 Result := FMaster;
393 end;
394
395 function TFB30ClientAPI.HasRollbackRetaining: boolean;
396 begin
397 Result := true;
398 end;
399
400 function TFB30ClientAPI.IsEmbeddedServer: boolean;
401 begin
402 Result := FIsEmbeddedServer;
403 end;
404
405 function TFB30ClientAPI.GetClientMajor: integer;
406 begin
407 Result := UtilIntf.GetClientVersion div 256;
408 end;
409
410 function TFB30ClientAPI.GetClientMinor: integer;
411 begin
412 Result := UtilIntf.GetClientVersion mod 256;
413 end;
414
415 function TFB30ClientAPI.DecodeInteger(bufptr: PByte; len: short): integer;
416 var P: PByte;
417 begin
418 Result := 0;
419 P := Bufptr + len - 1;
420 while P >= bufptr do
421 begin
422 Result := (Result shl 8 ) or P^;
423 Dec(P);
424 end;
425 end;
426
427 procedure TFB30ClientAPI.SQLEncodeDate(aDate: TDateTime; bufptr: PByte);
428 var
429 Yr, Mn, Dy: Word;
430 begin
431 DecodeDate(aDate, Yr, Mn, Dy);
432 PISC_Date(Bufptr)^ := UtilIntf.encodeDate(Yr, Mn, Dy);
433 end;
434
435 function TFB30ClientAPI.SQLDecodeDate(bufptr: PByte): TDateTime;
436 var
437 Yr, Mn, Dy: cardinal;
438 begin
439 UtilIntf.decodeDate(PISC_DATE(bufptr)^,@Yr, @Mn, @Dy);
440 try
441 result := EncodeDate(Yr, Mn,Dy);
442 except
443 on E: EConvertError do begin
444 IBError(ibxeInvalidDataConversion, [nil]);
445 end;
446 end;
447 end;
448
449 procedure TFB30ClientAPI.SQLEncodeTime(aTime: TDateTime; bufptr: PByte);
450 var
451 Hr, Mt, S: word;
452 DMs: cardinal;
453 begin
454 FBDecodeTime(aTime,Hr, Mt, S, DMs);
455 PISC_TIME(bufptr)^ := UtilIntf.encodeTime(Hr, Mt, S, DMs);
456 end;
457
458 function TFB30ClientAPI.SQLDecodeTime(bufptr: PByte): TDateTime;
459 var
460 Hr, Mt, S, DMs: cardinal;
461 begin
462 UtilIntf.decodeTime(PISC_TIME(bufptr)^,@Hr, @Mt, @S, @DMs);
463 try
464 Result := FBEncodeTime(Hr, Mt, S, DMs);
465 except
466 on E: EConvertError do begin
467 IBError(ibxeInvalidDataConversion, [nil]);
468 end;
469 end;
470 end;
471
472 procedure TFB30ClientAPI.SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte);
473 begin
474 SQLEncodeDate(aDateTime,bufPtr);
475 Inc(bufptr,sizeof(ISC_DATE));
476 SQLEncodeTime(aDateTime,bufPtr);
477 end;
478
479 function TFB30ClientAPI.SQLDecodeDateTime(bufptr: PByte): TDateTime;
480 begin
481 Result := SQLDecodeDate(bufPtr);
482 Inc(bufptr,sizeof(ISC_DATE));
483 Result := Result + SQLDecodeTime(bufPtr);
484 end;
485
486 function TFB30ClientAPI.FormatStatus(Status: TFBStatus): AnsiString;
487 var local_buffer: array[0..IBHugeLocalBufferLength - 1] of AnsiChar;
488 begin
489 Result := '';
490 if UtilIntf.formatStatus(@local_buffer,sizeof(local_buffer),(Status as TFB30Status).GetStatus) > 0 then
491 Result := strpas(local_buffer);
492 end;
493
494 procedure TFB30ClientAPI.SQLDecFloatEncode(aValue: tBCD; SQLType: cardinal;
495 bufptr: PByte);
496 var DecFloat16: IDecFloat16;
497 DecFloat34: IDecFloat34;
498 sign: integer;
499 exp: integer;
500 buffer: array [1..34] of byte;
501
502 procedure UnpackBuffer(width: integer);
503 var i,j: integer;
504 begin
505 Fillchar(buffer,sizeof(buffer),0);
506 if BCDPrecision(aValue) > width then
507 IBError(ibxeBCDTooBig,[BCDPrecision(aValue),width]);
508 j := 1 + (width - aValue.Precision);
509 for i := 0 to (aValue.Precision - 1) div 2 do
510 if j <= width then
511 begin
512 buffer[j] := (aValue.Fraction[i] and $f0) shr 4;
513 Inc(j);
514 if j <= width then
515 begin
516 buffer[j] := (aValue.Fraction[i] and $0f);
517 Inc(j);
518 end;
519 end;
520 {writeln('Precision = ',aValue.Precision,' Places = ',aValue.SignSpecialPlaces and $2f);
521 write('BCD Buffer = ');
522 for i := 1 to 34 do
523 write(buffer[i],' ');
524 writeln; }
525 end;
526
527 begin
528 inherited SQLDecFloatEncode(aValue, SQLType, bufptr);
529 sign := (aValue.SignSpecialPlaces and $80) shr 7;
530 exp := -(aValue.SignSpecialPlaces and $2f);
531
532 case SQLType of
533 SQL_DEC16:
534 begin
535 UnPackbuffer(16);
536 DecFloat16 := UtilIntf.getDecFloat16(StatusIntf);
537 Check4DataBaseError;
538 DecFloat16.fromBcd(sign,@buffer,exp,FB_DEC16Ptr(bufptr));
539 Check4DataBaseError;
540 end;
541
542 SQL_DEC34:
543 begin
544 UnPackbuffer(34);
545 DecFloat34 := UtilIntf.getDecFloat34(StatusIntf);
546 Check4DataBaseError;
547 DecFloat34.fromBcd(sign,@buffer,exp,FB_DEC34Ptr(bufptr));
548 Check4DataBaseError;
549 end;
550
551 else
552 IBError(ibxeInvalidDataConversion,[]);
553 end;
554 end;
555
556 function TFB30ClientAPI.SQLDecFloatDecode(SQLType: cardinal; bufptr: PByte): tBCD;
557
558 var DecFloat16: IDecFloat16;
559 DecFloat34: IDecFloat34;
560 sign: integer;
561 exp: integer;
562 buffer: array [1..38] of byte;
563
564 procedure packbuffer(buflen: integer);
565 var i,j: integer;
566 begin
567 { write('Decode: BCD Buffer = ');
568 for i := 1 to 34 do
569 write(buffer[i],' ');
570 writeln; }
571 {pack buffer}
572 i := 1;
573 while (i <= buflen) and (buffer[i] = 0) do {skip leading zeroes}
574 inc(i);
575
576 j := 0;
577 Result.Precision := 0;
578 while i <= buflen do
579 begin
580 inc(Result.Precision);
581 if odd(Result.Precision) then
582 Result.Fraction[j] := (buffer[i] and $0f) shl 4
583 else
584 begin
585 Result.Fraction[j] := Result.Fraction[j] or (buffer[i] and $0f);
586 Inc(j);
587 end;
588 inc(i);
589 end;
590 end;
591
592 begin
593 Result := inherited SQLDecFloatDecode(SQLType, bufptr);
594 FillChar(Result, sizeof(tBCD),0);
595 case SQLType of
596 SQL_DEC16:
597 begin
598 DecFloat16 := UtilIntf.getDecFloat16(StatusIntf);
599 Check4DataBaseError;
600 DecFloat16.toBcd(FB_DEC16Ptr(bufptr),@sign,@buffer,@exp);
601 Check4DataBaseError;
602 packbuffer(16);
603 end;
604
605 SQL_DEC34:
606 begin
607 DecFloat34 := UtilIntf.getDecFloat34(StatusIntf);
608 Check4DataBaseError;
609 DecFloat34.toBcd(FB_DEC34Ptr(bufptr),@sign,@buffer,@exp);
610 Check4DataBaseError;
611 packbuffer(34);
612 end;
613
614 else
615 IBError(ibxeInvalidDataConversion,[]);
616 end;
617 Result.SignSpecialPlaces := (-exp and $2f);
618 if sign <> 0 then
619 Result.SignSpecialPlaces := Result.SignSpecialPlaces or $80;
620 end;
621
622 procedure TFB30ClientAPI.StrToInt128(scale: integer; aValue: AnsiString;
623 bufptr: PByte);
624 begin
625 inherited StrToInt128(scale,aValue,bufPtr);
626
627 UtilIntf.getInt128(StatusIntf).fromString(StatusIntf,scale,PAnsiChar(aValue),FB_I128Ptr(bufptr));
628 Check4DatabaseError;
629 end;
630
631 function TFB30ClientAPI.Int128ToStr(bufptr: PByte; scale: integer
632 ): AnsiString;
633 const
634 bufLength = 64;
635 var Buffer: array[ 0.. bufLength] of AnsiChar;
636 begin
637 Result := inherited Int128ToStr(bufPtr,scale);
638
639 UtilIntf.getInt128(StatusIntf).toString(StatusIntf,FB_I128Ptr(bufptr),scale,buflength,PAnsiChar(@Buffer));
640 Check4DatabaseError;
641 Result := strpas(PAnsiChar(@Buffer));
642 end;
643
644 function TFB30ClientAPI.HasLocalTZDB: boolean;
645 const
646 bufLength = 128;
647 var Buffer: ISC_TIME_TZ;
648 Hr, Mt, S, DMs: cardinal;
649 tzBuffer: array[ 0.. bufLength] of AnsiChar;
650 begin
651 Result := HasTimeZoneSupport;
652 if Result then
653 begin
654 Buffer.utc_time := 0;
655 Buffer.time_zone := TimeZoneID_GMT;
656 UtilIntf.decodeTimeTz(StatusIntf, ISC_TIME_TZPtr(@Buffer),@Hr, @Mt, @S, @DMs,bufLength,PAnsiChar(@tzBuffer));
657 Check4DataBaseError;
658 Result := strpas(PAnsiChar(@tzBuffer)) <> 'GMT*';
659 end;
660 end;
661
662 function TFB30ClientAPI.HasTimeZoneSupport: boolean;
663 begin
664 Result := Firebird4orLater;
665 end;
666
667 function TFB30ClientAPI.HasExtendedTZSupport: boolean;
668 begin
669 Result := Firebird4orLater;
670 end;
671
672 function TFB30ClientAPI.HasInt128Support: boolean;
673 begin
674 Result := Firebird4orLater;
675 end;
676
677 end.
678
679