ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBOutputBlock.pas
Revision: 345
Committed: Mon Aug 23 14:22:29 2021 UTC (3 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 35446 byte(s)
Log Message:
Merged into public release

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 FBOutputBlock;
28 tony 56 {$IFDEF MSWINDOWS}
29     {$DEFINE WINDOWS}
30     {$ENDIF}
31 tony 45
32     {$IFDEF FPC}
33 tony 56 {$mode delphi}
34 tony 45 {$codepage UTF8}
35     {$interfaces COM}
36     {$ENDIF}
37    
38     { $DEFINE DEBUGOUTPUTBLOCK}
39    
40     interface
41    
42     {Provides common handling for the DB Info results, SQL Info and Service Response Block}
43    
44     uses
45     Classes, SysUtils, FBClientAPI, IB, FBActivityMonitor;
46    
47     const
48     DefaultBufferSize = 32000;
49 tony 143 DBInfoDefaultBufferSize = DefaultBufferSize; {allow for database page}
50 tony 45
51     type
52     TItemDataType = (dtString, dtString2, dtByte, dtBytes, dtInteger, dtIntegerFixed, dtnone,
53 tony 143 dtList,dtSpecial, dtDateTime, dtOctetString);
54 tony 45
55     POutputBlockItemData = ^TOutputBlockItemData;
56     TOutputBlockItemData = record
57     {Describes a Clumplet in the buffer. FBufPtr always points to the clumplet id
58     the rest of the clumplet up to the FSize is data. The data format is
59     given by FDataType, and the data length is given by FDataLength}
60 tony 56 FBufPtr: PByte;
61 tony 45 FDataLength: integer;
62     FSize: integer;
63     FDataType: TItemDataType;
64     FTruncated: boolean;
65     FError: boolean;
66     FSubItems: array of POutputBlockItemData;
67     end;
68    
69     { TOutputBlock }
70    
71     TOutputBlock = class(TFBInterfacedObject)
72     private
73 tony 56 FBuffer: PByte;
74 tony 45 FBufSize: integer;
75     FBufferParsed: boolean;
76 tony 263 FFirebirdClientAPI: TFBClientAPI;
77 tony 45 procedure ParseBuffer;
78     {$IFDEF DEBUGOUTPUTBLOCK}
79     procedure FormattedPrint(const aItems: array of POutputBlockItemData;
80 tony 56 Indent: AnsiString);
81 tony 45 {$ENDIF}
82     procedure PrintBuf;
83     protected
84     FIntegerType: TItemDataType;
85     FError: boolean;
86     FTruncated: boolean;
87     FItems: array of POutputBlockItemData;
88     procedure DoParseBuffer; virtual; abstract;
89 tony 56 function AddItem(BufPtr: PByte): POutputBlockItemData;
90     function AddIntegerItem(BufPtr: PByte): POutputBlockItemData;
91     function AddStringItem(BufPtr: PByte): POutputBlockItemData;
92     function AddShortStringItem(BufPtr: PByte): POutputBlockItemData;
93     function AddByteItem(BufPtr: PByte): POutputBlockItemData;
94     function AddBytesItem(BufPtr: PByte): POutputBlockItemData;
95     function AddListItem(BufPtr: PByte): POutputBlockItemData; virtual;
96     function AddSpecialItem(BufPtr: PByte): POutputBlockItemData; virtual;
97 tony 143 function AddDateTimeItem(BufPtr: PByte): POutputBlockItemData;
98     function AddOctetString(BufPtr: PByte): POutputBlockItemData;
99 tony 45 public
100 tony 263 constructor Create(api: TFBClientAPI; aSize: integer = DefaultBufferSize);
101 tony 45 destructor Destroy; override;
102 tony 56 function Buffer: PByte;
103 tony 45 function getBufSize: integer;
104    
105     public
106     function GetCount: integer;
107     function GetItem(index: integer): POutputBlockItemData;
108     function Find(ItemType: byte): POutputBlockItemData;
109     property Count: integer read GetCount;
110     property Items[index: integer]: POutputBlockItemData read getItem; default;
111     end;
112    
113     { TOutputBlockItem }
114    
115     TOutputBlockItem = class(TFBInterfacedObject,IUnknown)
116     private
117     FOwner: TOutputBlock;
118     FOwnerIntf: IUnknown;
119     FItemData: POutputBlockItemData;
120 tony 263 FFirebirdClientAPI: TFBClientAPI;
121 tony 45 protected
122     function GetItem(index: integer): POutputBlockItemData;
123     function Find(ItemType: byte): POutputBlockItemData;
124 tony 56 procedure SetString(out S: AnsiString; Buf: PByte; Len: integer;
125 tony 45 CodePage: TSystemCodePage);
126     property ItemData: POutputBlockItemData read FItemData;
127     property Owner: TOutputBlock read FOwner;
128     public
129     constructor Create(AOwner: TOutputBlock; Data: POutputBlockItemData);
130     public
131     function GetCount: integer;
132     function getItemType: byte;
133     function getSize: integer;
134     procedure getRawBytes(var Buffer);
135 tony 345 function getAsInteger: int64;
136 tony 45 function getParamType: byte;
137 tony 56 function getAsString: AnsiString;
138 tony 45 function getAsByte: byte;
139     function getAsBytes: TByteArray;
140 tony 143 function getAsDateTime: TDateTime;
141 tony 45 function CopyTo(stream: TStream; count: integer): integer;
142     end;
143    
144 tony 56 TServiceQueryResultSubItem = class(TOutputBlockItem,IServiceQueryResultSubItem);
145    
146 tony 45 { TCustomOutputBlock }
147    
148 tony 56 {$IFDEF FPC}
149     TCustomOutputBlock<_TItem,_IItem> = class(TOutputBlock)
150     {$ELSE}
151     TOutputBlockItemClass = class of TOutputBlockItem;
152     TCustomOutputBlock<_TItem: TOutputBlockItem;_IItem: IUnknown> = class(TOutputBlock)
153     {$ENDIF}
154 tony 45 public
155     function getItem(index: integer): _IItem;
156     function find(ItemType: byte): _IItem;
157     property Items[index: integer]: _IItem read getItem; default;
158     end;
159    
160     { TOutputBlockItemGroup }
161    
162 tony 56 {$IFDEF FPC}
163     TOutputBlockItemGroup<_TItem,_IItem> = class(TOutputBlockItem)
164     {$ELSE}
165     TOutputBlockItemGroup<_TItem: TOutputBlockItem; _IItem: IUnknown> = class(TOutputBlockItem)
166     {$ENDIF}
167 tony 45 public
168     function GetItem(index: integer): _IItem;
169     function Find(ItemType: byte): _IItem;
170     property Items[index: integer]: _IItem read getItem; default;
171     end;
172    
173     { TDBInfoItem }
174    
175 tony 56 {$IFDEF FPC}
176     TDBInfoItem = class;
177    
178     TDBInfoItem = class(TOutputBlockItemGroup<TDBInfoItem,IDBInfoItem>,IDBInfoItem)
179     {$ELSE}
180     TDBInfoItem = class(TOutputBlockItemGroup<TOutputBlockItem,IDBInfoItem>,IDBInfoItem)
181     {$ENDIF}
182 tony 45 public
183 tony 56 procedure DecodeIDCluster(var ConnectionType: integer; var DBFileName, DBSiteName: AnsiString);
184     procedure DecodeVersionString(var Version: byte; var VersionString: AnsiString);
185 tony 45 procedure DecodeUserNames(UserNames: TStrings);
186     function getOperationCounts: TDBOperationCounts;
187 tony 143 end;
188 tony 45
189     { TDBInformation }
190    
191 tony 56 TDBInformation = class(TCustomOutputBlock<TDBInfoItem,IDBInfoItem>, IDBInformation)
192 tony 45 protected
193 tony 56 function AddSpecialItem(BufPtr: PByte): POutputBlockItemData; override;
194 tony 45 procedure DoParseBuffer; override;
195     public
196 tony 263 constructor Create(api: TFBClientAPI; aSize: integer = DefaultBufferSize);
197 tony 143 {$IFNDEF FPC}
198     function Find(ItemType: byte): IDBInfoItem;
199     {$ENDIF}
200 tony 45 end;
201    
202     { TServiceQueryResultItem }
203    
204 tony 56 TServiceQueryResultItem = class(TOutputBlockItemGroup<TServiceQueryResultSubItem,IServiceQueryResultSubItem>,
205 tony 45 IServiceQueryResultItem);
206    
207     { TServiceQueryResults }
208    
209 tony 56 TServiceQueryResults = class(TCustomOutputBlock<TServiceQueryResultItem,IServiceQueryResultItem>, IServiceQueryResults)
210 tony 45 protected
211 tony 56 function AddListItem(BufPtr: PByte): POutputBlockItemData; override;
212     function AddSpecialItem(BufPtr: PByte): POutputBlockItemData; override;
213 tony 45 procedure DoParseBuffer; override;
214 tony 143 {$IFNDEF FPC}
215     public
216     function Find(ItemType: byte): IServiceQueryResultItem;
217     {$ENDIF}
218 tony 45 end;
219    
220 tony 56
221 tony 45 { ISQLInfoItem }
222    
223 tony 56 ISQLInfoSubItem = interface
224     ['{39852ee4-4851-44df-8dc0-26b991250098}']
225 tony 45 function getItemType: byte;
226     function getSize: integer;
227 tony 56 function getAsString: AnsiString;
228 tony 345 function getAsInteger: int64;
229 tony 56 end;
230    
231     ISQLInfoItem = interface(ISQLInfoSubItem)
232     ['{34e3c39d-fe4f-4211-a7e3-0266495a359d}']
233 tony 45 function GetCount: integer;
234 tony 56 function GetItem(index: integer): ISQLInfoSubItem;
235     function Find(ItemType: byte): ISQLInfoSubItem;
236 tony 45 property Count: integer read GetCount;
237 tony 56 property Items[index: integer]: ISQLInfoSubItem read getItem; default;
238 tony 45 end;
239    
240     {ISQLInfoResults}
241    
242     ISQLInfoResults = interface
243 tony 56 ['{0b3fbe20-6f80-44e7-85ef-e708bc1f2043}']
244 tony 45 function GetCount: integer;
245     function GetItem(index: integer): ISQLInfoItem;
246     function Find(ItemType: byte): ISQLInfoItem;
247     property Count: integer read GetCount;
248     property Items[index: integer]: ISQLInfoItem read getItem; default;
249     end;
250    
251 tony 56 TSQLInfoResultsSubItem = class(TOutputBlockItem,ISQLInfoSubItem);
252 tony 45
253     { TSQLInfoResultsItem }
254    
255 tony 56 TSQLInfoResultsItem = class(TOutputBlockItemGroup<TSQLInfoResultsSubItem,ISQLInfoSubItem>,ISQLInfoItem);
256 tony 45
257     { TSQLInfoResultsBuffer }
258    
259 tony 56 TSQLInfoResultsBuffer = class(TCustomOutputBlock<TSQLInfoResultsItem,ISQLInfoItem>, ISQLInfoResults)
260 tony 45 protected
261 tony 56 function AddListItem(BufPtr: PByte): POutputBlockItemData; override;
262 tony 45 procedure DoParseBuffer; override;
263     public
264 tony 263 constructor Create(api: TFBClientAPI; aSize: integer= DefaultBufferSize);
265 tony 45 end;
266    
267 tony 56 IBlobInfoItem = interface
268     ['{3a55e558-b97f-4cf3-af95-53b84f4d9a65}']
269     function getItemType: byte;
270     function getSize: integer;
271     function getAsString: AnsiString;
272 tony 345 function getAsInteger: int64;
273 tony 56 end;
274    
275     IBlobInfo = interface
276     ['{8a340109-f600-4d26-ab1d-e0be2c759f1c}']
277     function GetCount: integer;
278     function GetItem(index: integer): IBlobInfoItem;
279     function Find(ItemType: byte): IBlobInfoItem;
280     property Count: integer read GetCount;
281     property Items[index: integer]: IBlobInfoItem read getItem; default;
282     end;
283    
284     {$IFDEF FPC}
285     TBlobInfoItem = class;
286    
287     TBlobInfoItem = class(TOutputBlockItemGroup<TBlobInfoItem,IBlobInfoItem>,IBlobInfoItem)
288     {$ELSE}
289     TBlobInfoItem = class(TOutputBlockItemGroup<TOutputBlockItem,IBlobInfoItem>,IBlobInfoItem)
290     {$ENDIF}
291    
292     end;
293    
294     { TBlobInfo }
295    
296     TBlobInfo = class(TCustomOutputBlock<TBlobInfoItem,IBlobInfoItem>, IBlobInfo)
297     protected
298     procedure DoParseBuffer; override;
299     public
300 tony 263 constructor Create(api: TFBClientAPI; aSize: integer = DefaultBufferSize);
301 tony 56 end;
302    
303 tony 45 implementation
304    
305 tony 56 uses FBMessages {$IFNDEF FPC}, TypInfo {$ENDIF};
306 tony 45
307 tony 144 function BufToStr(P: PByte; Len: integer):AnsiString;
308     begin
309     SetLength(Result,Len);
310     Move(P^,Result[1],Len);
311     end;
312    
313 tony 56 {$IFDEF FPC}
314 tony 45 { TOutputBlockItemGroup }
315    
316 tony 56 function TOutputBlockItemGroup<_TItem,_IItem>.GetItem(index: integer): _IItem;
317 tony 45 var P: POutputBlockItemData;
318     begin
319     P := inherited getItem(index);
320     Result := _TItem.Create(self.Owner,P);
321     end;
322    
323 tony 56 function TOutputBlockItemGroup<_TItem,_IItem>.Find(ItemType: byte): _IItem;
324 tony 45 var P: POutputBlockItemData;
325     begin
326     P := inherited Find(ItemType);
327     Result := _TItem.Create(self.Owner,P);
328     end;
329    
330     { TCustomOutputBlock }
331    
332 tony 56 function TCustomOutputBlock<_TItem,_IItem>.getItem(index: integer): _IItem;
333 tony 45 var P: POutputBlockItemData;
334     begin
335     P := inherited getItem(index);
336     Result := _TItem.Create(self,P)
337     end;
338    
339 tony 56 function TCustomOutputBlock<_TItem,_IItem>.find(ItemType: byte): _IItem;
340 tony 45 var P: POutputBlockItemData;
341     begin
342     P := inherited Find(ItemType);
343 tony 143 if P = nil then
344     Result := nil
345     else
346     Result := _TItem.Create(self,P)
347 tony 45 end;
348    
349 tony 56 {$ELSE}
350    
351 tony 45 { TOutputBlockItemGroup }
352    
353 tony 56 function TOutputBlockItemGroup<_TItem,_IItem>.GetItem(index: integer): _IItem;
354     var P: POutputBlockItemData;
355     Obj: TOutputBlockItem;
356     begin
357     P := inherited getItem(index);
358     Obj := TOutputBlockItemClass(_TItem).Create(self.Owner,P);
359     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
360     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
361     end;
362    
363     function TOutputBlockItemGroup<_TItem,_IItem>.Find(ItemType: byte): _IItem;
364     var P: POutputBlockItemData;
365     Obj: TOutputBlockItem;
366     begin
367     P := inherited Find(ItemType);
368 tony 143 if P = nil then
369     Result := Default(_IITEM)
370     else
371     begin
372     Obj := TOutputBlockItemClass(_TItem).Create(self.Owner,P);
373     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
374     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
375     end;
376 tony 56 end;
377    
378     { TCustomOutputBlock }
379    
380     function TCustomOutputBlock<_TItem,_IItem>.getItem(index: integer): _IItem;
381     var P: POutputBlockItemData;
382     Obj: TOutputBlockItem;
383     begin
384     P := inherited getItem(index);
385     Obj := TOutputBlockItemClass(_TItem).Create(self,P);
386     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
387     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
388     end;
389    
390     function TCustomOutputBlock<_TItem,_IItem>.find(ItemType: byte): _IItem;
391     var P: POutputBlockItemData;
392     Obj: TOutputBlockItem;
393     begin
394     P := inherited Find(ItemType);
395     Obj := TOutputBlockItemClass(_TItem).Create(self,P);
396     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
397     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
398     end;
399    
400     {$ENDIF}
401    
402     { TOutputBlockItem }
403    
404 tony 45 function TOutputBlockItem.GetCount: integer;
405     begin
406     Result := Length(FItemData^.FSubItems);
407     end;
408    
409     function TOutputBlockItem.GetItem(index: integer): POutputBlockItemData;
410     begin
411     if (index >= 0) and (index < Length(FItemData^.FSubItems)) then
412     Result := FItemData^.FSubItems[index]
413     else
414 tony 263 with FFirebirdClientAPI do
415 tony 45 IBError(ibxeOutputBlockIndexError,[index]);
416     end;
417    
418     function TOutputBlockItem.Find(ItemType: byte): POutputBlockItemData;
419     var i: integer;
420     begin
421     Result := nil;
422     for i := 0 to GetCount - 1 do
423 tony 56 if byte(FItemData^.FSubItems[i]^.FBufPtr^) = ItemType then
424 tony 45 begin
425     Result := FItemData^.FSubItems[i];
426     Exit;
427     end;
428     end;
429    
430     { TOutputBlockItem }
431    
432 tony 56 procedure TOutputBlockItem.SetString(out S: AnsiString; Buf: PByte;
433     Len: integer; CodePage: TSystemCodePage);
434 tony 45 var rs: RawByteString;
435 tony 209 i: integer;
436 tony 45 begin
437 tony 209 {There seems to be a memory manager problem with SetString that can cause
438     an unhandled exception at the end of a program if it is used to set the
439     string. Safer to copy characters one by one. Note that Setlength does
440     not work around the bug either.}
441     rs := '';
442     for i := 0 to len-1 do
443     rs := rs + PAnsiChar(buf+i)^;
444     // system.SetString(rs,PAnsiChar(Buf),len);
445 tony 45 SetCodePage(rs,CodePage,false);
446     S := rs;
447     end;
448    
449     constructor TOutputBlockItem.Create(AOwner: TOutputBlock;
450     Data: POutputBlockItemData);
451     begin
452     inherited Create;
453     FOwner := AOwner;
454     FOwnerIntf := AOwner;
455 tony 263 FFirebirdClientAPI := AOwner.FFirebirdClientAPI;
456 tony 45 FItemData := Data;
457     end;
458    
459     function TOutputBlockItem.getItemType: byte;
460     begin
461     Result := byte(FItemData^.FBufPtr^);
462     end;
463    
464     function TOutputBlockItem.getSize: integer;
465     begin
466 tony 143 if FItemData = nil then
467     Result := 0
468     else
469     Result := FItemData^.FDataLength;
470 tony 45 end;
471    
472     procedure TOutputBlockItem.getRawBytes(var Buffer);
473     begin
474     with FItemData^ do
475     Move(FBufPtr^,Buffer,FDatalength);
476     end;
477    
478 tony 345 function TOutputBlockItem.getAsInteger: int64;
479 tony 45 var len: integer;
480     begin
481     with FItemData^ do
482     case FDataType of
483     dtIntegerFixed:
484 tony 263 with FFirebirdClientAPI do
485 tony 45 Result := DecodeInteger(FBufPtr+1,4);
486    
487     dtByte,
488     dtInteger:
489 tony 263 with FFirebirdClientAPI do
490 tony 45 begin
491     len := DecodeInteger(FBufPtr+1,2);
492     Result := DecodeInteger(FBufPtr+3,len);
493     end;
494     else
495     IBError(ibxeOutputBlockTypeError,[nil]);
496     end;
497     end;
498    
499     function TOutputBlockItem.getParamType: byte;
500     begin
501     Result := byte(FItemData^.FBufPtr^)
502     end;
503    
504 tony 56 function TOutputBlockItem.getAsString: AnsiString;
505 tony 45 var len: integer;
506     begin
507     Result := '';
508     with FItemData^ do
509     case FDataType of
510 tony 144 dtIntegerFixed,
511 tony 45 dtInteger:
512     Result := IntToStr(getAsInteger);
513     dtByte:
514     Result := IntToStr(getAsByte);
515     dtString:
516     begin
517     len := byte((FBufPtr+1)^);
518     SetString(Result,FBufPtr+2,len,CP_ACP);
519     end;
520     dtString2:
521     begin
522 tony 263 with FFirebirdClientAPI do
523 tony 45 len := DecodeInteger(FBufPtr+1,2);
524     SetString(Result,FBufPtr+3,len,CP_ACP);
525     end;
526 tony 143 dtOctetString:
527     begin
528 tony 263 with FFirebirdClientAPI do
529 tony 143 len := DecodeInteger(FBufPtr+1,2);
530     SetString(Result,FBufPtr+3,len,CP_NONE);
531     end;
532 tony 45 else
533     IBError(ibxeOutputBlockTypeError,[nil]);
534     end;
535     end;
536    
537     function TOutputBlockItem.getAsByte: byte;
538     begin
539     with FItemData^ do
540     if FDataType = dtByte then
541     Result := byte((FBufPtr+2)^)
542     else
543     IBError(ibxeOutputBlockTypeError,[nil]);
544     end;
545    
546     function TOutputBlockItem.getAsBytes: TByteArray;
547     var i: integer;
548 tony 56 P: PByte;
549 tony 45 begin
550     with FItemData^ do
551     if FDataType = dtBytes then
552     begin
553     SetLength(Result,FDataLength);
554     P := FBufPtr;
555     for i := 0 to FDataLength - 1 do
556     begin
557     Result[i] := byte(P^);
558     Inc(P);
559     end
560     end
561     else
562     IBError(ibxeOutputBlockTypeError,[nil]);
563     end;
564    
565 tony 143 function TOutputBlockItem.getAsDateTime: TDateTime;
566     var aDate: integer;
567     aTime: integer;
568     begin
569 tony 263 with FItemData^, FFirebirdClientAPI do
570 tony 143 if FDataType = dtDateTime then
571     begin
572     aDate := DecodeInteger(FBufPtr+3,4);
573     aTime := DecodeInteger(FBufPtr+7,4);
574     Result := SQLDecodeDate(@aDate) + SQLDecodeTime(@aTime)
575     end
576     else
577     IBError(ibxeOutputBlockTypeError,[nil]);
578     end;
579    
580    
581 tony 45 function TOutputBlockItem.CopyTo(stream: TStream; count: integer): integer;
582     var len: integer;
583     begin
584     if count < 0 then count := 0;
585     with FItemData^ do
586     begin
587     case FDataType of
588     dtString:
589     begin
590     len := byte((FBufPtr+1)^);
591     if (count > 0) and (count < len) then len := count;
592     Result := stream.Write((FBufPtr+2)^,len);
593     end;
594     dtString2:
595     begin
596 tony 263 with FFirebirdClientAPI do
597 tony 45 len := DecodeInteger(FBufPtr+1,2);
598     if (count > 0) and (count < len) then len := count;
599     Result := stream.Write((FBufPtr+3)^,len);
600     end;
601     else
602     IBError(ibxeOutputBlockTypeError,[nil]);
603     end;
604     end;
605     end;
606    
607     { TOutputBlock }
608    
609     procedure TOutputBlock.ParseBuffer;
610     begin
611     if not FBufferParsed then
612     begin
613     {$IFDEF DEBUGOUTPUTBLOCK}
614     PrintBuf;
615     {$ENDIF}
616     DoParseBuffer;
617     if FError or FTruncated then
618     SetLength(FItems,Length(FItems)-1);
619     {$IFDEF DEBUGOUTPUTBLOCK}
620     FormattedPrint(FItems,'');
621     {$ENDIF}
622     end;
623     FBufferParsed := true;
624     end;
625    
626 tony 56 function TOutputBlock.AddItem(BufPtr: PByte): POutputBlockItemData;
627 tony 45 begin
628     new(Result);
629     with Result^ do
630     begin
631     FDataType := dtNone;
632     FBufPtr := BufPtr;
633     FDataLength := 0;
634     FSize := 1;
635     SetLength(FSubItems,0);
636     end;
637     end;
638    
639 tony 56 function TOutputBlock.AddIntegerItem(BufPtr: PByte): POutputBlockItemData;
640 tony 45 begin
641     new(Result);
642     with Result^ do
643     begin
644     FDataType := FIntegerType;
645     FBufPtr := BufPtr;
646     if FDataType = dtIntegerFixed then
647     begin
648     FDataLength := 4;
649     FSize := 5;
650     end
651     else
652     begin
653 tony 263 with FFirebirdClientAPI do
654 tony 45 FDataLength := DecodeInteger(FBufPtr+1, 2);
655     FSize := FDataLength + 3;
656     end;
657     SetLength(FSubItems,0);
658     end;
659     end;
660    
661 tony 56 function TOutputBlock.AddStringItem(BufPtr: PByte): POutputBlockItemData;
662 tony 45 begin
663     new(Result);
664     with Result^ do
665     begin
666     FDataType := dtString2;
667     FBufPtr := BufPtr;
668 tony 263 with FFirebirdClientAPI do
669 tony 45 FDataLength := DecodeInteger(FBufPtr+1, 2);
670     FSize := FDataLength + 3;
671     SetLength(FSubItems,0);
672     end;
673     end;
674    
675 tony 56 function TOutputBlock.AddShortStringItem(BufPtr: PByte): POutputBlockItemData;
676 tony 45 begin
677     new(Result);
678     with Result^ do
679     begin
680     FDataType := dtString;
681     FBufPtr := BufPtr;
682     FDataLength := byte((FBufPtr+1)^);
683     FSize := FDataLength + 2;
684     SetLength(FSubItems,0);
685     end;
686     end;
687    
688 tony 56 function TOutputBlock.AddByteItem(BufPtr: PByte): POutputBlockItemData;
689 tony 45 begin
690     new(Result);
691     with Result^ do
692     begin
693     FDataType := dtByte;
694     FBufPtr := BufPtr;
695     FDataLength := 1;
696     FSize := 2;
697     SetLength(FSubItems,0);
698     end;
699     end;
700    
701 tony 56 function TOutputBlock.AddBytesItem(BufPtr: PByte): POutputBlockItemData;
702 tony 45 begin
703     new(Result);
704     with Result^ do
705     begin
706     FDataType := dtBytes;
707     FBufPtr := BufPtr;
708 tony 263 with FFirebirdClientAPI do
709 tony 45 FDataLength := DecodeInteger(FBufPtr+1, 2);
710     FSize := FDataLength + 3;
711     SetLength(FSubItems,0);
712     end;
713     end;
714    
715 tony 56 function TOutputBlock.AddListItem(BufPtr: PByte): POutputBlockItemData;
716 tony 45 begin
717     new(Result);
718     with Result^ do
719     begin
720     FDataType := dtList;
721     FBufPtr := BufPtr;
722     FSize := FBuffer + FBufSize - FBufPtr;
723     FDataLength := FSize - 1;
724     SetLength(FSubItems,0);
725     end;
726     end;
727    
728 tony 56 function TOutputBlock.AddSpecialItem(BufPtr: PByte): POutputBlockItemData;
729 tony 45 begin
730     new(Result);
731     with Result^ do
732     begin
733     FDataType := dtSpecial;
734     FBufPtr := BufPtr;
735     FSize := FBuffer + FBufSize - FBufPtr;
736     FDataLength := FSize - 1;
737     SetLength(FSubItems,0);
738     end;
739     end;
740    
741 tony 143 function TOutputBlock.AddDateTimeItem(BufPtr: PByte): POutputBlockItemData;
742     begin
743     new(Result);
744     with Result^ do
745     begin
746     FDataType := dtDateTime;
747     FBufPtr := BufPtr;
748 tony 263 with FFirebirdClientAPI do
749 tony 143 FDataLength := DecodeInteger(FBufPtr+1, 2);
750     FSize := FDataLength + 3;
751     SetLength(FSubItems,0);
752     end;
753     end;
754    
755     function TOutputBlock.AddOctetString(BufPtr: PByte): POutputBlockItemData;
756     begin
757     new(Result);
758     with Result^ do
759     begin
760     FDataType := dtOctetString;
761     FBufPtr := BufPtr;
762 tony 263 with FFirebirdClientAPI do
763 tony 143 FDataLength := DecodeInteger(FBufPtr+1, 2);
764     FSize := FDataLength + 3;
765     SetLength(FSubItems,0);
766     end;
767     end;
768    
769 tony 263 constructor TOutputBlock.Create(api: TFBClientAPI; aSize: integer);
770 tony 45 begin
771     inherited Create;
772 tony 263 FFirebirdClientAPI := api;
773 tony 45 FBufSize := aSize;
774     GetMem(FBuffer,aSize);
775     if FBuffer = nil then
776     OutOfMemoryError;
777     FillChar(FBuffer^,aSize,255);
778     FBufferParsed := false;
779     FIntegerType := dtIntegerFixed;
780     end;
781    
782     destructor TOutputBlock.Destroy;
783     var i, j: integer;
784     begin
785     for i := 0 to length(FItems) - 1 do
786     begin
787 tony 144 if FItems[i] <> nil then
788     begin
789     for j := 0 to Length(FItems[i]^.FSubItems) -1 do
790     if FItems[i]^.FSubItems[j] <> nil then
791     dispose(FItems[i]^.FSubItems[j]);
792     dispose(FItems[i]);
793     end;
794 tony 45 end;
795     FreeMem(FBuffer);
796     inherited Destroy;
797     end;
798    
799 tony 56 function TOutputBlock.Buffer: PByte;
800 tony 45 begin
801     Result := FBuffer;
802     end;
803    
804     function TOutputBlock.getBufSize: integer;
805     begin
806     Result := FBufSize;
807     end;
808    
809     function TOutputBlock.GetCount: integer;
810     begin
811     ParseBuffer;
812     Result := length(FItems);
813     end;
814    
815     function TOutputBlock.GetItem(index: integer): POutputBlockItemData;
816     begin
817     ParseBuffer;
818     if (index >= 0) and (index < Length(FItems)) then
819     Result := FItems[index]
820     else
821     IBError(ibxeOutputBlockIndexError,[index]);
822     end;
823    
824     function TOutputBlock.Find(ItemType: byte): POutputBlockItemData;
825     var i: integer;
826     begin
827     Result := nil;
828     for i := 0 to getCount - 1 do
829 tony 56 if byte(FItems[i]^.FBufPtr^) = ItemType then
830 tony 45 begin
831     Result := FItems[i];
832     Exit;
833     end;
834     end;
835    
836     {$IFDEF DEBUGOUTPUTBLOCK}
837     procedure TOutputBlock.FormattedPrint(
838 tony 56 const aItems: array of POutputBlockItemData; Indent: AnsiString);
839 tony 45
840     var i: integer;
841     item: TOutputBlockItem;
842     begin
843     if FError then
844     writeln('Error')
845     else
846     if FTruncated then
847     writeln('Truncated')
848     else
849     for i := 0 to Length(aItems) - 1 do
850     with aItems[i]^ do
851     begin
852     if FError then
853     writeln('Error')
854     else
855     if FTruncated then
856     writeln('Truncated')
857     else
858     case FDataType of
859     dtList:
860     begin
861     writeln(Indent,'ItemType = ',byte(FBufPtr^));
862     FormattedPrint(FSubItems,Indent + ' ');
863     end;
864     dtSpecial:
865     writeln(Indent,'ItemType = ',byte(FBufPtr^),' Length = ',FSize);
866     else
867     begin
868     item := TOutputBlockItem.Create(self,(aItems[i]));
869 tony 144 try
870     writeln(Indent,'ItemType = ',byte(FBufPtr^),' Value = ',(item as TOutputBlockItem).GetAsString);
871     except
872     writeln(Indent,'Unknown ItemType = ',byte(FBufPtr^));
873     end;
874 tony 45 end;
875     end;
876     end;
877     end;
878     {$ENDIF}
879    
880     procedure TOutputBlock.PrintBuf;
881     var i: integer;
882     begin
883     write(classname,': ');
884     for i := 0 to getBufSize - 1 do
885     begin
886     write(Format('%x ',[byte(Buffer[i])]));
887     if byte(FBuffer[i]) = isc_info_end then break;
888     end;
889     writeln;
890 tony 144 for i := 0 to getBufSize - 1 do
891     begin
892     if chr(FBuffer[i]) in [' '..'~'] then
893     write(chr(Buffer[i]))
894     else
895     write('.');
896     if byte(FBuffer[i]) = isc_info_end then break;
897     end;
898     writeln;
899 tony 45 end;
900    
901     { TDBInfoItem }
902    
903     procedure TDBInfoItem.DecodeIDCluster(var ConnectionType: integer;
904 tony 56 var DBFileName, DBSiteName: AnsiString);
905     var P: PByte;
906 tony 45 begin
907     with ItemData^ do
908 tony 56 if FBufPtr^ = isc_info_db_id then
909 tony 45 begin
910     P := FBufPtr + 3;
911     if FDataLength > 0 then
912     ConnectionType := integer(P^);
913     Inc(P);
914     SetString(DBFileName,P+1,byte(P^),CP_ACP);
915 tony 56 P := P + Length(DBFileName) + 1;
916 tony 45 SetString(DBSiteName,P+1,byte(P^),CP_ACP);
917     end
918     else
919     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
920     end;
921    
922     procedure TDBInfoItem.DecodeVersionString(var Version: byte;
923 tony 56 var VersionString: AnsiString);
924     var P: PByte;
925 tony 45 begin
926     with ItemData^ do
927 tony 56 if FBufPtr^ = isc_info_version then
928 tony 45 begin
929     P := FBufPtr+3;
930     VersionString := '';
931     Version := byte(P^);
932     Inc(P);
933     SetString(VersionString,P+1,byte(P^),CP_ACP);
934     end
935     else
936     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
937     end;
938    
939     procedure TDBInfoItem.DecodeUserNames(UserNames: TStrings);
940 tony 56 var P: PByte;
941     s: AnsiString;
942 tony 45 begin
943     with ItemData^ do
944 tony 56 if FBufPtr^ = isc_info_user_names then
945 tony 45 begin
946     P := FBufPtr+3;
947     while (P < FBufPtr + FSize) do
948     begin
949     SetString(s,P+1,byte(P^),CP_ACP);
950     UserNames.Add(s);
951 tony 56 P := P + Length(s) + 1;
952 tony 45 end;
953     end
954     else
955     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
956     end;
957    
958     function TDBInfoItem.getOperationCounts: TDBOperationCounts;
959     var tableCounts: integer;
960 tony 56 P: PByte;
961 tony 45 i: integer;
962     begin
963     with ItemData^ do
964     if byte(FBufPtr^) in [isc_info_backout_count, isc_info_delete_count,
965     isc_info_expunge_count,isc_info_insert_count, isc_info_purge_count,
966     isc_info_read_idx_count, isc_info_read_seq_count, isc_info_update_count] then
967     begin
968     tableCounts := FDataLength div 6;
969     SetLength(Result,TableCounts);
970     P := FBufPtr + 3;
971     for i := 0 to TableCounts -1 do
972 tony 263 with FFirebirdClientAPI do
973 tony 45 begin
974     Result[i].TableID := DecodeInteger(P,2);
975     Inc(P,2);
976     Result[i].Count := DecodeInteger(P,4);
977     Inc(P,4);
978     end;
979     end
980     else
981     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
982     end;
983    
984     { TDBInformation }
985    
986 tony 56 function TDBInformation.AddSpecialItem(BufPtr: PByte): POutputBlockItemData;
987 tony 45 begin
988     Result := inherited AddSpecialItem(BufPtr);
989     with Result^ do
990     begin
991 tony 263 with FFirebirdClientAPI do
992 tony 45 FDataLength := DecodeInteger(FBufPtr+1,2);
993     FSize := FDataLength + 3;
994     end;
995     end;
996    
997     procedure TDBInformation.DoParseBuffer;
998 tony 56 var P: PByte;
999 tony 45 index: integer;
1000     begin
1001     P := Buffer;
1002     index := 0;
1003     SetLength(FItems,0);
1004 tony 56 while (P^ <> isc_info_end) and (P < Buffer + getBufSize) do
1005 tony 45 begin
1006     SetLength(FItems,index+1);
1007     case byte(P^) of
1008 tony 61 isc_info_db_read_only,
1009 tony 45 isc_info_no_reserve,
1010     isc_info_allocation,
1011     isc_info_ods_minor_version,
1012     isc_info_ods_version,
1013     isc_info_db_SQL_dialect,
1014     isc_info_page_size,
1015     isc_info_current_memory,
1016     isc_info_forced_writes,
1017     isc_info_max_memory,
1018     isc_info_num_buffers,
1019     isc_info_sweep_interval,
1020     isc_info_fetches,
1021     isc_info_marks,
1022     isc_info_reads,
1023 tony 143 isc_info_writes,
1024     isc_info_active_tran_count,
1025     fb_info_pages_used,
1026     fb_info_pages_free,
1027     fb_info_conn_flags:
1028 tony 45 FItems[index] := AddIntegerItem(P);
1029    
1030     isc_info_implementation,
1031     isc_info_base_level:
1032     FItems[index] := AddBytesItem(P);
1033    
1034 tony 143 isc_info_creation_date:
1035     FItems[index] := AddDateTimeItem(P);
1036    
1037     fb_info_page_contents:
1038     FItems[index] := AddOctetString(P);
1039    
1040     fb_info_crypt_key:
1041     FItems[index] := AddStringItem(P);
1042    
1043 tony 45 isc_info_db_id,
1044     isc_info_version,
1045     isc_info_backout_count,
1046     isc_info_delete_count,
1047     isc_info_expunge_count,
1048     isc_info_insert_count,
1049     isc_info_purge_count,
1050     isc_info_read_idx_count,
1051     isc_info_read_seq_count,
1052     isc_info_update_count,
1053     isc_info_user_names:
1054     FItems[index] := AddSpecialItem(P);
1055    
1056     else
1057     FItems[index] := AddSpecialItem(P);
1058     end;
1059 tony 56 P := P + FItems[index]^.FSize;
1060 tony 45 Inc(index);
1061     end;
1062     end;
1063    
1064 tony 143 {$IFNDEF FPC}
1065     function TDBInformation.Find(ItemType: byte): IDBInfoItem;
1066     begin
1067     Result := inherited Find(ItemType);
1068     if Result.GetSize = 0 then
1069     Result := nil;
1070     end;
1071     {$ENDIF}
1072    
1073 tony 263 constructor TDBInformation.Create(api: TFBClientAPI; aSize: integer);
1074 tony 45 begin
1075 tony 263 inherited Create(api,aSize);
1076 tony 45 FIntegerType := dtInteger;
1077     end;
1078    
1079     { TServiceQueryResults }
1080    
1081 tony 56 function TServiceQueryResults.AddListItem(BufPtr: PByte): POutputBlockItemData;
1082     var P: PByte;
1083 tony 45 i: integer;
1084     group: byte;
1085     begin
1086     Result := inherited AddListItem(BufPtr);
1087     P := BufPtr + 1;
1088     i := 0;
1089     group := byte(BufPtr^);
1090     if group in [isc_info_svc_get_users,isc_info_svc_limbo_trans] then
1091     begin
1092 tony 263 with FFirebirdClientAPI do
1093 tony 45 Result^.FSize := DecodeInteger(P,2) + 3;
1094     Inc(P,2);
1095     end;
1096     with Result^ do
1097     begin
1098 tony 56 while (P < FBufPtr + FSize) and (P^ <> isc_info_flag_end) do
1099 tony 45 begin
1100     SetLength(FSubItems,i+1);
1101 tony 144 FSubItems[i] := nil;
1102 tony 45 case group of
1103     isc_info_svc_svr_db_info:
1104     case integer(P^) of
1105     isc_spb_num_att,
1106     isc_spb_num_db:
1107     FSubItems[i] := AddIntegerItem(P);
1108    
1109     isc_spb_dbname:
1110     FSubItems[i] := AddStringItem(P);
1111    
1112     else
1113 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1114 tony 45 end;
1115    
1116     isc_info_svc_get_license:
1117     case integer(P^) of
1118     isc_spb_lic_id,
1119     isc_spb_lic_key:
1120     FSubItems[i] := AddIntegerItem(P);
1121     else
1122 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1123 tony 45 end;
1124    
1125     isc_info_svc_limbo_trans:
1126     case integer(P^) of
1127     isc_spb_tra_id,
1128     isc_spb_single_tra_id,
1129     isc_spb_multi_tra_id:
1130     FSubItems[i] := AddIntegerItem(P);
1131    
1132     isc_spb_tra_host_site,
1133     isc_spb_tra_remote_site,
1134     isc_spb_tra_db_path:
1135     FSubItems[i] := AddStringItem(P);
1136    
1137     isc_spb_tra_advise,
1138     isc_spb_tra_state:
1139     FSubItems[i] := AddByteItem(P);
1140     else
1141 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1142 tony 45 end;
1143    
1144     isc_info_svc_get_users:
1145     case integer(P^) of
1146 tony 143 isc_spb_sec_admin,
1147 tony 45 isc_spb_sec_userid,
1148     isc_spb_sec_groupid:
1149     FSubItems[i] := AddIntegerItem(P);
1150    
1151     isc_spb_sec_username,
1152     isc_spb_sec_password,
1153     isc_spb_sec_firstname,
1154     isc_spb_sec_middlename,
1155     isc_spb_sec_lastname:
1156     FSubItems[i] := AddStringItem(P);
1157    
1158     else
1159 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1160 tony 45 end;
1161    
1162     end;
1163 tony 56 P := P + FSubItems[i]^.FSize;
1164 tony 45 Inc(i);
1165     end;
1166     FDataLength := 0;
1167     for i := 0 to Length(FSubItems) - 1 do
1168 tony 56 FDataLength := FDataLength + FSubItems[i]^.FSize;
1169 tony 45 if group in [isc_info_svc_get_users,isc_info_svc_limbo_trans] then
1170     Exit;
1171    
1172 tony 56 if (P < FBufPtr + FSize) and (P^ = isc_info_flag_end) then
1173 tony 45 FSize := FDataLength + 2 {include start and end flag}
1174     else
1175     FSize := FDataLength + 1; {start flag only}
1176     end;
1177     end;
1178    
1179 tony 56 function TServiceQueryResults.AddSpecialItem(BufPtr: PByte
1180 tony 45 ): POutputBlockItemData;
1181 tony 56 var P: PByte;
1182 tony 45 i: integer;
1183     begin
1184     Result := inherited AddSpecialItem(BufPtr);
1185     with Result^ do
1186     begin
1187 tony 263 with FFirebirdClientAPI do
1188 tony 45 FDataLength := DecodeInteger(FBufPtr+1, 2);
1189    
1190     P := FBufPtr + 3; {skip length bytes}
1191     i := 0;
1192     while P < FBufPtr + FDataLength do
1193     begin
1194     FSubItems[i] := AddIntegerItem(P);
1195 tony 56 P := P + FSubItems[i]^.FSize;
1196 tony 45 Inc(i);
1197     end;
1198     end;
1199     end;
1200    
1201     procedure TServiceQueryResults.DoParseBuffer;
1202 tony 56 var P: PByte;
1203 tony 45 i: integer;
1204     begin
1205     P := Buffer;
1206     i := 0;
1207 tony 56 while (P < Buffer + getBufSize) and (P^ <> isc_info_end) do
1208 tony 45 begin
1209     SetLength(FItems,i+1);
1210 tony 144 FItems[i] := nil;
1211 tony 45 case integer(P^) of
1212     isc_info_svc_line,
1213     isc_info_svc_get_env,
1214     isc_info_svc_get_env_lock,
1215     isc_info_svc_get_env_msg,
1216     isc_info_svc_user_dbpath,
1217     isc_info_svc_server_version,
1218     isc_info_svc_implementation,
1219     isc_info_svc_to_eof:
1220     FItems[i] := AddStringItem(P);
1221    
1222     isc_info_svc_get_license_mask,
1223     isc_info_svc_capabilities,
1224     isc_info_svc_version,
1225     isc_info_svc_running,
1226     isc_info_svc_stdin:
1227     FItems[i] := AddIntegerItem(P);
1228    
1229     isc_info_svc_timeout,
1230     isc_info_data_not_ready,
1231     isc_info_truncated:
1232     FItems[i] := AddItem(P);
1233    
1234     isc_info_svc_svr_db_info,
1235     isc_info_svc_get_license,
1236     isc_info_svc_limbo_trans,
1237     isc_info_svc_get_users:
1238     FItems[i] := AddListItem(P);
1239    
1240     isc_info_svc_get_config:
1241     FItems[i] := AddSpecialItem(P);
1242    
1243    
1244     else
1245 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,getBufSize - (P-Buffer))]);
1246 tony 45 end;
1247 tony 56 P := P + FItems[i]^.FSize;
1248 tony 45 Inc(i);
1249     end;
1250     end;
1251    
1252 tony 143 {$IFNDEF FPC}
1253     function TServiceQueryResults.Find(ItemType: byte): IServiceQueryResultItem;
1254     begin
1255     Result := inherited Find(ItemType);
1256     if Result.GetSize = 0 then
1257     Result := nil;
1258     end;
1259     {$ENDIF}
1260    
1261 tony 45 { TSQLInfoResultsBuffer }
1262    
1263 tony 56 function TSQLInfoResultsBuffer.AddListItem(BufPtr: PByte): POutputBlockItemData;
1264     var P: PByte;
1265 tony 45 i: integer;
1266     begin
1267     Result := inherited AddListItem(BufPtr);
1268     P := BufPtr + 1;
1269     i := 0;
1270    
1271     if byte(BufPtr^) = isc_info_sql_records then
1272     begin
1273 tony 263 with FFirebirdClientAPI do
1274 tony 45 Result^.FSize := DecodeInteger(P,2) + 3;
1275     Inc(P,2);
1276     with Result^ do
1277     begin
1278     while (P < FBufPtr + FSize) and (byte(P^) <> isc_info_end) do
1279     begin
1280     SetLength(FSubItems,i+1);
1281     case integer(P^) of
1282     isc_info_req_select_count,
1283     isc_info_req_insert_count,
1284     isc_info_req_update_count,
1285     isc_info_req_delete_count:
1286     FSubItems[i] := AddIntegerItem(P);
1287    
1288     isc_info_truncated:
1289     begin
1290     FTruncated := true;
1291     Exit;
1292     end;
1293    
1294     isc_info_error:
1295     begin
1296     FError := true;
1297     Exit;
1298     end;
1299     else
1300     FSubItems[i] := AddSpecialItem(P);
1301     end;
1302 tony 56 P := P + FSubItems[i]^.FSize;
1303 tony 45 Inc(i);
1304     end;
1305     end;
1306     end;
1307     end;
1308    
1309     procedure TSQLInfoResultsBuffer.DoParseBuffer;
1310 tony 56 var P: PByte;
1311 tony 45 index: integer;
1312     begin
1313     P := Buffer;
1314     index := 0;
1315     SetLength(FItems,0);
1316 tony 56 while (P^ <> isc_info_end) and (P < Buffer + getBufSize) do
1317 tony 45 begin
1318     SetLength(FItems,index+1);
1319     case byte(P^) of
1320     isc_info_sql_stmt_type:
1321     FItems[index] := AddIntegerItem(P);
1322    
1323     isc_info_sql_get_plan:
1324     FItems[index] := AddStringItem(P);
1325    
1326     isc_info_sql_records:
1327     FItems[index] := AddListItem(P);
1328    
1329     isc_info_truncated:
1330     begin
1331     FTruncated := true;
1332     Exit;
1333     end;
1334    
1335     isc_info_error:
1336     begin
1337     FError := true;
1338     Exit;
1339     end;
1340    
1341     else
1342     FItems[index] := AddSpecialItem(P);
1343     end;
1344 tony 56 P := P + FItems[index]^.FSize;
1345 tony 45 Inc(index);
1346     end;
1347     end;
1348    
1349 tony 263 constructor TSQLInfoResultsBuffer.Create(api: TFBClientAPI; aSize: integer);
1350 tony 45 begin
1351 tony 263 inherited Create(api,aSize);
1352 tony 45 FIntegerType := dtInteger;
1353     end;
1354    
1355 tony 56 { TBlobInfo }
1356    
1357     procedure TBlobInfo.DoParseBuffer;
1358     var P: PByte;
1359     index: integer;
1360     begin
1361     P := Buffer;
1362     index := 0;
1363     SetLength(FItems,0);
1364     while (P^ <> isc_info_end) and (P < Buffer + getBufSize) do
1365     begin
1366     SetLength(FItems,index+1);
1367     case byte(P^) of
1368     isc_info_blob_num_segments,
1369     isc_info_blob_max_segment,
1370     isc_info_blob_total_length,
1371     isc_info_blob_type:
1372     FItems[index] := AddIntegerItem(P);
1373     else
1374     FItems[index] := AddSpecialItem(P);
1375     end;
1376     P := P + FItems[index]^.FSize;
1377     Inc(index);
1378     end;
1379     end;
1380    
1381 tony 263 constructor TBlobInfo.Create(api: TFBClientAPI; aSize: integer);
1382 tony 56 begin
1383 tony 263 inherited Create(api,aSize);
1384 tony 56 FIntegerType := dtInteger;
1385     end;
1386    
1387 tony 45 end.
1388