ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBSQL.pas
(Generate patch)

Comparing ibx/trunk/runtime/IBSQL.pas (file contents):
Revision 5 by tony, Fri Feb 18 16:26:16 2011 UTC vs.
Revision 25 by tony, Sat Mar 14 10:44:03 2015 UTC

# Line 24 | Line 24
24   {       Corporation. All Rights Reserved.                                }
25   {    Contributor(s): Jeff Overcash                                       }
26   {                                                                        }
27 + {    IBX For Lazarus (Firebird Express)                                  }
28 + {    Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
29 + {    Portions created by MWA Software are copyright McCallum Whyman      }
30 + {    Associates Ltd 2011 - 2014                                                }
31 + {                                                                        }
32   {************************************************************************}
33  
34   unit IBSQL;
35  
36   {$Mode Delphi}
37  
38 + { IBSQL param names in dialect 3 quoted format (e.g. :"MyParam") are by default disabled.
39 +
40 + Dialect 3 quoted format parameter names represent a significant overhead and are of
41 + limited value - especially for users that use only TIBSQL or TIBCustomDataset
42 + descendents. They were previously used internally by IBX to simplify SQL generation
43 + for TTable components in Master/Slave relationships which are linked by
44 + Dialect 3 names. They were also generated by TStoredProc when the original
45 + parameter names are quoted.
46 +
47 + However, for some users they do cause a big processing overhead. The TTable/TStoredProc
48 + code has been re-written so that they are no required by IBX internally.
49 + The code to support quoted parameter names is now subject  to conditional compilation.
50 + To enable support, ALLOWDIALECT3PARAMNAMES should be defined when IBX is compiled.
51 +
52 + Hint: deleting the space between the brace and the dollar sign below
53 +
54 + }
55 +
56 + { $define ALLOWDIALECT3PARAMNAMES}
57 +
58 + {$ifndef ALLOWDIALECT3PARAMNAMES}
59 +
60 + { Even when dialect 3 quoted format parameter names are not supported, IBX still processes
61 +  parameter names case insensitive. This does result in some additional overhead
62 +  due to a call to "AnsiUpperCase". This can be avoided by undefining
63 +  "UseCaseSensitiveParamName" below.
64 +
65 +  Note: do not define "UseCaseSensitiveParamName" when "ALLOWDIALECT3PARAMNAMES"
66 +  is defined. This will not give a useful result.
67 + }
68 + {$define UseCaseSensitiveParamName}
69 + {$endif}
70 +
71   interface
72  
73   uses
74 < {$IFDEF LINUX }
37 <  baseunix,unix,
38 < {$ELSE}
39 < {$DEFINE HAS_SQLMONITOR}
74 > {$IFDEF WINDOWS }
75    Windows,
76 + {$ELSE}
77 +  baseunix, unix,
78   {$ENDIF}
79    SysUtils, Classes, Forms, Controls, IBHeader,
80    IBErrorCodes, IBExternals, DB, IB, IBDatabase, IBUtils, IBXConst;
81  
82 + const
83 +   sSQLErrorSeparator = ' When Executing: ';
84 +
85   type
86    TIBSQL = class;
87    TIBXSQLDA = class;
# Line 54 | Line 94 | type
94      FIndex: Integer;
95      FModified: Boolean;
96      FName: String;
97 +    FUniqueName: boolean;
98      FXSQLVAR: PXSQLVAR;       { Point to the PXSQLVAR in the owner object }
99  
100      function AdjustScale(Value: Int64; Scale: Integer): Double;
101      function AdjustScaleToInt64(Value: Int64; Scale: Integer): Int64;
102      function AdjustScaleToCurrency(Value: Int64; Scale: Integer): Currency;
103 +    function GetAsBoolean: boolean;
104      function GetAsCurrency: Currency;
105      function GetAsInt64: Int64;
106      function GetAsDateTime: TDateTime;
# Line 75 | Line 117 | type
117      function GetIsNullable: Boolean;
118      function GetSize: Integer;
119      function GetSQLType: Integer;
120 +    procedure SetAsBoolean(AValue: boolean);
121      procedure SetAsCurrency(Value: Currency);
122      procedure SetAsInt64(Value: Int64);
123      procedure SetAsDate(Value: TDateTime);
124 +    procedure SetAsLong(Value: Long);
125      procedure SetAsTime(Value: TDateTime);
126      procedure SetAsDateTime(Value: TDateTime);
127      procedure SetAsDouble(Value: Double);
128      procedure SetAsFloat(Value: Float);
85    procedure SetAsLong(Value: Long);
129      procedure SetAsPointer(Value: Pointer);
130      procedure SetAsQuad(Value: TISC_QUAD);
131      procedure SetAsShort(Value: Short);
# Line 91 | Line 134 | type
134      procedure SetAsXSQLVAR(Value: PXSQLVAR);
135      procedure SetIsNull(Value: Boolean);
136      procedure SetIsNullable(Value: Boolean);
137 +    procedure xSetAsBoolean(AValue: boolean);
138 +    procedure xSetAsCurrency(Value: Currency);
139 +    procedure xSetAsInt64(Value: Int64);
140 +    procedure xSetAsDate(Value: TDateTime);
141 +    procedure xSetAsTime(Value: TDateTime);
142 +    procedure xSetAsDateTime(Value: TDateTime);
143 +    procedure xSetAsDouble(Value: Double);
144 +    procedure xSetAsFloat(Value: Float);
145 +    procedure xSetAsLong(Value: Long);
146 +    procedure xSetAsPointer(Value: Pointer);
147 +    procedure xSetAsQuad(Value: TISC_QUAD);
148 +    procedure xSetAsShort(Value: Short);
149 +    procedure xSetAsString(Value: String);
150 +    procedure xSetAsVariant(Value: Variant);
151 +    procedure xSetAsXSQLVAR(Value: PXSQLVAR);
152 +    procedure xSetIsNull(Value: Boolean);
153 +    procedure xSetIsNullable(Value: Boolean);
154    public
155      constructor Create(Parent: TIBXSQLDA; Query: TIBSQL);
156      procedure Assign(Source: TIBXSQLVAR);
157 +    procedure Clear;
158      procedure LoadFromFile(const FileName: String);
159      procedure LoadFromStream(Stream: TStream);
160      procedure SaveToFile(const FileName: String);
161      procedure SaveToStream(Stream: TStream);
162      property AsDate: TDateTime read GetAsDateTime write SetAsDate;
163 +    property AsBoolean:boolean read GetAsBoolean write SetAsBoolean;
164      property AsTime: TDateTime read GetAsDateTime write SetAsTime;
165      property AsDateTime: TDateTime read GetAsDateTime write SetAsDateTime;
166      property AsDouble: Double read GetAsDouble write SetAsDouble;
# Line 126 | Line 188 | type
188  
189    TIBXSQLVARArray = Array of TIBXSQLVAR;
190  
191 <  { TIBXSQLVAR }
191 >  TIBXSQLDAType = (daInput,daOutput);
192 >
193 >  { TIBXSQLDA }
194 >
195    TIBXSQLDA = class(TObject)
196    protected
197      FSQL: TIBSQL;
198      FCount: Integer;
134    FNames: TStrings;
199      FSize: Integer;
200 +    FInputSQLDA: boolean;
201      FXSQLDA: PXSQLDA;
202      FXSQLVARs: TIBXSQLVARArray; { array of IBXQLVARs }
203      FUniqueRelationName: String;
204      function GetModified: Boolean;
140    function GetNames: String;
205      function GetRecordSize: Integer;
206      function GetXSQLDA: PXSQLDA;
207      function GetXSQLVAR(Idx: Integer): TIBXSQLVAR;
# Line 145 | Line 209 | type
209      procedure Initialize;
210      procedure SetCount(Value: Integer);
211    public
212 <    constructor Create(Query: TIBSQL);
212 >    constructor Create(Query: TIBSQL; sqldaType: TIBXSQLDAType);
213      destructor Destroy; override;
214 <    procedure AddName(FieldName: String; Idx: Integer);
214 >     procedure SetParamName(FieldName: String; Idx: Integer; UniqueName: boolean = false);
215      function ByName(Idx: String): TIBXSQLVAR;
216      property AsXSQLDA: PXSQLDA read GetXSQLDA;
217      property Count: Integer read FCount write SetCount;
218      property Modified: Boolean read GetModified;
155    property Names: String read GetNames;
219      property RecordSize: Integer read GetRecordSize;
220      property Vars[Idx: Integer]: TIBXSQLVAR read GetXSQLVAR; default;
221      property UniqueRelationName: String read FUniqueRelationName;
# Line 186 | Line 249 | type
249    { TIBOutputDelimitedFile }
250    TIBOutputDelimitedFile = class(TIBBatchOutput)
251    protected
252 <  {$IFDEF LINUX}
252 >  {$IFDEF UNIX}
253      FHandle: cint;
254    {$ELSE}
255      FHandle: THandle;
# Line 229 | Line 292 | type
292    { TIBOutputRawFile }
293    TIBOutputRawFile = class(TIBBatchOutput)
294    protected
295 <  {$IFDEF LINUX}
295 >  {$IFDEF UNIX}
296      FHandle: cint;
297    {$ELSE}
298      FHandle: THandle;
# Line 243 | Line 306 | type
306    { TIBInputRawFile }
307    TIBInputRawFile = class(TIBBatchInput)
308    protected
309 <   {$IFDEF LINUX}
309 >   {$IFDEF UNIX}
310      FHandle: cint;
311    {$ELSE}
312      FHandle: THandle;
# Line 265 | Line 328 | type
328    TIBSQL = class(TComponent)
329    private
330      FIBLoaded: Boolean;
331 +    FUniqueParamNames: Boolean;
332 +    function GetFieldCount: integer;
333 +    procedure SetUniqueParamNames(AValue: Boolean);
334    protected
335      FBase: TIBBase;
336      FBOF,                          { At BOF? }
# Line 324 | Line 390 | type
390      property Eof: Boolean read GetEOF;
391      property Fields[const Idx: Integer]: TIBXSQLVAR read GetFields;
392      property FieldIndex[FieldName: String]: Integer read GetFieldIndex;
393 +    property FieldCount: integer read GetFieldCount;
394      property Open: Boolean read FOpen;
395      property Params: TIBXSQLDA read GetSQLParams;
396      property Plan: String read GetPlan;
# Line 333 | Line 400 | type
400      property SQLType: TIBSQLTypes read FSQLType;
401      property TRHandle: PISC_TR_HANDLE read GetTRHandle;
402      property Handle: TISC_STMT_HANDLE read FHandle;
336    property GenerateParamNames: Boolean read FGenerateParamNames write FGenerateParamNames;
403      property UniqueRelationName: String read GetUniqueRelationName;
404    published
405      property Database: TIBDatabase read GetDatabase write SetDatabase;
406 +    property GenerateParamNames: Boolean read FGenerateParamNames write FGenerateParamNames;
407 +    property UniqueParamNames: Boolean read FUniqueParamNames write SetUniqueParamNames;
408      property GoToFirstRecordOnExecute: Boolean read FGoToFirstRecordOnExecute
409                                                 write FGoToFirstRecordOnExecute
410                                                 default True;
# Line 349 | Line 417 | type
417   implementation
418  
419   uses
420 <  IBIntf, IBBlob, Variants {$IFDEF HAS_SQLMONITOR}, IBSQLMonitor {$ENDIF};
420 >  IBIntf, IBBlob, Variants , IBSQLMonitor;
421  
422   { TIBXSQLVAR }
423   constructor TIBXSQLVAR.Create(Parent: TIBXSQLDA; Query: TIBSQL);
# Line 364 | Line 432 | var
432    szBuff: PChar;
433    s_bhandle, d_bhandle: TISC_BLOB_HANDLE;
434    bSourceBlob, bDestBlob: Boolean;
435 <  iSegs, iMaxSeg, iSize: Long;
435 >  iSegs: Int64;
436 >  iMaxSeg: Int64;
437 >  iSize: Int64;
438    iBlobType: Short;
439   begin
440    szBuff := nil;
# Line 426 | Line 496 | begin
496          0, nil), True);
497        try
498          IBBlob.WriteBlob(@d_bhandle, szBuff, iSize);
499 +        isNull := false
500        finally
501          FSQL.Call(isc_close_blob(StatusVector, @d_bhandle), True);
502        end;
# Line 521 | Line 592 | begin
592        result := Value;
593   end;
594  
595 + function TIBXSQLVAR.GetAsBoolean: boolean;
596 + begin
597 +  result := false;
598 +  if not IsNull then
599 +  begin
600 +    if FXSQLVAR^.sqltype and (not 1) = SQL_BOOLEAN then
601 +      result := PByte(FXSQLVAR^.sqldata)^ = ISC_TRUE
602 +    else
603 +      IBError(ibxeInvalidDataConversion, [nil]);
604 +  end
605 + end;
606 +
607   function TIBXSQLVAR.GetAsCurrency: Currency;
608   begin
609    result := 0;
# Line 584 | Line 667 | end;
667   function TIBXSQLVAR.GetAsDateTime: TDateTime;
668   var
669    tm_date: TCTimeStructure;
670 +  msecs: word;
671   begin
672    result := 0;
673    if not IsNull then
# Line 609 | Line 693 | begin
693        SQL_TYPE_TIME: begin
694          isc_decode_sql_time(PISC_TIME(FXSQLVAR^.sqldata), @tm_date);
695          try
696 +          msecs :=  (PISC_TIME(FXSQLVAR^.sqldata)^ mod 10000) div 10;
697            result := EncodeTime(Word(tm_date.tm_hour), Word(tm_date.tm_min),
698 <                               Word(tm_date.tm_sec), 0)
698 >                               Word(tm_date.tm_sec), msecs)
699          except
700            on E: EConvertError do begin
701              IBError(ibxeInvalidDataConversion, [nil]);
# Line 622 | Line 707 | begin
707          try
708            result := EncodeDate(Word(tm_date.tm_year + 1900), Word(tm_date.tm_mon + 1),
709                                Word(tm_date.tm_mday));
710 +          msecs := (PISC_TIMESTAMP(FXSQLVAR^.sqldata)^.timestamp_time mod 10000) div 10;
711            if result >= 0 then
712              result := result + EncodeTime(Word(tm_date.tm_hour), Word(tm_date.tm_min),
713 <                                          Word(tm_date.tm_sec), 0)
713 >                                          Word(tm_date.tm_sec), msecs)
714            else
715              result := result - EncodeTime(Word(tm_date.tm_hour), Word(tm_date.tm_min),
716 <                                          Word(tm_date.tm_sec), 0)
716 >                                          Word(tm_date.tm_sec), msecs)
717          except
718            on E: EConvertError do begin
719              IBError(ibxeInvalidDataConversion, [nil]);
# Line 757 | Line 843 | begin
843          result := '(Array)'; {do not localize}
844        SQL_BLOB: begin
845          ss := TStringStream.Create('');
846 <        SaveToStream(ss);
847 <        result := ss.DataString;
848 <        ss.Free;
846 >        try
847 >          SaveToStream(ss);
848 >          result := ss.DataString;
849 >        finally
850 >          ss.Free;
851 >        end;
852        end;
853        SQL_TEXT, SQL_VARYING: begin
854          sz := FXSQLVAR^.sqldata;
# Line 826 | Line 915 | begin
915            result := AsDouble;
916        SQL_INT64:
917          if FXSQLVAR^.sqlscale = 0 then
918 <          IBError(ibxeInvalidDataConversion, [nil])
918 >          result := AsInt64
919          else if FXSQLVAR^.sqlscale >= (-4) then
920            result := AsCurrency
921          else
922            result := AsDouble;
923        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
924          result := AsDouble;
925 +      SQL_BOOLEAN:
926 +        result := AsBoolean;
927        else
928          IBError(ibxeInvalidDataConversion, [nil]);
929      end;
# Line 921 | Line 1012 | begin
1012    result := FXSQLVAR^.sqltype and (not 1);
1013   end;
1014  
1015 + procedure TIBXSQLVAR.SetAsBoolean(AValue: boolean);
1016 + var
1017 +  i: Integer;
1018 + begin
1019 +  if FUniqueName then
1020 +     xSetAsBoolean(AValue)
1021 +  else
1022 +  for i := 0 to FParent.FCount - 1 do
1023 +    if FParent[i].FName = FName then
1024 +       FParent[i].xSetAsBoolean(AValue);
1025 + end;
1026 +
1027 + procedure TIBXSQLVAR.xSetAsCurrency(Value: Currency);
1028 + begin
1029 +  if IsNullable then
1030 +    IsNull := False;
1031 +  FXSQLVAR^.sqltype := SQL_INT64 or (FXSQLVAR^.sqltype and 1);
1032 +  FXSQLVAR^.sqlscale := -4;
1033 +  FXSQLVAR^.sqllen := SizeOf(Int64);
1034 +  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1035 +  PCurrency(FXSQLVAR^.sqldata)^ := Value;
1036 +  FModified := True;
1037 + end;
1038 +
1039   procedure TIBXSQLVAR.SetAsCurrency(Value: Currency);
1040   var
926  xvar: TIBXSQLVAR;
1041    i: Integer;
1042   begin
1043    if FSQL.Database.SQLDialect < 3 then
1044      AsDouble := Value
1045    else
1046    begin
1047 <    if IsNullable then
1048 <      IsNull := False;
1047 >
1048 >    if FUniqueName then
1049 >       xSetAsCurrency(Value)
1050 >    else
1051      for i := 0 to FParent.FCount - 1 do
1052 <      if FParent.FNames[i] = FName then
1053 <      begin
938 <        xvar := FParent[i];
939 <        xvar.FXSQLVAR^.sqltype := SQL_INT64 or (xvar.FXSQLVAR^.sqltype and 1);
940 <        xvar.FXSQLVAR^.sqlscale := -4;
941 <        xvar.FXSQLVAR^.sqllen := SizeOf(Int64);
942 <        IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
943 <        PCurrency(xvar.FXSQLVAR^.sqldata)^ := Value;
944 <        xvar.FModified := True;
945 <      end;
1052 >      if FParent[i].FName = FName then
1053 >           FParent[i].xSetAsCurrency(Value);
1054    end;
1055   end;
1056  
1057 + procedure TIBXSQLVAR.xSetAsInt64(Value: Int64);
1058 + begin
1059 +  if IsNullable then
1060 +    IsNull := False;
1061 +
1062 +  FXSQLVAR^.sqltype := SQL_INT64 or (FXSQLVAR^.sqltype and 1);
1063 +  FXSQLVAR^.sqlscale := 0;
1064 +  FXSQLVAR^.sqllen := SizeOf(Int64);
1065 +  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1066 +  PInt64(FXSQLVAR^.sqldata)^ := Value;
1067 +  FModified := True;
1068 + end;
1069 +
1070   procedure TIBXSQLVAR.SetAsInt64(Value: Int64);
1071   var
1072    i: Integer;
1073 <  xvar: TIBXSQLVAR;
1073 > begin
1074 >  if FUniqueName then
1075 >     xSetAsInt64(Value)
1076 >  else
1077 >  for i := 0 to FParent.FCount - 1 do
1078 >    if FParent[i].FName = FName then
1079 >          FParent[i].xSetAsInt64(Value);
1080 > end;
1081 >
1082 > procedure TIBXSQLVAR.xSetAsDate(Value: TDateTime);
1083 > var
1084 >   tm_date: TCTimeStructure;
1085 >   Yr, Mn, Dy: Word;
1086   begin
1087    if IsNullable then
1088      IsNull := False;
1089 <  for i := 0 to FParent.FCount - 1 do
1090 <    if FParent.FNames[i] = FName then
1091 <    begin
1092 <      xvar := FParent[i];
1093 <      xvar.FXSQLVAR^.sqltype := SQL_INT64 or (xvar.FXSQLVAR^.sqltype and 1);
1094 <      xvar.FXSQLVAR^.sqlscale := 0;
1095 <      xvar.FXSQLVAR^.sqllen := SizeOf(Int64);
1096 <      IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1097 <      PInt64(xvar.FXSQLVAR^.sqldata)^ := Value;
1098 <      xvar.FModified := True;
1099 <    end;
1089 >
1090 >  FXSQLVAR^.sqltype := SQL_TYPE_DATE or (FXSQLVAR^.sqltype and 1);
1091 >  DecodeDate(Value, Yr, Mn, Dy);
1092 >  with tm_date do begin
1093 >    tm_sec := 0;
1094 >    tm_min := 0;
1095 >    tm_hour := 0;
1096 >    tm_mday := Dy;
1097 >    tm_mon := Mn - 1;
1098 >    tm_year := Yr - 1900;
1099 >  end;
1100 >  FXSQLVAR^.sqllen := SizeOf(ISC_DATE);
1101 >  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1102 >  isc_encode_sql_date(@tm_date, PISC_DATE(FXSQLVAR^.sqldata));
1103 >  FModified := True;
1104   end;
1105  
1106   procedure TIBXSQLVAR.SetAsDate(Value: TDateTime);
1107   var
1108    i: Integer;
972  tm_date: TCTimeStructure;
973  Yr, Mn, Dy: Word;
974  xvar: TIBXSQLVAR;
1109   begin
1110    if FSQL.Database.SQLDialect < 3 then
1111    begin
1112      AsDateTime := Value;
1113      exit;
1114    end;
1115 +
1116 +  if FUniqueName then
1117 +     xSetAsDate(Value)
1118 +  else
1119 +  for i := 0 to FParent.FCount - 1 do
1120 +    if FParent[i].FName = FName then
1121 +       FParent[i].xSetAsDate(Value);
1122 + end;
1123 +
1124 + procedure TIBXSQLVAR.xSetAsTime(Value: TDateTime);
1125 + var
1126 +  tm_date: TCTimeStructure;
1127 +  Hr, Mt, S, Ms: Word;
1128 + begin
1129    if IsNullable then
1130      IsNull := False;
1131 <  for i := 0 to FParent.FCount - 1 do
1132 <    if FParent.FNames[i] = FName then
1133 <    begin
1134 <      xvar := FParent[i];
1135 <      xvar.FXSQLVAR^.sqltype := SQL_TYPE_DATE or (xvar.FXSQLVAR^.sqltype and 1);
1136 <      DecodeDate(Value, Yr, Mn, Dy);
1137 <      with tm_date do begin
1138 <        tm_sec := 0;
1139 <        tm_min := 0;
1140 <        tm_hour := 0;
1141 <        tm_mday := Dy;
1142 <        tm_mon := Mn - 1;
1143 <        tm_year := Yr - 1900;
1144 <      end;
1145 <      xvar.FXSQLVAR^.sqllen := SizeOf(ISC_DATE);
1146 <      IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1147 <      isc_encode_sql_date(@tm_date, PISC_DATE(xvar.FXSQLVAR^.sqldata));
1000 <      xvar.FModified := True;
1001 <    end;
1131 >
1132 >  FXSQLVAR^.sqltype := SQL_TYPE_TIME or (FXSQLVAR^.sqltype and 1);
1133 >  DecodeTime(Value, Hr, Mt, S, Ms);
1134 >  with tm_date do begin
1135 >    tm_sec := S;
1136 >    tm_min := Mt;
1137 >    tm_hour := Hr;
1138 >    tm_mday := 0;
1139 >    tm_mon := 0;
1140 >    tm_year := 0;
1141 >  end;
1142 >  FXSQLVAR^.sqllen := SizeOf(ISC_TIME);
1143 >  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1144 >  isc_encode_sql_time(@tm_date, PISC_TIME(FXSQLVAR^.sqldata));
1145 >  if Ms > 0 then
1146 >    Inc(PISC_TIME(FXSQLVAR^.sqldata)^,Ms*10);
1147 >  FModified := True;
1148   end;
1149  
1150   procedure TIBXSQLVAR.SetAsTime(Value: TDateTime);
1151   var
1152    i: Integer;
1007  tm_date: TCTimeStructure;
1008  Hr, Mt, S, Ms: Word;
1009  xvar: TIBXSQLVAR;
1153   begin
1154    if FSQL.Database.SQLDialect < 3 then
1155    begin
1156      AsDateTime := Value;
1157      exit;
1158    end;
1159 <  if IsNullable then
1160 <    IsNull := False;
1159 >
1160 >  if FUniqueName then
1161 >     xSetAsTime(Value)
1162 >  else
1163    for i := 0 to FParent.FCount - 1 do
1164 <    if FParent.FNames[i] = FName then
1165 <    begin
1021 <      xvar := FParent[i];
1022 <      xvar.FXSQLVAR^.sqltype := SQL_TYPE_TIME or (xvar.FXSQLVAR^.sqltype and 1);
1023 <      DecodeTime(Value, Hr, Mt, S, Ms);
1024 <      with tm_date do begin
1025 <        tm_sec := S;
1026 <        tm_min := Mt;
1027 <        tm_hour := Hr;
1028 <        tm_mday := 0;
1029 <        tm_mon := 0;
1030 <        tm_year := 0;
1031 <      end;
1032 <      xvar.FXSQLVAR^.sqllen := SizeOf(ISC_TIME);
1033 <      IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1034 <      isc_encode_sql_time(@tm_date, PISC_TIME(xvar.FXSQLVAR^.sqldata));
1035 <      xvar.FModified := True;
1036 <    end;
1164 >    if FParent[i].FName = FName then
1165 >       FParent[i].xSetAsTime(Value);
1166   end;
1167  
1168 < procedure TIBXSQLVAR.SetAsDateTime(Value: TDateTime);
1168 > procedure TIBXSQLVAR.xSetAsDateTime(Value: TDateTime);
1169   var
1041  i: Integer;
1170    tm_date: TCTimeStructure;
1171    Yr, Mn, Dy, Hr, Mt, S, Ms: Word;
1044  xvar: TIBXSQLVAR;
1172   begin
1173    if IsNullable then
1174      IsNull := False;
1175 +
1176 +  FXSQLVAR^.sqltype := SQL_TIMESTAMP or (FXSQLVAR^.sqltype and 1);
1177 +  DecodeDate(Value, Yr, Mn, Dy);
1178 +  DecodeTime(Value, Hr, Mt, S, Ms);
1179 +  with tm_date do begin
1180 +    tm_sec := S;
1181 +    tm_min := Mt;
1182 +    tm_hour := Hr;
1183 +    tm_mday := Dy;
1184 +    tm_mon := Mn - 1;
1185 +    tm_year := Yr - 1900;
1186 +  end;
1187 +  FXSQLVAR^.sqllen := SizeOf(TISC_QUAD);
1188 +  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1189 +  isc_encode_date(@tm_date, PISC_QUAD(FXSQLVAR^.sqldata));
1190 +  if Ms > 0 then
1191 +    Inc(PISC_TIMESTAMP(FXSQLVAR^.sqldata)^.timestamp_time,Ms*10);
1192 +  FModified := True;
1193 + end;
1194 +
1195 + procedure TIBXSQLVAR.SetAsDateTime(Value: TDateTime);
1196 + var
1197 +  i: Integer;
1198 + begin
1199 +  if FUniqueName then
1200 +     xSetAsDateTime(value)
1201 +  else
1202    for i := 0 to FParent.FCount - 1 do
1203 <    if FParent.FNames[i] = FName then
1204 <    begin
1205 <      xvar := FParent[i];
1206 <      xvar.FXSQLVAR^.sqltype := SQL_TIMESTAMP or (xvar.FXSQLVAR^.sqltype and 1);
1207 <      DecodeDate(Value, Yr, Mn, Dy);
1208 <      DecodeTime(Value, Hr, Mt, S, Ms);
1209 <      with tm_date do begin
1210 <        tm_sec := S;
1211 <        tm_min := Mt;
1212 <        tm_hour := Hr;
1213 <        tm_mday := Dy;
1214 <        tm_mon := Mn - 1;
1215 <        tm_year := Yr - 1900;
1216 <      end;
1217 <      xvar.FXSQLVAR^.sqllen := SizeOf(TISC_QUAD);
1064 <      IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1065 <      isc_encode_date(@tm_date, PISC_QUAD(xvar.FXSQLVAR^.sqldata));
1066 <      xvar.FModified := True;
1067 <    end;
1203 >    if FParent[i].FName = FName then
1204 >       FParent[i].xSetAsDateTime(Value);
1205 > end;
1206 >
1207 > procedure TIBXSQLVAR.xSetAsDouble(Value: Double);
1208 > begin
1209 >  if IsNullable then
1210 >    IsNull := False;
1211 >
1212 >  FXSQLVAR^.sqltype := SQL_DOUBLE or (FXSQLVAR^.sqltype and 1);
1213 >  FXSQLVAR^.sqllen := SizeOf(Double);
1214 >  FXSQLVAR^.sqlscale := 0;
1215 >  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1216 >  PDouble(FXSQLVAR^.sqldata)^ := Value;
1217 >  FModified := True;
1218   end;
1219  
1220   procedure TIBXSQLVAR.SetAsDouble(Value: Double);
1221   var
1222    i: Integer;
1223 <  xvar: TIBXSQLVAR;
1223 > begin
1224 >  if FUniqueName then
1225 >     xSetAsDouble(Value)
1226 >  else
1227 >  for i := 0 to FParent.FCount - 1 do
1228 >    if FParent[i].FName = FName then
1229 >       FParent[i].xSetAsDouble(Value);
1230 > end;
1231 >
1232 > procedure TIBXSQLVAR.xSetAsFloat(Value: Float);
1233   begin
1234    if IsNullable then
1235      IsNull := False;
1236 <  for i := 0 to FParent.FCount - 1 do
1237 <    if FParent.FNames[i] = FName then
1238 <    begin
1239 <      xvar := FParent[i];
1240 <      xvar.FXSQLVAR^.sqltype := SQL_DOUBLE or (xvar.FXSQLVAR^.sqltype and 1);
1241 <      xvar.FXSQLVAR^.sqllen := SizeOf(Double);
1242 <      xvar.FXSQLVAR^.sqlscale := 0;
1084 <      IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1085 <      PDouble(xvar.FXSQLVAR^.sqldata)^ := Value;
1086 <      xvar.FModified := True;
1087 <    end;
1236 >
1237 >  FXSQLVAR^.sqltype := SQL_FLOAT or (FXSQLVAR^.sqltype and 1);
1238 >  FXSQLVAR^.sqllen := SizeOf(Float);
1239 >  FXSQLVAR^.sqlscale := 0;
1240 >  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1241 >  PSingle(FXSQLVAR^.sqldata)^ := Value;
1242 >  FModified := True;
1243   end;
1244  
1245   procedure TIBXSQLVAR.SetAsFloat(Value: Float);
1246   var
1247    i: Integer;
1248 <  xvar: TIBXSQLVAR;
1248 > begin
1249 >  if FUniqueName then
1250 >     xSetAsFloat(Value)
1251 >  else
1252 >  for i := 0 to FParent.FCount - 1 do
1253 >    if FParent[i].FName = FName then
1254 >       FParent[i].xSetAsFloat(Value);
1255 > end;
1256 >
1257 > procedure TIBXSQLVAR.xSetAsLong(Value: Long);
1258   begin
1259    if IsNullable then
1260      IsNull := False;
1261 <  for i := 0 to FParent.FCount - 1 do
1262 <    if FParent.FNames[i] = FName then
1263 <    begin
1264 <      xvar := FParent[i];
1265 <      xvar.FXSQLVAR^.sqltype := SQL_FLOAT or (xvar.FXSQLVAR^.sqltype and 1);
1266 <      xvar.FXSQLVAR^.sqllen := SizeOf(Float);
1267 <      xvar.FXSQLVAR^.sqlscale := 0;
1104 <      IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1105 <      PSingle(xvar.FXSQLVAR^.sqldata)^ := Value;
1106 <      xvar.FModified := True;
1107 <    end;
1261 >
1262 >  FXSQLVAR^.sqltype := SQL_LONG or (FXSQLVAR^.sqltype and 1);
1263 >  FXSQLVAR^.sqllen := SizeOf(Long);
1264 >  FXSQLVAR^.sqlscale := 0;
1265 >  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1266 >  PLong(FXSQLVAR^.sqldata)^ := Value;
1267 >  FModified := True;
1268   end;
1269  
1270   procedure TIBXSQLVAR.SetAsLong(Value: Long);
1271   var
1272    i: Integer;
1113  xvar: TIBXSQLVAR;
1273   begin
1274 <  if IsNullable then
1275 <    IsNull := False;
1274 >  if FUniqueName then
1275 >     xSetAsLong(Value)
1276 >  else
1277    for i := 0 to FParent.FCount - 1 do
1278 <    if FParent.FNames[i] = FName then
1279 <    begin
1120 <      xvar := FParent[i];
1121 <      xvar.FXSQLVAR^.sqltype := SQL_LONG or (xvar.FXSQLVAR^.sqltype and 1);
1122 <      xvar.FXSQLVAR^.sqllen := SizeOf(Long);
1123 <      xvar.FXSQLVAR^.sqlscale := 0;
1124 <      IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1125 <      PLong(xvar.FXSQLVAR^.sqldata)^ := Value;
1126 <      xvar.FModified := True;
1127 <    end;
1278 >    if FParent[i].FName = FName then
1279 >       FParent[i].xSetAsLong(Value);
1280   end;
1281  
1282 < procedure TIBXSQLVAR.SetAsPointer(Value: Pointer);
1131 < var
1132 <  i: Integer;
1133 <  xvar: TIBXSQLVAR;
1282 > procedure TIBXSQLVAR.xSetAsPointer(Value: Pointer);
1283   begin
1284    if IsNullable and (Value = nil) then
1285      IsNull := True
1286    else begin
1287      IsNull := False;
1288 <    for i := 0 to FParent.FCount - 1 do
1289 <      if FParent.FNames[i] = FName then
1141 <      begin
1142 <        xvar := FParent[i];
1143 <        xvar.FXSQLVAR^.sqltype := SQL_TEXT or (FXSQLVAR^.sqltype and 1);
1144 <        Move(Value^, xvar.FXSQLVAR^.sqldata^, xvar.FXSQLVAR^.sqllen);
1145 <        xvar.FModified := True;
1146 <      end;
1288 >    FXSQLVAR^.sqltype := SQL_TEXT or (FXSQLVAR^.sqltype and 1);
1289 >    Move(Value^, FXSQLVAR^.sqldata^, FXSQLVAR^.sqllen);
1290    end;
1291 +  FModified := True;
1292 + end;
1293 +
1294 + procedure TIBXSQLVAR.SetAsPointer(Value: Pointer);
1295 + var
1296 +  i: Integer;
1297 + begin
1298 +    if FUniqueName then
1299 +       xSetAsPointer(Value)
1300 +    else
1301 +    for i := 0 to FParent.FCount - 1 do
1302 +      if FParent[i].FName = FName then
1303 +         FParent[i].xSetAsPointer(Value);
1304 + end;
1305 +
1306 + procedure TIBXSQLVAR.xSetAsQuad(Value: TISC_QUAD);
1307 + begin
1308 +  if IsNullable then
1309 +      IsNull := False;
1310 +  if (FXSQLVAR^.sqltype and (not 1) <> SQL_BLOB) and
1311 +     (FXSQLVAR^.sqltype and (not 1) <> SQL_ARRAY) then
1312 +    IBError(ibxeInvalidDataConversion, [nil]);
1313 +  FXSQLVAR^.sqllen := SizeOf(TISC_QUAD);
1314 +  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1315 +  PISC_QUAD(FXSQLVAR^.sqldata)^ := Value;
1316 +  FModified := True;
1317   end;
1318  
1319   procedure TIBXSQLVAR.SetAsQuad(Value: TISC_QUAD);
1320   var
1321    i: Integer;
1322 <  xvar: TIBXSQLVAR;
1322 > begin
1323 >  if FUniqueName then
1324 >     xSetAsQuad(Value)
1325 >  else
1326 >  for i := 0 to FParent.FCount - 1 do
1327 >    if FParent[i].FName = FName then
1328 >       FParent[i].xSetAsQuad(Value);
1329 > end;
1330 >
1331 > procedure TIBXSQLVAR.xSetAsShort(Value: Short);
1332   begin
1333    if IsNullable then
1334      IsNull := False;
1335 <  for i := 0 to FParent.FCount - 1 do
1336 <    if FParent.FNames[i] = FName then
1337 <    begin
1338 <      xvar := FParent[i];
1339 <      if (xvar.FXSQLVAR^.sqltype and (not 1) <> SQL_BLOB) and
1340 <         (xvar.FXSQLVAR^.sqltype and (not 1) <> SQL_ARRAY) then
1341 <        IBError(ibxeInvalidDataConversion, [nil]);
1164 <      xvar.FXSQLVAR^.sqllen := SizeOf(TISC_QUAD);
1165 <      IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1166 <      PISC_QUAD(xvar.FXSQLVAR^.sqldata)^ := Value;
1167 <      xvar.FModified := True;
1168 <    end;
1335 >
1336 >  FXSQLVAR^.sqltype := SQL_SHORT or (FXSQLVAR^.sqltype and 1);
1337 >  FXSQLVAR^.sqllen := SizeOf(Short);
1338 >  FXSQLVAR^.sqlscale := 0;
1339 >  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1340 >  PShort(FXSQLVAR^.sqldata)^ := Value;
1341 >  FModified := True;
1342   end;
1343  
1344   procedure TIBXSQLVAR.SetAsShort(Value: Short);
1345   var
1346    i: Integer;
1174  xvar: TIBXSQLVAR;
1347   begin
1348 <  if IsNullable then
1349 <    IsNull := False;
1348 >  if FUniqueName then
1349 >     xSetAsShort(Value)
1350 >  else
1351    for i := 0 to FParent.FCount - 1 do
1352 <    if FParent.FNames[i] = FName then
1353 <    begin
1181 <      xvar := FParent[i];
1182 <      xvar.FXSQLVAR^.sqltype := SQL_SHORT or (xvar.FXSQLVAR^.sqltype and 1);
1183 <      xvar.FXSQLVAR^.sqllen := SizeOf(Short);
1184 <      xvar.FXSQLVAR^.sqlscale := 0;
1185 <      IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen);
1186 <      PShort(xvar.FXSQLVAR^.sqldata)^ := Value;
1187 <      xvar.FModified := True;
1188 <    end;
1352 >    if FParent[i].FName = FName then
1353 >       FParent[i].xSetAsShort(Value);
1354   end;
1355  
1356 < procedure TIBXSQLVAR.SetAsString(Value: String);
1356 > procedure TIBXSQLVAR.xSetAsString(Value: String);
1357   var
1358 <  stype: Integer;
1359 <  ss: TStringStream;
1358 >   stype: Integer;
1359 >   ss: TStringStream;
1360  
1361 <  procedure SetStringValue;
1362 <  var
1363 <    i: Integer;
1364 <    xvar: TIBXSQLVAR;
1365 <  begin
1366 <    for i := 0 to FParent.FCount - 1 do
1367 <      if FParent.FNames[i] = FName then
1368 <      begin
1369 <        xvar := FParent[i];
1370 <        if (xvar.FXSQLVAR^.sqlname = 'DB_KEY') or {do not localize}
1371 <           (xvar.FXSQLVAR^.sqlname = 'RDB$DB_KEY') then {do not localize}
1372 <          Move(Value[1], xvar.FXSQLVAR^.sqldata^, xvar.FXSQLVAR^.sqllen)
1373 <        else begin
1209 <          xvar.FXSQLVAR^.sqltype := SQL_TEXT or (FXSQLVAR^.sqltype and 1);
1210 <          xvar.FXSQLVAR^.sqllen := Length(Value);
1211 <          IBAlloc(xvar.FXSQLVAR^.sqldata, 0, xvar.FXSQLVAR^.sqllen + 1);
1212 <          if (Length(Value) > 0) then
1213 <            Move(Value[1], xvar.FXSQLVAR^.sqldata^, xvar.FXSQLVAR^.sqllen);
1214 <        end;
1215 <        xvar.FModified := True;
1361 >   procedure SetStringValue;
1362 >   var
1363 >      i: Integer;
1364 >   begin
1365 >      if (FXSQLVAR^.sqlname = 'DB_KEY') or {do not localize}
1366 >         (FXSQLVAR^.sqlname = 'RDB$DB_KEY') then {do not localize}
1367 >        Move(Value[1], FXSQLVAR^.sqldata^, FXSQLVAR^.sqllen)
1368 >      else begin
1369 >        FXSQLVAR^.sqltype := SQL_TEXT or (FXSQLVAR^.sqltype and 1);
1370 >        FXSQLVAR^.sqllen := Length(Value);
1371 >        IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen + 1);
1372 >        if (Length(Value) > 0) then
1373 >          Move(Value[1], FXSQLVAR^.sqldata^, FXSQLVAR^.sqllen);
1374        end;
1375 <  end;
1375 >      FModified := True;
1376 >   end;
1377  
1378   begin
1379    if IsNullable then
1380      IsNull := False;
1381 +
1382    stype := FXSQLVAR^.sqltype and (not 1);
1383    if (stype = SQL_TEXT) or (stype = SQL_VARYING) then
1384      SetStringValue
# Line 1236 | Line 1396 | begin
1396        IsNull := True
1397      else if (stype = SQL_TIMESTAMP) or (stype = SQL_TYPE_DATE) or
1398        (stype = SQL_TYPE_TIME) then
1399 <      SetAsDateTime(StrToDateTime(Value))
1399 >      xSetAsDateTime(StrToDateTime(Value))
1400      else
1401        SetStringValue;
1402    end;
1403   end;
1404  
1405 < procedure TIBXSQLVAR.SetAsVariant(Value: Variant);
1405 > procedure TIBXSQLVAR.SetAsString(Value: String);
1406 > var
1407 >   i: integer;
1408 > begin
1409 >  if FUniqueName then
1410 >     xSetAsString(Value)
1411 >  else
1412 >  for i := 0 to FParent.FCount - 1 do
1413 >    if FParent[i].FName = FName then
1414 >       FParent[i].xSetAsString(Value);
1415 > end;
1416 >
1417 > procedure TIBXSQLVAR.xSetAsVariant(Value: Variant);
1418   begin
1419    if VarIsNull(Value) then
1420      IsNull := True
1421    else case VarType(Value) of
1422      varEmpty, varNull:
1423        IsNull := True;
1424 <    varSmallint, varInteger, varByte:
1424 >    varSmallint, varInteger, varByte,
1425 >      varWord, varShortInt:
1426        AsLong := Value;
1427 +    varInt64:
1428 +      AsInt64 := Value;
1429      varSingle, varDouble:
1430        AsDouble := Value;
1431      varCurrency:
1432        AsCurrency := Value;
1433      varBoolean:
1434 <      if Value then
1260 <        AsLong := ISC_TRUE
1261 <      else
1262 <        AsLong := ISC_FALSE;
1434 >      AsBoolean := Value;
1435      varDate:
1436        AsDateTime := Value;
1437      varOleStr, varString:
# Line 1271 | Line 1443 | begin
1443    end;
1444   end;
1445  
1446 < procedure TIBXSQLVAR.SetAsXSQLVAR(Value: PXSQLVAR);
1446 > procedure TIBXSQLVAR.SetAsVariant(Value: Variant);
1447 > var
1448 >   i: integer;
1449 > begin
1450 >  if FUniqueName then
1451 >     xSetAsVariant(Value)
1452 >  else
1453 >  for i := 0 to FParent.FCount - 1 do
1454 >    if FParent[i].FName = FName then
1455 >       FParent[i].xSetAsVariant(Value);
1456 > end;
1457 >
1458 > procedure TIBXSQLVAR.xSetAsXSQLVAR(Value: PXSQLVAR);
1459   var
1276  i: Integer;
1277  xvar: TIBXSQLVAR;
1460    sqlind: PShort;
1461    sqldata: PChar;
1462    local_sqllen: Integer;
1463   begin
1464 <  for i := 0 to FParent.FCount - 1 do
1465 <    if FParent.FNames[i] = FName then
1466 <    begin
1467 <      xvar := FParent[i];
1468 <      sqlind := xvar.FXSQLVAR^.sqlind;
1469 <      sqldata := xvar.FXSQLVAR^.sqldata;
1470 <      Move(Value^, xvar.FXSQLVAR^, SizeOf(TXSQLVAR));
1471 <      xvar.FXSQLVAR^.sqlind := sqlind;
1472 <      xvar.FXSQLVAR^.sqldata := sqldata;
1473 <      if (Value^.sqltype and 1 = 1) then
1474 <      begin
1475 <        if (xvar.FXSQLVAR^.sqlind = nil) then
1476 <          IBAlloc(xvar.FXSQLVAR^.sqlind, 0, SizeOf(Short));
1477 <        xvar.FXSQLVAR^.sqlind^ := Value^.sqlind^;
1478 <      end
1479 <      else
1480 <        if (xvar.FXSQLVAR^.sqlind <> nil) then
1481 <          ReallocMem(xvar.FXSQLVAR^.sqlind, 0);
1482 <      if ((xvar.FXSQLVAR^.sqltype and (not 1)) = SQL_VARYING) then
1483 <        local_sqllen := xvar.FXSQLVAR^.sqllen + 2
1484 <      else
1485 <        local_sqllen := xvar.FXSQLVAR^.sqllen;
1304 <      FXSQLVAR^.sqlscale := Value^.sqlscale;
1305 <      IBAlloc(xvar.FXSQLVAR^.sqldata, 0, local_sqllen);
1306 <      Move(Value^.sqldata[0], xvar.FXSQLVAR^.sqldata[0], local_sqllen);
1307 <      xvar.FModified := True;
1308 <    end;
1464 >  sqlind := FXSQLVAR^.sqlind;
1465 >  sqldata := FXSQLVAR^.sqldata;
1466 >  Move(Value^, FXSQLVAR^, SizeOf(TXSQLVAR));
1467 >  FXSQLVAR^.sqlind := sqlind;
1468 >  FXSQLVAR^.sqldata := sqldata;
1469 >  if (Value^.sqltype and 1 = 1) then
1470 >  begin
1471 >    if (FXSQLVAR^.sqlind = nil) then
1472 >      IBAlloc(FXSQLVAR^.sqlind, 0, SizeOf(Short));
1473 >    FXSQLVAR^.sqlind^ := Value^.sqlind^;
1474 >  end
1475 >  else
1476 >    if (FXSQLVAR^.sqlind <> nil) then
1477 >      ReallocMem(FXSQLVAR^.sqlind, 0);
1478 >  if ((FXSQLVAR^.sqltype and (not 1)) = SQL_VARYING) then
1479 >    local_sqllen := FXSQLVAR^.sqllen + 2
1480 >  else
1481 >    local_sqllen := FXSQLVAR^.sqllen;
1482 >  FXSQLVAR^.sqlscale := Value^.sqlscale;
1483 >  IBAlloc(FXSQLVAR^.sqldata, 0, local_sqllen);
1484 >  Move(Value^.sqldata[0], FXSQLVAR^.sqldata[0], local_sqllen);
1485 >  FModified := True;
1486   end;
1487  
1488 < procedure TIBXSQLVAR.SetIsNull(Value: Boolean);
1488 > procedure TIBXSQLVAR.SetAsXSQLVAR(Value: PXSQLVAR);
1489   var
1490    i: Integer;
1491 <  xvar: TIBXSQLVAR;
1491 > begin
1492 >  if FUniqueName then
1493 >     xSetAsXSQLVAR(Value)
1494 >  else
1495 >  for i := 0 to FParent.FCount - 1 do
1496 >    if FParent[i].FName = FName then
1497 >       FParent[i].xSetAsXSQLVAR(Value);
1498 > end;
1499 >
1500 > procedure TIBXSQLVAR.xSetIsNull(Value: Boolean);
1501   begin
1502    if Value then
1503    begin
1504      if not IsNullable then
1505        IsNullable := True;
1506 <    for i := 0 to FParent.FCount - 1 do
1507 <      if FParent.FNames[i] = FName then
1508 <      begin
1509 <        xvar := FParent[i];
1324 <        if Assigned(xvar.FXSQLVAR^.sqlind) then
1325 <          xvar.FXSQLVAR^.sqlind^ := -1;
1326 <        xvar.FModified := True;
1327 <      end;
1506 >
1507 >    if Assigned(FXSQLVAR^.sqlind) then
1508 >      FXSQLVAR^.sqlind^ := -1;
1509 >    FModified := True;
1510    end
1511    else
1512      if ((not Value) and IsNullable) then
1513      begin
1514 <      for i := 0 to FParent.FCount - 1 do
1515 <        if FParent.FNames[i] = FName then
1516 <        begin
1335 <          xvar := FParent[i];
1336 <          if Assigned(xvar.FXSQLVAR^.sqlind) then
1337 <            xvar.FXSQLVAR^.sqlind^ := 0;
1338 <          xvar.FModified := True;
1339 <        end;
1514 >      if Assigned(FXSQLVAR^.sqlind) then
1515 >        FXSQLVAR^.sqlind^ := 0;
1516 >      FModified := True;
1517      end;
1518   end;
1519  
1520 < procedure TIBXSQLVAR.SetIsNullable(Value: Boolean);
1520 > procedure TIBXSQLVAR.SetIsNull(Value: Boolean);
1521   var
1522    i: Integer;
1346  xvar: TIBXSQLVAR;
1523   begin
1524 +  if FUniqueName then
1525 +     xSetIsNull(Value)
1526 +  else
1527    for i := 0 to FParent.FCount - 1 do
1528 <    if FParent.FNames[i] = FName then
1528 >    if FParent[i].FName = FName then
1529 >       FParent[i].xSetIsNull(Value);
1530 > end;
1531 >
1532 > procedure TIBXSQLVAR.xSetIsNullable(Value: Boolean);
1533 > begin
1534 >  if (Value <> IsNullable) then
1535 >  begin
1536 >    if Value then
1537      begin
1538 <      xvar := FParent[i];
1539 <      if (Value <> IsNullable) then
1540 <      begin
1541 <        if Value then
1542 <        begin
1543 <          xvar.FXSQLVAR^.sqltype := xvar.FXSQLVAR^.sqltype or 1;
1544 <          IBAlloc(xvar.FXSQLVAR^.sqlind, 0, SizeOf(Short));
1358 <        end
1359 <        else
1360 <        begin
1361 <          xvar.FXSQLVAR^.sqltype := xvar.FXSQLVAR^.sqltype and (not 1);
1362 <          ReallocMem(xvar.FXSQLVAR^.sqlind, 0);
1363 <        end;
1364 <      end;
1538 >      FXSQLVAR^.sqltype := FXSQLVAR^.sqltype or 1;
1539 >      IBAlloc(FXSQLVAR^.sqlind, 0, SizeOf(Short));
1540 >    end
1541 >    else
1542 >    begin
1543 >      FXSQLVAR^.sqltype := FXSQLVAR^.sqltype and (not 1);
1544 >      ReallocMem(FXSQLVAR^.sqlind, 0);
1545      end;
1546 +  end;
1547 + end;
1548 +
1549 + procedure TIBXSQLVAR.SetIsNullable(Value: Boolean);
1550 + var
1551 +  i: Integer;
1552 + begin
1553 +  if FUniqueName then
1554 +     xSetIsNullable(Value)
1555 +  else
1556 +  for i := 0 to FParent.FCount - 1 do
1557 +    if FParent[i].FName = FName then
1558 +       FParent[i].xSetIsNullable(Value);
1559 + end;
1560 +
1561 + procedure TIBXSQLVAR.xSetAsBoolean(AValue: boolean);
1562 + begin
1563 +  if IsNullable then
1564 +    IsNull := False;
1565 +
1566 +  FXSQLVAR^.sqltype := SQL_BOOLEAN;
1567 +  FXSQLVAR^.sqllen := 1;
1568 +  FXSQLVAR^.sqlscale := 0;
1569 +  IBAlloc(FXSQLVAR^.sqldata, 0, FXSQLVAR^.sqllen);
1570 +  if AValue then
1571 +    PByte(FXSQLVAR^.sqldata)^ := ISC_TRUE
1572 +  else
1573 +    PByte(FXSQLVAR^.sqldata)^ := ISC_FALSE;
1574 +  FModified := True;
1575   end;
1576  
1577 + procedure TIBXSQLVAR.Clear;
1578 + begin
1579 +  IsNull := true;
1580 + end;
1581 +
1582 +
1583   { TIBXSQLDA }
1584 < constructor TIBXSQLDA.Create(Query: TIBSQL);
1584 > constructor TIBXSQLDA.Create(Query: TIBSQL; sqldaType: TIBXSQLDAType);
1585   begin
1586    inherited Create;
1587    FSQL := Query;
1373  FNames := TStringList.Create;
1588    FSize := 0;
1589    FUniqueRelationName := '';
1590 +  FInputSQLDA := sqldaType = daInput;
1591   end;
1592  
1593   destructor TIBXSQLDA.Destroy;
1594   var
1595    i: Integer;
1596   begin
1382  FNames.Free;
1597    if FXSQLDA <> nil then
1598    begin
1599      for i := 0 to FSize - 1 do
# Line 1395 | Line 1609 | begin
1609    inherited Destroy;
1610   end;
1611  
1612 < procedure TIBXSQLDA.AddName(FieldName: String; Idx: Integer);
1612 >    procedure TIBXSQLDA.SetParamName(FieldName: String; Idx: Integer;
1613 >    UniqueName: boolean);
1614   var
1615 <  fn: String;
1615 >  fn: string;
1616   begin
1617 <  fn := FormatIdentifierValue(FSQL.Database.SQLDialect, FieldName);
1618 <  while FNames.Count <= Idx do
1619 <    FNames.Add('');
1620 <  FNames[Idx] := fn;
1621 <  FXSQLVARs[Idx].FName := fn;
1617 >  {$ifdef UseCaseSensitiveParamName}
1618 >  FXSQLVARs[Idx].FName := AnsiUpperCase(FieldName);
1619 >  {$else}
1620 >  FXSQLVARs[Idx].FName := FieldName;
1621 >  {$endif}
1622    FXSQLVARs[Idx].FIndex := Idx;
1623 +  FXSQLVARs[Idx].FUniqueName :=  UniqueName
1624   end;
1625  
1626   function TIBXSQLDA.GetModified: Boolean;
# Line 1420 | Line 1636 | begin
1636      end;
1637   end;
1638  
1423 function TIBXSQLDA.GetNames: String;
1424 begin
1425  result := FNames.Text;
1426 end;
1427
1639   function TIBXSQLDA.GetRecordSize: Integer;
1640   begin
1641    result := SizeOf(TIBXSQLDA) + XSQLDA_LENGTH(FSize);
# Line 1452 | Line 1663 | end;
1663   function TIBXSQLDA.GetXSQLVARByName(Idx: String): TIBXSQLVAR;
1664   var
1665    s: String;
1666 <  i, Cnt: Integer;
1666 >  i: Integer;
1667   begin
1668 <  s := FormatIdentifierValue(FSQL.Database.SQLDialect, Idx);
1669 <  i := 0;
1670 <  Cnt := FNames.Count;
1671 <  while (i < Cnt) and (FNames[i] <> s) do Inc(i);
1672 <  if i = Cnt then
1673 <    result := nil
1674 <  else
1675 <    result := GetXSQLVAR(i);
1668 >  {$ifdef ALLOWDIALECT3PARAMNAMES}
1669 >  s := FormatIdentifierValueNC(FSQL.Database.SQLDialect, Idx);
1670 >  {$else}
1671 >  {$ifdef UseCaseSensitiveParamName}
1672 >   s := AnsiUpperCase(Idx);
1673 >  {$else}
1674 >   s := Idx;
1675 >  {$endif}
1676 >  {$endif}
1677 >  for i := 0 to FCount - 1 do
1678 >    if Vars[i].FName = s then
1679 >    begin
1680 >         Result := FXSQLVARs[i];
1681 >         Exit;
1682 >    end;
1683 >  Result := nil;
1684   end;
1685  
1686   procedure TIBXSQLDA.Initialize;
1687 +
1688 +    function VarByName(idx: string; limit: integer): TIBXSQLVAR;
1689 +    var
1690 +       k: integer;
1691 +    begin
1692 +         for k := 0 to limit do
1693 +             if FXSQLVARs[k].FName = idx then
1694 +             begin
1695 +                  Result := FXSQLVARs[k];
1696 +                  Exit;
1697 +             end;
1698 +         Result := nil;
1699 +    end;
1700 +
1701   var
1702    i, j, j_len: Integer;
1470  NamesWereEmpty: Boolean;
1703    st: String;
1704    bUnique: Boolean;
1705 +  sBaseName: string;
1706   begin
1707    bUnique := True;
1475  NamesWereEmpty := (FNames.Count = 0);
1708    if FXSQLDA <> nil then
1709    begin
1710      for i := 0 to FCount - 1 do
1711      begin
1712        with FXSQLVARs[i].Data^ do
1713        begin
1714 +
1715 +        {First get the unique relation name, if any}
1716 +
1717          if bUnique and (strpas(relname) <> '') then
1718          begin
1719            if FUniqueRelationName = '' then
# Line 1490 | Line 1725 | begin
1725                bUnique := False;
1726              end;
1727          end;
1728 <        if NamesWereEmpty then
1728 >
1729 >        {If an output SQLDA then copy the aliasnames to the FName list. Ensure
1730 >         that they are all upper case only and disambiguated.
1731 >        }
1732 >
1733 >        if not FInputSQLDA then
1734          begin
1735 <          st := strpas(aliasname);
1735 >          st := Space2Underscore(AnsiUppercase(strpas(aliasname)));
1736            if st = '' then
1737            begin
1738 <            st := 'F_'; {do not localize}
1738 >            sBaseName := 'F_'; {do not localize}
1739              aliasname_length := 2;
1740              j := 1; j_len := 1;
1741 <            StrPCopy(aliasname, st + IntToStr(j));
1741 >            st := sBaseName + IntToStr(j);
1742            end
1743            else
1744            begin
1505            StrPCopy(aliasname, st);
1745              j := 0; j_len := 0;
1746 +            sBaseName := st;
1747            end;
1748 <          while GetXSQLVARByName(strpas(aliasname)) <> nil do
1748 >
1749 >          {Look for other columns with the same name and make unique}
1750 >
1751 >          while VarByName(st,i-1) <> nil do
1752            begin
1753 <            Inc(j); j_len := Length(IntToStr(j));
1754 <            if j_len + aliasname_length > 31 then
1755 <              StrPCopy(aliasname,
1756 <                       Copy(st, 1, 31 - j_len) +
1757 <                       IntToStr(j))
1758 <            else
1516 <              StrPCopy(aliasname, st + IntToStr(j));
1753 >               Inc(j);
1754 >               j_len := Length(IntToStr(j));
1755 >               if j_len + Length(sBaseName) > 31 then
1756 >                  st := Copy(sBaseName, 1, 31 - j_len) + IntToStr(j)
1757 >               else
1758 >                  st := sBaseName + IntToStr(j);
1759            end;
1760 <          Inc(aliasname_length, j_len);
1761 <          AddName(strpas(aliasname), i);
1760 >
1761 >          FXSQLVARs[i].FName := st;
1762          end;
1763 +
1764 +        {Finally initialise the XSQLVAR}
1765 +
1766 +        FXSQLVARs[i].FIndex := i;
1767 +
1768          case sqltype and (not 1) of
1769            SQL_TEXT, SQL_TYPE_DATE, SQL_TYPE_TIME, SQL_TIMESTAMP,
1770 <          SQL_BLOB, SQL_ARRAY, SQL_QUAD, SQL_SHORT,
1770 >          SQL_BLOB, SQL_ARRAY, SQL_QUAD, SQL_SHORT, SQL_BOOLEAN,
1771            SQL_LONG, SQL_INT64, SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: begin
1772              if (sqllen = 0) then
1773                { Make sure you get a valid pointer anyway
# Line 1550 | Line 1797 | var
1797    i, OldSize: Integer;
1798    p : PXSQLVAR;
1799   begin
1553  FNames.Clear;
1800    FCount := Value;
1801    if FCount = 0 then
1802      FUniqueRelationName := ''
# Line 1587 | Line 1833 | end;
1833  
1834   destructor TIBOutputDelimitedFile.Destroy;
1835   begin
1836 < {$IFDEF LINUX}
1836 > {$IFDEF UNIX}
1837    if FHandle <> -1 then
1838       fpclose(FHandle);
1839   {$ELSE}
# Line 1603 | Line 1849 | end;
1849   procedure TIBOutputDelimitedFile.ReadyFile;
1850   var
1851    i: Integer;
1852 <  {$IFDEF LINUX}
1852 >  {$IFDEF UNIX}
1853    BytesWritten: cint;
1854    {$ELSE}
1855    BytesWritten: DWORD;
# Line 1614 | Line 1860 | begin
1860      FColDelimiter := TAB;
1861    if FRowDelimiter = '' then
1862      FRowDelimiter := CRLF;
1863 <  {$IFDEF LINUX}
1863 >  {$IFDEF UNIX}
1864    FHandle := FpOpen(Filename,O_WrOnly or O_Creat);
1865    {$ELSE}
1866    FHandle := CreateFile(PChar(Filename), GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
# Line 1630 | Line 1876 | begin
1876        else
1877          st := st + FColDelimiter + strpas(Columns[i].Data^.aliasname);
1878      st := st + FRowDelimiter;
1879 <    {$IFDEF LINUX}
1879 >    {$IFDEF UNIX}
1880      if FHandle <> -1 then
1881         BytesWritten := FpWrite(FHandle,st[1],Length(st));
1882      if BytesWritten = -1 then
1883         raise Exception.Create('File Write Error');
1884      {$ELSE}
1885 <    WriteFile(FHandle, PChar(st[1]), Length(st), BytesWritten, nil);
1885 >    WriteFile(FHandle, st[1], Length(st), BytesWritten, nil);
1886      {$ENDIF}
1887    end;
1888   end;
# Line 1644 | Line 1890 | end;
1890   function TIBOutputDelimitedFile.WriteColumns: Boolean;
1891   var
1892    i: Integer;
1893 <  {$IFDEF LINUX}
1893 >  {$IFDEF UNIX}
1894    BytesWritten: cint;
1895    {$ELSE}
1896    BytesWritten: DWORD;
# Line 1652 | Line 1898 | var
1898    st: string;
1899   begin
1900    result := False;
1901 <  {$IFDEF LINUX}
1901 >  {$IFDEF UNIX}
1902    if FHandle <> -1 then
1903    {$ELSE}
1904    if FHandle <> 0 then
# Line 1666 | Line 1912 | begin
1912        st := st + StripString(Columns[i].AsString, FColDelimiter + FRowDelimiter);
1913      end;
1914      st := st + FRowDelimiter;
1915 <  {$IFDEF LINUX}
1915 >  {$IFDEF UNIX}
1916      BytesWritten := FpWrite(FHandle,st[1],Length(st));
1917    {$ELSE}
1918      WriteFile(FHandle, st[1], Length(st), BytesWritten, nil);
# Line 1783 | Line 2029 | end;
2029   { TIBOutputRawFile }
2030   destructor TIBOutputRawFile.Destroy;
2031   begin
2032 < {$IFDEF LINUX}
2032 > {$IFDEF UNIX}
2033    if FHandle <> -1 then
2034       fpclose(FHandle);
2035   {$ELSE}
# Line 1798 | Line 2044 | end;
2044  
2045   procedure TIBOutputRawFile.ReadyFile;
2046   begin
2047 <  {$IFDEF LINUX}
2047 >  {$IFDEF UNIX}
2048    FHandle := FpOpen(Filename,O_WrOnly or O_Creat);
2049    {$ELSE}
2050    FHandle := CreateFile(PChar(Filename), GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
# Line 1818 | Line 2064 | begin
2064    begin
2065      for i := 0 to Columns.Count - 1 do
2066      begin
2067 <      {$IFDEF LINUX}
2067 >      {$IFDEF UNIX}
2068        BytesWritten := FpWrite(FHandle,Columns[i].Data^.sqldata^, Columns[i].Data^.sqllen);
2069        {$ELSE}
2070        WriteFile(FHandle, Columns[i].Data^.sqldata^, Columns[i].Data^.sqllen,
# Line 1834 | Line 2080 | end;
2080   { TIBInputRawFile }
2081   destructor TIBInputRawFile.Destroy;
2082   begin
2083 < {$IFDEF LINUX}
2083 > {$IFDEF UNIX}
2084    if FHandle <> -1 then
2085       fpclose(FHandle);
2086   {$ELSE}
# Line 1850 | Line 2096 | var
2096    BytesRead: DWord;
2097   begin
2098    result := False;
2099 < {$IFDEF LINUX}
2099 > {$IFDEF UNIX}
2100    if FHandle <> -1 then
2101   {$ELSE}
2102    if FHandle <> 0 then
# Line 1858 | Line 2104 | begin
2104    begin
2105      for i := 0 to Params.Count - 1 do
2106      begin
2107 <      {$IFDEF LINUX}
2107 >      {$IFDEF UNIX}
2108        BytesRead := FpRead(FHandle,Params[i].Data^.sqldata^,Params[i].Data^.sqllen);
2109        {$ELSE}
2110 <      ReadFile(FHandle, Params[i].Data^.sqldata^, Params[i].Data^.sqllen);
2110 >      ReadFile(FHandle, Params[i].Data^.sqldata^, Params[i].Data^.sqllen,
2111                 BytesRead, nil);
2112        {$ENDIF}
2113        if BytesRead <> DWORD(Params[i].Data^.sqllen) then
# Line 1873 | Line 2119 | end;
2119  
2120   procedure TIBInputRawFile.ReadyFile;
2121   begin
2122 < {$IFDEF LINUX}
2122 > {$IFDEF UNIX}
2123    if FHandle <> -1 then
2124       fpclose(FHandle);
2125    FHandle := FpOpen(Filename,O_RdOnly);
# Line 1909 | Line 2155 | begin
2155    TStringList(FSQL).OnChanging := SQLChanging;
2156    FProcessedSQL := TStringList.Create;
2157    FHandle := nil;
2158 <  FSQLParams := TIBXSQLDA.Create(self);
2159 <  FSQLRecord := TIBXSQLDA.Create(self);
2158 >  FSQLParams := TIBXSQLDA.Create(self,daInput);
2159 >  FSQLRecord := TIBXSQLDA.Create(self,daOutput);
2160    FSQLType := SQLUnknown;
2161    FParamCheck := True;
2162    FCursor := Name + RandomString(8);
# Line 2023 | Line 2269 | begin
2269    result := FSQLRecord;
2270   end;
2271  
2272 + function TIBSQL.GetFieldCount: integer;
2273 + begin
2274 +  Result := FSQLRecord.Count
2275 + end;
2276 +
2277 + procedure TIBSQL.SetUniqueParamNames(AValue: Boolean);
2278 + begin
2279 +  if FUniqueParamNames = AValue then Exit;
2280 +  FreeHandle;
2281 +  FUniqueParamNames := AValue;
2282 + end;
2283 +
2284   procedure TIBSQL.DoBeforeDatabaseDisconnect(Sender: TObject);
2285   begin
2286    if (FHandle <> nil) then begin
# Line 2062 | Line 2320 | begin
2320                              @FHandle,
2321                              Database.SQLDialect,
2322                              FSQLParams.AsXSQLDA,
2323 <                            FSQLRecord.AsXSQLDA), False);
2324 <      if (fetch_res <> 0) and (fetch_res <> isc_deadlock) then
2323 >                            FSQLRecord.AsXSQLDA), True);
2324 > (*      if (fetch_res <> 0) and (fetch_res <> isc_deadlock) then
2325        begin
2326           { Sometimes a prepared stored procedure appears to get
2327             off sync on the server ....This code is meant to try
# Line 2078 | Line 2336 | begin
2336                              Database.SQLDialect,
2337                              FSQLParams.AsXSQLDA,
2338                              FSQLRecord.AsXSQLDA), True);
2339 <      end;
2339 >      end;  *)
2340      end
2341      else
2342        Call(isc_dsql_execute(StatusVector,
# Line 2087 | Line 2345 | begin
2345                             Database.SQLDialect,
2346                             FSQLParams.AsXSQLDA), True)
2347    end;
2090  {$IFDEF HAS_SQLMONITOR}
2348    if not (csDesigning in ComponentState) then
2349      MonitorHook.SQLExecute(Self);
2093  {$ENDIF}
2350   end;
2351  
2352   function TIBSQL.GetEOF: Boolean;
# Line 2152 | Line 2408 | begin
2408        FBOF := False;
2409        result := FSQLRecord;
2410      end;
2155  {$IFDEF HAS_SQLMONITOR}
2411      if not (csDesigning in ComponentState) then
2412        MonitorHook.SQLFetch(Self);
2158  {$ENDIF}
2413    end;
2414   end;
2415  
# Line 2222 | Line 2476 | begin
2476    result := FRecordCount;
2477   end;
2478  
2479 < function TIBSQL.GetRowsAffected: integer;
2479 > function TIBSQL.GetRowsAffected: Integer;
2480   var
2481    result_buffer: array[0..1048] of Char;
2482    info_request: Char;
# Line 2273 | Line 2527 | var
2527    cCurChar, cNextChar, cQuoteChar: Char;
2528    sSQL, sProcessedSQL, sParamName: String;
2529    i, iLenSQL, iSQLPos: Integer;
2530 <  iCurState, iCurParamState: Integer;
2530 >  iCurState {$ifdef ALLOWDIALECT3PARAMNAMES}, iCurParamState {$endif}: Integer;
2531    iParamSuffix: Integer;
2532    slNames: TStrings;
2533  
# Line 2282 | Line 2536 | const
2536    CommentState = 1;
2537    QuoteState = 2;
2538    ParamState = 3;
2539 + {$ifdef ALLOWDIALECT3PARAMNAMES}
2540    ParamDefaultState = 0;
2541    ParamQuoteState = 1;
2542 +  {$endif}
2543  
2544    procedure AddToProcessedSQL(cChar: Char);
2545    begin
# Line 2303 | Line 2559 | begin
2559      i := 1;
2560      iSQLPos := 1;
2561      iCurState := DefaultState;
2562 +    {$ifdef ALLOWDIALECT3PARAMNAMES}
2563      iCurParamState := ParamDefaultState;
2564 +    {$endif}
2565      { Now, traverse through the SQL string, character by character,
2566       picking out the parameters and formatting correctly for InterBase }
2567      while (i <= iLenSQL) do begin
# Line 2354 | Line 2612 | begin
2612          ParamState:
2613          begin
2614            { collect the name of the parameter }
2615 +          {$ifdef ALLOWDIALECT3PARAMNAMES}
2616            if iCurParamState = ParamDefaultState then
2617            begin
2618              if cCurChar = '"' then
2619                iCurParamState := ParamQuoteState
2620 <            else if (cCurChar in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$']) then
2620 >            else
2621 >            {$endif}
2622 >            if (cCurChar in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$']) then
2623                  sParamName := sParamName + cCurChar
2624              else if FGenerateParamNames then
2625              begin
2626                sParamName := 'IBXParam' + IntToStr(iParamSuffix); {do not localize}
2627                Inc(iParamSuffix);
2628                iCurState := DefaultState;
2629 <              slNames.Add(sParamName);
2629 >              slNames.AddObject(sParamName,self); //Note local convention
2630 >                                                  //add pointer to self to mark entry
2631                sParamName := '';
2632              end
2633              else
2634                IBError(ibxeSQLParseError, [SParamNameExpected]);
2635 +          {$ifdef ALLOWDIALECT3PARAMNAMES}
2636            end
2637            else begin
2638              { determine if Quoted parameter name is finished }
# Line 2384 | Line 2647 | begin
2647              else
2648                sParamName := sParamName + cCurChar
2649            end;
2650 +          {$endif}
2651            { determine if the unquoted parameter name is finished }
2652 <          if (iCurParamState <> ParamQuoteState) and
2652 >          if {$ifdef ALLOWDIALECT3PARAMNAMES}(iCurParamState <> ParamQuoteState) and {$endif}
2653              (iCurState <> DefaultState) then
2654            begin
2655              if not (cNextChar in ['A'..'Z', 'a'..'z',
# Line 2405 | Line 2669 | begin
2669      AddToProcessedSQL(#0);
2670      FSQLParams.Count := slNames.Count;
2671      for i := 0 to slNames.Count - 1 do
2672 <      FSQLParams.AddName(slNames[i], i);
2672 >      FSQLParams.SetParamName(slNames[i], i,FUniqueParamNames or (slNames.Objects[i] <> nil));
2673      FProcessedSQL.Text := sProcessedSQL;
2674    finally
2675      slNames.Free;
# Line 2486 | Line 2750 | begin
2750        end;
2751      end;
2752      FPrepared := True;
2489  {$IFDEF HAS_SQLMONITOR}
2753      if not (csDesigning in ComponentState) then
2754        MonitorHook.SQLPrepare(Self);
2492  {$ENDIF}
2755    except
2756      on E: Exception do begin
2757        if (FHandle <> nil) then
2758          FreeHandle;
2759 <      raise;
2759 >      if E is EIBInterBaseError then
2760 >        raise EIBInterBaseError.Create(EIBInterBaseError(E).SQLCode,
2761 >                                       EIBInterBaseError(E).IBErrorCode,
2762 >                                       EIBInterBaseError(E).Message +
2763 >                                       sSQLErrorSeparator + FProcessedSQL.Text)
2764 >      else
2765 >        raise;
2766      end;
2767    end;
2768   end;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines