ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBParamBlock.pas
Revision: 143
Committed: Fri Feb 23 12:11:21 2018 UTC (6 years, 9 months ago) by tony
Content type: text/x-pascal
Original Path: ibx/trunk/fbintf/client/FBParamBlock.pas
File size: 19538 byte(s)
Log Message:
Fixes Merged

File Contents

# User Rev Content
1 tony 45 (*
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 FBParamBlock;
28 tony 56 {$IFDEF MSWINDOWS}
29     {$DEFINE WINDOWS}
30     {$ENDIF}
31 tony 45
32     {$IFDEF FPC}
33 tony 56 {$mode delphi}
34 tony 45 {$interfaces COM}
35     {$ENDIF}
36    
37     interface
38    
39     {Provides common handling for the DPB, TPB, SPB and Service Request Block (SRB)}
40    
41     uses
42     Classes, SysUtils, IB, FBClientAPI, FBActivityMonitor;
43    
44     type
45     TParamDataType = (dtString, dtString2, dtString0, dtByte, dtByte2, dtInteger, dtInteger1,
46     dtInteger2, dtShortInteger,dtTinyInteger,dtnone);
47    
48     PParamBlockItemData = ^TParamBlockItemData;
49     TParamBlockItemData = record
50     {Describes a Clumplet in the buffer. FBufPtr always points to the clumplet id
51     the rest of the clumplet up to the FBufLength is data. The data format is
52     given by FDataType}
53 tony 56 FBufPtr: PByte;
54 tony 45 FBuflength: integer;
55     FDataType: TParamDataType;
56     end;
57    
58     TParamBlockItem = class;
59    
60     { TParamBlock }
61    
62     TParamBlock = class(TFBInterfacedObject)
63     private
64     FItems: array of PParamBlockItemData;
65     FBufferSize: integer;
66     procedure AdjustBuffer;
67     procedure MoveBy(Item: PParamBlockItemData; delta: integer);
68     procedure UpdateRequestItemSize(Item: TParamBlockItem; NewSize: integer);
69     protected
70 tony 56 FBuffer: PByte;
71 tony 45 FDataLength: integer;
72     function Add(ParamType: byte): PParamBlockItemData;
73     function Find(ParamType: byte): PParamBlockItemData;
74     function GetItems(index: integer): PParamBlockItemData;
75     public
76     constructor Create;
77     destructor Destroy; override;
78 tony 56 function getBuffer: PByte;
79 tony 45 function getDataLength: integer;
80     function AvailableBufferSpace: integer;
81    
82     public
83     function getCount: integer;
84     procedure Remove(ParamType: byte);
85     procedure PrintBuf;
86     end;
87    
88     { TParamBlockItem }
89    
90     TParamBlockItem = class(TFBInterfacedObject)
91     private
92     FOwner: TParamBlock;
93     FOwnerIntf: IUnknown;
94     FParamData: PParamBlockItemData;
95     protected
96     property ParamData: PParamBlockItemData read FParamData;
97     public
98     constructor Create(AOwner: TParamBlock; Data: PParamBlockItemData);
99     public
100     function getAsInteger: integer;
101     function getParamType: byte;
102 tony 56 function getAsString: AnsiString;
103 tony 45 function getAsByte: byte;
104     procedure addByte(aValue: byte);
105     procedure addShortInteger(aValue: integer);
106     procedure setAsByte(aValue: byte);
107     procedure setAsByte2(aValue: byte);
108     procedure SetAsInteger(aValue: integer);
109     procedure SetAsInteger1(aValue: integer);
110     procedure SetAsInteger2(aValue: integer);
111     procedure SetAsShortInteger(aValue: integer);
112     procedure SetAsTinyInteger(aValue: integer);
113 tony 56 procedure SetAsString(aValue: AnsiString);
114     procedure SetAsString2(aValue: AnsiString);
115     procedure SetAsString0(aValue: AnsiString);
116 tony 45 end;
117    
118     { TDPBItem }
119    
120     TDPBItem = class(TParamBlockItem,IDPBItem);
121    
122     { TTPBItem }
123    
124     TTPBItem = class(TParamBlockItem,ITPBItem);
125    
126     { TSPBItem }
127    
128     TSPBItem = class(TParamBlockItem,ISPBItem);
129    
130     { TSRBItem }
131    
132     TSRBItem = class(TParamBlockItem,ISRBItem)
133     public
134 tony 56 {$IFDEF FPC}
135     procedure ISRBItem.SetAsString = SetAsString2;
136     procedure ISRBItem.SetAsByte = SetAsByte2;
137     {$ELSE}
138     procedure SetAsString(aValue: AnsiString) ;
139     procedure SetAsByte(aValue: byte);
140     {$ENDIF}
141 tony 45 end;
142    
143     { TSQPBItem }
144    
145     TSQPBItem = class(TParamBlockItem,ISQPBItem)
146     public
147     function CopyFrom(source: TStream; count: integer): integer;
148 tony 56 {$IFDEF FPC}
149 tony 45 procedure ISQPBItem.SetAsInteger = SetAsInteger2;
150     procedure ISQPBItem.SetAsString = SetAsString2;
151 tony 56 {$ELSE}
152     procedure SetAsString(aValue: AnsiString) ;
153     procedure SetAsInteger(aValue: integer);
154     {$ENDIF}
155 tony 45 end;
156    
157     { TBPBItem }
158    
159     TBPBItem = class(TParamBlockItem,IBPBItem)
160     public
161 tony 56 {$IFDEF FPC}
162 tony 45 procedure IBPBItem.SetAsInteger = SetAsInteger1;
163 tony 56 {$ELSE}
164     procedure SetAsInteger(aValue: integer);
165     {$ENDIF}
166 tony 45 end;
167    
168 tony 143 { TDIRBItem }
169    
170     TDIRBItem = class(TParamBlockItem,IDIRBItem)
171     public
172     {$IFDEF FPC}
173     procedure IDIRBItem.SetAsInteger = SetAsInteger2;
174     {$ELSE}
175     procedure SetAsInteger(aValue: integer);
176     {$ENDIF}
177     end;
178    
179 tony 56 { TCustomParamBlock }
180    
181     {$IFDEF FPC}
182     TCustomParamBlock<_TItem, _IItem> = class(TParamBlock)
183     {$ELSE}
184     TParamBlockItemClass = class of TParamBlockItem;
185     TCustomParamBlock<_TItem: TParamBlockItem; _IItem: IParameterBlockItem> = class(TParamBlock)
186     {$ENDIF}
187     public
188     function Add(ParamType: byte): _IItem;
189     function Find(ParamType: byte): _IItem;
190     function GetItems(index: integer): _IItem;
191     end;
192    
193     { TDPB }
194    
195     TDPB = class (TCustomParamBlock<TDPBItem,IDPBItem>, IDPB)
196     public
197     constructor Create;
198     end;
199    
200     { TTPB }
201    
202     TTPB = class (TCustomParamBlock<TTPBItem,ITPBItem>, ITPB)
203     public
204     constructor Create;
205     end;
206    
207     { TSPB }
208    
209     TSPB = class (TCustomParamBlock<TSPBItem,ISPBItem>, ISPB)
210     public
211     constructor Create;
212     end;
213    
214     { TSRB }
215    
216     TSRB = class (TCustomParamBlock<TSRBItem,ISRBItem>, ISRB);
217    
218     { TSQPB }
219    
220     TSQPB = class (TCustomParamBlock<TSQPBItem,ISQPBItem>, ISQPB);
221    
222 tony 45 { TBPB }
223    
224 tony 56 TBPB = class (TCustomParamBlock<TBPBItem,IBPBItem>, IBPB)
225 tony 45 public
226     constructor Create;
227     end;
228    
229 tony 143 TDIRB = class (TCustomParamBlock<TDIRBItem,IDIRBItem>, IDIRB);
230    
231 tony 45 implementation
232    
233 tony 56 uses FBMessages {$IFNDEF FPC} , TypInfo {$ENDIF};
234 tony 45
235     const
236     MaxBufferSize = 65535;
237    
238 tony 143 { TDIRBItem }
239     {$IFNDEF FPC}
240     procedure TDIRBItem.SetAsInteger(aValue: integer);
241     begin
242     SetAsInteger2(aValue);
243     end;
244     {$ENDIF}
245    
246 tony 56 { TBPBItem }
247     {$IFNDEF FPC}
248     procedure TBPBItem.SetAsInteger(aValue: integer);
249 tony 45 begin
250 tony 56 SetAsInteger1(aValue);
251 tony 45 end;
252 tony 56 {$ENDIF}
253 tony 45
254 tony 56 { TSRBItem }
255    
256     {$IFNDEF FPC}
257     procedure TSRBItem.SetAsString(aValue: AnsiString);
258 tony 45 begin
259 tony 56 SetAsString2(aValue);
260 tony 45 end;
261    
262 tony 56 procedure TSRBItem.SetAsByte(aValue: byte);
263 tony 45 begin
264 tony 56 SetAsByte2(aValue);
265 tony 45 end;
266 tony 56 {$ENDIF}
267 tony 45
268     { TSQPBItem }
269    
270     function TSQPBItem.CopyFrom(source: TStream; count: integer): integer;
271     begin
272     if count > (FOwner.AvailableBufferSpace - 4) then
273     count := FOwner.AvailableBufferSpace - 4;
274     with FParamData^ do
275     begin
276     FOwner.UpdateRequestItemSize(self,count + 4);
277     Result := source.Read((FBufPtr+3)^,count);
278     with FirebirdClientAPI do
279     EncodeInteger(Result,2,FBufPtr+1);
280 tony 56 (FBufPtr+Result + 3)^ := isc_info_end;
281 tony 45 if Result <> count then
282     FOwner.UpdateRequestItemSize(self,Result + 4);
283     FDataType := dtString2;
284     end;
285     end;
286    
287 tony 56 {$IFNDEF FPC}
288     procedure TSQPBItem.SetAsString(aValue: AnsiString);
289     begin
290     SetAsString2(aValue);
291     end;
292 tony 45
293 tony 56 procedure TSQPBItem.SetAsInteger(aValue: integer);
294 tony 45 begin
295 tony 56 SetAsInteger2(aValue);
296 tony 45 end;
297 tony 56 {$ENDIF}
298 tony 45
299     { TParamBlockItem }
300    
301     constructor TParamBlockItem.Create(AOwner: TParamBlock;
302     Data: PParamBlockItemData);
303     begin
304     inherited Create;
305     FOwner := AOwner;
306     FOwnerIntf := AOwner;
307     FParamData := Data;
308     end;
309    
310     function TParamBlockItem.getAsInteger: integer;
311     begin
312     with FirebirdClientAPI, FParamData^ do
313     case FDataType of
314     dtInteger:
315     Result := DecodeInteger(FBufPtr+1,4);
316     dtShortInteger:
317     Result := DecodeInteger(FBufPtr+1,2);
318     dtTinyInteger:
319     Result := DecodeInteger(FBufPtr+1,1);
320     dtInteger1:
321     Result := DecodeInteger(FBufPtr+2,2);
322     dtInteger2:
323     Result := DecodeInteger(FBufPtr+3,4);
324     else
325     IBError(ibxePBParamTypeError,[nil]);
326     end;
327     end;
328    
329     function TParamBlockItem.getParamType: byte;
330     begin
331     Result := byte(FParamData^.FBufPtr^);
332     end;
333    
334 tony 56 function TParamBlockItem.getAsString: AnsiString;
335 tony 45 var len: byte;
336     begin
337     Result := '';
338    
339     with FParamData^ do
340     case FDataType of
341     dtInteger,
342     dtInteger1,
343     dtInteger2,
344     dtShortInteger,
345     dtTinyInteger:
346     Result := IntToStr(getAsInteger);
347     dtByte,
348     dtByte2:
349     Result := IntToStr(getAsByte);
350     dtString:
351     begin
352 tony 56 len := (FBufPtr+1)^;
353     SetString(Result,PAnsiChar(FBufPtr+2),len);
354 tony 45 end;
355     dtString2:
356     begin
357     with FirebirdClientAPI do
358     len := DecodeInteger(FBufPtr+1,2);
359 tony 56 SetString(Result,PAnsiChar(FBufPtr+3),len);
360 tony 45 end;
361     dtString0:
362 tony 56 Result := strpas(PAnsiChar(FBufPtr+1));
363 tony 45 else
364     IBError(ibxeOutputBlockTypeError,[nil]);
365     end;
366     end;
367    
368     function TParamBlockItem.getAsByte: byte;
369     begin
370     with FParamData^ do
371     if FDataType = dtByte then
372     Result := byte((FBufPtr+2)^)
373     else
374     if FDataType = dtByte2 then
375     Result := byte((FBufPtr+1)^)
376     else
377     IBError(ibxePBParamTypeError,[nil]);
378     end;
379    
380     procedure TParamBlockItem.addByte(aValue: byte);
381     var len: integer;
382 tony 56 P: PByte;
383 tony 45 begin
384     with FParamData^ do
385     begin
386     P := FBufPtr + FBufLength;
387     len := FBufLength + 1;
388     FOwner.UpdateRequestItemSize(self,len);
389 tony 56 P^ := aValue;
390 tony 45 end;
391     end;
392    
393     procedure TParamBlockItem.addShortInteger(aValue: integer);
394     var len: integer;
395 tony 56 P: PByte;
396 tony 45 begin
397     with FParamData^ do
398     begin
399     P := FBufPtr + FBufLength;
400     len := FBufLength + 2;
401     FOwner.UpdateRequestItemSize(self,len);
402     with FirebirdClientAPI do
403     EncodeInteger(aValue,2,P);
404     end;
405     end;
406    
407     procedure TParamBlockItem.setAsByte(aValue: byte);
408     begin
409     with FParamData^ do
410     begin
411     if FBufLength <> 3 then
412     FOwner.UpdateRequestItemSize(self,3);
413     FDataType := dtByte;
414 tony 56 (FBufPtr+1)^ := $1;
415     (FBufPtr+2)^ := aValue;
416 tony 45 end;
417     end;
418    
419     procedure TParamBlockItem.setAsByte2(aValue: byte);
420     begin
421     with FParamData^ do
422     begin
423     if FBufLength <> 2 then
424     FOwner.UpdateRequestItemSize(self,2);
425     FDataType := dtByte2;
426 tony 56 (FBufPtr+1)^ := aValue;
427 tony 45 end;
428     end;
429    
430     {Four byte integer - no length}
431    
432     procedure TParamBlockItem.SetAsInteger(aValue: integer);
433     begin
434     with FParamData^ do
435     begin
436     if FBufLength <> 5 then
437     FOwner.UpdateRequestItemSize(self,5);
438     with FirebirdClientAPI do
439     EncodeInteger(aValue,4,FBufPtr+1);
440     FDataType := dtInteger;
441     end;
442     end;
443    
444     {Four byte integer - length byte}
445    
446     procedure TParamBlockItem.SetAsInteger1(aValue: integer);
447     begin
448     with FParamData^ do
449     begin
450     if FBufLength <> 6 then
451     FOwner.UpdateRequestItemSize(self,6);
452 tony 56 (FBufPtr+1)^ := $4;
453 tony 45 with FirebirdClientAPI do
454     EncodeInteger(aValue,4,FBufPtr+2);
455     FDataType := dtInteger1;
456     end;
457     end;
458    
459     {Four byte integer - 2 byte length}
460    
461     procedure TParamBlockItem.SetAsInteger2(aValue: integer);
462     begin
463     with FParamData^ do
464     begin
465     if FBufLength <> 7 then
466     FOwner.UpdateRequestItemSize(self,7);
467     with FirebirdClientAPI do
468     begin
469     EncodeInteger(4,2,FBufPtr+1); {Encode length as two bytes}
470     EncodeInteger(aValue,4,FBufPtr+3);
471     end;
472     FDataType := dtInteger2
473     end;
474     end;
475    
476     procedure TParamBlockItem.SetAsShortInteger(aValue: integer);
477     begin
478     with FParamData^ do
479     begin
480     if FBufLength <> 3 then
481     FOwner.UpdateRequestItemSize(self,3);
482     with FirebirdClientAPI do
483     EncodeInteger(aValue,2,FBufPtr+1);
484     FDataType := dtShortInteger;
485     end;
486     end;
487    
488     procedure TParamBlockItem.SetAsTinyInteger(aValue: integer);
489     begin
490     with FParamData^ do
491     begin
492     if FBufLength <> 2 then
493     FOwner.UpdateRequestItemSize(self,2);
494     with FirebirdClientAPI do
495     EncodeInteger(aValue,1,FBufPtr+1);
496     FDataType := dtTinyInteger;
497     end;
498     end;
499    
500     {Short string encoding}
501    
502 tony 56 procedure TParamBlockItem.SetAsString(aValue: AnsiString);
503 tony 45 var len: integer;
504     begin
505     with FParamData^ do
506     begin
507     len := Length(aValue);
508     if len > 255 then
509     IBError(ibxStringTooLong,[aValue,255]);
510     FOwner.UpdateRequestItemSize(self,len+2);
511 tony 56 (FBufPtr+1)^ := len;
512 tony 45 if len > 0 then
513     Move(aValue[1],(FBufPtr+2)^,len);
514     FDataType := dtString;
515     end;
516     end;
517    
518     {Long string up to 65535 encoding}
519    
520 tony 56 procedure TParamBlockItem.SetAsString2(aValue: AnsiString);
521 tony 45 var len: integer;
522     begin
523     with FParamData^ do
524     begin
525     len := Length(aValue);
526     if len > 65535 then
527     IBError(ibxStringTooLong,[aValue,65535]);
528     FOwner.UpdateRequestItemSize(self,len + 3);
529     with FirebirdClientAPI do
530     EncodeInteger(len,2,FBufPtr+1);
531     if len > 0 then
532     Move(aValue[1],(FBufPtr+3)^,len);
533     FDataType := dtString2;
534     end;
535     end;
536    
537     {Zero byte terminated string encoding}
538    
539 tony 56 procedure TParamBlockItem.SetAsString0(aValue: AnsiString);
540 tony 45 var len: integer;
541     begin
542     with FParamData^ do
543     begin
544     len := Length(aValue);
545     FOwner.UpdateRequestItemSize(self,len+2);
546     if len > 0 then
547     Move(aValue[1],(FBufPtr+1)^,len);
548 tony 56 (FBufPtr+len+1)^ := 0;
549 tony 45 FDataType := dtString0;
550     end;
551     end;
552    
553     { TParamBlock }
554    
555     procedure TParamBlock.AdjustBuffer;
556 tony 56 var P: PByte;
557 tony 45 i: integer;
558     headerLen: integer;
559     begin
560     if FDataLength > FBufferSize then
561     begin
562     if Length(FItems) > 0 then
563     headerLen := FItems[0]^.FBufPtr - FBuffer
564     else
565     headerLen := 0;
566     FBufferSize := 2*FDataLength;
567     ReallocMem(FBuffer,FBufferSize);
568     P := FBuffer + headerLen;
569     for i := 0 to Length(FItems) - 1 do
570     begin
571     FItems[i]^.FBufPtr := P;
572     Inc(P,FItems[i]^.FBuflength);
573     end;
574     end;
575     end;
576    
577     procedure TParamBlock.MoveBy(Item: PParamBlockItemData; delta: integer);
578 tony 56 var src, dest: PByte;
579 tony 45 i: integer;
580     begin
581     with Item^ do
582     begin
583     src := FBufptr;
584     dest := FBufptr + delta ;
585     if delta > 0 then
586     begin
587     for i := FBufLength - 1 downto 0 do
588     (dest +i)^ := (src+i)^;
589     end
590     else
591     begin
592     for i := 0 to FBufLength - 1 do
593     (dest +i)^ := (src+i)^;
594     end;
595 tony 56 FBufPtr := FBufPtr + delta;
596 tony 45 end;
597     end;
598    
599     procedure TParamBlock.UpdateRequestItemSize(Item: TParamBlockItem;
600     NewSize: integer);
601     var i, delta: integer;
602     begin
603     delta := NewSize - Item.FParamData^.FBufLength;
604     Item.FParamData^.FBufLength := NewSize;
605     if delta > 0 then
606     begin
607     if FDataLength + delta > MaxBufferSize then
608     IBError(ibxeParamBufferOverflow,[nil]);
609 tony 56 FDataLength := FDataLength + delta;
610 tony 45 AdjustBuffer;
611     i := Length(FItems) - 1;
612     while i >= 0 do
613     begin
614     if FItems[i] = Item.FParamData then
615     break; {we're done}
616     Moveby(FItems[i],delta);
617     Dec(i);
618     end;
619     end
620     else
621     begin
622     i := 0;
623     while i < Length(FItems) do
624     begin
625     if FItems[i] = Item.FParamData then
626     break; {we're done}
627     Inc(i);
628     end;
629     Inc(i);
630     while i < Length(FItems) do
631     begin
632     Moveby(FItems[i],delta);
633     Inc(i);
634     end;
635 tony 56 FDataLength := FDataLength + delta;
636 tony 45 end;
637     end;
638    
639     constructor TParamBlock.Create;
640     begin
641     inherited Create;
642     GetMem(FBuffer,128);
643     if FBuffer = nil then
644     OutOfMemoryError;
645     FBufferSize := 128;
646     FDataLength := 0;
647     end;
648    
649     destructor TParamBlock.Destroy;
650     var i: integer;
651     begin
652     for i := 0 to Length(FItems) -1 do
653     dispose(FItems[i]);
654     Freemem(FBuffer);
655     inherited Destroy;
656     end;
657    
658 tony 56 function TParamBlock.getBuffer: PByte;
659 tony 45 begin
660     if FDataLength = 0 then
661     Result := nil
662     else
663     Result := FBuffer;
664     end;
665    
666     function TParamBlock.getDataLength: integer;
667     begin
668     Result := FDataLength
669     end;
670    
671     function TParamBlock.AvailableBufferSpace: integer;
672     begin
673     Result := MaxBufferSize - FDataLength;
674     end;
675    
676     function TParamBlock.Add(ParamType: byte): PParamBlockItemData;
677     begin
678     new(Result);
679     Result^.FBufPtr := FBuffer + FDataLength;
680     Result^.FBufLength := 1;
681 tony 56 Result^.FBufPtr^ := ParamType;
682 tony 45 Result^.FDataType := dtnone; {default}
683     Inc(FDataLength,1);
684     AdjustBuffer;
685     SetLength(FItems,Length(FItems)+1);
686     FItems[Length(FItems) - 1 ] := Result;
687     end;
688    
689     function TParamBlock.Find(ParamType: byte): PParamBlockItemData;
690     var i: integer;
691     begin
692     Result := nil;
693     for i := 0 to getCount - 1 do
694 tony 56 if byte(FItems[i]^.FBufPtr^) = ParamType then
695 tony 45 begin
696     Result := FItems[i];
697     Exit;
698     end;
699     end;
700    
701     function TParamBlock.GetItems(index: integer): PParamBlockItemData;
702     begin
703     if (index >= 0 ) and (index < Length(FItems)) then
704     Result := FItems[index]
705     else
706     IBError(ibxePBIndexError,[index]);
707     end;
708    
709     function TParamBlock.getCount: integer;
710     begin
711     Result := Length(FItems);
712     end;
713    
714     procedure TParamBlock.Remove(ParamType: byte);
715     var P: PParamBlockItemData;
716     i, j: integer;
717     begin
718     P := nil;
719     for i := 0 to getCount - 1 do
720 tony 56 if byte(FItems[i]^.FBufPtr^) = ParamType then
721 tony 45 begin
722     P := FItems[i];
723     for j := i + 1 to getCount - 1 do
724     begin
725     MoveBy(FItems[j],-P^.FBufLength);
726     FItems[j - 1] := FItems[j];
727     end;
728 tony 56 FDataLength := FDataLength - P^.FBufLength;
729 tony 45 dispose(P);
730     SetLength(FItems,Length(FItems)-1);
731     Exit;
732     end;
733     end;
734    
735     procedure TParamBlock.PrintBuf;
736     var i: integer;
737     begin
738     write(ClassName,': ');
739     for i := 0 to getDataLength - 1 do
740     write(Format('%x ',[byte(FBuffer[i])]));
741     writeln
742     end;
743    
744 tony 56 { TCustomParamBlock }
745    
746     {$IFDEF FPC}
747     function TCustomParamBlock<_TItem, _IItem>.Add(ParamType: byte): _IItem;
748     var Item: PParamBlockItemData;
749     begin
750     Item := inherited Add(ParamType);
751     Result := _TItem.Create(self,Item);
752     end;
753    
754     function TCustomParamBlock<_TItem, _IItem>.Find(ParamType: byte): _IItem;
755     var Item: PParamBlockItemData;
756     begin
757     Result := nil;
758     Item := inherited Find(ParamType);
759     if Item <> nil then
760     Result := _TItem.Create(self,Item);
761     end;
762    
763     function TCustomParamBlock<_TItem, _IItem>.GetItems(index: integer): _IItem;
764     var Item: PParamBlockItemData;
765     begin
766     Item := inherited getItems(index);
767     Result := _TItem.Create(self,Item);
768     end;
769     {$ELSE}
770     function TCustomParamBlock<_TItem, _IItem>.Add(ParamType: byte): _IItem;
771     var Item: PParamBlockItemData;
772     Obj: TParamBlockItem;
773     begin
774     Item := inherited Add(ParamType);
775     Obj := TParamBlockItemClass(_TItem).Create(self,Item);
776     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
777     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
778     end;
779    
780     function TCustomParamBlock<_TItem, _IItem>.Find(ParamType: byte): _IItem;
781     var Item: PParamBlockItemData;
782     Obj: TParamBlockItem;
783     begin
784     FillChar(Result,sizeof(Result),0); {workaround for older versions of Delphi}
785     Item := inherited Find(ParamType);
786     if Item <> nil then
787     begin
788     Obj := TParamBlockItemClass(_TItem).Create(self,Item);
789     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
790     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
791     end;
792     end;
793    
794     function TCustomParamBlock<_TItem, _IItem>.GetItems(index: integer): _IItem;
795     var Item: PParamBlockItemData;
796     Obj: TParamBlockItem;
797     begin
798     Item := inherited getItems(index);
799     Obj := TParamBlockItemClass(_TItem).Create(self,Item);
800     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
801     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
802     end;
803     {$ENDIF}
804    
805 tony 45 { TDPB }
806    
807     constructor TDPB.Create;
808     begin
809     inherited Create;
810     FDataLength := 1;
811 tony 56 FBuffer^ := isc_dpb_version1;
812 tony 45 end;
813    
814     { TTPB }
815    
816     constructor TTPB.Create;
817     begin
818     inherited Create;
819     FDataLength := 1;
820 tony 56 FBuffer^ := isc_tpb_version3;
821 tony 45 end;
822    
823     { TSPB }
824    
825     constructor TSPB.Create;
826     begin
827     inherited Create;
828     FDataLength := 2;
829 tony 56 FBuffer^ := isc_spb_version;
830     (FBuffer+1)^ := isc_spb_current_version;
831 tony 45 end;
832    
833 tony 56 { TBPB }
834    
835     constructor TBPB.Create;
836     begin
837     inherited Create;
838     FDataLength := 1;
839     FBuffer^ := isc_bpb_version1;
840     end;
841    
842 tony 45 end.
843