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