ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBArray.pas
Revision: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (7 years, 11 months ago) by tony
Content type: text/x-pascal
File size: 26145 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 FBArray;
28
29 {$IFDEF FPC}
30 {$mode objfpc}{$H+}
31 {$codepage UTF8}
32 {$interfaces COM}
33 {$ENDIF}
34
35 interface
36
37 uses
38 Classes, SysUtils, IB, IBHeader, FBTransaction,
39 FBSQLData, FBClientAPI, IBExternals, FBActivityMonitor;
40
41 (*
42
43 COMMENTS (copied from IBPP)
44
45 1)
46 For an array column of type CHAR(X), the internal type returned or expected is blr_text.
47 In such case, the byte array received or submitted to get/put_slice is formatted in
48 elements of X bytes, which correspond to what is reported in array_desc_length.
49 The elements are not '\0' terminated but are right-padded with spaces ' '.
50
51 2)
52 For an array column of type VARCHAR(X), the internal type is blr_varying.
53 The underlying format is rather curious and different than what is used in XSQLDA.
54 The element size is reported in array_desc_length as X.
55 Yet each element of the byte array is expected to be of size X+2 (just as if we were
56 to stuff a short in the first 2 bytes to store the length (as is done with XSQLDA).
57 No. The string of X characters maximum has to be stored in the chunks of X+2 bytes as
58 a zero-terminated c-string. Note that the buffer is indeed one byte too large.
59 Internally, the API probably convert in-place in these chunks the zero-terminated string
60 to a variable-size string with a short in front and the string data non zero-terminated
61 behind.
62
63 *)
64
65 type
66 TFBArray = class;
67
68 { TFBArrayElement }
69
70 TFBArrayElement = class(TSQLDataItem)
71 private
72 FBufPtr: PChar;
73 FArray: TFBArray;
74 protected
75 function GetSQLDialect: integer; override;
76 procedure Changing; override;
77 procedure Changed; override;
78 function SQLData: PChar; override;
79 function GetDataLength: cardinal; override;
80 function GetCodePage: TSystemCodePage; override;
81 procedure SetDataLength(len: cardinal); override;
82 procedure SetSQLType(aValue: cardinal); override;
83 public
84 constructor Create(anArray: TFBArray; P: PChar);
85 function GetSQLType: cardinal; override;
86 function GetName: string; override;
87 function GetScale: integer; override;
88 function GetSize: integer;
89 function GetAsString: string; override;
90 procedure SetAsLong(Value: Long); override;
91 procedure SetAsShort(Value: Short); override;
92 procedure SetAsInt64(Value: Int64); override;
93 procedure SetAsString(Value: String); override;
94 procedure SetAsDouble(Value: Double); override;
95 procedure SetAsFloat(Value: Float); override;
96 procedure SetAsCurrency(Value: Currency); override;
97 end;
98
99 { TFBArrayMetaData }
100
101 TFBArrayMetaData = class(TFBInterfacedObject,IArrayMetaData)
102 protected
103 FArrayDesc: TISC_ARRAY_DESC;
104 procedure LoadMetaData(aAttachment: IAttachment; aTransaction: ITransaction;
105 relationName, columnName: string); virtual; abstract;
106 function NumOfElements: integer;
107 public
108 constructor Create(aAttachment: IAttachment; aTransaction: ITransaction;
109 relationName, columnName: string);
110 function GetCodePage: TSystemCodePage; virtual; abstract;
111
112 public
113 {IArrayMetaData}
114 function GetSQLType: cardinal;
115 function GetSQLTypeName: string;
116 function GetScale: integer;
117 function GetSize: cardinal;
118 function GetCharSetID: cardinal; virtual; abstract;
119 function GetTableName: string;
120 function GetColumnName: string;
121 function GetDimensions: integer;
122 function GetBounds: TArrayBounds;
123 end;
124
125
126 { TFBArray }
127
128 TFBArray = class(TActivityReporter,IArray)
129 private
130 FMetaData: IArrayMetaData;
131 FIsNew: boolean;
132 FLoaded: boolean;
133 FModified: boolean;
134 FAttachment: IAttachment;
135 FTransactionIntf: ITransaction;
136 FTransactionSeqNo: integer;
137 FSQLDialect: integer;
138 FOffsets: array of integer;
139 FElement: TFBArrayElement;
140 FElementIntf: IUnknown;
141 FElementSize: integer;
142 FEventHandlers: array of TArrayEventHandler;
143 procedure GetArraySlice;
144 procedure PutArraySlice(Force: boolean=false);
145 function GetOffset(index: array of integer): PChar;
146 function GetDataLength: short;
147 protected
148 FBuffer: PChar;
149 FBufSize: ISC_LONG;
150 FArrayID: TISC_QUAD;
151 procedure AllocateBuffer; virtual;
152 procedure Changing;
153 procedure Changed;
154 function GetArrayDesc: PISC_ARRAY_DESC;
155 procedure InternalGetSlice; virtual; abstract;
156 procedure InternalPutSlice(Force: boolean); virtual; abstract;
157 public
158 constructor Create(aAttachment: IAttachment; aTransaction: TFBTransaction;
159 aField: IArrayMetaData); overload;
160 constructor Create(aAttachment: IAttachment; aTransaction: TFBTransaction;
161 aField: IArrayMetaData; ArrayID: TISC_QUAD); overload;
162 destructor Destroy; override;
163 function GetSQLDialect: integer;
164 procedure TransactionEnding(aTransaction: ITransaction; Force: boolean);
165
166 public
167 {IArrayMetaData}
168 function GetSQLType: cardinal;
169 function GetSQLTypeName: string;
170 function GetScale: integer;
171 function GetSize: cardinal;
172 function GetCharSetID: cardinal;
173 function GetTableName: string;
174 function GetColumnName: string;
175 function GetDimensions: integer;
176 function GetBounds: TArrayBounds;
177 {IArray}
178 function GetArrayID: TISC_QUAD;
179 procedure Clear;
180 function IsEmpty: boolean;
181 procedure PreLoad;
182 procedure CancelChanges;
183 procedure SaveChanges;
184 function GetAsInteger(index: array of integer): integer;
185 function GetAsBoolean(index: array of integer): boolean;
186 function GetAsCurrency(index: array of integer): Currency;
187 function GetAsInt64(index: array of integer): Int64;
188 function GetAsDateTime(index: array of integer): TDateTime;
189 function GetAsDouble(index: array of integer): Double;
190 function GetAsFloat(index: array of integer): Float;
191 function GetAsLong(index: array of integer): Long;
192 function GetAsShort(index: array of integer): Short;
193 function GetAsString(index: array of integer): String;
194 function GetAsVariant(index: array of integer): Variant;
195 procedure SetAsInteger(index: array of integer; AValue: integer);
196 procedure SetAsBoolean(index: array of integer; AValue: boolean);
197 procedure SetAsCurrency(index: array of integer; Value: Currency);
198 procedure SetAsInt64(index: array of integer; Value: Int64);
199 procedure SetAsDate(index: array of integer; Value: TDateTime);
200 procedure SetAsLong(index: array of integer; Value: Long);
201 procedure SetAsTime(index: array of integer; Value: TDateTime);
202 procedure SetAsDateTime(index: array of integer; Value: TDateTime);
203 procedure SetAsDouble(index: array of integer; Value: Double);
204 procedure SetAsFloat(index: array of integer; Value: Float);
205 procedure SetAsShort(index: array of integer; Value: Short);
206 procedure SetAsString(index: array of integer; Value: String);
207 procedure SetAsVariant(index: array of integer; Value: Variant);
208 procedure SetBounds(dim, UpperBound, LowerBound: integer);
209 function GetAttachment: IAttachment;
210 function GetTransaction: ITransaction;
211 procedure AddEventHandler(Handler: TArrayEventHandler);
212 procedure RemoveEventHandler(Handler: TArrayEventHandler);
213 end;
214
215 implementation
216
217 uses FBMessages;
218
219 { TFBArrayElement }
220
221 function TFBArrayElement.GetSQLDialect: integer;
222 begin
223 Result := FArray.GetSQLDialect;
224 end;
225
226 procedure TFBArrayElement.Changing;
227 begin
228 inherited Changing;
229 FArray.Changing;
230 end;
231
232 procedure TFBArrayElement.Changed;
233 begin
234 inherited Changed;
235 FArray.Changed;
236 end;
237
238 function TFBArrayElement.SQLData: PChar;
239 begin
240 Result := FBufPtr;
241 end;
242
243 function TFBArrayElement.GetDataLength: cardinal;
244 begin
245 Result := FArray.GetDataLength
246 end;
247
248 function TFBArrayElement.GetCodePage: TSystemCodePage;
249 begin
250 Result := (FArray.FMetaData as TFBArrayMetaData).GetCodePage;
251 end;
252
253 procedure TFBArrayElement.SetDataLength(len: cardinal);
254 begin
255 if len > GetDataLength then
256 IBError(ibxeArrayElementOverFlow,[nil]);
257 end;
258
259 constructor TFBArrayElement.Create(anArray: TFBArray; P: PChar);
260 begin
261 inherited Create;
262 FArray := anArray;
263 FBufPtr := P;
264 end;
265
266 function TFBArrayElement.GetSQLType: cardinal;
267 begin
268 Result := FArray.FMetaData.GetSQLType;
269 end;
270
271 function TFBArrayElement.GetName: string;
272 begin
273 Result := FArray.FMetaData.GetColumnName;
274 end;
275
276 function TFBArrayElement.GetScale: integer;
277 begin
278 Result := FArray.FMetaData.GetScale;
279 end;
280
281 function TFBArrayElement.GetSize: integer;
282 begin
283 Result := GetDataLength;
284 end;
285
286 function TFBArrayElement.GetAsString: string;
287 var rs: RawByteString;
288 begin
289 case GetSQLType of
290 SQL_VARYING:
291 begin
292 rs := strpas(FBufPtr);
293 SetCodePage(rs,GetCodePage,false);
294 Result := rs;
295 end;
296 SQL_TEXT:
297 begin
298 SetString(rs,FBufPtr,GetDataLength);
299 SetCodePage(rs,GetCodePage,false);
300 Result := rs;
301 end
302 else
303 Result := inherited GetAsString;
304 end;
305 end;
306
307 procedure TFBArrayElement.SetAsLong(Value: Long);
308 begin
309 AsInt64 := Value;
310 end;
311
312 procedure TFBArrayElement.SetAsShort(Value: Short);
313 begin
314 AsInt64 := Value;
315 end;
316
317 procedure TFBArrayElement.SetAsInt64(Value: Int64);
318 begin
319 CheckActive;
320 case GetSQLType of
321 SQL_LONG:
322 PLong(SQLData)^ := Value;
323 SQL_SHORT:
324 PShort(SQLData)^ := Value;
325 SQL_INT64:
326 PInt64(SQLData)^ := Value;
327 SQL_TEXT, SQL_VARYING:
328 SetAsString(IntToStr(Value));
329 SQL_D_FLOAT,
330 SQL_DOUBLE:
331 PDouble(SQLData)^ := Value;
332 SQL_FLOAT:
333 PSingle(SQLData)^ := Value;
334 else
335 IBError(ibxeInvalidDataConversion, [nil]);
336 end;
337 Changed;
338 end;
339
340 procedure TFBArrayElement.SetAsString(Value: String);
341 var len: integer;
342 ElementSize: integer;
343 begin
344 CheckActive;
345 case GetSQLType of
346 SQL_BOOLEAN:
347 if CompareText(Value,STrue) = 0 then
348 AsBoolean := true
349 else
350 if CompareText(Value,SFalse) = 0 then
351 AsBoolean := false
352 else
353 IBError(ibxeInvalidDataConversion,[nil]);
354
355 SQL_VARYING:
356 begin
357 Value := Transliterate(Value,GetCodePage);
358 len := Length(Value);
359 ElementSize := GetDataLength;
360 if len > ElementSize - 2 then
361 len := ElementSize - 2;
362 if Len > 0 then
363 Move(Value[1],FBufPtr^,len);
364 if Len < ElementSize - 2 then
365 (FBufPtr+len)^ := #0;
366 Changed;
367 end;
368
369 SQL_TEXT:
370 begin
371 Value := Transliterate(Value,GetCodePage);
372 ElementSize := GetDataLength;
373 FillChar(FBufPtr^,ElementSize,' ');
374 len := Length(Value);
375 if len > ElementSize - 1 then len := ElementSize - 1;
376 Move(Value[1],FBufPtr^,len);
377 Changed;
378 end;
379
380 SQL_SHORT,
381 SQL_LONG,
382 SQL_INT64:
383 if trim(Value) = '' then
384 SetAsInt64(0)
385 else
386 SetAsInt64(StrToInt(Value));
387
388 SQL_D_FLOAT,
389 SQL_DOUBLE,
390 SQL_FLOAT:
391 if trim(Value) = '' then
392 SetAsDouble(0)
393 else
394 SetAsDouble(StrToFloat(Value));
395
396 SQL_TIMESTAMP:
397 SetAsDateTime(StrToDateTime(Value));
398
399 SQL_TYPE_DATE:
400 SetAsDate(StrToDateTime(Value));
401
402 SQL_TYPE_TIME:
403 SetAsTime(StrToDateTime(Value));
404
405 else
406 IBError(ibxeInvalidDataConversion,[nil]);
407 end;
408 end;
409
410 procedure TFBArrayElement.SetAsDouble(Value: Double);
411 begin
412 CheckActive;
413 case GetSQLType of
414 SQL_D_FLOAT,
415 SQL_DOUBLE:
416 PDouble(SQLData)^ := Value;
417 SQL_FLOAT:
418 PSingle(SQLData)^ := Value;
419 SQL_SHORT:
420 if Scale < 0 then
421 PShort(SQLData)^ := AdjustScaleFromDouble(Value,Scale)
422 else
423 IBError(ibxeInvalidDataConversion, [nil]);
424 SQL_LONG:
425 if Scale < 0 then
426 PLong(SQLData)^ := AdjustScaleFromDouble(Value,Scale)
427 else
428 IBError(ibxeInvalidDataConversion, [nil]);
429 SQL_INT64:
430 if Scale < 0 then
431 PInt64(SQLData)^ := AdjustScaleFromDouble(Value,Scale)
432 else
433 IBError(ibxeInvalidDataConversion, [nil]);
434 SQL_TEXT, SQL_VARYING:
435 AsString := FloatToStr(Value);
436 else
437 IBError(ibxeInvalidDataConversion, [nil]);
438 end;
439 Changed;
440 end;
441
442 procedure TFBArrayElement.SetAsFloat(Value: Float);
443 begin
444 AsDouble := Value;
445 end;
446
447 procedure TFBArrayElement.SetAsCurrency(Value: Currency);
448 begin
449 CheckActive;
450 if (GetSQLDialect < 3) or (SQLType <> SQL_INT64) then
451 AsDouble := Value
452 else
453 begin
454 if Scale = -4 then
455 PCurrency(SQLData)^ := Value
456 else
457 PInt64(SQLData)^ := AdjustScaleFromCurrency(Value,Scale);
458 Changed;
459 end
460 end;
461
462 procedure TFBArrayElement.SetSQLType(aValue: cardinal);
463 begin
464 if aValue = GetSQLType then
465 IBError(ibxeInvalidDataConversion, [nil]);
466 end;
467
468 {TFBArrayMetaData}
469
470 constructor TFBArrayMetaData.Create(aAttachment: IAttachment;
471 aTransaction: ITransaction; relationName, columnName: string);
472 begin
473 inherited Create;
474 LoadMetaData(aAttachment,aTransaction,relationName, columnName);
475 end;
476
477 function TFBArrayMetaData.GetSQLType: cardinal;
478 begin
479 case FArrayDesc.array_desc_dtype of
480 blr_cstring,
481 blr_cstring2,
482 blr_text,blr_text2:
483 Result := SQL_TEXT;
484 blr_short:
485 Result := SQL_SHORT;
486 blr_long:
487 Result := SQL_LONG;
488 blr_quad, blr_blob_id:
489 Result := SQL_QUAD;
490 blr_float:
491 Result := SQL_FLOAT;
492 blr_double,blr_d_float:
493 Result := SQL_D_FLOAT;
494 blr_timestamp:
495 Result := SQL_TIMESTAMP;
496 blr_varying,blr_varying2:
497 Result := SQL_VARYING;
498 blr_sql_date:
499 Result := SQL_TYPE_DATE;
500 blr_sql_time:
501 Result := SQL_TYPE_TIME;
502 blr_int64:
503 Result := SQL_INT64;
504 end;
505 end;
506
507 function TFBArrayMetaData.GetSQLTypeName: string;
508 begin
509 Result := TSQLDataItem.GetSQLTypeName(GetSQLType);
510 end;
511
512 function TFBArrayMetaData.GetScale: integer;
513 begin
514 Result := byte(FArrayDesc.array_desc_scale);
515 end;
516
517 function TFBArrayMetaData.GetSize: cardinal;
518 begin
519 Result := FArrayDesc.array_desc_length;
520 end;
521
522 function TFBArrayMetaData.GetTableName: string;
523 begin
524 with FArrayDesc do
525 SetString(Result,PChar(@array_desc_relation_name),sizeof(array_desc_relation_name));
526 Result := trim(Result);
527 end;
528
529 function TFBArrayMetaData.GetColumnName: string;
530 begin
531 with FArrayDesc do
532 SetString(Result,PChar(@FArrayDesc.array_desc_field_name),sizeof(array_desc_field_name));
533 Result := trim(Result);
534 end;
535
536 function TFBArrayMetaData.GetDimensions: integer;
537 begin
538 Result := FArrayDesc.array_desc_dimensions;
539 end;
540
541 function TFBArrayMetaData.GetBounds: TArrayBounds;
542 var i: integer;
543 begin
544 SetLength(Result,GetDimensions);
545 for i := 0 to GetDimensions - 1 do
546 begin
547 Result[i].UpperBound := FArrayDesc.array_desc_bounds[i].array_bound_upper;
548 Result[i].LowerBound := FArrayDesc.array_desc_bounds[i].array_bound_lower;
549 end;
550 end;
551
552 function TFBArrayMetaData.NumOfElements: integer;
553 var i: integer;
554 Bounds: TArrayBounds;
555 begin
556 Result := 1;
557 Bounds := GetBounds;
558 for i := 0 to Length(Bounds) - 1 do
559 Result *= (Bounds[i].UpperBound - Bounds[i].LowerBound + 1);
560 end;
561
562
563 { TFBArray }
564
565 procedure TFBArray.AllocateBuffer;
566 var i: integer;
567 l: integer;
568 Bounds: TArrayBounds;
569 Dims: integer;
570 begin
571 SetLength(FOffsets,0);
572 FreeMem(FBuffer);
573 FBuffer := nil;
574 FLoaded := false;
575
576 with FMetaData as TFBArrayMetaData do
577 begin
578 l := NumOfElements;
579 FElementSize := FArrayDesc.array_desc_length;
580 case GetSQLType of
581 SQL_VARYING:
582 FElementSize += 2;
583 SQL_TEXT:
584 FElementSize += 1;
585 end;
586 FBufSize := FElementSize * l;
587
588 with FirebirdClientAPI do
589 IBAlloc(FBuffer,0,FBufSize);
590
591 Dims := GetDimensions;
592 SetLength(FOffsets,GetDimensions);
593 Bounds := GetBounds;
594 if FArrayDesc.array_desc_flags = 0 {row major} then
595 begin
596 FOffsets[0] := 1;
597 for i := 0 to Dims - 2 do
598 FOffsets[i+1] := FOffsets[i] * (Bounds[i].UpperBound - Bounds[i].LowerBound + 1);
599 end
600 else
601 begin
602 {column major}
603 FOffsets[Dims-1] := 1;
604 for i := Dims - 1 downto 1 do
605 FOffsets[i-1] := FOffsets[i] * (Bounds[i].UpperBound - Bounds[i].LowerBound + 1);
606 end;
607 end;
608 end;
609
610 procedure TFBArray.Changing;
611 var i: integer;
612 begin
613 for i := 0 to Length(FEventHandlers) - 1 do
614 FEventHandlers[i](self,arChanging);
615 end;
616
617 procedure TFBArray.Changed;
618 var i: integer;
619 begin
620 FModified := true;
621 for i := 0 to Length(FEventHandlers) - 1 do
622 FEventHandlers[i](self,arChanged);
623 end;
624
625 procedure TFBArray.GetArraySlice;
626 begin
627 if FIsNew or FLoaded then Exit;
628 InternalGetSlice;
629 FLoaded := true;
630 end;
631
632 procedure TFBArray.PutArraySlice(Force: boolean);
633 begin
634 if not FModified or not FTransactionIntf.InTransaction or
635 (FTransactionSeqNo < (FTransactionIntf as TFBTransaction).TransactionSeqNo) then Exit;
636
637 InternalPutSlice(Force);
638 FModified := false;
639 FIsNew := false;
640 end;
641
642 function TFBArray.GetOffset(index: array of integer): PChar;
643 var i: integer;
644 Bounds: TArrayBounds;
645 FlatIndex: integer;
646 begin
647 if FMetaData.GetDimensions <> Length(index) then
648 IBError(ibxeInvalidArrayDimensions,[Length(index)]);
649
650 FlatIndex := 0;
651 Bounds := FMetaData.GetBounds;
652 for i := 0 to Length(index) - 1 do
653 begin
654 if (index[i] < Bounds[i].LowerBound) or (index[i] > Bounds[i].UpperBound) then
655 IBError(ibxeInvalidSubscript,[index[i],i]);
656
657 FlatIndex += FOffsets[i]*(index[i] - Bounds[i].LowerBound);
658 end;
659 Result := FBuffer + FlatIndex*FElementSize;
660 end;
661
662 function TFBArray.GetDataLength: short;
663 begin
664 Result := FElementSize;
665 end;
666
667 function TFBArray.GetArrayDesc: PISC_ARRAY_DESC;
668 begin
669 Result := @((FMetaData as TFBArrayMetaData).FArrayDesc);
670 end;
671
672 constructor TFBArray.Create(aAttachment: IAttachment; aTransaction: TFBTransaction; aField: IArrayMetaData);
673 begin
674 inherited Create(aTransaction);
675 FMetaData := aField;
676 FAttachment := aAttachment;
677 FTransactionIntf := aTransaction;
678 FTransactionSeqNo := aTransaction.TransactionSeqNo;
679 FIsNew := true;
680 FModified := false;
681 FSQLDialect := aAttachment.GetSQLDialect;
682 AllocateBuffer;
683 FElement := TFBArrayElement.Create(self,FBuffer);
684 FElementIntf := FElement;
685 Setlength(FEventHandlers,0);
686 end;
687
688 constructor TFBArray.Create(aAttachment: IAttachment; aTransaction: TFBTransaction;
689 aField: IArrayMetaData; ArrayID: TISC_QUAD);
690 begin
691 inherited Create(aTransaction);
692 FMetaData := aField;
693 FArrayID := ArrayID;
694 FAttachment := aAttachment;
695 FTransactionIntf := aTransaction;
696 FTransactionSeqNo := aTransaction.TransactionSeqNo;
697 FIsNew := false;
698 FModified := false;
699 FSQLDialect := aAttachment.GetSQLDialect;
700 AllocateBuffer;
701 FElement := TFBArrayElement.Create(self,FBuffer);
702 FElementIntf := FElement;
703 Setlength(FEventHandlers,0);
704 end;
705
706 destructor TFBArray.Destroy;
707 begin
708 FreeMem(FBuffer);
709 inherited Destroy;
710 end;
711
712 function TFBArray.GetArrayID: TISC_QUAD;
713 begin
714 PutArraySlice;
715 Result := FArrayID;
716 end;
717
718 procedure TFBArray.Clear;
719 begin
720 FIsNew := true;
721 FModified := false;
722 FArrayID.gds_quad_high := 0;
723 FArrayID.gds_quad_low := 0;
724 AllocateBuffer;
725 end;
726
727 function TFBArray.IsEmpty: boolean;
728 begin
729 Result := FIsNew and not FModified;
730 end;
731
732 procedure TFBArray.PreLoad;
733 begin
734 GetArraySlice;
735 end;
736
737 procedure TFBArray.CancelChanges;
738 begin
739 FModified := false;
740 AllocateBuffer;
741 end;
742
743 procedure TFBArray.SaveChanges;
744 begin
745 PutArraySlice;
746 end;
747
748 function TFBArray.GetSQLDialect: integer;
749 begin
750 Result := FSQLDialect;
751 end;
752
753 procedure TFBArray.TransactionEnding(aTransaction: ITransaction; Force: boolean
754 );
755 begin
756 if (aTransaction = FTransactionIntf) and FModified and not FIsNew then
757 PutArraySlice(Force);
758 end;
759
760 function TFBArray.GetSQLType: cardinal;
761 begin
762 Result := FMetaData.GetSQLType;
763 end;
764
765 function TFBArray.GetSQLTypeName: string;
766 begin
767 Result := FMetaData.GetSQLTypeName;
768 end;
769
770 function TFBArray.GetScale: integer;
771 begin
772 Result := FMetaData.GetScale;
773 end;
774
775 function TFBArray.GetSize: cardinal;
776 begin
777 Result := FMetaData.GetSize;
778 end;
779
780 function TFBArray.GetCharSetID: cardinal;
781 begin
782 Result := FMetaData.GetCharSetID;
783 end;
784
785 function TFBArray.GetTableName: string;
786 begin
787 Result := FMetaData.GetTableName;
788 end;
789
790 function TFBArray.GetColumnName: string;
791 begin
792 Result := FMetaData.GetColumnName;
793 end;
794
795 function TFBArray.GetDimensions: integer;
796 begin
797 Result := FMetaData.GetDimensions;
798 end;
799
800 function TFBArray.GetBounds: TArrayBounds;
801 begin
802 Result := FMetaData.GetBounds;
803 end;
804
805 function TFBArray.GetAsInteger(index: array of integer): integer;
806 begin
807 GetArraySlice;
808 FElement.FBufPtr := GetOffset(index);
809 Result := FElement.GetAsLong;
810 end;
811
812 function TFBArray.GetAsBoolean(index: array of integer): boolean;
813 begin
814 GetArraySlice;
815 FElement.FBufPtr := GetOffset(index);
816 Result := FElement.GetAsBoolean;
817 end;
818
819 function TFBArray.GetAsCurrency(index: array of integer): Currency;
820 begin
821 GetArraySlice;
822 FElement.FBufPtr := GetOffset(index);
823 Result := FElement.GetAsCurrency;
824 end;
825
826 function TFBArray.GetAsInt64(index: array of integer): Int64;
827 begin
828 GetArraySlice;
829 FElement.FBufPtr := GetOffset(index);
830 Result := FElement.GetAsInt64;
831 end;
832
833 function TFBArray.GetAsDateTime(index: array of integer): TDateTime;
834 begin
835 GetArraySlice;
836 FElement.FBufPtr := GetOffset(index);
837 Result := FElement.GetAsDateTime;
838 end;
839
840 function TFBArray.GetAsDouble(index: array of integer): Double;
841 begin
842 GetArraySlice;
843 FElement.FBufPtr := GetOffset(index);
844 Result := FElement.GetAsDouble;
845 end;
846
847 function TFBArray.GetAsFloat(index: array of integer): Float;
848 begin
849 GetArraySlice;
850 FElement.FBufPtr := GetOffset(index);
851 Result := FElement.GetAsFloat;
852 end;
853
854 function TFBArray.GetAsLong(index: array of integer): Long;
855 begin
856 GetArraySlice;
857 FElement.FBufPtr := GetOffset(index);
858 Result := FElement.GetAsLong;
859 end;
860
861 function TFBArray.GetAsShort(index: array of integer): Short;
862 begin
863 GetArraySlice;
864 FElement.FBufPtr := GetOffset(index);
865 Result := FElement.GetAsShort;
866 end;
867
868 function TFBArray.GetAsString(index: array of integer): String;
869 begin
870 GetArraySlice;
871 FElement.FBufPtr := GetOffset(index);
872 Result := FElement.GetAsString;
873 end;
874
875 function TFBArray.GetAsVariant(index: array of integer): Variant;
876 begin
877 GetArraySlice;
878 FElement.FBufPtr := GetOffset(index);
879 Result := FElement.GetAsVariant;
880 end;
881
882 procedure TFBArray.SetAsInteger(index: array of integer; AValue: integer);
883 begin
884 FElement.FBufPtr := GetOffset(index);
885 FElement.SetAsLong(AValue);
886 end;
887
888 procedure TFBArray.SetAsBoolean(index: array of integer; AValue: boolean);
889 begin
890 FElement.FBufPtr := GetOffset(index);
891 FElement.SetAsBoolean(AValue);
892 end;
893
894 procedure TFBArray.SetAsCurrency(index: array of integer; Value: Currency);
895 begin
896 FElement.FBufPtr := GetOffset(index);
897 FElement.SetAsCurrency(Value);
898 end;
899
900 procedure TFBArray.SetAsInt64(index: array of integer; Value: Int64);
901 begin
902 FElement.FBufPtr := GetOffset(index);
903 FElement.SetAsInt64(Value);
904 end;
905
906 procedure TFBArray.SetAsDate(index: array of integer; Value: TDateTime);
907 begin
908 FElement.FBufPtr := GetOffset(index);
909 FElement.SetAsDate(Value);
910 end;
911
912 procedure TFBArray.SetAsLong(index: array of integer; Value: Long);
913 begin
914 FElement.FBufPtr := GetOffset(index);
915 FElement.SetAsLong(Value);
916 end;
917
918 procedure TFBArray.SetAsTime(index: array of integer; Value: TDateTime);
919 begin
920 FElement.FBufPtr := GetOffset(index);
921 FElement.SetAsTime(Value);
922 end;
923
924 procedure TFBArray.SetAsDateTime(index: array of integer; Value: TDateTime);
925 begin
926 FElement.FBufPtr := GetOffset(index);
927 FElement.SetAsDateTime(Value);
928 end;
929
930 procedure TFBArray.SetAsDouble(index: array of integer; Value: Double);
931 begin
932 FElement.FBufPtr := GetOffset(index);
933 FElement.SetAsDouble(Value);
934 end;
935
936 procedure TFBArray.SetAsFloat(index: array of integer; Value: Float);
937 begin
938 FElement.FBufPtr := GetOffset(index);
939 FElement.SetAsFloat(Value);
940 end;
941
942 procedure TFBArray.SetAsShort(index: array of integer; Value: Short);
943 begin
944 FElement.FBufPtr := GetOffset(index);
945 FElement.SetAsShort(Value);
946 end;
947
948 procedure TFBArray.SetAsString(index: array of integer; Value: String);
949 begin
950 FElement.FBufPtr := GetOffset(index);
951 FElement.SetAsString(Value);
952 end;
953
954 procedure TFBArray.SetAsVariant(index: array of integer; Value: Variant);
955 begin
956 FElement.FBufPtr := GetOffset(index);
957 FElement.SetAsVariant(Value);
958 end;
959
960 procedure TFBArray.SetBounds(dim, UpperBound, LowerBound: integer);
961 begin
962 with (FMetaData as TFBArrayMetaData) do
963 begin
964 if (dim < 0) or (dim > GetDimensions) then
965 IBError(ibxeInvalidArrayDimensions,[dim]);
966
967 if (UpperBound > FArrayDesc.array_desc_bounds[dim].array_bound_upper) or
968 (LowerBound < FArrayDesc.array_desc_bounds[dim].array_bound_lower) or
969 (UpperBound < FArrayDesc.array_desc_bounds[dim].array_bound_lower) or
970 (LowerBound > FArrayDesc.array_desc_bounds[dim].array_bound_upper) then
971 IBError(ibxArrayBoundsCantIncrease,[nil]);
972
973 PutArraySlice; {Save any changes}
974
975 FArrayDesc.array_desc_bounds[dim].array_bound_upper := UpperBound;
976 FArrayDesc.array_desc_bounds[dim].array_bound_lower := LowerBound;
977 end;
978 AllocateBuffer;
979 end;
980
981 function TFBArray.GetAttachment: IAttachment;
982 begin
983 Result := FAttachment;
984 end;
985
986 function TFBArray.GetTransaction: ITransaction;
987 begin
988 Result := FTransactionIntf;
989 end;
990
991 procedure TFBArray.AddEventHandler(Handler: TArrayEventHandler);
992 begin
993 SetLength(FEventHandlers,Length(FEventHandlers)+1);
994 FEventHandlers[Length(FEventHandlers)-1] := Handler;
995 end;
996
997 procedure TFBArray.RemoveEventHandler(Handler: TArrayEventHandler);
998 var i,j : integer;
999 begin
1000 for i := Length(FEventHandlers) - 1 downto 0 do
1001 if FEventHandlers[i] = Handler then
1002 begin
1003 for j := i to Length(FEventHandlers) - 2 do
1004 FEventHandlers[i] := FEventHandlers[i+1];
1005 SetLength(FEventHandlers,Length(FEventHandlers) - 1);
1006 end;
1007 end;
1008
1009 end.
1010