ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBArray.pas
Revision: 47
Committed: Mon Jan 9 15:31:51 2017 UTC (7 years, 10 months ago) by tony
Content type: text/x-pascal
File size: 28006 byte(s)
Log Message:
Committing updates for Release R2-0-1

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