ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBArray.pas
Revision: 421
Committed: Sat Oct 21 14:22:28 2023 UTC (6 months, 1 week ago) by tony
Content type: text/x-pascal
File size: 35763 byte(s)
Log Message:
Release 2.6.3 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 FBArray;
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 interface
39
40 uses
41 Classes, SysUtils, IBHeader, IB, FBTransaction,
42 FBSQLData, FBClientAPI, IBExternals, FBActivityMonitor, FmtBCD;
43
44 (*
45
46 COMMENTS (copied from IBPP)
47
48 1)
49 For an array column of type CHAR(X), the internal type returned or expected is blr_text.
50 In such case, the byte array received or submitted to get/put_slice is formatted in
51 elements of X bytes, which correspond to what is reported in array_desc_length.
52 The elements are not '\0' terminated but are right-padded with spaces ' '.
53
54 2)
55 For an array column of type VARCHAR(X), the internal type is blr_varying.
56 The underlying format is rather curious and different than what is used in XSQLDA.
57 The element size is reported in array_desc_length as X.
58 Yet each element of the byte array is expected to be of size X+2 (just as if we were
59 to stuff a short in the first 2 bytes to store the length (as is done with XSQLDA).
60 No. The string of X characters maximum has to be stored in the chunks of X+2 bytes as
61 a zero-terminated c-string. Note that the buffer is indeed one byte too large.
62 Internally, the API probably convert in-place in these chunks the zero-terminated string
63 to a variable-size string with a short in front and the string data non zero-terminated
64 behind.
65
66 *)
67
68 type
69 TFBArray = class;
70
71 { TFBArrayElement }
72
73 TFBArrayElement = class(TSQLDataItem)
74 private
75 FBufPtr: PByte;
76 FArray: TFBArray;
77 protected
78 function GetAttachment: IAttachment; override;
79 function GetSQLDialect: integer; override;
80 procedure Changing; override;
81 procedure Changed; override;
82 function SQLData: PByte; override;
83 function GetDataLength: cardinal; override;
84 function GetCodePage: TSystemCodePage; override;
85 function getCharSetID: cardinal; override;
86 procedure SetDataLength(len: cardinal); override;
87 procedure SetSQLType(aValue: cardinal); override;
88 public
89 constructor Create(anArray: TFBArray; P: PByte);
90 function GetSQLType: cardinal; override;
91 function GetName: AnsiString; override;
92 function GetScale: integer; override;
93 function GetSize: integer;
94 function GetCharSetWidth: integer; override;
95 function GetAsString: AnsiString; override;
96 procedure SetAsLong(Value: Long); override;
97 procedure SetAsShort(Value: Short); override;
98 procedure SetAsInt64(Value: Int64); override;
99 procedure SetAsString(Value: AnsiString); override;
100 procedure SetAsDouble(Value: Double); override;
101 procedure SetAsFloat(Value: Float); override;
102 procedure SetAsCurrency(Value: Currency); override;
103 procedure SetAsBcd(aValue: tBCD); override;
104 procedure SetAsNumeric(Value: IFBNumeric); override;
105 end;
106
107 { TFBArrayMetaData }
108
109 TFBArrayMetaData = class(TFBInterfacedObject,IArrayMetaData)
110 private
111 function GetDType(SQLType: cardinal): UChar;
112 protected
113 FArrayDesc: TISC_ARRAY_DESC;
114 FCharSetID: integer;
115 FAttachment: IAttachment;
116 procedure LoadMetaData(aAttachment: IAttachment; aTransaction: ITransaction;
117 relationName, columnName: AnsiString); virtual; abstract;
118 function NumOfElements: integer;
119 public
120 constructor Create(aAttachment: IAttachment; aTransaction: ITransaction;
121 relationName, columnName: AnsiString); overload;
122 constructor Create(aAttachment: IAttachment;SQLType: cardinal; tableName: AnsiString; columnName: AnsiString;
123 Scale: integer; size: cardinal; charSetID: cardinal;
124 dimensions: cardinal; bounds: TArrayBounds); overload;
125 function GetCodePage: TSystemCodePage; virtual; abstract;
126
127 public
128 {IArrayMetaData}
129 function GetSQLType: cardinal;
130 function GetSQLTypeName: AnsiString;
131 function GetScale: integer;
132 function GetSize: cardinal;
133 function GetCharSetID: cardinal; virtual; abstract;
134 function GetCharSetWidth: integer; virtual; abstract;
135 function GetTableName: AnsiString;
136 function GetColumnName: AnsiString;
137 function GetDimensions: integer;
138 function GetBounds: TArrayBounds;
139 end;
140
141
142 { TFBArray }
143
144 TFBArray = class(TActivityReporter,IArray,ITransactionUser)
145 private
146 FConnectionCodePage: TSystemCodePage;
147 FFirebirdClientAPI: TFBClientAPI;
148 FMetaData: IArrayMetaData;
149 FIsNew: boolean;
150 FLoaded: boolean;
151 FModified: boolean;
152 FAttachment: IAttachment;
153 FTransactionIntf: ITransaction;
154 FTransactionSeqNo: integer;
155 FSQLDialect: integer;
156 FOffsets: array of integer;
157 FElement: TFBArrayElement;
158 FElementIntf: IUnknown;
159 FElementSize: integer;
160 FEventHandlers: array of TArrayEventHandler;
161 procedure GetArraySlice;
162 procedure PutArraySlice(Force: boolean=false);
163 function GetOffset(index: array of integer): PByte;
164 function GetDataLength: short;
165 protected
166 FBuffer: PByte;
167 FBufSize: ISC_LONG;
168 FArrayID: TISC_QUAD;
169 procedure AllocateBuffer; virtual;
170 procedure Changing; virtual;
171 procedure Changed; virtual;
172 function GetArrayDesc: PISC_ARRAY_DESC;
173 procedure InternalGetSlice; virtual; abstract;
174 procedure InternalPutSlice(Force: boolean); virtual; abstract;
175 public
176 constructor Create(aAttachment: IAttachment; aTransaction: TFBTransaction;
177 aField: IArrayMetaData); overload;
178 constructor Create(aAttachment: IAttachment; aTransaction: TFBTransaction;
179 aField: IArrayMetaData; ArrayID: TISC_QUAD); overload;
180 destructor Destroy; override;
181 function GetSQLDialect: integer;
182 property ConnectionCodePage: TSystemCodePage read FConnectionCodePage;
183
184 public
185 {ITransactionUser}
186 procedure TransactionEnding(aTransaction: ITransaction; Force: boolean);
187
188 public
189 {IArrayMetaData}
190 function GetSQLType: cardinal;
191 function GetSQLTypeName: AnsiString;
192 function GetScale: integer;
193 function GetSize: cardinal;
194 function GetCharSetID: cardinal;
195 function GetCharSetWidth: integer;
196 function GetTableName: AnsiString;
197 function GetColumnName: AnsiString;
198 function GetDimensions: integer;
199 function GetBounds: TArrayBounds;
200 {IArray}
201 function GetArrayID: TISC_QUAD;
202 procedure Clear;
203 function IsEmpty: boolean;
204 procedure PreLoad;
205 procedure CancelChanges;
206 procedure SaveChanges;
207 function GetAsInteger(index: array of integer): integer;
208 function GetAsBoolean(index: array of integer): boolean;
209 function GetAsCurrency(index: array of integer): Currency;
210 function GetAsInt64(index: array of integer): Int64;
211 function GetAsDateTime(index: array of integer): TDateTime; overload;
212 procedure GetAsDateTime(index: array of integer; var aDateTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID); overload;
213 procedure GetAsDateTime(index: array of integer; var aDateTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString); overload;
214 procedure GetAsTime(index: array of integer; var aTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID; OnDate: TDateTime); overload;
215 procedure GetAsTime(index: array of integer; var aTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString; OnDate: TDateTime); overload;
216 function GetAsUTCDateTime(index: array of integer): TDateTime;
217 function GetAsDouble(index: array of integer): Double;
218 function GetAsFloat(index: array of integer): Float;
219 function GetAsLong(index: array of integer): Long;
220 function GetAsShort(index: array of integer): Short;
221 function GetAsString(index: array of integer): AnsiString;
222 function GetAsVariant(index: array of integer): Variant;
223 function GetAsBCD(index: array of integer): tBCD;
224 procedure SetAsInteger(index: array of integer; AValue: integer);
225 procedure SetAsBoolean(index: array of integer; AValue: boolean);
226 procedure SetAsCurrency(index: array of integer; Value: Currency);
227 procedure SetAsInt64(index: array of integer; Value: Int64);
228 procedure SetAsDate(index: array of integer; Value: TDateTime);
229 procedure SetAsLong(index: array of integer; Value: Long);
230 procedure SetAsTime(index: array of integer; Value: TDateTime); overload;
231 procedure SetAsTime(index: array of integer; aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
232 procedure SetAsTime(index: array of integer; aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString); overload;
233 procedure SetAsDateTime(index: array of integer; Value: TDateTime); overload;
234 procedure SetAsDateTime(index: array of integer; aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
235 procedure SetAsDateTime(index: array of integer; aValue: TDateTime; aTimeZone: AnsiString); overload;
236 procedure SetAsUTCDateTime(index: array of integer; aUTCTime: TDateTime);
237 procedure SetAsDouble(index: array of integer; Value: Double);
238 procedure SetAsFloat(index: array of integer; Value: Float);
239 procedure SetAsShort(index: array of integer; Value: Short);
240 procedure SetAsString(index: array of integer; Value: AnsiString);
241 procedure SetAsVariant(index: array of integer; Value: Variant);
242 procedure SetAsBcd(index: array of integer; aValue: tBCD);
243 procedure SetBounds(dim, UpperBound, LowerBound: integer);
244 function GetAttachment: IAttachment;
245 function GetTransaction: ITransaction;
246 procedure AddEventHandler(Handler: TArrayEventHandler);
247 procedure RemoveEventHandler(Handler: TArrayEventHandler);
248 end;
249
250 implementation
251
252 uses FBMessages, IBUtils, FBNumeric;
253
254 { TFBArrayElement }
255
256 function TFBArrayElement.GetAttachment: IAttachment;
257 begin
258 Result := FArray.GetAttachment;
259 end;
260
261 function TFBArrayElement.GetSQLDialect: integer;
262 begin
263 Result := FArray.GetSQLDialect;
264 end;
265
266 procedure TFBArrayElement.Changing;
267 begin
268 inherited Changing;
269 FArray.Changing;
270 end;
271
272 procedure TFBArrayElement.Changed;
273 begin
274 inherited Changed;
275 FArray.Changed;
276 end;
277
278 function TFBArrayElement.SQLData: PByte;
279 begin
280 Result := FBufPtr;
281 end;
282
283 function TFBArrayElement.GetDataLength: cardinal;
284 begin
285 Result := FArray.GetDataLength
286 end;
287
288 function TFBArrayElement.GetCodePage: TSystemCodePage;
289 begin
290 Result := (FArray.FMetaData as TFBArrayMetaData).GetCodePage;
291 end;
292
293 function TFBArrayElement.getCharSetID: cardinal;
294 begin
295 Result := (FArray.FMetaData as TFBArrayMetaData).GetCharSetID;
296 end;
297
298 procedure TFBArrayElement.SetDataLength(len: cardinal);
299 begin
300 if len > GetDataLength then
301 IBError(ibxeArrayElementOverFlow,[nil]);
302 end;
303
304 constructor TFBArrayElement.Create(anArray: TFBArray; P: PByte);
305 begin
306 inherited Create(anArray.FFirebirdClientAPI);
307 FArray := anArray;
308 FBufPtr := P;
309 end;
310
311 function TFBArrayElement.GetSQLType: cardinal;
312 begin
313 Result := FArray.FMetaData.GetSQLType;
314 end;
315
316 function TFBArrayElement.GetName: AnsiString;
317 begin
318 Result := FArray.FMetaData.GetColumnName;
319 end;
320
321 function TFBArrayElement.GetScale: integer;
322 begin
323 Result := FArray.FMetaData.GetScale;
324 end;
325
326 function TFBArrayElement.GetSize: integer;
327 begin
328 Result := GetDataLength;
329 end;
330
331 function TFBArrayElement.GetCharSetWidth: integer;
332 begin
333 Result := FArray.FMetaData.GetCharSetWidth;
334 end;
335
336 function TFBArrayElement.GetAsString: AnsiString;
337 var rs: RawByteString;
338 begin
339 case GetSQLType of
340 SQL_VARYING:
341 begin
342 rs := strpas(PAnsiChar(FBufPtr));
343 SetCodePage(rs,GetCodePage,false);
344 Result := rs;
345 end;
346 SQL_TEXT:
347 begin
348 SetString(rs,PAnsiChar(FBufPtr),GetDataLength);
349 SetCodePage(rs,GetCodePage,false);
350 Result := rs;
351 end
352 else
353 Result := inherited GetAsString;
354 end;
355 end;
356
357 procedure TFBArrayElement.SetAsLong(Value: Long);
358 begin
359 AsInt64 := Value;
360 end;
361
362 procedure TFBArrayElement.SetAsShort(Value: Short);
363 begin
364 AsInt64 := Value;
365 end;
366
367 procedure TFBArrayElement.SetAsInt64(Value: Int64);
368 begin
369 CheckActive;
370 case GetSQLType of
371 SQL_LONG:
372 PLong(SQLData)^ := NumericFromRawValues(Value,getScale).getRawValue;
373 SQL_SHORT:
374 PShort(SQLData)^ := NumericFromRawValues(Value,getScale).getRawValue;
375 SQL_INT64:
376 PInt64(SQLData)^ := NumericFromRawValues(Value,getScale).getRawValue;
377 SQL_TEXT, SQL_VARYING:
378 SetAsString(IntToStr(Value));
379 SQL_D_FLOAT,
380 SQL_DOUBLE:
381 PDouble(SQLData)^ := Value;
382 SQL_FLOAT:
383 PSingle(SQLData)^ := Value;
384 else
385 IBError(ibxeInvalidDataConversion, [nil]);
386 end;
387 Changed;
388 end;
389
390 procedure TFBArrayElement.SetAsString(Value: AnsiString);
391 var len: integer;
392 ElementSize: integer;
393 Int64Value: Int64;
394 aScale: integer;
395 begin
396 CheckActive;
397 case GetSQLType of
398 SQL_BOOLEAN:
399 if AnsiCompareText(Value,STrue) = 0 then
400 AsBoolean := true
401 else
402 if AnsiCompareText(Value,SFalse) = 0 then
403 AsBoolean := false
404 else
405 IBError(ibxeInvalidDataConversion,[nil]);
406
407 SQL_VARYING:
408 begin
409 Value := TransliterateToCodePage(Value,GetCodePage);
410 len := Length(Value);
411 ElementSize := GetDataLength;
412 if len > ElementSize - 2 then
413 len := ElementSize - 2;
414 if Len > 0 then
415 Move(Value[1],FBufPtr^,len);
416 if Len < ElementSize - 2 then
417 (FBufPtr+len)^ := 0;
418 Changed;
419 end;
420
421 SQL_TEXT:
422 begin
423 Value := TransliterateToCodePage(Value,GetCodePage);
424 ElementSize := GetDataLength;
425 FillChar(FBufPtr^,ElementSize,' ');
426 len := Length(Value);
427 if len > ElementSize - 1 then len := ElementSize - 1;
428 Move(Value[1],FBufPtr^,len);
429 Changed;
430 end;
431
432 SQL_SHORT,
433 SQL_LONG,
434 SQL_INT64:
435 if TryStrToNumeric(Value,Int64Value,aScale) then
436 SetAsNumeric(NumericFromRawValues(Int64Value,aScale))
437 else
438 SetAsCurrency(StrToCurr(Value));
439
440 SQL_D_FLOAT,
441 SQL_DOUBLE,
442 SQL_FLOAT:
443 if TryStrToNumeric(Value,Int64Value,aScale) then
444 SetAsDouble(NumericToDouble(Int64Value,AScale))
445 else
446 IBError(ibxeInvalidDataConversion,[nil]);
447
448 SQL_DEC_FIXED,
449 SQL_DEC16,
450 SQL_DEC34,
451 SQL_INT128:
452 SetAsBCD(StrToBCD(Value));
453
454 SQL_TIMESTAMP:
455 SetAsDateTime(StrToDateTime(Value));
456
457 SQL_TYPE_DATE:
458 SetAsDate(StrToDateTime(Value));
459
460 SQL_TYPE_TIME:
461 SetAsTime(StrToDateTime(Value));
462
463 else
464 IBError(ibxeInvalidDataConversion,[nil]);
465 end;
466 end;
467
468 procedure TFBArrayElement.SetAsDouble(Value: Double);
469 begin
470 CheckActive;
471 case GetSQLType of
472 SQL_D_FLOAT,
473 SQL_DOUBLE:
474 PDouble(SQLData)^ := Value;
475 SQL_FLOAT:
476 PSingle(SQLData)^ := Value;
477 SQL_SHORT:
478 if Scale < 0 then
479 PShort(SQLData)^ := SafeSmallInt(DoubleToNumeric(Value).AdjustScaleTo(Scale).getRawValue)
480 else
481 IBError(ibxeInvalidDataConversion, [nil]);
482 SQL_LONG:
483 if Scale < 0 then
484 PLong(SQLData)^ := SafeInteger(DoubleToNumeric(Value).AdjustScaleTo(Scale).getRawValue)
485 else
486 IBError(ibxeInvalidDataConversion, [nil]);
487 SQL_INT64:
488 if Scale < 0 then
489 PInt64(SQLData)^ := DoubleToNumeric(Value).AdjustScaleTo(Scale).getRawValue
490 else
491 IBError(ibxeInvalidDataConversion, [nil]);
492 SQL_TEXT, SQL_VARYING:
493 AsString := FloatToStr(Value);
494 else
495 IBError(ibxeInvalidDataConversion, [nil]);
496 end;
497 Changed;
498 end;
499
500 procedure TFBArrayElement.SetAsFloat(Value: Float);
501 begin
502 AsDouble := Value;
503 end;
504
505 procedure TFBArrayElement.SetAsCurrency(Value: Currency);
506 begin
507 CheckActive;
508 if (GetSQLDialect < 3) or (SQLType <> SQL_INT64) then
509 AsDouble := Value
510 else
511 begin
512 if Scale = -4 then
513 PCurrency(SQLData)^ := Value
514 else
515 PInt64(SQLData)^ := CurrToNumeric(Value).AdjustScaleTo(Scale).getRawValue;
516 Changed;
517 end
518 end;
519
520 procedure TFBArrayElement.SetAsBcd(aValue: tBCD);
521 var C: Currency;
522 begin
523 CheckActive;
524 with FirebirdClientAPI do
525 case SQLType of
526 SQL_DEC_FIXED,
527 SQL_DEC16,
528 SQL_DEC34:
529 SQLDecFloatEncode(aValue,SQLType,SQLData);
530
531 SQL_INT128:
532 StrToInt128(Scale,BcdToStr(aValue),SQLData);
533
534 else
535 begin
536 BCDToCurr(aValue,C);
537 SetAsCurrency(C);
538 end;
539 end;
540 Changed;
541 end;
542
543 procedure TFBArrayElement.SetAsNumeric(Value: IFBNumeric);
544 begin
545 CheckActive;
546 case GetSQLType of
547 SQL_LONG:
548 PLong(SQLData)^ := SafeInteger(Value.AdjustScaleTo(Scale).getRawValue);
549 SQL_SHORT:
550 PShort(SQLData)^ := SafeSmallInt(Value.AdjustScaleTo(Scale).getRawValue);
551 SQL_INT64:
552 PInt64(SQLData)^ := Value.AdjustScaleTo(Scale).getRawValue;
553 SQL_TEXT, SQL_VARYING:
554 SetAsString(Value.getAsString);
555 SQL_D_FLOAT,
556 SQL_DOUBLE:
557 PDouble(SQLData)^ := Value.getAsDouble;
558 SQL_FLOAT:
559 PSingle(SQLData)^ := Value.getAsDouble;
560 else
561 IBError(ibxeInvalidDataConversion, [nil]);
562 end;
563 Changed;
564 end;
565
566 procedure TFBArrayElement.SetSQLType(aValue: cardinal);
567 begin
568 if aValue <> GetSQLType then
569 IBError(ibxeInvalidDataConversion, [nil]);
570 end;
571
572 {TFBArrayMetaData}
573
574 constructor TFBArrayMetaData.Create(aAttachment: IAttachment;
575 aTransaction: ITransaction; relationName, columnName: AnsiString);
576 begin
577 inherited Create;
578 FAttachment := aAttachment;
579 LoadMetaData(aAttachment,aTransaction,relationName, columnName);
580 end;
581
582 constructor TFBArrayMetaData.Create(aAttachment: IAttachment;
583 SQLType: cardinal; tableName: AnsiString; columnName: AnsiString;
584 Scale: integer; size: cardinal; charSetID: cardinal; dimensions: cardinal;
585 bounds: TArrayBounds);
586 var i: integer;
587 begin
588 inherited Create;
589 FAttachment := aAttachment;
590 with FArrayDesc do
591 begin
592 array_desc_dtype := GetDType(SQLType);
593 array_desc_scale := Scale;
594 array_desc_length := UShort(size);
595 StrPLCopy(array_desc_field_name,columnName,sizeof(array_desc_field_name));
596 StrPLCopy(array_desc_relation_name,tableName,sizeof(array_desc_relation_name));
597 array_desc_dimensions := dimensions;
598 array_desc_flags := 0;
599 FCharSetID := charSetID;
600 for i := 0 to Length(bounds) - 1 do
601 begin
602 array_desc_bounds[i].array_bound_lower := bounds[i].LowerBound;
603 array_desc_bounds[i].array_bound_upper := bounds[i].UpperBound;
604 end;
605 end;
606 end;
607
608 function TFBArrayMetaData.GetSQLType: cardinal;
609 begin
610 case FArrayDesc.array_desc_dtype of
611 blr_cstring,
612 blr_cstring2,
613 blr_text,blr_text2:
614 Result := SQL_TEXT;
615 blr_short:
616 Result := SQL_SHORT;
617 blr_long:
618 Result := SQL_LONG;
619 blr_quad, blr_blob_id:
620 Result := SQL_QUAD;
621 blr_float:
622 Result := SQL_FLOAT;
623 blr_double,blr_d_float:
624 Result := SQL_D_FLOAT;
625 blr_timestamp:
626 Result := SQL_TIMESTAMP;
627 blr_varying,blr_varying2:
628 Result := SQL_VARYING;
629 blr_sql_date:
630 Result := SQL_TYPE_DATE;
631 blr_sql_time:
632 Result := SQL_TYPE_TIME;
633 blr_int64:
634 Result := SQL_INT64;
635 blr_sql_time_tz:
636 Result := SQL_TIME_TZ;
637 blr_timestamp_tz:
638 Result := SQL_TIMESTAMP_TZ;
639 blr_ex_time_tz:
640 Result := SQL_TIME_TZ_EX;
641 blr_ex_timestamp_tz:
642 Result := SQL_TIMESTAMP_TZ_EX;
643 blr_dec64:
644 Result := SQL_DEC16;
645 blr_dec128:
646 Result := SQL_DEC34;
647 blr_int128:
648 Result := SQL_INT128;
649 end;
650 end;
651
652 function TFBArrayMetaData.GetSQLTypeName: AnsiString;
653 begin
654 Result := TSQLDataItem.GetSQLTypeName(GetSQLType);
655 end;
656
657 function TFBArrayMetaData.GetScale: integer;
658 begin
659 Result := FArrayDesc.array_desc_scale;
660 end;
661
662 function TFBArrayMetaData.GetSize: cardinal;
663 begin
664 Result := FArrayDesc.array_desc_length;
665 end;
666
667 function TFBArrayMetaData.GetTableName: AnsiString;
668 begin
669 with FArrayDesc do
670 SetString(Result,PAnsiChar(@array_desc_relation_name),sizeof(array_desc_relation_name));
671 Result := trim(Result);
672 end;
673
674 function TFBArrayMetaData.GetColumnName: AnsiString;
675 begin
676 with FArrayDesc do
677 SetString(Result,PAnsiChar(@FArrayDesc.array_desc_field_name),sizeof(array_desc_field_name));
678 Result := trim(Result);
679 end;
680
681 function TFBArrayMetaData.GetDimensions: integer;
682 begin
683 Result := FArrayDesc.array_desc_dimensions;
684 end;
685
686 function TFBArrayMetaData.GetBounds: TArrayBounds;
687 var i: integer;
688 begin
689 SetLength(Result,GetDimensions);
690 for i := 0 to GetDimensions - 1 do
691 begin
692 Result[i].UpperBound := FArrayDesc.array_desc_bounds[i].array_bound_upper;
693 Result[i].LowerBound := FArrayDesc.array_desc_bounds[i].array_bound_lower;
694 end;
695 end;
696
697 function TFBArrayMetaData.GetDType(SQLType: cardinal): UChar;
698 begin
699 case SQLType of
700 SQL_TEXT:
701 Result := blr_text;
702 SQL_SHORT:
703 Result := blr_short;
704 SQL_LONG:
705 Result := blr_long;
706 SQL_QUAD:
707 Result := blr_quad;
708 SQL_FLOAT:
709 Result := blr_float;
710 SQL_D_FLOAT:
711 Result := blr_double;
712 SQL_TIMESTAMP:
713 Result := blr_timestamp;
714 SQL_VARYING:
715 Result := blr_varying;
716 SQL_TYPE_DATE:
717 Result := blr_sql_date;
718 SQL_TYPE_TIME:
719 Result := blr_sql_time;
720 SQL_INT64:
721 Result := blr_int64;
722 SQL_TIME_TZ:
723 Result := blr_sql_time_tz;
724 SQL_TIMESTAMP_TZ:
725 Result := blr_timestamp_tz;
726 SQL_TIME_TZ_EX:
727 Result := blr_ex_time_tz;
728 SQL_TIMESTAMP_TZ_EX:
729 Result := blr_ex_timestamp_tz;
730 SQL_DEC16:
731 Result := blr_dec64;
732 SQL_DEC34:
733 Result := blr_dec128;
734 SQL_INT128:
735 Result := blr_int128;
736 end;
737 end;
738
739 function TFBArrayMetaData.NumOfElements: integer;
740 var i: integer;
741 Bounds: TArrayBounds;
742 begin
743 Result := 1;
744 Bounds := GetBounds;
745 for i := 0 to Length(Bounds) - 1 do
746 Result := Result * (Bounds[i].UpperBound - Bounds[i].LowerBound + 1);
747 end;
748
749
750 { TFBArray }
751
752 procedure TFBArray.AllocateBuffer;
753 var i: integer;
754 l: integer;
755 Bounds: TArrayBounds;
756 Dims: integer;
757 begin
758 SetLength(FOffsets,0);
759 FreeMem(FBuffer);
760 FBuffer := nil;
761 FLoaded := false;
762
763 with FMetaData as TFBArrayMetaData do
764 begin
765 l := NumOfElements;
766 FElementSize := FArrayDesc.array_desc_length;
767 case GetSQLType of
768 SQL_VARYING:
769 FElementSize := FElementSize + 2;
770 SQL_TEXT:
771 FElementSize := FElementSize + 1;
772 end;
773 FBufSize := FElementSize * l;
774
775 with FFirebirdClientAPI do
776 IBAlloc(FBuffer,0,FBufSize);
777
778 Dims := GetDimensions;
779 SetLength(FOffsets,GetDimensions);
780 Bounds := GetBounds;
781 if FArrayDesc.array_desc_flags = 0 {row major} then
782 begin
783 FOffsets[0] := 1;
784 for i := 0 to Dims - 2 do
785 FOffsets[i+1] := FOffsets[i] * (Bounds[i].UpperBound - Bounds[i].LowerBound + 1);
786 end
787 else
788 begin
789 {column major}
790 FOffsets[Dims-1] := 1;
791 for i := Dims - 1 downto 1 do
792 FOffsets[i-1] := FOffsets[i] * (Bounds[i].UpperBound - Bounds[i].LowerBound + 1);
793 end;
794 end;
795 end;
796
797 procedure TFBArray.Changing;
798 var i: integer;
799 begin
800 for i := 0 to Length(FEventHandlers) - 1 do
801 FEventHandlers[i](self,arChanging);
802 end;
803
804 procedure TFBArray.Changed;
805 var i: integer;
806 begin
807 FModified := true;
808 for i := 0 to Length(FEventHandlers) - 1 do
809 FEventHandlers[i](self,arChanged);
810 end;
811
812 procedure TFBArray.GetArraySlice;
813 begin
814 if FIsNew or FLoaded then Exit;
815 InternalGetSlice;
816 FLoaded := true;
817 end;
818
819 procedure TFBArray.PutArraySlice(Force: boolean);
820 begin
821 if not FModified or not FTransactionIntf.InTransaction or
822 (FTransactionSeqNo < (FTransactionIntf as TFBTransaction).TransactionSeqNo) then Exit;
823
824 InternalPutSlice(Force);
825 FModified := false;
826 FIsNew := false;
827 FLoaded := true;
828 end;
829
830 function TFBArray.GetOffset(index: array of integer): PByte;
831 var i: integer;
832 Bounds: TArrayBounds;
833 FlatIndex: integer;
834 begin
835 if FMetaData.GetDimensions <> Length(index) then
836 IBError(ibxeInvalidArrayDimensions,[Length(index)]);
837
838 FlatIndex := 0;
839 Bounds := FMetaData.GetBounds;
840 for i := 0 to Length(index) - 1 do
841 begin
842 if (index[i] < Bounds[i].LowerBound) or (index[i] > Bounds[i].UpperBound) then
843 IBError(ibxeInvalidSubscript,[index[i],i]);
844
845 FlatIndex := FlatIndex + FOffsets[i]*(index[i] - Bounds[i].LowerBound);
846 end;
847 Result := FBuffer + FlatIndex*FElementSize;
848 end;
849
850 function TFBArray.GetDataLength: short;
851 begin
852 Result := FElementSize;
853 end;
854
855 function TFBArray.GetArrayDesc: PISC_ARRAY_DESC;
856 begin
857 Result := @((FMetaData as TFBArrayMetaData).FArrayDesc);
858 end;
859
860 constructor TFBArray.Create(aAttachment: IAttachment; aTransaction: TFBTransaction; aField: IArrayMetaData);
861 begin
862 inherited Create(aTransaction);
863 FMetaData := aField;
864 FAttachment := aAttachment;
865 FFirebirdClientAPI := aTransaction.FirebirdAPI;
866 FTransactionIntf := aTransaction;
867 FTransactionSeqNo := aTransaction.TransactionSeqNo;
868 FIsNew := true;
869 FModified := false;
870 FSQLDialect := aAttachment.GetSQLDialect;
871 AllocateBuffer;
872 FElement := TFBArrayElement.Create(self,FBuffer);
873 FElementIntf := FElement;
874 FConnectionCodePage := aAttachment.GetCodePage;
875 Setlength(FEventHandlers,0);
876 end;
877
878 constructor TFBArray.Create(aAttachment: IAttachment; aTransaction: TFBTransaction;
879 aField: IArrayMetaData; ArrayID: TISC_QUAD);
880 begin
881 inherited Create(aTransaction);
882 FMetaData := aField;
883 FArrayID := ArrayID;
884 FAttachment := aAttachment;
885 FFirebirdClientAPI := aTransaction.FirebirdAPI;
886 FTransactionIntf := aTransaction;
887 FTransactionSeqNo := aTransaction.TransactionSeqNo;
888 FIsNew := false;
889 FModified := false;
890 FSQLDialect := aAttachment.GetSQLDialect;
891 AllocateBuffer;
892 FElement := TFBArrayElement.Create(self,FBuffer);
893 FElementIntf := FElement;
894 FConnectionCodePage := aAttachment.GetCodePage;
895 Setlength(FEventHandlers,0);
896 end;
897
898 destructor TFBArray.Destroy;
899 begin
900 FreeMem(FBuffer);
901 inherited Destroy;
902 end;
903
904 function TFBArray.GetArrayID: TISC_QUAD;
905 begin
906 PutArraySlice;
907 Result := FArrayID;
908 end;
909
910 procedure TFBArray.Clear;
911 begin
912 FIsNew := true;
913 FModified := false;
914 FArrayID.gds_quad_high := 0;
915 FArrayID.gds_quad_low := 0;
916 AllocateBuffer;
917 end;
918
919 function TFBArray.IsEmpty: boolean;
920 begin
921 Result := FIsNew and not FModified;
922 end;
923
924 procedure TFBArray.PreLoad;
925 begin
926 GetArraySlice;
927 end;
928
929 procedure TFBArray.CancelChanges;
930 begin
931 FModified := false;
932 AllocateBuffer;
933 end;
934
935 procedure TFBArray.SaveChanges;
936 begin
937 PutArraySlice;
938 end;
939
940 function TFBArray.GetSQLDialect: integer;
941 begin
942 Result := FSQLDialect;
943 end;
944
945 procedure TFBArray.TransactionEnding(aTransaction: ITransaction; Force: boolean
946 );
947 begin
948 if ((aTransaction as TObject) = (FTransactionIntf as TObject)) and FModified and not FIsNew then
949 PutArraySlice(Force);
950 end;
951
952 function TFBArray.GetSQLType: cardinal;
953 begin
954 Result := FMetaData.GetSQLType;
955 end;
956
957 function TFBArray.GetSQLTypeName: AnsiString;
958 begin
959 Result := FMetaData.GetSQLTypeName;
960 end;
961
962 function TFBArray.GetScale: integer;
963 begin
964 Result := FMetaData.GetScale;
965 end;
966
967 function TFBArray.GetSize: cardinal;
968 begin
969 Result := FMetaData.GetSize;
970 end;
971
972 function TFBArray.GetCharSetID: cardinal;
973 begin
974 Result := FMetaData.GetCharSetID;
975 end;
976
977 function TFBArray.GetCharSetWidth: integer;
978 begin
979 Result := FMetaData.GetCharSetWidth;
980 end;
981
982 function TFBArray.GetTableName: AnsiString;
983 begin
984 Result := FMetaData.GetTableName;
985 end;
986
987 function TFBArray.GetColumnName: AnsiString;
988 begin
989 Result := FMetaData.GetColumnName;
990 end;
991
992 function TFBArray.GetDimensions: integer;
993 begin
994 Result := FMetaData.GetDimensions;
995 end;
996
997 function TFBArray.GetBounds: TArrayBounds;
998 begin
999 Result := FMetaData.GetBounds;
1000 end;
1001
1002 function TFBArray.GetAsInteger(index: array of integer): integer;
1003 begin
1004 GetArraySlice;
1005 FElement.FBufPtr := GetOffset(index);
1006 Result := FElement.GetAsLong;
1007 end;
1008
1009 function TFBArray.GetAsBoolean(index: array of integer): boolean;
1010 begin
1011 GetArraySlice;
1012 FElement.FBufPtr := GetOffset(index);
1013 Result := FElement.GetAsBoolean;
1014 end;
1015
1016 function TFBArray.GetAsCurrency(index: array of integer): Currency;
1017 begin
1018 GetArraySlice;
1019 FElement.FBufPtr := GetOffset(index);
1020 Result := FElement.GetAsCurrency;
1021 end;
1022
1023 function TFBArray.GetAsInt64(index: array of integer): Int64;
1024 begin
1025 GetArraySlice;
1026 FElement.FBufPtr := GetOffset(index);
1027 Result := FElement.GetAsInt64;
1028 end;
1029
1030 function TFBArray.GetAsDateTime(index: array of integer): TDateTime;
1031 begin
1032 GetArraySlice;
1033 FElement.FBufPtr := GetOffset(index);
1034 Result := FElement.GetAsDateTime;
1035 end;
1036
1037 procedure TFBArray.GetAsDateTime(index: array of integer;
1038 var aDateTime: TDateTime; var dstOffset: smallint;
1039 var aTimezoneID: TFBTimeZoneID);
1040 begin
1041 GetArraySlice;
1042 FElement.FBufPtr := GetOffset(index);
1043 FElement.GetAsDateTime(aDateTime,dstOffset,aTimezoneID);
1044 end;
1045
1046 procedure TFBArray.GetAsDateTime(index: array of integer;
1047 var aDateTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString);
1048 begin
1049 GetArraySlice;
1050 FElement.FBufPtr := GetOffset(index);
1051 FElement.GetAsDateTime(aDateTime,dstOffset,aTimezone);
1052 end;
1053
1054 procedure TFBArray.GetAsTime(index: array of integer; var aTime: TDateTime;
1055 var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID; OnDate: TDateTime);
1056 begin
1057 GetArraySlice;
1058 FElement.FBufPtr := GetOffset(index);
1059 FElement.GetAsTime(aTime,dstOffset,aTimezoneID,OnDate);
1060 end;
1061
1062 procedure TFBArray.GetAsTime(index: array of integer; var aTime: TDateTime;
1063 var dstOffset: smallint; var aTimezone: AnsiString; OnDate: TDateTime);
1064 begin
1065 GetArraySlice;
1066 FElement.FBufPtr := GetOffset(index);
1067 FElement.GetAsTime(aTime,dstOffset,aTimezone,OnDate);
1068 end;
1069
1070 function TFBArray.GetAsUTCDateTime(index: array of integer): TDateTime;
1071 begin
1072 GetArraySlice;
1073 FElement.FBufPtr := GetOffset(index);
1074 Result := FElement.GetAsUTCDateTime;
1075 end;
1076
1077 function TFBArray.GetAsDouble(index: array of integer): Double;
1078 begin
1079 GetArraySlice;
1080 FElement.FBufPtr := GetOffset(index);
1081 Result := FElement.GetAsDouble;
1082 end;
1083
1084 function TFBArray.GetAsFloat(index: array of integer): Float;
1085 begin
1086 GetArraySlice;
1087 FElement.FBufPtr := GetOffset(index);
1088 Result := FElement.GetAsFloat;
1089 end;
1090
1091 function TFBArray.GetAsLong(index: array of integer): Long;
1092 begin
1093 GetArraySlice;
1094 FElement.FBufPtr := GetOffset(index);
1095 Result := FElement.GetAsLong;
1096 end;
1097
1098 function TFBArray.GetAsShort(index: array of integer): Short;
1099 begin
1100 GetArraySlice;
1101 FElement.FBufPtr := GetOffset(index);
1102 Result := FElement.GetAsShort;
1103 end;
1104
1105 function TFBArray.GetAsString(index: array of integer): AnsiString;
1106 begin
1107 GetArraySlice;
1108 FElement.FBufPtr := GetOffset(index);
1109 Result := FElement.GetAsString;
1110 end;
1111
1112 function TFBArray.GetAsVariant(index: array of integer): Variant;
1113 begin
1114 GetArraySlice;
1115 FElement.FBufPtr := GetOffset(index);
1116 Result := FElement.GetAsVariant;
1117 end;
1118
1119 function TFBArray.GetAsBCD(index: array of integer): tBCD;
1120 begin
1121 GetArraySlice;
1122 FElement.FBufPtr := GetOffset(index);
1123 Result := FElement.GetAsBCD;
1124 end;
1125
1126 procedure TFBArray.SetAsInteger(index: array of integer; AValue: integer);
1127 begin
1128 FElement.FBufPtr := GetOffset(index);
1129 FElement.SetAsLong(AValue);
1130 end;
1131
1132 procedure TFBArray.SetAsBoolean(index: array of integer; AValue: boolean);
1133 begin
1134 FElement.FBufPtr := GetOffset(index);
1135 FElement.SetAsBoolean(AValue);
1136 end;
1137
1138 procedure TFBArray.SetAsCurrency(index: array of integer; Value: Currency);
1139 begin
1140 FElement.FBufPtr := GetOffset(index);
1141 FElement.SetAsCurrency(Value);
1142 end;
1143
1144 procedure TFBArray.SetAsInt64(index: array of integer; Value: Int64);
1145 begin
1146 FElement.FBufPtr := GetOffset(index);
1147 FElement.SetAsInt64(Value);
1148 end;
1149
1150 procedure TFBArray.SetAsDate(index: array of integer; Value: TDateTime);
1151 begin
1152 FElement.FBufPtr := GetOffset(index);
1153 FElement.SetAsDate(Value);
1154 end;
1155
1156 procedure TFBArray.SetAsLong(index: array of integer; Value: Long);
1157 begin
1158 FElement.FBufPtr := GetOffset(index);
1159 FElement.SetAsLong(Value);
1160 end;
1161
1162 procedure TFBArray.SetAsTime(index: array of integer; Value: TDateTime);
1163 begin
1164 FElement.FBufPtr := GetOffset(index);
1165 FElement.SetAsTime(Value);
1166 end;
1167
1168 procedure TFBArray.SetAsTime(index: array of integer; aValue: TDateTime; OnDate: TDateTime;
1169 aTimeZoneID: TFBTimeZoneID);
1170 begin
1171 FElement.FBufPtr := GetOffset(index);
1172 FElement.SetAsTime(aValue,OnDate,aTimeZoneID);
1173 end;
1174
1175 procedure TFBArray.SetAsTime(index: array of integer; aValue: TDateTime; OnDate: TDateTime;
1176 aTimeZone: AnsiString);
1177 begin
1178 FElement.FBufPtr := GetOffset(index);
1179 FElement.SetAsTime(aValue,OnDate, aTimeZone);
1180 end;
1181
1182 procedure TFBArray.SetAsDateTime(index: array of integer; Value: TDateTime);
1183 begin
1184 FElement.FBufPtr := GetOffset(index);
1185 FElement.SetAsDateTime(Value);
1186 end;
1187
1188 procedure TFBArray.SetAsDateTime(index: array of integer; aValue: TDateTime;
1189 aTimeZoneID: TFBTimeZoneID);
1190 begin
1191 FElement.FBufPtr := GetOffset(index);
1192 FElement.SetAsDateTime(aValue,aTimeZoneID);
1193 end;
1194
1195 procedure TFBArray.SetAsDateTime(index: array of integer; aValue: TDateTime;
1196 aTimeZone: AnsiString);
1197 begin
1198 FElement.FBufPtr := GetOffset(index);
1199 FElement.SetAsDateTime(aValue,aTimeZone);
1200 end;
1201
1202 procedure TFBArray.SetAsUTCDateTime(index: array of integer;
1203 aUTCTime: TDateTime);
1204 begin
1205 FElement.FBufPtr := GetOffset(index);
1206 FElement.SetAsUTCDateTime(aUTCTime);
1207 end;
1208
1209 procedure TFBArray.SetAsDouble(index: array of integer; Value: Double);
1210 begin
1211 FElement.FBufPtr := GetOffset(index);
1212 FElement.SetAsDouble(Value);
1213 end;
1214
1215 procedure TFBArray.SetAsFloat(index: array of integer; Value: Float);
1216 begin
1217 FElement.FBufPtr := GetOffset(index);
1218 FElement.SetAsFloat(Value);
1219 end;
1220
1221 procedure TFBArray.SetAsShort(index: array of integer; Value: Short);
1222 begin
1223 FElement.FBufPtr := GetOffset(index);
1224 FElement.SetAsShort(Value);
1225 end;
1226
1227 procedure TFBArray.SetAsString(index: array of integer; Value: AnsiString);
1228 begin
1229 FElement.FBufPtr := GetOffset(index);
1230 FElement.SetAsString(Value);
1231 end;
1232
1233 procedure TFBArray.SetAsVariant(index: array of integer; Value: Variant);
1234 begin
1235 FElement.FBufPtr := GetOffset(index);
1236 FElement.SetAsVariant(Value);
1237 end;
1238
1239 procedure TFBArray.SetAsBcd(index: array of integer; aValue: tBCD);
1240 begin
1241 FElement.FBufPtr := GetOffset(index);
1242 FElement.SetAsBcd(aValue);
1243 end;
1244
1245 procedure TFBArray.SetBounds(dim, UpperBound, LowerBound: integer);
1246 begin
1247 with (FMetaData as TFBArrayMetaData) do
1248 begin
1249 if (dim < 0) or (dim > GetDimensions) then
1250 IBError(ibxeInvalidArrayDimensions,[dim]);
1251
1252 if (UpperBound > FArrayDesc.array_desc_bounds[dim].array_bound_upper) or
1253 (LowerBound < FArrayDesc.array_desc_bounds[dim].array_bound_lower) or
1254 (UpperBound < FArrayDesc.array_desc_bounds[dim].array_bound_lower) or
1255 (LowerBound > FArrayDesc.array_desc_bounds[dim].array_bound_upper) then
1256 IBError(ibxArrayBoundsCantIncrease,[nil]);
1257
1258 PutArraySlice; {Save any changes}
1259
1260 FArrayDesc.array_desc_bounds[dim].array_bound_upper := UpperBound;
1261 FArrayDesc.array_desc_bounds[dim].array_bound_lower := LowerBound;
1262 end;
1263 AllocateBuffer;
1264 end;
1265
1266 function TFBArray.GetAttachment: IAttachment;
1267 begin
1268 Result := FAttachment;
1269 end;
1270
1271 function TFBArray.GetTransaction: ITransaction;
1272 begin
1273 Result := FTransactionIntf;
1274 end;
1275
1276 procedure TFBArray.AddEventHandler(Handler: TArrayEventHandler);
1277 begin
1278 SetLength(FEventHandlers,Length(FEventHandlers)+1);
1279 FEventHandlers[Length(FEventHandlers)-1] := Handler;
1280 end;
1281
1282 procedure TFBArray.RemoveEventHandler(Handler: TArrayEventHandler);
1283 var i,j : integer;
1284 begin
1285 for i := Length(FEventHandlers) - 1 downto 0 do
1286 if (TMethod(FEventHandlers[i]).Code = TMethod(Handler).Code) and
1287 (TMethod(FEventHandlers[i]).Data = TMethod(Handler).Data) then
1288 begin
1289 for j := i to Length(FEventHandlers) - 2 do
1290 FEventHandlers[i] := FEventHandlers[i+1];
1291 SetLength(FEventHandlers,Length(FEventHandlers) - 1);
1292 end;
1293 end;
1294
1295 end.
1296

Properties

Name Value
svn:eol-style native