ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBOutputBlock.pas
Revision: 61
Committed: Sun Apr 2 11:40:29 2017 UTC (7 years, 7 months ago) by tony
Content type: text/x-pascal
Original Path: ibx/trunk/fbintf/client/FBOutputBlock.pas
File size: 31502 byte(s)
Log Message:

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