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

# Content
1 (*
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