ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBParamBlock.pas
Revision: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (7 years, 11 months ago) by tony
Content type: text/x-pascal
File size: 16613 byte(s)
Log Message:
Committing updates for Release R2-0-0

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