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: 345
Committed: Mon Aug 23 14:22:29 2021 UTC (3 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 21437 byte(s)
Log Message:
Merged 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 FBActivityMonitor;
42
43 type
44
45 { TFB30Status }
46
47 TFB30Status = class(TFBStatus,IStatus)
48 protected
49 FStatus: Firebird.IStatus;
50 FDirty: boolean;
51 public
52 destructor Destroy; override;
53 procedure Init;
54 procedure FreeHandle;
55 function InErrorState: boolean;
56 function Warning: boolean;
57 function GetStatus: Firebird.IStatus;
58 function StatusVector: PStatusVector; override;
59 property Dirty: boolean read FDirty;
60 end;
61
62 { TFB30StatusObject }
63
64 TFB30StatusObject = class(TFB30Status)
65 public
66 constructor Create(aOwner: TFBClientAPI; status: Firebird.IStatus; prefix: Ansistring='');
67 end;
68
69 Tfb_get_master_interface = function: IMaster;
70 {$IFDEF WINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF}
71
72 { TFB30ClientAPI }
73
74 TFB30ClientAPI = class(TFBClientAPI,IFirebirdAPI,IFBIMasterProvider)
75 private
76 FMaster: Firebird.IMaster;
77 FUtil: Firebird.IUtil;
78 FProvider: Firebird.IProvider;
79 FConfigManager: Firebird.IConfigManager;
80 FStatus: TFB30Status;
81 FIsEmbeddedServer: boolean;
82 FStatusIntf: IStatus; {Keep a reference to the interface - automatic destroy
83 when this class is freed and last reference to IStatus
84 goes out of scope.}
85 procedure CheckPlugins;
86 public
87 constructor Create(aFBLibrary: TFBLibrary);
88 destructor Destroy; override;
89
90 function StatusIntf: Firebird.IStatus;
91 procedure Check4DataBaseError; overload;
92 procedure Check4DataBaseError(st: Firebird.IStatus); overload;
93 function InErrorState: boolean;
94 function LoadInterface: boolean; override;
95 procedure FBShutdown; override;
96 function GetAPI: IFirebirdAPI; override;
97 function Firebird4orLater: boolean;
98 {$IFDEF UNIX}
99 function GetFirebirdLibList: string; override;
100 {$ENDIF}
101
102 public
103 {IFirebirdAPI}
104 function GetStatus: IStatus; override;
105 function AllocateDPB: IDPB;
106 function AllocateTPB: ITPB;
107
108 {Database connections}
109 function OpenDatabase(DatabaseName: AnsiString; DPB: IDPB; RaiseExceptionOnConnectError: boolean=true): IAttachment;
110 function CreateDatabase(DatabaseName: AnsiString; DPB: IDPB; RaiseExceptionOnError: boolean=true): IAttachment; overload;
111 function CreateDatabase(sql: AnsiString; aSQLDialect: integer; RaiseExceptionOnError: boolean=true): IAttachment; overload;
112 {Start Transaction against multiple databases}
113 function StartTransaction(Attachments: array of IAttachment;
114 TPB: array of byte; DefaultCompletion: TTransactionCompletion): ITransaction; overload;
115 function StartTransaction(Attachments: array of IAttachment;
116 TPB: ITPB; DefaultCompletion: TTransactionCompletion): ITransaction; overload;
117
118 {Service Manager}
119 function AllocateSPB: ISPB;
120 function GetServiceManager(ServerName: AnsiString; Protocol: TProtocol; SPB: ISPB): IServiceManager; overload;
121 function GetServiceManager(ServerName: AnsiString; Port: Ansistring; Protocol: TProtocol; SPB: ISPB): IServiceManager; overload;
122
123 {Information}
124 function HasServiceAPI: boolean;
125 function HasRollbackRetaining: boolean;
126 function IsEmbeddedServer: boolean; override;
127 function GetClientMajor: integer; override;
128 function GetClientMinor: integer; override;
129 function HasLocalTZDB: boolean; override;
130 function HasTimeZoneSupport: boolean; override;
131 function HasExtendedTZSupport: boolean; override;
132 function HasInt128Support: boolean; override;
133
134 {Firebird 3 API}
135 function HasMasterIntf: boolean;
136 function GetIMaster: TObject;
137
138 {IFBIMasterProvider}
139 function GetIMasterIntf: Firebird.IMaster;
140
141 {Encode/Decode}
142 procedure SQLEncodeDate(aDate: TDateTime; bufptr: PByte); override;
143 function SQLDecodeDate(bufptr: PByte): TDateTime; override;
144 procedure SQLEncodeTime(aTime: TDateTime; bufptr: PByte); override;
145 function SQLDecodeTime(bufptr: PByte): TDateTime; override;
146 procedure SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte); override;
147 function SQLDecodeDateTime(bufptr: PByte): TDateTime; override;
148 function FormatStatus(Status: TFBStatus): AnsiString; override;
149 function FormatFBStatus(Status: Firebird.IStatus): AnsiString;
150
151 {Firebird 4 Extensions}
152 procedure SQLDecFloatEncode(aValue: tBCD; SQLType: cardinal; bufptr: PByte);
153 override;
154 function SQLDecFloatDecode(SQLType: cardinal; bufptr: PByte): tBCD; override;
155 function Int128ToStr(bufptr: PByte; scale: integer): AnsiString; override;
156 procedure StrToInt128(scale: integer; aValue: AnsiString; bufptr: PByte); override;
157
158 {Firebird Interfaces}
159 property MasterIntf: Firebird.IMaster read FMaster;
160 property UtilIntf: Firebird.IUtil read FUtil;
161 property ProviderIntf: Firebird.IProvider read FProvider;
162
163 end;
164
165 { TXPBParameterBlock }
166
167 TXPBParameterBlock = class(TFBInterfacedObject)
168 private
169 FBuilder: Firebird.IXpbBuilder;
170 FFirebird30ClientAPI: TFB30ClientAPI;
171 public
172 constructor Create(api: TFB30ClientAPI; kind: cardinal);
173 destructor Destroy; override;
174 function getBuffer: PByte;
175 function getDataLength: cardinal;
176 procedure insertInt(tag: Byte; value: Integer);
177 property Builder: Firebird.IXpbBuilder read FBuilder;
178 public
179 procedure PrintBuf;
180 end;
181
182 implementation
183
184 uses FB30Attachment, {$IFDEF FPC}dynlibs{$ELSE} windows{$ENDIF},
185 FBMessages, FB30Services, FB30Transaction, IBUtils, DateUtils,
186 FBAttachment, FBTransaction, FBServices;
187
188 type
189 PISC_DATE = ^ISC_DATE;
190 PISC_TIME = ^ISC_TIME;
191
192 { TXPBParameterBlock }
193
194 constructor TXPBParameterBlock.Create(api: TFB30ClientAPI; kind: cardinal);
195 begin
196 inherited Create;
197 FFirebird30ClientAPI := api;
198 with FFirebird30ClientAPI do
199 begin
200 FBuilder := UtilIntf.getXpbBuilder(StatusIntf,kind,nil,0);
201 Check4DataBaseError;
202 end;
203 end;
204
205 destructor TXPBParameterBlock.Destroy;
206 begin
207 if FBuilder <> nil then
208 begin
209 FBuilder.dispose;
210 FBuilder := nil;
211 end;
212 inherited Destroy;
213 end;
214
215 function TXPBParameterBlock.getBuffer: PByte;
216 begin
217 with FFirebird30ClientAPI do
218 begin
219 Result := PByte(FBuilder.getBuffer(StatusIntf));
220 Check4DataBaseError;
221 end;
222 end;
223
224 function TXPBParameterBlock.getDataLength: cardinal;
225 begin
226 with FFirebird30ClientAPI do
227 begin
228 Result := FBuilder.getBufferLength(StatusIntf);
229 Check4DataBaseError;
230 end;
231 end;
232
233 procedure TXPBParameterBlock.insertInt(tag: Byte; value: Integer);
234 begin
235 with FFirebird30ClientAPI do
236 begin
237 Builder.insertInt(StatusIntf,tag,value);
238 Check4DataBaseError;
239 end;
240 end;
241
242 procedure TXPBParameterBlock.PrintBuf;
243 var i: integer;
244 buffer: PByte;
245 begin
246 write(ClassName,': (',getDataLength,') ');
247 buffer := getBuffer;
248 for i := 0 to getDataLength - 1 do
249 begin
250 write(Format('%x ',[buffer^]));
251 Inc(buffer);
252 end;
253 writeln
254 end;
255
256 { TFB30StatusObject }
257
258 constructor TFB30StatusObject.Create(aOwner: TFBClientAPI;
259 status: Firebird.IStatus; prefix: Ansistring);
260 begin
261 inherited Create(aOwner,prefix);
262 FStatus := status;
263 end;
264
265 { TFB30Status }
266
267 destructor TFB30Status.Destroy;
268 begin
269 FreeHandle;
270 inherited Destroy;
271 end;
272
273 procedure TFB30Status.Init;
274 begin
275 if assigned(FStatus) and Dirty then
276 begin
277 FStatus.Init;
278 FDirty := false;
279 end;
280 end;
281
282 procedure TFB30Status.FreeHandle;
283 begin
284 if FStatus <> nil then
285 begin
286 FStatus.dispose;
287 FStatus := nil;
288 end;
289 end;
290
291 function TFB30Status.InErrorState: boolean;
292 begin
293 with GetStatus do
294 Result := ((getState and STATE_ERRORS) <> 0);
295 if Result then
296 FDirty := true;
297 end;
298
299 function TFB30Status.Warning: boolean;
300 begin
301 with GetStatus do
302 Result := ((getState and STATE_WARNINGS) <> 0);
303 if Result then
304 FDirty := true;
305 end;
306
307 function TFB30Status.GetStatus: Firebird.IStatus;
308 begin
309 if FStatus = nil then
310 with FOwner do
311 FStatus := (FOwner as TFB30ClientAPI).MasterIntf.GetStatus;
312 Result := FStatus;
313 end;
314
315 function TFB30Status.StatusVector: PStatusVector;
316 begin
317 Result := PStatusVector(GetStatus.getErrors);
318 end;
319
320 { TFB30ClientAPI }
321
322 procedure TFB30ClientAPI.CheckPlugins;
323 var FBConf: Firebird.IFirebirdConf;
324 Plugins: AnsiString;
325 PluginsList: TStringList;
326 begin
327 FIsEmbeddedServer := false;
328 FBConf := FConfigManager.getFirebirdConf;
329 try
330 Plugins := FBConf.asString(FBConf.getKey('Providers'));
331 finally
332 FBConf.release;
333 end;
334 if Plugins = '' then Exit;
335
336 PluginsList := TStringList.Create;
337 try
338 PluginsList.CommaText := Plugins;
339 FIsEmbeddedServer := (PluginsList.IndexOf('Engine12') <> -1) or {Firebird 3}
340 (PluginsList.IndexOf('Engine13') <> -1); {Firebird 4}
341 finally
342 PluginsList.Free;
343 end;
344 end;
345
346 function TFB30ClientAPI.Firebird4orLater: boolean;
347 begin
348 Result := (GetClientMajor > 4) or (
349 (GetClientMajor = 4) and (UtilIntf.vtable.version >= 4)
350 and (UtilIntf.vtable.version <> 21) {ignore FB4 Beta1}
351 and (UtilIntf.vtable.version <> 24)) {ignore FB4 Beta2}
352 end;
353
354 {$IFDEF UNIX}
355 function TFB30ClientAPI.GetFirebirdLibList: string;
356 begin
357 Result := 'libfbclient.so:libfbclient.so.2';
358 end;
359 {$ENDIF}
360
361 function TFB30ClientAPI.LoadInterface: boolean;
362 var
363 fb_get_master_interface: Tfb_get_master_interface;
364 begin
365 Result := inherited LoadInterface;
366 fb_get_master_interface := GetProcAddress(GetFBLibrary.GetHandle, 'fb_get_master_interface'); {do not localize}
367 if assigned(fb_get_master_interface) then
368 begin
369 FMaster := fb_get_master_interface;
370 FUtil := FMaster.getUtilInterface;
371 FProvider := FMaster.getDispatcher;
372 FConfigManager := FMaster.getConfigManager;
373 CheckPlugins;
374 end;
375 Result := Result and HasMasterIntf;
376 end;
377
378 procedure TFB30ClientAPI.FBShutdown;
379 begin
380 if assigned(fb_shutdown) then
381 begin
382 FStatus.FreeHandle;
383 if assigned(FProvider) then
384 begin
385 FProvider.release;
386 FProvider := nil;
387 end;
388 end;
389 inherited;
390 end;
391
392 function TFB30ClientAPI.GetAPI: IFirebirdAPI;
393 begin
394 Result := self;
395 end;
396
397 constructor TFB30ClientAPI.Create(aFBLibrary: TFBLibrary);
398 begin
399 inherited Create(aFBLibrary);
400 FStatus := TFB30Status.Create(self);
401 FStatusIntf := FStatus;
402 end;
403
404 destructor TFB30ClientAPI.Destroy;
405 begin
406 FStatus.FreeHandle;
407 if assigned(FProvider) then
408 FProvider.release;
409 inherited Destroy;
410 end;
411
412 function TFB30ClientAPI.StatusIntf: Firebird.IStatus;
413 begin
414 Result := FStatus.GetStatus;
415 Result.Init;
416 end;
417
418 procedure TFB30ClientAPI.Check4DataBaseError;
419 begin
420 if FStatus.InErrorState then
421 IBDataBaseError;
422 end;
423
424 procedure TFB30ClientAPI.Check4DataBaseError(st: Firebird.IStatus);
425 begin
426 if ((st.getState and st.STATE_ERRORS) <> 0) then
427 raise EIBInterBaseError.Create(TFB30StatusObject.Create(self,st));
428 end;
429
430 function TFB30ClientAPI.InErrorState: boolean;
431 begin
432 Result := FStatus.InErrorState;
433 end;
434
435 function TFB30ClientAPI.GetStatus: IStatus;
436 begin
437 Result := FStatusIntf;
438 end;
439
440 function TFB30ClientAPI.AllocateDPB: IDPB;
441 begin
442 Result := TDPB.Create(self);
443 end;
444
445 function TFB30ClientAPI.AllocateTPB: ITPB;
446 begin
447 Result := TTPB.Create(self);
448 end;
449
450 function TFB30ClientAPI.OpenDatabase(DatabaseName: AnsiString; DPB: IDPB;
451 RaiseExceptionOnConnectError: boolean): IAttachment;
452 begin
453 Result := TFB30Attachment.Create(self,DatabaseName, DPB, RaiseExceptionOnConnectError);
454 if not Result.IsConnected then
455 Result := nil;
456 end;
457
458 function TFB30ClientAPI.CreateDatabase(DatabaseName: AnsiString; DPB: IDPB;
459 RaiseExceptionOnError: boolean): IAttachment;
460 begin
461 Result := TFB30Attachment.CreateDatabase(self,DatabaseName,DPB, RaiseExceptionOnError);
462 if not Result.IsConnected then
463 Result := nil;
464 end;
465
466 function TFB30ClientAPI.CreateDatabase(sql: AnsiString; aSQLDialect: integer;
467 RaiseExceptionOnError: boolean): IAttachment;
468 begin
469 Result := TFB30Attachment.CreateDatabase(self,sql,aSQLDialect, RaiseExceptionOnError);
470 if not Result.IsConnected then
471 Result := nil;
472 end;
473
474 function TFB30ClientAPI.StartTransaction(Attachments: array of IAttachment;
475 TPB: array of byte; DefaultCompletion: TTransactionCompletion): ITransaction;
476 begin
477 Result := TFB30Transaction.Create(self,Attachments,TPB,DefaultCompletion);
478 end;
479
480 function TFB30ClientAPI.StartTransaction(Attachments: array of IAttachment;
481 TPB: ITPB; DefaultCompletion: TTransactionCompletion): ITransaction;
482 begin
483 Result := TFB30Transaction.Create(self,Attachments,TPB,DefaultCompletion);
484 end;
485
486 function TFB30ClientAPI.AllocateSPB: ISPB;
487 begin
488 Result := TSPB.Create(self);
489 end;
490
491 function TFB30ClientAPI.GetServiceManager(ServerName: AnsiString;
492 Protocol: TProtocol; SPB: ISPB): IServiceManager;
493 begin
494 Result := TFB30ServiceManager.Create(self,ServerName,Protocol,SPB);
495 end;
496
497 function TFB30ClientAPI.GetServiceManager(ServerName: AnsiString;
498 Port: Ansistring; Protocol: TProtocol; SPB: ISPB): IServiceManager;
499 begin
500 Result := TFB30ServiceManager.Create(self,ServerName,Protocol,SPB,Port);
501 end;
502
503 function TFB30ClientAPI.HasServiceAPI: boolean;
504 begin
505 Result := true;
506 end;
507
508 function TFB30ClientAPI.HasMasterIntf: boolean;
509 begin
510 Result := MasterIntf <> nil;
511 end;
512
513 function TFB30ClientAPI.GetIMaster: TObject;
514 begin
515 Result := FMaster;
516 end;
517
518 function TFB30ClientAPI.GetIMasterIntf: Firebird.IMaster;
519 begin
520 Result := FMaster;
521 end;
522
523 function TFB30ClientAPI.HasRollbackRetaining: boolean;
524 begin
525 Result := true;
526 end;
527
528 function TFB30ClientAPI.IsEmbeddedServer: boolean;
529 begin
530 Result := FIsEmbeddedServer;
531 end;
532
533 function TFB30ClientAPI.GetClientMajor: integer;
534 begin
535 Result := UtilIntf.GetClientVersion div 256;
536 end;
537
538 function TFB30ClientAPI.GetClientMinor: integer;
539 begin
540 Result := UtilIntf.GetClientVersion mod 256;
541 end;
542
543 procedure TFB30ClientAPI.SQLEncodeDate(aDate: TDateTime; bufptr: PByte);
544 var
545 Yr, Mn, Dy: Word;
546 begin
547 DecodeDate(aDate, Yr, Mn, Dy);
548 PISC_Date(Bufptr)^ := UtilIntf.encodeDate(Yr, Mn, Dy);
549 end;
550
551 function TFB30ClientAPI.SQLDecodeDate(bufptr: PByte): TDateTime;
552 var
553 Yr, Mn, Dy: cardinal;
554 begin
555 UtilIntf.decodeDate(PISC_DATE(bufptr)^,@Yr, @Mn, @Dy);
556 try
557 result := EncodeDate(Yr, Mn,Dy);
558 except
559 on E: EConvertError do begin
560 IBError(ibxeInvalidDataConversion, [nil]);
561 end;
562 end;
563 end;
564
565 procedure TFB30ClientAPI.SQLEncodeTime(aTime: TDateTime; bufptr: PByte);
566 var
567 Hr, Mt, S: word;
568 DMs: cardinal;
569 begin
570 FBDecodeTime(aTime,Hr, Mt, S, DMs);
571 PISC_TIME(bufptr)^ := UtilIntf.encodeTime(Hr, Mt, S, DMs);
572 end;
573
574 function TFB30ClientAPI.SQLDecodeTime(bufptr: PByte): TDateTime;
575 var
576 Hr, Mt, S, DMs: cardinal;
577 begin
578 UtilIntf.decodeTime(PISC_TIME(bufptr)^,@Hr, @Mt, @S, @DMs);
579 try
580 Result := FBEncodeTime(Hr, Mt, S, DMs);
581 except
582 on E: EConvertError do begin
583 IBError(ibxeInvalidDataConversion, [nil]);
584 end;
585 end;
586 end;
587
588 procedure TFB30ClientAPI.SQLEncodeDateTime(aDateTime: TDateTime; bufptr: PByte);
589 begin
590 SQLEncodeDate(aDateTime,bufPtr);
591 Inc(bufptr,sizeof(ISC_DATE));
592 SQLEncodeTime(aDateTime,bufPtr);
593 end;
594
595 function TFB30ClientAPI.SQLDecodeDateTime(bufptr: PByte): TDateTime;
596 begin
597 Result := SQLDecodeDate(bufPtr);
598 Inc(bufptr,sizeof(ISC_DATE));
599 Result := Result + SQLDecodeTime(bufPtr);
600 end;
601
602 function TFB30ClientAPI.FormatStatus(Status: TFBStatus): AnsiString;
603 begin
604 Result := FormatFBStatus((Status as TFB30Status).GetStatus);
605 end;
606
607 function TFB30ClientAPI.FormatFBStatus(Status: Firebird.IStatus): AnsiString;
608 var local_buffer: array[0..IBHugeLocalBufferLength - 1] of AnsiChar;
609 begin
610 Result := '';
611 if UtilIntf.formatStatus(@local_buffer,sizeof(local_buffer) - 1,Status) > 0 then
612 Result := strpas(local_buffer);
613 end;
614
615 procedure TFB30ClientAPI.SQLDecFloatEncode(aValue: tBCD; SQLType: cardinal;
616 bufptr: PByte);
617 var DecFloat16: IDecFloat16;
618 DecFloat34: IDecFloat34;
619 sign: integer;
620 exp: integer;
621 buffer: array [1..34] of byte;
622
623 procedure UnpackBuffer(width: integer);
624 var i,j: integer;
625 begin
626 Fillchar(buffer,sizeof(buffer),0);
627 if BCDPrecision(aValue) > width then
628 IBError(ibxeBCDTooBig,[BCDPrecision(aValue),width]);
629 j := 1 + (width - aValue.Precision);
630 for i := 0 to (aValue.Precision - 1) div 2 do
631 if j <= width then
632 begin
633 buffer[j] := (aValue.Fraction[i] and $f0) shr 4;
634 Inc(j);
635 if j <= width then
636 begin
637 buffer[j] := (aValue.Fraction[i] and $0f);
638 Inc(j);
639 end;
640 end;
641 {writeln('Precision = ',aValue.Precision,' Places = ',aValue.SignSpecialPlaces and $2f);
642 write('BCD Buffer = ');
643 for i := 1 to 34 do
644 write(buffer[i],' ');
645 writeln; }
646 end;
647
648 begin
649 inherited SQLDecFloatEncode(aValue, SQLType, bufptr);
650 sign := (aValue.SignSpecialPlaces and $80) shr 7;
651 exp := -(aValue.SignSpecialPlaces and $2f);
652
653 case SQLType of
654 SQL_DEC16:
655 begin
656 UnPackbuffer(16);
657 DecFloat16 := UtilIntf.getDecFloat16(StatusIntf);
658 Check4DataBaseError;
659 DecFloat16.fromBcd(sign,@buffer,exp,FB_DEC16Ptr(bufptr));
660 Check4DataBaseError;
661 end;
662
663 SQL_DEC34:
664 begin
665 UnPackbuffer(34);
666 DecFloat34 := UtilIntf.getDecFloat34(StatusIntf);
667 Check4DataBaseError;
668 DecFloat34.fromBcd(sign,@buffer,exp,FB_DEC34Ptr(bufptr));
669 Check4DataBaseError;
670 end;
671
672 else
673 IBError(ibxeInvalidDataConversion,[]);
674 end;
675 end;
676
677 function TFB30ClientAPI.SQLDecFloatDecode(SQLType: cardinal; bufptr: PByte): tBCD;
678
679 var DecFloat16: IDecFloat16;
680 DecFloat34: IDecFloat34;
681 sign: integer;
682 exp: integer;
683 buffer: array [1..38] of byte;
684
685 procedure packbuffer(buflen: integer);
686 var i,j: integer;
687 begin
688 { write('Decode: BCD Buffer = ');
689 for i := 1 to 34 do
690 write(buffer[i],' ');
691 writeln; }
692 {pack buffer}
693 i := 1;
694 while (i <= buflen) and (buffer[i] = 0) do {skip leading zeroes}
695 inc(i);
696
697 j := 0;
698 Result.Precision := 0;
699 while i <= buflen do
700 begin
701 inc(Result.Precision);
702 if odd(Result.Precision) then
703 Result.Fraction[j] := (buffer[i] and $0f) shl 4
704 else
705 begin
706 Result.Fraction[j] := Result.Fraction[j] or (buffer[i] and $0f);
707 Inc(j);
708 end;
709 inc(i);
710 end;
711 end;
712
713 begin
714 Result := inherited SQLDecFloatDecode(SQLType, bufptr);
715 FillChar(Result, sizeof(tBCD),0);
716 case SQLType of
717 SQL_DEC16:
718 begin
719 DecFloat16 := UtilIntf.getDecFloat16(StatusIntf);
720 Check4DataBaseError;
721 DecFloat16.toBcd(FB_DEC16Ptr(bufptr),@sign,@buffer,@exp);
722 Check4DataBaseError;
723 packbuffer(16);
724 end;
725
726 SQL_DEC34:
727 begin
728 DecFloat34 := UtilIntf.getDecFloat34(StatusIntf);
729 Check4DataBaseError;
730 DecFloat34.toBcd(FB_DEC34Ptr(bufptr),@sign,@buffer,@exp);
731 Check4DataBaseError;
732 packbuffer(34);
733 end;
734
735 else
736 IBError(ibxeInvalidDataConversion,[]);
737 end;
738 Result.SignSpecialPlaces := (-exp and $2f);
739 if sign <> 0 then
740 Result.SignSpecialPlaces := Result.SignSpecialPlaces or $80;
741 end;
742
743 procedure TFB30ClientAPI.StrToInt128(scale: integer; aValue: AnsiString;
744 bufptr: PByte);
745 begin
746 inherited StrToInt128(scale,aValue,bufPtr);
747
748 UtilIntf.getInt128(StatusIntf).fromString(StatusIntf,scale,PAnsiChar(aValue),FB_I128Ptr(bufptr));
749 Check4DatabaseError;
750 end;
751
752 function TFB30ClientAPI.Int128ToStr(bufptr: PByte; scale: integer
753 ): AnsiString;
754 const
755 bufLength = 64;
756 var Buffer: array[ 0.. bufLength] of AnsiChar;
757 begin
758 Result := inherited Int128ToStr(bufPtr,scale);
759
760 UtilIntf.getInt128(StatusIntf).toString(StatusIntf,FB_I128Ptr(bufptr),scale,buflength,PAnsiChar(@Buffer));
761 Check4DatabaseError;
762 Result := strpas(PAnsiChar(@Buffer));
763 end;
764
765 function TFB30ClientAPI.HasLocalTZDB: boolean;
766 const
767 bufLength = 128;
768 var Buffer: ISC_TIME_TZ;
769 Hr, Mt, S, DMs: cardinal;
770 tzBuffer: array[ 0.. bufLength] of AnsiChar;
771 begin
772 Result := HasTimeZoneSupport;
773 if Result then
774 begin
775 Buffer.utc_time := 0;
776 Buffer.time_zone := TimeZoneID_GMT;
777 UtilIntf.decodeTimeTz(StatusIntf, ISC_TIME_TZPtr(@Buffer),@Hr, @Mt, @S, @DMs,bufLength,PAnsiChar(@tzBuffer));
778 Check4DataBaseError;
779 Result := strpas(PAnsiChar(@tzBuffer)) <> 'GMT*';
780 end;
781 end;
782
783 function TFB30ClientAPI.HasTimeZoneSupport: boolean;
784 begin
785 Result := Firebird4orLater;
786 end;
787
788 function TFB30ClientAPI.HasExtendedTZSupport: boolean;
789 begin
790 Result := Firebird4orLater;
791 end;
792
793 function TFB30ClientAPI.HasInt128Support: boolean;
794 begin
795 Result := Firebird4orLater;
796 end;
797
798 end.
799
800