ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBSQLData.pas
(Generate patch)

Comparing:
ibx/trunk/fbintf/client/FBSQLData.pas (file contents), Revision 315 by tony, Thu Feb 25 11:56:36 2021 UTC vs.
ibx/branches/udr/client/FBSQLData.pas (file contents), Revision 391 by tony, Thu Jan 27 16:34:24 2022 UTC

# Line 122 | Line 122 | type
122    private
123       FFirebirdClientAPI: TFBClientAPI;
124       FTimeZoneServices: IExTimeZoneServices;
125     function AdjustScale(Value: Int64; aScale: Integer): Double;
126     function AdjustScaleToInt64(Value: Int64; aScale: Integer): Int64;
127     function AdjustScaleToCurrency(Value: Int64; aScale: Integer): Currency;
125       function GetDateFormatStr(IncludeTime: boolean): AnsiString;
126       function GetTimeFormatStr: AnsiString;
127       function GetTimestampFormatStr: AnsiString;
# Line 132 | Line 129 | type
129       procedure InternalGetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint;
130         var aTimezone: AnsiString; var aTimeZoneID: TFBTimeZoneID);
131    protected
135     function AdjustScaleFromCurrency(Value: Currency; aScale: Integer): Int64;
136     function AdjustScaleFromDouble(Value: Double; aScale: Integer): Int64;
132       procedure CheckActive; virtual;
133       procedure CheckTZSupport;
134       function GetAttachment: IAttachment; virtual; abstract;
135 +     function GetTransaction: ITransaction; virtual; abstract;
136       function GetSQLDialect: integer; virtual; abstract;
137       function GetTimeZoneServices: IExTimeZoneServices; virtual;
138       procedure Changed; virtual;
# Line 154 | Line 150 | type
150       property FirebirdClientAPI: TFBClientAPI read FFirebirdClientAPI;
151    public
152       constructor Create(api: TFBClientAPI);
153 <     function GetSQLType: cardinal; virtual; abstract;
153 >     function CanChangeMetaData: boolean; virtual;
154 >     function GetSQLType: cardinal; virtual; abstract; {Current Field Data SQL Type}
155       function GetSQLTypeName: AnsiString; overload;
156 <     class function GetSQLTypeName(SQLType: short): AnsiString; overload;
156 >     class function GetSQLTypeName(SQLType: cardinal): AnsiString; overload;
157       function GetStrDataLength: short;
158 +     function getColMetadata: IParamMetaData; virtual; abstract;
159       function GetName: AnsiString; virtual; abstract;
160 <     function GetScale: integer; virtual; abstract;
160 >     function GetScale: integer; virtual; abstract; {Current Field Data scale}
161       function GetAsBoolean: boolean;
162       function GetAsCurrency: Currency;
163       function GetAsInt64: Int64;
# Line 178 | Line 176 | type
176       function GetAsQuad: TISC_QUAD;
177       function GetAsShort: short;
178       function GetAsString: AnsiString; virtual;
179 +     function GetAsNumeric: IFBNumeric;
180       function GetIsNull: Boolean; virtual;
181       function GetIsNullable: boolean; virtual;
182       function GetAsVariant: Variant;
# Line 205 | Line 204 | type
204       procedure SetAsShort(Value: short); virtual;
205       procedure SetAsString(Value: AnsiString); virtual;
206       procedure SetAsVariant(Value: Variant);
207 <     procedure SetAsNumeric(Value: Int64; aScale: integer);
207 >     procedure SetAsNumeric(Value: IFBNumeric); virtual;
208       procedure SetAsBcd(aValue: tBCD); virtual;
209       procedure SetIsNull(Value: Boolean); virtual;
210       procedure SetIsNullable(Value: Boolean); virtual;
# Line 247 | Line 246 | type
246      FUniqueRelationName: AnsiString;
247      FColumnList: array of TSQLVarData;
248      function GetStatement: IStatement; virtual; abstract;
249 +    function GetAttachment: IAttachment; virtual;
250 +    function GetTransaction: ITransaction; virtual;
251      function GetPrepareSeqNo: integer; virtual; abstract;
252      function GetTransactionSeqNo: integer; virtual; abstract;
253      procedure SetCount(aValue: integer); virtual; abstract;
# Line 265 | Line 266 | type
266      function StateChanged(var ChangeSeqNo: integer): boolean; virtual; abstract;
267      property CaseSensitiveParams: boolean read FCaseSensitiveParams
268                                              write FCaseSensitiveParams; {Only used when IsInputDataArea true}
269 +    function CanChangeMetaData: boolean; virtual; abstract;
270      property Count: integer read GetCount;
271 <    property Column[index: integer]: TSQLVarData read GetColumn;
271 >    property Column[index: integer]: TSQLVarData read GetColumn; default;
272      property UniqueRelationName: AnsiString read FUniqueRelationName;
273      property Statement: IStatement read GetStatement;
274 +    property Attachment: IAttachment read GetAttachment;
275      property PrepareSeqNo: integer read GetPrepareSeqNo;
276 +    property Transaction: ITransaction read GetTransaction;
277      property TransactionSeqNo: integer read GetTransactionSeqNo;
278    end;
279  
# Line 283 | Line 287 | type
287      FModified: boolean;
288      FUniqueName: boolean;
289      FVarString: RawByteString;
290 +    FColMetaData: IParamMetaData;
291      function GetStatement: IStatement;
292      procedure SetName(AValue: AnsiString);
293    protected
294 +    FArrayIntf: IArray;
295 +    function GetAttachment: IAttachment;
296 +    function GetTransaction: ITransaction;
297      function GetSQLType: cardinal; virtual; abstract;
298      function GetSubtype: integer; virtual; abstract;
299      function GetAliasName: AnsiString;  virtual; abstract;
# Line 294 | Line 302 | type
302      function GetRelationName: AnsiString;  virtual; abstract;
303      function GetScale: integer; virtual; abstract;
304      function GetCharSetID: cardinal; virtual; abstract;
305 <    function GetCharSetWidth: integer; virtual; abstract;
306 <    function GetCodePage: TSystemCodePage; virtual; abstract;
305 >    function GetCharSetWidth: integer;
306 >    function GetCodePage: TSystemCodePage;
307      function GetIsNull: Boolean;   virtual; abstract;
308      function GetIsNullable: boolean; virtual; abstract;
309      function GetSQLData: PByte;  virtual; abstract;
310      function GetDataLength: cardinal; virtual; abstract; {current field length}
311      function GetSize: cardinal; virtual; abstract; {field length as given by metadata}
312 +    function GetDefaultTextSQLType: cardinal; virtual; abstract;
313 +    procedure InternalSetSQLType(aValue: cardinal); virtual; abstract;
314 +    procedure InternalSetScale(aValue: integer); virtual; abstract;
315 +    procedure InternalSetDataLength(len: cardinal); virtual; abstract;
316      procedure SetIsNull(Value: Boolean); virtual; abstract;
317      procedure SetIsNullable(Value: Boolean);  virtual; abstract;
318      procedure SetSQLData(AValue: PByte; len: cardinal); virtual; abstract;
319 <    procedure SetScale(aValue: integer); virtual; abstract;
320 <    procedure SetDataLength(len: cardinal); virtual; abstract;
321 <    procedure SetSQLType(aValue: cardinal); virtual; abstract;
319 >    procedure SetScale(aValue: integer);
320 >    procedure SetDataLength(len: cardinal);
321 >    procedure SetSQLType(aValue: cardinal);
322      procedure SetCharSetID(aValue: cardinal); virtual; abstract;
323 +    procedure SetMetaSize(aValue: cardinal); virtual;
324    public
325      constructor Create(aParent: TSQLDataArea; aIndex: integer);
326 +    function CanChangeMetaData: boolean;
327      procedure SetString(aValue: AnsiString);
328      procedure Changed; virtual;
329      procedure RowChange; virtual;
330 <    function GetAsArray(Array_ID: TISC_QUAD): IArray; virtual; abstract;
330 >    function GetAsArray: IArray; virtual; abstract;
331      function GetAsBlob(Blob_ID: TISC_QUAD; BPB: IBPB): IBlob; virtual; abstract;
332      function CreateBlob: IBlob; virtual; abstract;
333      function GetArrayMetaData: IArrayMetaData; virtual; abstract;
334      function GetBlobMetaData: IBlobMetaData; virtual; abstract;
335 +    function getColMetadata: IParamMetaData;
336      procedure Initialize; virtual;
337 +    procedure SaveMetaData;
338 +    procedure SetArray(AValue: IArray);
339  
340    public
341      property AliasName: AnsiString read GetAliasName;
# Line 329 | Line 346 | type
346      property Index: integer read FIndex;
347      property Name: AnsiString read FName write SetName;
348      property CharSetID: cardinal read GetCharSetID write SetCharSetID;
349 +    property CodePage: TSystemCodePage read GetCodePage;
350      property SQLType: cardinal read GetSQLType write SetSQLType;
351      property SQLSubtype: integer read GetSubtype;
352      property SQLData: PByte read GetSQLData;
# Line 344 | Line 362 | type
362  
363    { TColumnMetaData }
364  
365 <  TColumnMetaData = class(TSQLDataItem,IColumnMetaData)
365 >  TColumnMetaData = class(TSQLDataItem,IColumnMetaData,IParamMetaData)
366    private
367      FIBXSQLVAR: TSQLVarData;
368      FOwner: IUnknown;         {Keep reference to ensure Metadata/statement not discarded}
# Line 352 | Line 370 | type
370      FChangeSeqNo: integer;
371    protected
372      procedure CheckActive; override;
355    function GetAttachment: IAttachment; override;
373      function SQLData: PByte; override;
374      function GetDataLength: cardinal; override;
375      function GetCodePage: TSystemCodePage; override;
# Line 361 | Line 378 | type
378      constructor Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
379      destructor Destroy; override;
380      function GetSQLDialect: integer; override;
381 +    function getColMetadata: IParamMetaData; override;
382  
383    public
384      {IColumnMetaData}
# Line 380 | Line 398 | type
398      function GetArrayMetaData: IArrayMetaData;
399      function GetBlobMetaData: IBlobMetaData;
400      function GetStatement: IStatement;
401 <    function GetTransaction: ITransaction; virtual;
401 >    function GetTransaction: ITransaction; override;
402 >    function GetAttachment: IAttachment; override;
403      property Name: AnsiString read GetName;
404      property Size: cardinal read GetSize;
405      property CharSetID: cardinal read getCharSetID;
# Line 393 | Line 412 | type
412    { TIBSQLData }
413  
414    TIBSQLData = class(TColumnMetaData,ISQLData)
396  private
397    FTransaction: ITransaction;
415    protected
416      procedure CheckActive; override;
417    public
401    function GetTransaction: ITransaction; override;
418      function GetIsNull: Boolean; override;
419      function GetAsArray: IArray;
420      function GetAsBlob: IBlob; overload;
# Line 407 | Line 423 | type
423      property AsBlob: IBlob read GetAsBlob;
424   end;
425  
426 +  { TSQLParamMetaData }
427 +
428 +  TSQLParamMetaData = class(TFBInterfacedObject,IParamMetaData)
429 +  private
430 +    FSQLType: cardinal;
431 +    FSQLSubType: integer;
432 +    FScale: integer;
433 +    FCharSetID: cardinal;
434 +    FNullable: boolean;
435 +    FSize: cardinal;
436 +    FCodePage: TSystemCodePage;
437 +  public
438 +    constructor Create(src: TSQLVarData);
439 +    {IParamMetaData}
440 +    function GetSQLType: cardinal;
441 +    function GetSQLTypeName: AnsiString;
442 +    function getSubtype: integer;
443 +    function getScale: integer;
444 +    function getCharSetID: cardinal;
445 +    function getCodePage: TSystemCodePage;
446 +    function getIsNullable: boolean;
447 +    function GetSize: cardinal;
448 +    property SQLType: cardinal read GetSQLType;
449 +  end;
450 +
451    { TSQLParam }
452  
453    TSQLParam = class(TIBSQLData,ISQLParam,ISQLData)
# Line 419 | Line 460 | type
460      procedure SetSQLType(aValue: cardinal); override;
461    public
462      procedure Clear;
463 +    function CanChangeMetaData: boolean; override;
464 +    function getColMetadata: IParamMetaData; override;
465      function GetModified: boolean; override;
466      function GetAsPointer: Pointer;
467 +    function GetAsString: AnsiString; override;
468      procedure SetName(Value: AnsiString); override;
469      procedure SetIsNull(Value: Boolean);  override;
470      procedure SetIsNullable(Value: Boolean); override;
# Line 450 | Line 494 | type
494      procedure SetAsQuad(AValue: TISC_QUAD);
495      procedure SetCharSetID(aValue: cardinal);
496      procedure SetAsBcd(aValue: tBCD);
497 +    procedure SetAsNumeric(aValue: IFBNumeric);
498  
499      property AsBlob: IBlob read GetAsBlob write SetAsBlob;
500      property IsNullable: Boolean read GetIsNullable write SetIsNullable;
# Line 490 | Line 535 | type
535      {ISQLParams}
536      function getCount: integer;
537      function getSQLParam(index: integer): ISQLParam;
538 <    function ByName(Idx: AnsiString): ISQLParam ;
538 >    function ParamExists(Idx: AnsiString): boolean;
539 >    function ByName(Idx: AnsiString): ISQLParam ; virtual;
540      function GetModified: Boolean;
541      function GetHasCaseSensitiveParams: Boolean;
542 +    function GetStatement: IStatement;
543 +    function GetTransaction: ITransaction;
544 +    function GetAttachment: IAttachment;
545 +    procedure Clear;
546    end;
547  
548    { TResults }
# Line 511 | Line 561 | type
561       constructor Create(aResults: TSQLDataArea);
562        {IResults}
563       function getCount: integer;
564 <     function ByName(Idx: AnsiString): ISQLData;
564 >     function ByName(Idx: AnsiString): ISQLData; virtual;
565 >     function FieldExists(Idx: AnsiString): boolean;
566       function getSQLData(index: integer): ISQLData;
567       procedure GetData(index: integer; var IsNull:boolean; var len: short; var data: PByte);
568       function GetStatement: IStatement;
569 <     function GetTransaction: ITransaction; virtual;
569 >     function GetTransaction: ITransaction;
570 >     function GetAttachment: IAttachment;
571       procedure SetRetainInterfaces(aValue: boolean);
572   end;
573  
574   implementation
575  
576 < uses FBMessages, variants, IBUtils, FBTransaction, DateUtils;
576 > uses FBMessages, variants, IBUtils, FBTransaction, FBNumeric, DateUtils;
577 >
578 > { TSQLParamMetaData }
579 >
580 > constructor TSQLParamMetaData.Create(src: TSQLVarData);
581 > begin
582 >  inherited Create;
583 >  FSQLType := src.GetSQLType;
584 >  FSQLSubType := src.getSubtype;
585 >  FScale := src.GetScale;
586 >  FCharSetID := src.getCharSetID;
587 >  FNullable := src.GetIsNullable;
588 >  FSize := src.GetSize;
589 >  FCodePage := src.GetCodePage;
590 > end;
591 >
592 > function TSQLParamMetaData.GetSQLType: cardinal;
593 > begin
594 >  Result := FSQLType;
595 > end;
596 >
597 > function TSQLParamMetaData.GetSQLTypeName: AnsiString;
598 > begin
599 >  Result := TSQLDataItem.GetSQLTypeName(FSQLType);
600 > end;
601 >
602 > function TSQLParamMetaData.getSubtype: integer;
603 > begin
604 >  Result := FSQLSubType;
605 > end;
606 >
607 > function TSQLParamMetaData.getScale: integer;
608 > begin
609 >  Result := FScale;
610 > end;
611 >
612 > function TSQLParamMetaData.getCharSetID: cardinal;
613 > begin
614 >  Result := FCharSetID;
615 > end;
616 >
617 > function TSQLParamMetaData.getCodePage: TSystemCodePage;
618 > begin
619 >  Result :=  FCodePage;
620 > end;
621 >
622 > function TSQLParamMetaData.getIsNullable: boolean;
623 > begin
624 >  Result :=  FNullable;
625 > end;
626 >
627 > function TSQLParamMetaData.GetSize: cardinal;
628 > begin
629 >  Result := FSize;
630 > end;
631  
632   { TSQLDataArea }
633  
# Line 537 | Line 643 | begin
643    Result := Length(FColumnList);
644   end;
645  
646 + function TSQLDataArea.GetTransaction: ITransaction;
647 + begin
648 +  Result := GetStatement.GetTransaction;
649 + end;
650 +
651 + function TSQLDataArea.GetAttachment: IAttachment;
652 + begin
653 +  Result := GetStatement.GetAttachment;
654 + end;
655 +
656   procedure TSQLDataArea.SetUniqueRelationName;
657   var
658    i: Integer;
# Line 669 | Line 785 | begin
785      FName := AValue;
786   end;
787  
788 + function TSQLVarData.GetAttachment: IAttachment;
789 + begin
790 +  Result := Parent.Attachment;
791 + end;
792 +
793 + function TSQLVarData.GetTransaction: ITransaction;
794 + begin
795 +  Result := Parent.Transaction;
796 + end;
797 +
798 + function TSQLVarData.GetCharSetWidth: integer;
799 + begin
800 +  result := 1;
801 +  GetAttachment.CharSetWidth(GetCharSetID,result);
802 + end;
803 +
804 + function TSQLVarData.GetCodePage: TSystemCodePage;
805 + begin
806 +  result := CP_NONE;
807 +  GetAttachment.CharSetID2CodePage(GetCharSetID,result);
808 + end;
809 +
810 + procedure TSQLVarData.SetScale(aValue: integer);
811 + begin
812 +  if aValue = Scale then
813 +    Exit;
814 +  if not CanChangeMetaData  then
815 +    IBError(ibxeScaleCannotBeChanged,[]);
816 +  InternalSetScale(aValue);
817 + end;
818 +
819 + procedure TSQLVarData.SetDataLength(len: cardinal);
820 + begin
821 +  if len = DataLength then
822 +    Exit;
823 +  InternalSetDataLength(len);
824 + end;
825 +
826 + procedure TSQLVarData.SetSQLType(aValue: cardinal);
827 + begin
828 +  if aValue = SQLType then
829 +    Exit;
830 +  if not CanChangeMetaData then
831 +    IBError(ibxeSQLTypeUnchangeable,[TSQLDataItem.GetSQLTypeName(SQLType),
832 +                                          TSQLDataItem.GetSQLTypeName(aValue)]);
833 +  InternalSetSQLType(aValue);
834 + end;
835 +
836 + procedure TSQLVarData.SetMetaSize(aValue: cardinal);
837 + begin
838 +  //Ignore
839 + end;
840 +
841 + procedure TSQLVarData.SaveMetaData;
842 + begin
843 +  FColMetaData := TSQLParamMetaData.Create(self);
844 + end;
845 +
846 + procedure TSQLVarData.SetArray(AValue: IArray);
847 + begin
848 +  FArrayIntf := AValue;
849 + end;
850 +
851   constructor TSQLVarData.Create(aParent: TSQLDataArea; aIndex: integer);
852   begin
853    inherited Create;
# Line 677 | Line 856 | begin
856    FUniqueName := true;
857   end;
858  
859 + function TSQLVarData.CanChangeMetaData: boolean;
860 + begin
861 +  Result := Parent.CanChangeMetaData;
862 + end;
863 +
864   procedure TSQLVarData.SetString(aValue: AnsiString);
865   begin
866    {we take full advantage here of reference counted strings. When setting a string
# Line 685 | Line 869 | begin
869     a zero byte when the string is empty, neatly avoiding a nil pointer error.}
870  
871    FVarString := aValue;
872 <  SQLType := SQL_TEXT;
872 >  if SQLType = SQL_BLOB then
873 >    SetMetaSize(GetAttachment.GetInlineBlobLimit);
874 >  if CanChangeMetaData then
875 >    SQLType := GetDefaultTextSQLType;
876    Scale := 0;
877 +  if  (SQLType <> SQL_VARYING) and (SQLType <> SQL_TEXT) then
878 +    IBError(ibxeUnableTosetaTextType,[Index,Name,TSQLDataItem.GetSQLTypeName(SQLType)]);
879 +  if not CanChangeMetaData and (Length(aValue) > GetSize) then
880 +    IBError(ibxeStringOverflow,[Length(aValue),DataLength]);
881    SetSQLData(PByte(PAnsiChar(FVarString)),Length(aValue));
882   end;
883  
# Line 697 | Line 888 | end;
888  
889   procedure TSQLVarData.RowChange;
890   begin
891 +  FArrayIntf := nil;
892    FModified := false;
893    FVarString := '';
894   end;
895  
896 + function TSQLVarData.getColMetadata: IParamMetaData;
897 + begin
898 +  Result := FColMetaData;
899 + end;
900 +
901   procedure TSQLVarData.Initialize;
902  
903    function FindVarByName(idx: AnsiString; limit: integer): TSQLVarData;
# Line 760 | Line 957 | end;
957  
958   {TSQLDataItem}
959  
763 function TSQLDataItem.AdjustScale(Value: Int64; aScale: Integer): Double;
764 var
765  Scaling : Int64;
766  i: Integer;
767  Val: Double;
768 begin
769  Scaling := 1; Val := Value;
770  if aScale > 0 then
771  begin
772    for i := 1 to aScale do
773      Scaling := Scaling * 10;
774    result := Val * Scaling;
775  end
776  else
777    if aScale < 0 then
778    begin
779      for i := -1 downto aScale do
780        Scaling := Scaling * 10;
781      result := Val / Scaling;
782    end
783    else
784      result := Val;
785 end;
786
787 function TSQLDataItem.AdjustScaleToInt64(Value: Int64; aScale: Integer): Int64;
788 var
789  Scaling : Int64;
790  i: Integer;
791  Val: Int64;
792 begin
793  Scaling := 1; Val := Value;
794  if aScale > 0 then begin
795    for i := 1 to aScale do Scaling := Scaling * 10;
796    result := Val * Scaling;
797  end else if aScale < 0 then begin
798    for i := -1 downto aScale do Scaling := Scaling * 10;
799    result := Val div Scaling;
800  end else
801    result := Val;
802 end;
803
804 function TSQLDataItem.AdjustScaleToCurrency(Value: Int64; aScale: Integer
805  ): Currency;
806 var
807  Scaling : Int64;
808  i : Integer;
809  FractionText, PadText, CurrText: AnsiString;
810 begin
811  Result := 0;
812  Scaling := 1;
813  PadText := '';
814  if aScale > 0 then
815  begin
816    for i := 1 to aScale do
817      Scaling := Scaling * 10;
818    result := Value * Scaling;
819  end
820  else
821    if aScale < 0 then
822    begin
823      for i := -1 downto aScale do
824        Scaling := Scaling * 10;
825      FractionText := IntToStr(abs(Value mod Scaling));
826      for i := Length(FractionText) to -aScale -1 do
827        PadText := '0' + PadText;
828      {$IF declared(DefaultFormatSettings)}
829      with DefaultFormatSettings do
830      {$ELSE}
831      {$IF declared(FormatSettings)}
832      with FormatSettings do
833      {$IFEND}
834      {$IFEND}
835      if Value < 0 then
836        CurrText := '-' + IntToStr(Abs(Value div Scaling)) + DecimalSeparator + PadText + FractionText
837      else
838        CurrText := IntToStr(Abs(Value div Scaling)) + DecimalSeparator + PadText + FractionText;
839      try
840        result := StrToCurr(CurrText);
841      except
842        on E: Exception do
843          IBError(ibxeInvalidDataConversion, [nil]);
844      end;
845    end
846    else
847      result := Value;
848 end;
849
960   function TSQLDataItem.GetDateFormatStr(IncludeTime: boolean): AnsiString;
961   begin
962    {$IF declared(DefaultFormatSettings)}
# Line 944 | Line 1054 | begin
1054      end;
1055   end;
1056  
947 function TSQLDataItem.AdjustScaleFromCurrency(Value: Currency; aScale: Integer
948  ): Int64;
949 var
950  Scaling : Int64;
951  i : Integer;
952 begin
953  Result := 0;
954  Scaling := 1;
955  if aScale < 0 then
956  begin
957    for i := -1 downto aScale do
958      Scaling := Scaling * 10;
959    result := trunc(Value * Scaling);
960  end
961  else
962  if aScale > 0 then
963  begin
964    for i := 1 to aScale do
965       Scaling := Scaling * 10;
966    result := trunc(Value / Scaling);
967  end
968  else
969    result := trunc(Value);
970 end;
971
972 function TSQLDataItem.AdjustScaleFromDouble(Value: Double; aScale: Integer
973  ): Int64;
974 var
975  Scaling : Int64;
976  i : Integer;
977 begin
978  Result := 0;
979  Scaling := 1;
980  if aScale < 0 then
981  begin
982    for i := -1 downto aScale do
983      Scaling := Scaling * 10;
984    result := trunc(Value * Scaling);
985  end
986  else
987  if aScale > 0 then
988  begin
989    for i := 1 to aScale do
990       Scaling := Scaling * 10;
991    result := trunc(Value / Scaling);
992  end
993  else
994    result := trunc(Value);
995 end;
996
1057   procedure TSQLDataItem.CheckActive;
1058   begin
1059    //Do nothing by default
# Line 1060 | Line 1120 | begin
1120    FFirebirdClientAPI := api;
1121   end;
1122  
1123 + function TSQLDataItem.CanChangeMetaData: boolean;
1124 + begin
1125 +  Result := false;
1126 + end;
1127 +
1128   function TSQLDataItem.GetSQLTypeName: AnsiString;
1129   begin
1130    Result := GetSQLTypeName(GetSQLType);
1131   end;
1132  
1133 < class function TSQLDataItem.GetSQLTypeName(SQLType: short): AnsiString;
1133 > class function TSQLDataItem.GetSQLTypeName(SQLType: cardinal): AnsiString;
1134   begin
1135    Result := 'Unknown';
1136    case SQLType of
# Line 1135 | Line 1200 | begin
1200            end;
1201          end;
1202          SQL_SHORT:
1203 <          result := AdjustScaleToCurrency(Int64(PShort(SQLData)^),
1204 <                                      Scale);
1203 >          result := NumericFromRawValues(Int64(PShort(SQLData)^),
1204 >                                      Scale).getAsCurrency;
1205          SQL_LONG:
1206 <          result := AdjustScaleToCurrency(Int64(PLong(SQLData)^),
1207 <                                      Scale);
1206 >          result := NumericFromRawValues(Int64(PLong(SQLData)^),
1207 >                                      Scale).getAsCurrency;
1208          SQL_INT64:
1209 <          result := AdjustScaleToCurrency(PInt64(SQLData)^,
1210 <                                      Scale);
1209 >          result := NumericFromRawValues(PInt64(SQLData)^,
1210 >                                      Scale).getAsCurrency;
1211          SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1212 <          result := Trunc(AsDouble);
1212 >          result := Round(AsDouble);
1213  
1214          SQL_DEC_FIXED,
1215          SQL_DEC16,
# Line 1173 | Line 1238 | begin
1238          end;
1239        end;
1240        SQL_SHORT:
1241 <        result := AdjustScaleToInt64(Int64(PShort(SQLData)^),
1242 <                                    Scale);
1241 >        result := NumericFromRawValues(Int64(PShort(SQLData)^),
1242 >                                    Scale).getAsInt64;
1243        SQL_LONG:
1244 <        result := AdjustScaleToInt64(Int64(PLong(SQLData)^),
1245 <                                    Scale);
1244 >        result := NumericFromRawValues(Int64(PLong(SQLData)^),
1245 >                                    Scale).getAsInt64;
1246        SQL_INT64:
1247 <        result := AdjustScaleToInt64(PInt64(SQLData)^,
1248 <                                    Scale);
1247 >        result := NumericFromRawValues(PInt64(SQLData)^,
1248 >                                    Scale).getAsInt64;
1249        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1250 <        result := Trunc(AsDouble);
1250 >        result := Round(AsDouble);
1251        else
1252          IBError(ibxeInvalidDataConversion, [nil]);
1253      end;
# Line 1309 | Line 1374 | begin
1374          end;
1375        end;
1376        SQL_SHORT:
1377 <        result := AdjustScale(Int64(PShort(SQLData)^),
1378 <                              Scale);
1377 >        result := NumericFromRawValues(Int64(PShort(SQLData)^),
1378 >                              Scale).getAsDouble;
1379        SQL_LONG:
1380 <        result := AdjustScale(Int64(PLong(SQLData)^),
1381 <                              Scale);
1380 >        result := NumericFromRawValues(Int64(PLong(SQLData)^),
1381 >                              Scale).getAsDouble;
1382        SQL_INT64:
1383 <        result := AdjustScale(PInt64(SQLData)^, Scale);
1383 >        result := NumericFromRawValues(PInt64(SQLData)^, Scale).getAsDouble;
1384        SQL_FLOAT:
1385          result := PFloat(SQLData)^;
1386        SQL_DOUBLE, SQL_D_FLOAT:
# Line 1361 | Line 1426 | begin
1426          end;
1427        end;
1428        SQL_SHORT:
1429 <        result := Trunc(AdjustScale(Int64(PShort(SQLData)^),
1430 <                                    Scale));
1429 >        result := NumericFromRawValues(Int64(PShort(SQLData)^),
1430 >                                    Scale).getAsInteger;
1431        SQL_LONG:
1432 <        result := Trunc(AdjustScale(Int64(PLong(SQLData)^),
1433 <                                    Scale));
1432 >        result := NumericFromRawValues(Int64(PLong(SQLData)^),
1433 >                                    Scale).getAsInteger;
1434        SQL_INT64:
1435 <        result := Trunc(AdjustScale(PInt64(SQLData)^, Scale));
1435 >        result := NumericFromRawValues(PInt64(SQLData)^, Scale).getAsInteger;
1436 >
1437        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1438 <        result := Trunc(AsDouble);
1438 >        result := Round(AsDouble);
1439        SQL_DEC_FIXED,
1440        SQL_DEC16,
1441        SQL_DEC34,
# Line 1464 | Line 1530 | end;
1530   function GetStrLen(p: PAnsiChar; FieldWidth, MaxDataLength: cardinal): integer;
1531   var i: integer;
1532      cplen: integer;
1467    s: AnsiString;
1533   begin
1534    Result := 0;
1470  s := strpas(p);
1535    for i := 1 to FieldWidth do
1536    begin
1537      cplen := UTF8CodepointSizeFull(p);
# Line 1584 | Line 1648 | begin
1648          result := Int128ToStr(SQLData,scale);
1649  
1650        else
1651 <        IBError(ibxeInvalidDataConversion, [nil]);
1651 >        IBError(ibxeInvalidDataConversion, [GetSQLTypeName]);
1652      end;
1653   end;
1654  
1655 + function TSQLDataItem.GetAsNumeric: IFBNumeric;
1656 + var aValue: Int64;
1657 + begin
1658 +  case SQLType of
1659 +   SQL_TEXT, SQL_VARYING:
1660 +     Result := StrToNumeric(GetAsString);
1661 +
1662 +   SQL_SHORT:
1663 +     Result := NumericFromRawValues(PShort(SQLData)^, Scale);
1664 +
1665 +   SQL_LONG:
1666 +     Result := NumericFromRawValues(PLong(SQLData)^, Scale);
1667 +
1668 +   SQL_INT64:
1669 +     Result := NumericFromRawValues(PInt64(SQLData)^, Scale);
1670 +
1671 +   SQL_DEC16,
1672 +   SQL_DEC34,
1673 +   SQL_DEC_FIXED,
1674 +   SQL_INT128:
1675 +     Result := BCDToNumeric(GetAsBCD);
1676 +
1677 +   else
1678 +     IBError(ibxeInvalidDataConversion, [nil]);
1679 +  end;
1680 + end;
1681 +
1682   function TSQLDataItem.GetIsNull: Boolean;
1683   begin
1684    CheckActive;
# Line 1726 | Line 1817 | begin
1817    if GetSQLDialect < 3 then
1818      AsDouble := Value
1819    else
1820 +  if not CanChangeMetaData and ((SQLType <> SQL_INT64) or (Scale <> -4)) then
1821 +    SetAsNumeric(CurrToNumeric(Value))
1822 +  else
1823    begin
1824      Changing;
1825      if IsNullable then
# Line 1741 | Line 1835 | end;
1835   procedure TSQLDataItem.SetAsInt64(Value: Int64);
1836   begin
1837    CheckActive;
1838 <  Changing;
1839 <  if IsNullable then
1840 <    IsNull := False;
1838 >  if not CanChangeMetaData and ((SQLType <> SQL_INT64) or (Scale <> 0)) then
1839 >    SetAsNumeric(IntToNumeric(Value))
1840 >  else
1841 >  begin
1842 >    Changing;
1843 >    if IsNullable then
1844 >      IsNull := False;
1845  
1846 <  SQLType := SQL_INT64;
1847 <  Scale := 0;
1848 <  DataLength := SizeOf(Int64);
1849 <  PInt64(SQLData)^ := Value;
1850 <  Changed;
1846 >    SQLType := SQL_INT64;
1847 >    Scale := 0;
1848 >    DataLength := SizeOf(Int64);
1849 >    PInt64(SQLData)^ := Value;
1850 >    Changed;
1851 >  end;
1852   end;
1853  
1854   procedure TSQLDataItem.SetAsDate(Value: TDateTime);
# Line 1884 | Line 1983 | end;
1983   procedure TSQLDataItem.SetAsDouble(Value: Double);
1984   begin
1985    CheckActive;
1986 <  if IsNullable then
1987 <    IsNull := False;
1986 >  if not CanChangeMetaData and (SQLType <> SQL_DOUBLE) then
1987 >    SetAsNumeric(DoubleToNumeric(Value))
1988 >  else
1989 >  begin
1990 >    if IsNullable then
1991 >      IsNull := False;
1992  
1993 <  Changing;
1994 <  SQLType := SQL_DOUBLE;
1995 <  DataLength := SizeOf(Double);
1996 <  Scale := 0;
1997 <  PDouble(SQLData)^ := Value;
1998 <  Changed;
1993 >    Changing;
1994 >    SQLType := SQL_DOUBLE;
1995 >    DataLength := SizeOf(Double);
1996 >    Scale := 0;
1997 >    PDouble(SQLData)^ := Value;
1998 >    Changed;
1999 >  end;
2000   end;
2001  
2002   procedure TSQLDataItem.SetAsFloat(Value: Float);
2003   begin
2004    CheckActive;
2005 <  if IsNullable then
2006 <    IsNull := False;
2005 >  if not CanChangeMetaData and (SQLType <> SQL_FLOAT) then
2006 >    SetAsNumeric(DoubleToNumeric(Value))
2007 >  else
2008 >  begin
2009 >    if IsNullable then
2010 >      IsNull := False;
2011  
2012 <  Changing;
2013 <  SQLType := SQL_FLOAT;
2014 <  DataLength := SizeOf(Float);
2015 <  Scale := 0;
2016 <  PSingle(SQLData)^ := Value;
2017 <  Changed;
2012 >    Changing;
2013 >    SQLType := SQL_FLOAT;
2014 >    DataLength := SizeOf(Float);
2015 >    Scale := 0;
2016 >    PSingle(SQLData)^ := Value;
2017 >    Changed;
2018 >  end;
2019   end;
2020  
2021   procedure TSQLDataItem.SetAsLong(Value: Long);
2022   begin
2023    CheckActive;
2024 <  if IsNullable then
2025 <    IsNull := False;
2024 >  if not CanChangeMetaData and ((SQLType <> SQL_LONG) or (Scale <> 0)) then
2025 >    SetAsNumeric(IntToNumeric(Value))
2026 >  else
2027 >  begin
2028 >    if IsNullable then
2029 >      IsNull := False;
2030  
2031 <  Changing;
2032 <  SQLType := SQL_LONG;
2033 <  DataLength := SizeOf(Long);
2034 <  Scale := 0;
2035 <  PLong(SQLData)^ := Value;
2036 <  Changed;
2031 >    Changing;
2032 >    SQLType := SQL_LONG;
2033 >    DataLength := SizeOf(Long);
2034 >    Scale := 0;
2035 >    PLong(SQLData)^ := Value;
2036 >    Changed;
2037 >  end;
2038   end;
2039  
2040   procedure TSQLDataItem.SetAsPointer(Value: Pointer);
# Line 1955 | Line 2069 | end;
2069   procedure TSQLDataItem.SetAsShort(Value: short);
2070   begin
2071    CheckActive;
2072 <  Changing;
2073 <  if IsNullable then
2074 <    IsNull := False;
2072 >  if not CanChangeMetaData and ((SQLType <> SQL_SHORT) or (Scale <> 0)) then
2073 >    SetAsNumeric(IntToNumeric(Value))
2074 >  else
2075 >  begin
2076 >    Changing;
2077 >    if IsNullable then
2078 >      IsNull := False;
2079  
2080 <  SQLType := SQL_SHORT;
2081 <  DataLength := SizeOf(Short);
2082 <  Scale := 0;
2083 <  PShort(SQLData)^ := Value;
2084 <  Changed;
2080 >    SQLType := SQL_SHORT;
2081 >    DataLength := SizeOf(Short);
2082 >    Scale := 0;
2083 >    PShort(SQLData)^ := Value;
2084 >    Changed;
2085 >  end;
2086   end;
2087  
2088   procedure TSQLDataItem.SetAsString(Value: AnsiString);
# Line 1982 | Line 2101 | begin
2101    else case VarType(Value) of
2102      varEmpty, varNull:
2103        IsNull := True;
2104 <    varSmallint, varInteger, varByte,
2105 <      varWord, varShortInt:
2106 <      AsLong := Value;
1988 <    varInt64:
1989 <      AsInt64 := Value;
2104 >    varSmallint, varInteger, varByte, varLongWord,
2105 >      varWord, varShortInt, varInt64:
2106 >        SetAsNumeric(IntToNumeric(Int64(Value)));
2107      varSingle, varDouble:
2108        AsDouble := Value;
2109      varCurrency:
2110 <      AsCurrency := Value;
2110 >      SetAsNumeric(CurrToNumeric(Currency(Value)));
2111      varBoolean:
2112        AsBoolean := Value;
2113      varDate:
# Line 2009 | Line 2126 | begin
2126    end;
2127   end;
2128  
2129 < procedure TSQLDataItem.SetAsNumeric(Value: Int64; aScale: integer);
2129 > procedure TSQLDataItem.SetAsNumeric(Value: IFBNumeric);
2130   begin
2131    CheckActive;
2132    Changing;
2133    if IsNullable then
2134      IsNull := False;
2135  
2136 <  SQLType := SQL_INT64;
2137 <  Scale := aScale;
2138 <  DataLength := SizeOf(Int64);
2139 <  PInt64(SQLData)^ := Value;
2136 >  if CanChangeMetadata then
2137 >  begin
2138 >    {Restore original values}
2139 >    SQLType := getColMetadata.GetSQLType;
2140 >    Scale := getColMetadata.getScale;
2141 >    SetDataLength(getColMetadata.GetSize);
2142 >  end;
2143 >
2144 >  with FFirebirdClientAPI do
2145 >  case GetSQLType of
2146 >  SQL_LONG:
2147 >      PLong(SQLData)^ := SafeInteger(Value.AdjustScaleTo(Scale).getRawValue);
2148 >  SQL_SHORT:
2149 >    PShort(SQLData)^ := SafeSmallInt(Value.AdjustScaleTo(Scale).getRawValue);
2150 >  SQL_INT64:
2151 >    PInt64(SQLData)^ := Value.AdjustScaleTo(Scale).getRawValue;
2152 >  SQL_TEXT, SQL_VARYING:
2153 >   SetAsString(Value.getAsString);
2154 >  SQL_D_FLOAT,
2155 >  SQL_DOUBLE:
2156 >    PDouble(SQLData)^ := Value.getAsDouble;
2157 >  SQL_FLOAT:
2158 >    PSingle(SQLData)^ := Value.getAsDouble;
2159 >  SQL_DEC_FIXED,
2160 >  SQL_DEC16,
2161 >  SQL_DEC34:
2162 >     SQLDecFloatEncode(Value.getAsBCD,SQLType,SQLData);
2163 >  SQL_INT128:
2164 >    StrToInt128(Scale,Value.getAsString,SQLData);
2165 >  else
2166 >    IBError(ibxeInvalidDataConversion, [nil]);
2167 >  end;
2168    Changed;
2169   end;
2170  
2171   procedure TSQLDataItem.SetAsBcd(aValue: tBCD);
2027 var C: Currency;
2172   begin
2173    CheckActive;
2174    Changing;
2175    if IsNullable then
2176      IsNull := False;
2177  
2178 +  if not CanChangeMetaData then
2179 +  begin
2180 +    SetAsNumeric(BCDToNumeric(aValue));
2181 +    Exit;
2182 +  end;
2183  
2184    with FFirebirdClientAPI do
2185    if aValue.Precision <= 16 then
# Line 2100 | Line 2249 | end;
2249  
2250   function TColumnMetaData.GetAttachment: IAttachment;
2251   begin
2252 <  Result := GetStatement.GetAttachment;
2252 >  Result := FIBXSQLVAR.GetAttachment;
2253   end;
2254  
2255   function TColumnMetaData.SQLData: PByte;
# Line 2120 | Line 2269 | end;
2269  
2270   constructor TColumnMetaData.Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
2271   begin
2272 <  inherited Create(aIBXSQLVAR.GetStatement.GetAttachment.getFirebirdAPI as TFBClientAPI);
2272 >  inherited Create(aIBXSQLVAR.GetAttachment.getFirebirdAPI as TFBClientAPI);
2273    FIBXSQLVAR := aIBXSQLVAR;
2274    FOwner := aOwner;
2275    FPrepareSeqNo := FIBXSQLVAR.Parent.PrepareSeqNo;
# Line 2136 | Line 2285 | end;
2285  
2286   function TColumnMetaData.GetSQLDialect: integer;
2287   begin
2288 <  Result := FIBXSQLVAR.Statement.GetSQLDialect;
2288 >  Result := FIBXSQLVAR.GetAttachment.GetSQLDialect;
2289 > end;
2290 >
2291 > function TColumnMetaData.getColMetadata: IParamMetaData;
2292 > begin
2293 >  Result := self;
2294   end;
2295  
2296   function TColumnMetaData.GetIndex: integer;
# Line 2235 | Line 2389 | end;
2389  
2390   function TColumnMetaData.GetTransaction: ITransaction;
2391   begin
2392 <  Result := GetStatement.GetTransaction;
2392 >  Result := FIBXSQLVAR.GetTransaction;
2393   end;
2394  
2395   { TIBSQLData }
# Line 2257 | Line 2411 | begin
2411      IBError(ibxeBOF,[nil]);
2412   end;
2413  
2260 function TIBSQLData.GetTransaction: ITransaction;
2261 begin
2262  if FTransaction = nil then
2263    Result := inherited GetTransaction
2264  else
2265    Result := FTransaction;
2266 end;
2267
2414   function TIBSQLData.GetIsNull: Boolean;
2415   begin
2416    CheckActive;
# Line 2274 | Line 2420 | end;
2420   function TIBSQLData.GetAsArray: IArray;
2421   begin
2422    CheckActive;
2423 <  result := FIBXSQLVAR.GetAsArray(AsQuad);
2423 >  result := FIBXSQLVAR.GetAsArray;
2424   end;
2425  
2426   function TIBSQLData.GetAsBlob: IBlob;
# Line 2318 | Line 2464 | end;
2464  
2465   var b: IBlob;
2466      dt: TDateTime;
2321    CurrValue: Currency;
2322    FloatValue: single;
2467      timezone: AnsiString;
2468 +    Int64Value: Int64;
2469 +    BCDValue: TBCD;
2470 +    aScale: integer;
2471   begin
2472    CheckActive;
2473    if IsNullable then
# Line 2337 | Line 2484 | begin
2484        IBError(ibxeInvalidDataConversion,[nil]);
2485  
2486    SQL_BLOB:
2487 +    if Length(Value) < GetAttachment.GetInlineBlobLimit then
2488 +      DoSetString
2489 +    else
2490      begin
2491        Changing;
2492        b := FIBXSQLVAR.CreateBlob;
# Line 2349 | Line 2499 | begin
2499    SQL_TEXT:
2500      DoSetString;
2501  
2502 <    SQL_SHORT,
2503 <    SQL_LONG,
2504 <    SQL_INT64:
2505 <      if TryStrToCurr(Value,CurrValue) then
2506 <        SetAsNumeric(AdjustScaleFromCurrency(CurrValue,GetScale),GetScale)
2507 <      else
2508 <        DoSetString;
2502 >  SQL_SHORT,
2503 >  SQL_LONG,
2504 >  SQL_INT64:
2505 >    if TryStrToNumeric(Value,Int64Value,aScale) then
2506 >      SetAsNumeric(NumericFromRawValues(Int64Value,aScale))
2507 >    else
2508 >      DoSetString;
2509  
2510 <    SQL_D_FLOAT,
2511 <    SQL_DOUBLE,
2512 <    SQL_FLOAT:
2513 <      if TryStrToFloat(Value,FloatValue) then
2514 <        SetAsDouble(FloatValue)
2515 <      else
2516 <        DoSetString;
2510 >  SQL_DEC_FIXED,
2511 >  SQL_DEC16,
2512 >  SQL_DEC34,
2513 >  SQL_INT128:
2514 >    if TryStrToBCD(Value,BCDValue) then
2515 >      SetAsNumeric(BCDToNumeric(BCDValue))
2516 >    else
2517 >      DoSetString;
2518 >
2519 >  SQL_D_FLOAT,
2520 >  SQL_DOUBLE,
2521 >  SQL_FLOAT:
2522 >    if TryStrToNumeric(Value,Int64Value,aScale) then
2523 >      SetAsNumeric(NumericFromRawValues(Int64Value,AScale))
2524 >    else
2525 >      DoSetString;
2526  
2527 <    SQL_TIMESTAMP:
2527 >  SQL_TIMESTAMP:
2528        if TryStrToDateTime(Value,dt) then
2529          SetAsDateTime(dt)
2530        else
2531          DoSetString;
2532  
2533 <    SQL_TYPE_DATE:
2533 >  SQL_TYPE_DATE:
2534        if TryStrToDateTime(Value,dt) then
2535          SetAsDate(dt)
2536        else
2537          DoSetString;
2538  
2539 <    SQL_TYPE_TIME:
2539 >  SQL_TYPE_TIME:
2540        if TryStrToDateTime(Value,dt) then
2541          SetAsTime(dt)
2542        else
2543          DoSetString;
2544  
2545 <    SQL_TIMESTAMP_TZ:
2545 >  SQL_TIMESTAMP_TZ,
2546 >  SQL_TIMESTAMP_TZ_EX:
2547        if ParseDateTimeTZString(value,dt,timezone) then
2548          SetAsDateTime(dt,timezone)
2549        else
2550          DoSetString;
2551  
2552 <    SQL_TIME_TZ:
2552 >  SQL_TIME_TZ,
2553 >  SQL_TIME_TZ_EX:
2554        if ParseDateTimeTZString(value,dt,timezone,true) then
2555          SetAsTime(dt,GetAttachment.GetTimeZoneServices.GetTimeTZDate,timezone)
2556        else
2557          DoSetString;
2558  
2559 <    SQL_DEC_FIXED,
2560 <    SQL_DEC16,
2400 <    SQL_DEC34,
2401 <    SQL_INT128:
2402 <      SetAsBCD(StrToBCD(Value));
2403 <
2404 <    else
2405 <      IBError(ibxeInvalidDataConversion,[nil]);
2559 >  else
2560 >    IBError(ibxeInvalidDataConversion,[GetSQLTypeName(getColMetaData.SQLTYPE)]);
2561    end;
2562   end;
2563  
# Line 2440 | Line 2595 | begin
2595    IsNull := true;
2596   end;
2597  
2598 + function TSQLParam.CanChangeMetaData: boolean;
2599 + begin
2600 +  Result := FIBXSQLVAR.CanChangeMetaData;
2601 + end;
2602 +
2603 + function TSQLParam.getColMetadata: IParamMetaData;
2604 + begin
2605 +  Result := FIBXSQLVAR.getColMetadata;
2606 + end;
2607 +
2608   function TSQLParam.GetModified: boolean;
2609   begin
2610    CheckActive;
# Line 2453 | Line 2618 | begin
2618    Result := inherited GetAsPointer;
2619   end;
2620  
2621 + function TSQLParam.GetAsString: AnsiString;
2622 + var rs: RawByteString;
2623 + begin
2624 +  Result := '';
2625 +  if (SQLType = SQL_VARYING) and not IsNull then
2626 +  {SQLData points to start of string - default is to length word}
2627 +  begin
2628 +    CheckActive;
2629 +    SetString(rs,PAnsiChar(SQLData),DataLength);
2630 +    SetCodePage(rs,GetCodePage,false);
2631 +    Result := rs;
2632 +  end
2633 +  else
2634 +    Result := inherited GetAsString;
2635 + end;
2636 +
2637   procedure TSQLParam.SetName(Value: AnsiString);
2638   begin
2639    CheckActive;
# Line 2498 | Line 2679 | begin
2679    if not FIBXSQLVAR.UniqueName then
2680      IBError(ibxeDuplicateParamName,[FIBXSQLVAR.Name]);
2681  
2682 +  FIBXSQLVAR.SetArray(anArray); {save array interface}
2683    SetAsQuad(AnArray.GetArrayID);
2684   end;
2685  
# Line 2973 | Line 3155 | begin
3155    end;
3156   end;
3157  
3158 + procedure TSQLParam.SetAsNumeric(aValue: IFBNumeric);
3159 + var i: integer;
3160 +    OldSQLVar: TSQLVarData;
3161 + begin
3162 +  if FIBXSQLVAR.UniqueName then
3163 +    inherited SetAsNumeric(AValue)
3164 +  else
3165 +  with FIBXSQLVAR.Parent do
3166 +  begin
3167 +    for i := 0 to Count - 1 do
3168 +      if Column[i].Name = Name then
3169 +      begin
3170 +        OldSQLVar := FIBXSQLVAR;
3171 +        FIBXSQLVAR := Column[i];
3172 +        try
3173 +          inherited SetAsNumeric(AValue);
3174 +        finally
3175 +          FIBXSQLVAR := OldSQLVar;
3176 +        end;
3177 +      end;
3178 +  end;
3179 + end;
3180 +
3181   { TMetaData }
3182  
3183   procedure TMetaData.CheckActive;
# Line 2994 | Line 3199 | end;
3199  
3200   destructor TMetaData.Destroy;
3201   begin
3202 <  (FStatement as TInterfaceOwner).Remove(self);
3202 >  if FStatement <> nil then
3203 >    (FStatement as TInterfaceOwner).Remove(self);
3204    inherited Destroy;
3205   end;
3206  
# Line 3060 | Line 3266 | end;
3266  
3267   destructor TSQLParams.Destroy;
3268   begin
3269 <  (FStatement as TInterfaceOwner).Remove(self);
3269 >  if FStatement <> nil then
3270 >    (FStatement as TInterfaceOwner).Remove(self);
3271    inherited Destroy;
3272   end;
3273  
# Line 3086 | Line 3293 | begin
3293    end;
3294   end;
3295  
3296 + function TSQLParams.ParamExists(Idx: AnsiString): boolean;
3297 + begin
3298 +  CheckActive;
3299 +  Result := FSQLParams.ColumnByName(Idx) <> nil;
3300 + end;
3301 +
3302   function TSQLParams.ByName(Idx: AnsiString): ISQLParam;
3303   var aIBXSQLVAR: TSQLVarData;
3304   begin
# Line 3116 | Line 3329 | begin
3329    Result := FSQLParams.CaseSensitiveParams;
3330   end;
3331  
3332 + function TSQLParams.GetStatement: IStatement;
3333 + begin
3334 +  Result := FSQLParams.GetStatement;
3335 + end;
3336 +
3337 + function TSQLParams.GetTransaction: ITransaction;
3338 + begin
3339 +  Result := FSQLParams.GetTransaction;
3340 + end;
3341 +
3342 + function TSQLParams.GetAttachment: IAttachment;
3343 + begin
3344 +  Result := FSQLParams.GetAttachment;
3345 + end;
3346 +
3347 + procedure TSQLParams.Clear;
3348 + var i: integer;
3349 + begin
3350 +  for i := 0 to getCount - 1 do
3351 +    getSQLParam(i).Clear;
3352 + end;
3353 +
3354   { TResults }
3355  
3356   procedure TResults.CheckActive;
# Line 3140 | Line 3375 | begin
3375      IBError(ibxeInvalidColumnIndex,[nil]);
3376  
3377    if not HasInterface(aIBXSQLVAR.Index) then
3378 <    AddInterface(aIBXSQLVAR.Index, TIBSQLData.Create(self,aIBXSQLVAR));
3379 <  col := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3380 <  col.FTransaction := GetTransaction;
3378 >  begin
3379 >    col := TIBSQLData.Create(self,aIBXSQLVAR);
3380 >    AddInterface(aIBXSQLVAR.Index, col);
3381 >  end
3382 >  else
3383 >    col := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3384    Result := col;
3385   end;
3386  
# Line 3180 | Line 3418 | begin
3418    end;
3419   end;
3420  
3421 + function TResults.FieldExists(Idx: AnsiString): boolean;
3422 + begin
3423 +  Result :=  FResults.ColumnByName(Idx) <> nil;
3424 + end;
3425 +
3426   function TResults.getSQLData(index: integer): ISQLData;
3427   begin
3428    CheckActive;
# Line 3207 | Line 3450 | end;
3450  
3451   function TResults.GetTransaction: ITransaction;
3452   begin
3453 <  Result := FStatement.GetTransaction;
3453 >  Result := FResults.GetTransaction;
3454 > end;
3455 >
3456 > function TResults.GetAttachment: IAttachment;
3457 > begin
3458 >  Result := FResults.GetAttachment;
3459   end;
3460  
3461   procedure TResults.SetRetainInterfaces(aValue: boolean);

Comparing:
ibx/trunk/fbintf/client/FBSQLData.pas (property svn:eol-style), Revision 315 by tony, Thu Feb 25 11:56:36 2021 UTC vs.
ibx/branches/udr/client/FBSQLData.pas (property svn:eol-style), Revision 391 by tony, Thu Jan 27 16:34:24 2022 UTC

# Line 0 | Line 1
1 + native

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines