ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBOutputBlock.pas
Revision: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (7 years, 4 months ago) by tony
Content type: text/x-pascal
File size: 27329 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 FBOutputBlock;
28    
29     {$IFDEF FPC}
30     {$mode objfpc}{$H+}
31     {$codepage UTF8}
32     {$interfaces COM}
33     {$ENDIF}
34    
35     { $DEFINE DEBUGOUTPUTBLOCK}
36    
37     interface
38    
39     {Provides common handling for the DB Info results, SQL Info and Service Response Block}
40    
41     uses
42     Classes, SysUtils, FBClientAPI, IB, FBActivityMonitor;
43    
44     const
45     DefaultBufferSize = 32000;
46     DBInfoDefaultBufferSize = 512;
47    
48     type
49     TItemDataType = (dtString, dtString2, dtByte, dtBytes, dtInteger, dtIntegerFixed, dtnone,
50     dtList,dtSpecial);
51    
52     POutputBlockItemData = ^TOutputBlockItemData;
53     TOutputBlockItemData = record
54     {Describes a Clumplet in the buffer. FBufPtr always points to the clumplet id
55     the rest of the clumplet up to the FSize is data. The data format is
56     given by FDataType, and the data length is given by FDataLength}
57     FBufPtr: PChar;
58     FDataLength: integer;
59     FSize: integer;
60     FDataType: TItemDataType;
61     FTruncated: boolean;
62     FError: boolean;
63     FSubItems: array of POutputBlockItemData;
64     end;
65    
66     { TOutputBlock }
67    
68     TOutputBlock = class(TFBInterfacedObject)
69     private
70     FBuffer: PChar;
71     FBufSize: integer;
72     FBufferParsed: boolean;
73     procedure ParseBuffer;
74     {$IFDEF DEBUGOUTPUTBLOCK}
75     procedure FormattedPrint(const aItems: array of POutputBlockItemData;
76     Indent: string);
77     {$ENDIF}
78     procedure PrintBuf;
79     protected
80     FIntegerType: TItemDataType;
81     FError: boolean;
82     FTruncated: boolean;
83     FItems: array of POutputBlockItemData;
84     procedure DoParseBuffer; virtual; abstract;
85     function AddItem(BufPtr: PChar): POutputBlockItemData;
86     function AddIntegerItem(BufPtr: PChar): POutputBlockItemData;
87     function AddStringItem(BufPtr: PChar): POutputBlockItemData;
88     function AddShortStringItem(BufPtr: PChar): POutputBlockItemData;
89     function AddByteItem(BufPtr: PChar): POutputBlockItemData;
90     function AddBytesItem(BufPtr: PChar): POutputBlockItemData;
91     function AddListItem(BufPtr: PChar): POutputBlockItemData; virtual;
92     function AddSpecialItem(BufPtr: PChar): POutputBlockItemData; virtual;
93     public
94     constructor Create(aSize: integer = DefaultBufferSize);
95     destructor Destroy; override;
96     function Buffer: PChar;
97     function getBufSize: integer;
98    
99     public
100     function GetCount: integer;
101     function GetItem(index: integer): POutputBlockItemData;
102     function Find(ItemType: byte): POutputBlockItemData;
103     property Count: integer read GetCount;
104     property Items[index: integer]: POutputBlockItemData read getItem; default;
105     end;
106    
107     { TOutputBlockItem }
108    
109     TOutputBlockItem = class(TFBInterfacedObject,IUnknown)
110     private
111     FOwner: TOutputBlock;
112     FOwnerIntf: IUnknown;
113     FItemData: POutputBlockItemData;
114     protected
115     function GetItem(index: integer): POutputBlockItemData;
116     function Find(ItemType: byte): POutputBlockItemData;
117     procedure SetString(out S: AnsiString; Buf: PAnsiChar; Len: SizeInt;
118     CodePage: TSystemCodePage);
119     property ItemData: POutputBlockItemData read FItemData;
120     property Owner: TOutputBlock read FOwner;
121     public
122     constructor Create(AOwner: TOutputBlock; Data: POutputBlockItemData);
123     public
124     function GetCount: integer;
125     function getItemType: byte;
126     function getSize: integer;
127     procedure getRawBytes(var Buffer);
128     function getAsInteger: integer;
129     function getParamType: byte;
130     function getAsString: string;
131     function getAsByte: byte;
132     function getAsBytes: TByteArray;
133     function CopyTo(stream: TStream; count: integer): integer;
134     end;
135    
136     { TCustomOutputBlock }
137    
138     generic TCustomOutputBlock<_TItem,_IItem> = class(TOutputBlock)
139     public
140     function getItem(index: integer): _IItem;
141     function find(ItemType: byte): _IItem;
142     property Items[index: integer]: _IItem read getItem; default;
143     end;
144    
145     { TOutputBlockItemGroup }
146    
147     generic TOutputBlockItemGroup<_TItem;_IItem> = class(TOutputBlockItem)
148     public
149     function GetItem(index: integer): _IItem;
150     function Find(ItemType: byte): _IItem;
151     property Items[index: integer]: _IItem read getItem; default;
152     end;
153    
154     TDBInfoItem = class;
155    
156     { TDBInfoItem }
157    
158     TDBInfoItem = class(specialize TOutputBlockItemGroup<TDBInfoItem,IDBInfoItem>,IDBInfoItem)
159     public
160     procedure DecodeIDCluster(var ConnectionType: integer; var DBFileName, DBSiteName: string);
161     procedure DecodeVersionString(var Version: byte; var VersionString: string);
162     procedure DecodeUserNames(UserNames: TStrings);
163     function getOperationCounts: TDBOperationCounts;
164     end;
165    
166     { TDBInformation }
167    
168     TDBInformation = class(specialize TCustomOutputBlock<TDBInfoItem,IDBInfoItem>, IDBInformation)
169     protected
170     function AddSpecialItem(BufPtr: PChar): POutputBlockItemData; override;
171     procedure DoParseBuffer; override;
172     public
173     constructor Create(aSize: integer=DBInfoDefaultBufferSize);
174     end;
175    
176     TServiceQueryResultSubItem = class(TOutputBlockItem,IServiceQueryResultSubItem);
177    
178     { TServiceQueryResultItem }
179    
180     TServiceQueryResultItem = class(specialize TOutputBlockItemGroup<TServiceQueryResultSubItem,IServiceQueryResultSubItem>,
181     IServiceQueryResultItem);
182    
183     { TServiceQueryResults }
184    
185     TServiceQueryResults = class(specialize TCustomOutputBlock<TServiceQueryResultItem,IServiceQueryResultItem>, IServiceQueryResults)
186     protected
187     function AddListItem(BufPtr: PChar): POutputBlockItemData; override;
188     function AddSpecialItem(BufPtr: PChar): POutputBlockItemData; override;
189     procedure DoParseBuffer; override;
190     end;
191    
192     { ISQLInfoItem }
193    
194     ISQLInfoItem = interface
195     function getItemType: byte;
196     function getSize: integer;
197     function getAsString: string;
198     function getAsInteger: integer;
199     function GetCount: integer;
200     function GetItem(index: integer): ISQLInfoItem;
201     function Find(ItemType: byte): ISQLInfoItem;
202     property Count: integer read GetCount;
203     property Items[index: integer]: ISQLInfoItem read getItem; default;
204     end;
205    
206     {ISQLInfoResults}
207    
208     ISQLInfoResults = interface
209     function GetCount: integer;
210     function GetItem(index: integer): ISQLInfoItem;
211     function Find(ItemType: byte): ISQLInfoItem;
212     property Count: integer read GetCount;
213     property Items[index: integer]: ISQLInfoItem read getItem; default;
214     end;
215    
216     TSQLInfoResultsItem = class;
217    
218     { TSQLInfoResultsItem }
219    
220     TSQLInfoResultsItem = class(specialize TOutputBlockItemGroup<TSQLInfoResultsItem,ISQLInfoItem>,ISQLInfoItem);
221    
222     { TSQLInfoResultsBuffer }
223    
224     TSQLInfoResultsBuffer = class(specialize TCustomOutputBlock<TSQLInfoResultsItem,ISQLInfoItem>, ISQLInfoResults)
225     protected
226     function AddListItem(BufPtr: PChar): POutputBlockItemData; override;
227     procedure DoParseBuffer; override;
228     public
229     constructor Create(aSize: integer = 1024);
230     end;
231    
232     implementation
233    
234     uses FBMessages;
235    
236     { TOutputBlockItemGroup }
237    
238     function TOutputBlockItemGroup.GetItem(index: integer): _IItem;
239     var P: POutputBlockItemData;
240     begin
241     P := inherited getItem(index);
242     Result := _TItem.Create(self.Owner,P);
243     end;
244    
245     function TOutputBlockItemGroup.Find(ItemType: byte): _IItem;
246     var P: POutputBlockItemData;
247     begin
248     P := inherited Find(ItemType);
249     Result := _TItem.Create(self.Owner,P);
250     end;
251    
252     { TCustomOutputBlock }
253    
254     function TCustomOutputBlock.getItem(index: integer): _IItem;
255     var P: POutputBlockItemData;
256     begin
257     P := inherited getItem(index);
258     Result := _TItem.Create(self,P)
259     end;
260    
261     function TCustomOutputBlock.find(ItemType: byte): _IItem;
262     var P: POutputBlockItemData;
263     begin
264     P := inherited Find(ItemType);
265     Result := _TItem.Create(self,P)
266     end;
267    
268     { TOutputBlockItemGroup }
269    
270     function TOutputBlockItem.GetCount: integer;
271     begin
272     Result := Length(FItemData^.FSubItems);
273     end;
274    
275     function TOutputBlockItem.GetItem(index: integer): POutputBlockItemData;
276     begin
277     if (index >= 0) and (index < Length(FItemData^.FSubItems)) then
278     Result := FItemData^.FSubItems[index]
279     else
280     with FirebirdClientAPI do
281     IBError(ibxeOutputBlockIndexError,[index]);
282     end;
283    
284     function TOutputBlockItem.Find(ItemType: byte): POutputBlockItemData;
285     var i: integer;
286     begin
287     Result := nil;
288     for i := 0 to GetCount - 1 do
289     if FItemData^.FSubItems[i]^.FBufPtr^ = char(ItemType) then
290     begin
291     Result := FItemData^.FSubItems[i];
292     Exit;
293     end;
294     end;
295    
296     { TOutputBlockItem }
297    
298     procedure TOutputBlockItem.SetString(out S: AnsiString; Buf: PAnsiChar;
299     Len: SizeInt; CodePage: TSystemCodePage);
300     var rs: RawByteString;
301     begin
302     system.SetString(rs,Buf,len);
303     SetCodePage(rs,CodePage,false);
304     S := rs;
305     end;
306    
307     constructor TOutputBlockItem.Create(AOwner: TOutputBlock;
308     Data: POutputBlockItemData);
309     begin
310     inherited Create;
311     FOwner := AOwner;
312     FOwnerIntf := AOwner;
313     FItemData := Data;
314     end;
315    
316     function TOutputBlockItem.getItemType: byte;
317     begin
318     Result := byte(FItemData^.FBufPtr^);
319     end;
320    
321     function TOutputBlockItem.getSize: integer;
322     begin
323     Result := FItemData^.FDataLength;
324     end;
325    
326     procedure TOutputBlockItem.getRawBytes(var Buffer);
327     begin
328     with FItemData^ do
329     Move(FBufPtr^,Buffer,FDatalength);
330     end;
331    
332     function TOutputBlockItem.getAsInteger: integer;
333     var len: integer;
334     begin
335     with FItemData^ do
336     case FDataType of
337     dtIntegerFixed:
338     with FirebirdClientAPI do
339     Result := DecodeInteger(FBufPtr+1,4);
340    
341     dtByte,
342     dtInteger:
343     with FirebirdClientAPI do
344     begin
345     len := DecodeInteger(FBufPtr+1,2);
346     Result := DecodeInteger(FBufPtr+3,len);
347     end;
348     else
349     IBError(ibxeOutputBlockTypeError,[nil]);
350     end;
351     end;
352    
353     function TOutputBlockItem.getParamType: byte;
354     begin
355     Result := byte(FItemData^.FBufPtr^)
356     end;
357    
358     function TOutputBlockItem.getAsString: string;
359     var len: integer;
360     begin
361     Result := '';
362     with FItemData^ do
363     case FDataType of
364     dtInteger:
365     Result := IntToStr(getAsInteger);
366     dtByte:
367     Result := IntToStr(getAsByte);
368     dtString:
369     begin
370     len := byte((FBufPtr+1)^);
371     SetString(Result,FBufPtr+2,len,CP_ACP);
372     end;
373     dtString2:
374     begin
375     with FirebirdClientAPI do
376     len := DecodeInteger(FBufPtr+1,2);
377     SetString(Result,FBufPtr+3,len,CP_ACP);
378     end;
379     else
380     IBError(ibxeOutputBlockTypeError,[nil]);
381     end;
382     end;
383    
384     function TOutputBlockItem.getAsByte: byte;
385     begin
386     with FItemData^ do
387     if FDataType = dtByte then
388     Result := byte((FBufPtr+2)^)
389     else
390     IBError(ibxeOutputBlockTypeError,[nil]);
391     end;
392    
393     function TOutputBlockItem.getAsBytes: TByteArray;
394     var i: integer;
395     P: PChar;
396     begin
397     with FItemData^ do
398     if FDataType = dtBytes then
399     begin
400     SetLength(Result,FDataLength);
401     P := FBufPtr;
402     for i := 0 to FDataLength - 1 do
403     begin
404     Result[i] := byte(P^);
405     Inc(P);
406     end
407     end
408     else
409     IBError(ibxeOutputBlockTypeError,[nil]);
410     end;
411    
412     function TOutputBlockItem.CopyTo(stream: TStream; count: integer): integer;
413     var len: integer;
414     begin
415     if count < 0 then count := 0;
416     with FItemData^ do
417     begin
418     case FDataType of
419     dtString:
420     begin
421     len := byte((FBufPtr+1)^);
422     if (count > 0) and (count < len) then len := count;
423     Result := stream.Write((FBufPtr+2)^,len);
424     end;
425     dtString2:
426     begin
427     with FirebirdClientAPI do
428     len := DecodeInteger(FBufPtr+1,2);
429     if (count > 0) and (count < len) then len := count;
430     Result := stream.Write((FBufPtr+3)^,len);
431     end;
432     else
433     IBError(ibxeOutputBlockTypeError,[nil]);
434     end;
435     end;
436     end;
437    
438     { TOutputBlock }
439    
440     procedure TOutputBlock.ParseBuffer;
441     begin
442     if not FBufferParsed then
443     begin
444     {$IFDEF DEBUGOUTPUTBLOCK}
445     PrintBuf;
446     {$ENDIF}
447     DoParseBuffer;
448     if FError or FTruncated then
449     SetLength(FItems,Length(FItems)-1);
450     {$IFDEF DEBUGOUTPUTBLOCK}
451     FormattedPrint(FItems,'');
452     {$ENDIF}
453     end;
454     FBufferParsed := true;
455     end;
456    
457     function TOutputBlock.AddItem(BufPtr: PChar): POutputBlockItemData;
458     begin
459     new(Result);
460     with Result^ do
461     begin
462     FDataType := dtNone;
463     FBufPtr := BufPtr;
464     FDataLength := 0;
465     FSize := 1;
466     SetLength(FSubItems,0);
467     end;
468     end;
469    
470     function TOutputBlock.AddIntegerItem(BufPtr: PChar): POutputBlockItemData;
471     begin
472     new(Result);
473     with Result^ do
474     begin
475     FDataType := FIntegerType;
476     FBufPtr := BufPtr;
477     if FDataType = dtIntegerFixed then
478     begin
479     FDataLength := 4;
480     FSize := 5;
481     end
482     else
483     begin
484     with FirebirdClientAPI do
485     FDataLength := DecodeInteger(FBufPtr+1, 2);
486     FSize := FDataLength + 3;
487     end;
488     SetLength(FSubItems,0);
489     end;
490     end;
491    
492     function TOutputBlock.AddStringItem(BufPtr: PChar): POutputBlockItemData;
493     begin
494     new(Result);
495     with Result^ do
496     begin
497     FDataType := dtString2;
498     FBufPtr := BufPtr;
499     with FirebirdClientAPI do
500     FDataLength := DecodeInteger(FBufPtr+1, 2);
501     FSize := FDataLength + 3;
502     SetLength(FSubItems,0);
503     end;
504     end;
505    
506     function TOutputBlock.AddShortStringItem(BufPtr: PChar): POutputBlockItemData;
507     begin
508     new(Result);
509     with Result^ do
510     begin
511     FDataType := dtString;
512     FBufPtr := BufPtr;
513     FDataLength := byte((FBufPtr+1)^);
514     FSize := FDataLength + 2;
515     SetLength(FSubItems,0);
516     end;
517     end;
518    
519     function TOutputBlock.AddByteItem(BufPtr: PChar): POutputBlockItemData;
520     begin
521     new(Result);
522     with Result^ do
523     begin
524     FDataType := dtByte;
525     FBufPtr := BufPtr;
526     FDataLength := 1;
527     FSize := 2;
528     SetLength(FSubItems,0);
529     end;
530     end;
531    
532     function TOutputBlock.AddBytesItem(BufPtr: PChar): POutputBlockItemData;
533     begin
534     new(Result);
535     with Result^ do
536     begin
537     FDataType := dtBytes;
538     FBufPtr := BufPtr;
539     with FirebirdClientAPI do
540     FDataLength := DecodeInteger(FBufPtr+1, 2);
541     FSize := FDataLength + 3;
542     SetLength(FSubItems,0);
543     end;
544     end;
545    
546     function TOutputBlock.AddListItem(BufPtr: PChar): POutputBlockItemData;
547     begin
548     new(Result);
549     with Result^ do
550     begin
551     FDataType := dtList;
552     FBufPtr := BufPtr;
553     FSize := FBuffer + FBufSize - FBufPtr;
554     FDataLength := FSize - 1;
555     SetLength(FSubItems,0);
556     end;
557     end;
558    
559     function TOutputBlock.AddSpecialItem(BufPtr: PChar): POutputBlockItemData;
560     begin
561     new(Result);
562     with Result^ do
563     begin
564     FDataType := dtSpecial;
565     FBufPtr := BufPtr;
566     FSize := FBuffer + FBufSize - FBufPtr;
567     FDataLength := FSize - 1;
568     SetLength(FSubItems,0);
569     end;
570     end;
571    
572     constructor TOutputBlock.Create(aSize: integer);
573     begin
574     inherited Create;
575     FBufSize := aSize;
576     GetMem(FBuffer,aSize);
577     if FBuffer = nil then
578     OutOfMemoryError;
579     FillChar(FBuffer^,aSize,255);
580     FBufferParsed := false;
581     FIntegerType := dtIntegerFixed;
582     end;
583    
584     destructor TOutputBlock.Destroy;
585     var i, j: integer;
586     begin
587     for i := 0 to length(FItems) - 1 do
588     begin
589     for j := 0 to Length(FItems[i]^.FSubItems) -1 do
590     dispose(FItems[i]^.FSubItems[j]);
591     dispose(FItems[i]);
592     end;
593     FreeMem(FBuffer);
594     inherited Destroy;
595     end;
596    
597     function TOutputBlock.Buffer: PChar;
598     begin
599     Result := FBuffer;
600     end;
601    
602     function TOutputBlock.getBufSize: integer;
603     begin
604     Result := FBufSize;
605     end;
606    
607     function TOutputBlock.GetCount: integer;
608     begin
609     ParseBuffer;
610     Result := length(FItems);
611     end;
612    
613     function TOutputBlock.GetItem(index: integer): POutputBlockItemData;
614     begin
615     ParseBuffer;
616     if (index >= 0) and (index < Length(FItems)) then
617     Result := FItems[index]
618     else
619     IBError(ibxeOutputBlockIndexError,[index]);
620     end;
621    
622     function TOutputBlock.Find(ItemType: byte): POutputBlockItemData;
623     var i: integer;
624     begin
625     Result := nil;
626     for i := 0 to getCount - 1 do
627     if FItems[i]^.FBufPtr^ = char(ItemType) then
628     begin
629     Result := FItems[i];
630     Exit;
631     end;
632     end;
633    
634     {$IFDEF DEBUGOUTPUTBLOCK}
635     procedure TOutputBlock.FormattedPrint(
636     const aItems: array of POutputBlockItemData; Indent: string);
637    
638     var i: integer;
639     item: TOutputBlockItem;
640     begin
641     if FError then
642     writeln('Error')
643     else
644     if FTruncated then
645     writeln('Truncated')
646     else
647     for i := 0 to Length(aItems) - 1 do
648     with aItems[i]^ do
649     begin
650     if FError then
651     writeln('Error')
652     else
653     if FTruncated then
654     writeln('Truncated')
655     else
656     case FDataType of
657     dtList:
658     begin
659     writeln(Indent,'ItemType = ',byte(FBufPtr^));
660     FormattedPrint(FSubItems,Indent + ' ');
661     end;
662     dtSpecial:
663     writeln(Indent,'ItemType = ',byte(FBufPtr^),' Length = ',FSize);
664     else
665     begin
666     item := TOutputBlockItem.Create(self,(aItems[i]));
667     writeln(Indent,'ItemType = ',byte(FBufPtr^),' Value = ',(item as TOutputBlockItem).GetAsString);
668     end;
669     end;
670     end;
671     end;
672     {$ENDIF}
673    
674     procedure TOutputBlock.PrintBuf;
675     var i: integer;
676     begin
677     write(classname,': ');
678     for i := 0 to getBufSize - 1 do
679     begin
680     write(Format('%x ',[byte(Buffer[i])]));
681     if byte(FBuffer[i]) = isc_info_end then break;
682     end;
683     writeln;
684     end;
685    
686     { TDBInfoItem }
687    
688     procedure TDBInfoItem.DecodeIDCluster(var ConnectionType: integer;
689     var DBFileName, DBSiteName: string);
690     var P: PChar;
691     begin
692     with ItemData^ do
693     if FBufPtr^ = char(isc_info_db_id) then
694     begin
695     P := FBufPtr + 3;
696     if FDataLength > 0 then
697     ConnectionType := integer(P^);
698     Inc(P);
699     SetString(DBFileName,P+1,byte(P^),CP_ACP);
700     P += Length(DBFileName) + 1;
701     SetString(DBSiteName,P+1,byte(P^),CP_ACP);
702     end
703     else
704     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
705     end;
706    
707     procedure TDBInfoItem.DecodeVersionString(var Version: byte;
708     var VersionString: string);
709     var P: PChar;
710     begin
711     with ItemData^ do
712     if FBufPtr^ = char(isc_info_version) then
713     begin
714     P := FBufPtr+3;
715     VersionString := '';
716     Version := byte(P^);
717     Inc(P);
718     SetString(VersionString,P+1,byte(P^),CP_ACP);
719     end
720     else
721     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
722     end;
723    
724     procedure TDBInfoItem.DecodeUserNames(UserNames: TStrings);
725     var P: PChar;
726     s: string;
727     begin
728     with ItemData^ do
729     if FBufPtr^ = char(isc_info_user_names) then
730     begin
731     P := FBufPtr+3;
732     while (P < FBufPtr + FSize) do
733     begin
734     SetString(s,P+1,byte(P^),CP_ACP);
735     UserNames.Add(s);
736     P += Length(s) + 1;
737     end;
738     end
739     else
740     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
741     end;
742    
743     function TDBInfoItem.getOperationCounts: TDBOperationCounts;
744     var tableCounts: integer;
745     P: PChar;
746     i: integer;
747     begin
748     with ItemData^ do
749     if byte(FBufPtr^) in [isc_info_backout_count, isc_info_delete_count,
750     isc_info_expunge_count,isc_info_insert_count, isc_info_purge_count,
751     isc_info_read_idx_count, isc_info_read_seq_count, isc_info_update_count] then
752     begin
753     tableCounts := FDataLength div 6;
754     SetLength(Result,TableCounts);
755     P := FBufPtr + 3;
756     for i := 0 to TableCounts -1 do
757     with FirebirdClientAPI do
758     begin
759     Result[i].TableID := DecodeInteger(P,2);
760     Inc(P,2);
761     Result[i].Count := DecodeInteger(P,4);
762     Inc(P,4);
763     end;
764     end
765     else
766     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
767     end;
768    
769     { TDBInformation }
770    
771     function TDBInformation.AddSpecialItem(BufPtr: PChar): POutputBlockItemData;
772     begin
773     Result := inherited AddSpecialItem(BufPtr);
774     with Result^ do
775     begin
776     with FirebirdClientAPI do
777     FDataLength := DecodeInteger(FBufPtr+1,2);
778     FSize := FDataLength + 3;
779     end;
780     end;
781    
782     procedure TDBInformation.DoParseBuffer;
783     var P: PChar;
784     index: integer;
785     begin
786     P := Buffer;
787     index := 0;
788     SetLength(FItems,0);
789     while (P^ <> char(isc_info_end)) and (P < Buffer + getBufSize) do
790     begin
791     SetLength(FItems,index+1);
792     case byte(P^) of
793     isc_info_no_reserve,
794     isc_info_allocation,
795     isc_info_ods_minor_version,
796     isc_info_ods_version,
797     isc_info_db_SQL_dialect,
798     isc_info_page_size,
799     isc_info_current_memory,
800     isc_info_forced_writes,
801     isc_info_max_memory,
802     isc_info_num_buffers,
803     isc_info_sweep_interval,
804     isc_info_fetches,
805     isc_info_marks,
806     isc_info_reads,
807     isc_info_writes:
808     FItems[index] := AddIntegerItem(P);
809    
810     isc_info_implementation,
811     isc_info_base_level:
812     FItems[index] := AddBytesItem(P);
813    
814     isc_info_db_id,
815     isc_info_version,
816     isc_info_backout_count,
817     isc_info_delete_count,
818     isc_info_expunge_count,
819     isc_info_insert_count,
820     isc_info_purge_count,
821     isc_info_read_idx_count,
822     isc_info_read_seq_count,
823     isc_info_update_count,
824     isc_info_user_names:
825     FItems[index] := AddSpecialItem(P);
826    
827     else
828     FItems[index] := AddSpecialItem(P);
829     end;
830     P += FItems[index]^.FSize;
831     Inc(index);
832     end;
833     end;
834    
835     constructor TDBInformation.Create(aSize: integer);
836     begin
837     inherited Create(aSize);
838     FIntegerType := dtInteger;
839     end;
840    
841     { TServiceQueryResults }
842    
843     function TServiceQueryResults.AddListItem(BufPtr: PChar): POutputBlockItemData;
844     var P: PChar;
845     i: integer;
846     group: byte;
847     begin
848     Result := inherited AddListItem(BufPtr);
849     P := BufPtr + 1;
850     i := 0;
851     group := byte(BufPtr^);
852     if group in [isc_info_svc_get_users,isc_info_svc_limbo_trans] then
853     begin
854     with FirebirdClientAPI do
855     Result^.FSize := DecodeInteger(P,2) + 3;
856     Inc(P,2);
857     end;
858     with Result^ do
859     begin
860     while (P < FBufPtr + FSize) and (P^ <> char(isc_info_flag_end)) do
861     begin
862     SetLength(FSubItems,i+1);
863     case group of
864     isc_info_svc_svr_db_info:
865     case integer(P^) of
866     isc_spb_num_att,
867     isc_spb_num_db:
868     FSubItems[i] := AddIntegerItem(P);
869    
870     isc_spb_dbname:
871     FSubItems[i] := AddStringItem(P);
872    
873     else
874     IBError(ibxeOutputParsingError, [integer(P^)]);
875     end;
876    
877     isc_info_svc_get_license:
878     case integer(P^) of
879     isc_spb_lic_id,
880     isc_spb_lic_key:
881     FSubItems[i] := AddIntegerItem(P);
882     else
883     IBError(ibxeOutputParsingError, [integer(P^)]);
884     end;
885    
886     isc_info_svc_limbo_trans:
887     case integer(P^) of
888     isc_spb_tra_id,
889     isc_spb_single_tra_id,
890     isc_spb_multi_tra_id:
891     FSubItems[i] := AddIntegerItem(P);
892    
893     isc_spb_tra_host_site,
894     isc_spb_tra_remote_site,
895     isc_spb_tra_db_path:
896     FSubItems[i] := AddStringItem(P);
897    
898     isc_spb_tra_advise,
899     isc_spb_tra_state:
900     FSubItems[i] := AddByteItem(P);
901     else
902     IBError(ibxeOutputParsingError, [integer(P^)]);
903     end;
904    
905     isc_info_svc_get_users:
906     case integer(P^) of
907     isc_spb_sec_userid,
908     isc_spb_sec_groupid:
909     FSubItems[i] := AddIntegerItem(P);
910    
911     isc_spb_sec_username,
912     isc_spb_sec_password,
913     isc_spb_sec_firstname,
914     isc_spb_sec_middlename,
915     isc_spb_sec_lastname:
916     FSubItems[i] := AddStringItem(P);
917    
918     else
919     IBError(ibxeOutputParsingError, [integer(P^)]);
920     end;
921    
922     end;
923     P += FSubItems[i]^.FSize;
924     Inc(i);
925     end;
926     FDataLength := 0;
927     for i := 0 to Length(FSubItems) - 1 do
928     FDataLength += FSubItems[i]^.FSize;
929     if group in [isc_info_svc_get_users,isc_info_svc_limbo_trans] then
930     Exit;
931    
932     if (P < FBufPtr + FSize) and (P^ = char(isc_info_flag_end)) then
933     FSize := FDataLength + 2 {include start and end flag}
934     else
935     FSize := FDataLength + 1; {start flag only}
936     end;
937     end;
938    
939     function TServiceQueryResults.AddSpecialItem(BufPtr: PChar
940     ): POutputBlockItemData;
941     var P: PChar;
942     i: integer;
943     begin
944     Result := inherited AddSpecialItem(BufPtr);
945     with Result^ do
946     begin
947     with FirebirdClientAPI do
948     FDataLength := DecodeInteger(FBufPtr+1, 2);
949    
950     P := FBufPtr + 3; {skip length bytes}
951     i := 0;
952     while P < FBufPtr + FDataLength do
953     begin
954     FSubItems[i] := AddIntegerItem(P);
955     P += FSubItems[i]^.FSize;
956     Inc(i);
957     end;
958     end;
959     end;
960    
961     procedure TServiceQueryResults.DoParseBuffer;
962     var P: PChar;
963     i: integer;
964     begin
965     P := Buffer;
966     i := 0;
967     while (P < Buffer + getBufSize) and (P^ <> char(isc_info_end)) do
968     begin
969     SetLength(FItems,i+1);
970     case integer(P^) of
971     isc_info_svc_line,
972     isc_info_svc_get_env,
973     isc_info_svc_get_env_lock,
974     isc_info_svc_get_env_msg,
975     isc_info_svc_user_dbpath,
976     isc_info_svc_server_version,
977     isc_info_svc_implementation,
978     isc_info_svc_to_eof:
979     FItems[i] := AddStringItem(P);
980    
981     isc_info_svc_get_license_mask,
982     isc_info_svc_capabilities,
983     isc_info_svc_version,
984     isc_info_svc_running,
985     isc_info_svc_stdin:
986     FItems[i] := AddIntegerItem(P);
987    
988     isc_info_svc_timeout,
989     isc_info_data_not_ready,
990     isc_info_truncated:
991     FItems[i] := AddItem(P);
992    
993     isc_info_svc_svr_db_info,
994     isc_info_svc_get_license,
995     isc_info_svc_limbo_trans,
996     isc_info_svc_get_users:
997     FItems[i] := AddListItem(P);
998    
999     isc_info_svc_get_config:
1000     FItems[i] := AddSpecialItem(P);
1001    
1002    
1003     else
1004     IBError(ibxeOutputParsingError, [integer(P^)]);
1005     end;
1006     P += FItems[i]^.FSize;
1007     Inc(i);
1008     end;
1009     end;
1010    
1011     { TSQLInfoResultsBuffer }
1012    
1013     function TSQLInfoResultsBuffer.AddListItem(BufPtr: PChar): POutputBlockItemData;
1014     var P: PChar;
1015     i: integer;
1016     begin
1017     Result := inherited AddListItem(BufPtr);
1018     P := BufPtr + 1;
1019     i := 0;
1020    
1021     if byte(BufPtr^) = isc_info_sql_records then
1022     begin
1023     with FirebirdClientAPI do
1024     Result^.FSize := DecodeInteger(P,2) + 3;
1025     Inc(P,2);
1026     with Result^ do
1027     begin
1028     while (P < FBufPtr + FSize) and (byte(P^) <> isc_info_end) do
1029     begin
1030     SetLength(FSubItems,i+1);
1031     case integer(P^) of
1032     isc_info_req_select_count,
1033     isc_info_req_insert_count,
1034     isc_info_req_update_count,
1035     isc_info_req_delete_count:
1036     FSubItems[i] := AddIntegerItem(P);
1037    
1038     isc_info_truncated:
1039     begin
1040     FTruncated := true;
1041     Exit;
1042     end;
1043    
1044     isc_info_error:
1045     begin
1046     FError := true;
1047     Exit;
1048     end;
1049     else
1050     FSubItems[i] := AddSpecialItem(P);
1051     end;
1052     P += FSubItems[i]^.FSize;
1053     Inc(i);
1054     end;
1055     end;
1056     end;
1057     end;
1058    
1059     procedure TSQLInfoResultsBuffer.DoParseBuffer;
1060     var P: PChar;
1061     index: integer;
1062     begin
1063     P := Buffer;
1064     index := 0;
1065     SetLength(FItems,0);
1066     while (P^ <> char(isc_info_end)) and (P < Buffer + getBufSize) do
1067     begin
1068     SetLength(FItems,index+1);
1069     case byte(P^) of
1070     isc_info_sql_stmt_type:
1071     FItems[index] := AddIntegerItem(P);
1072    
1073     isc_info_sql_get_plan:
1074     FItems[index] := AddStringItem(P);
1075    
1076     isc_info_sql_records:
1077     FItems[index] := AddListItem(P);
1078    
1079     isc_info_truncated:
1080     begin
1081     FTruncated := true;
1082     Exit;
1083     end;
1084    
1085     isc_info_error:
1086     begin
1087     FError := true;
1088     Exit;
1089     end;
1090    
1091     else
1092     FItems[index] := AddSpecialItem(P);
1093     end;
1094     P += FItems[index]^.FSize;
1095     Inc(index);
1096     end;
1097     end;
1098    
1099     constructor TSQLInfoResultsBuffer.Create(aSize: integer);
1100     begin
1101     inherited Create(aSize);
1102     FIntegerType := dtInteger;
1103     end;
1104    
1105     end.
1106