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: 390
Committed: Sat Jan 22 16:15:12 2022 UTC (2 years, 10 months ago) by tony
Content type: text/x-pascal
File size: 23232 byte(s)
Log Message:
In Firebird 3 and later API: the status vector is now a thread var

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

Properties

Name Value
svn:eol-style native