ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/3.0/FB30ClientAPI.pas
Revision: 386
Committed: Tue Jan 18 12:05:35 2022 UTC (2 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 22556 byte(s)
Log Message:
Silent exceptions bug fixed

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

Properties

Name Value
svn:eol-style native