ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBOutputBlock.pas
Revision: 143
Committed: Fri Feb 23 12:11:21 2018 UTC (6 years, 2 months ago) by tony
Content type: text/x-pascal
File size: 33999 byte(s)
Log Message:
Fixes Merged

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