ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/journaling/fbintf/client/FBArray.pas
Revision: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (8 years ago) by tony
Content type: text/x-pascal
Original Path: ibx/trunk/fbintf/client/FBArray.pas
File size: 26145 byte(s)
Log Message:
Committing updates for Release R2-0-0

File Contents

# User Rev Content
1 tony 45 (*
2     * Firebird Interface (fbintf). The fbintf components provide a set of
3     * Pascal language bindings for the Firebird API.
4     *
5     * The contents of this file are subject to the Initial Developer's
6     * Public License Version 1.0 (the "License"); you may not use this
7     * file except in compliance with the License. You may obtain a copy
8     * of the License here:
9     *
10     * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11     *
12     * Software distributed under the License is distributed on an "AS
13     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14     * implied. See the License for the specific language governing rights
15     * and limitations under the License.
16     *
17     * The Initial Developer of the Original Code is Tony Whyman.
18     *
19     * The Original Code is (C) 2016 Tony Whyman, MWA Software
20     * (http://www.mwasoftware.co.uk).
21     *
22     * All Rights Reserved.
23     *
24     * Contributor(s): ______________________________________.
25     *
26     *)
27     unit 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