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

Comparing ibx/trunk/runtime/IBCustomDataSet.pas (file contents):
Revision 60 by tony, Mon Mar 27 15:21:02 2017 UTC vs.
Revision 101 by tony, Thu Jan 18 14:37:18 2018 UTC

# Line 53 | Line 53 | uses
53    unix,
54   {$ENDIF}
55    SysUtils, Classes, IBDatabase, IBExternals, IB,  IBSQL, Db,
56 <  IBUtils, IBBlob, IBSQLParser;
56 >  IBUtils, IBBlob, IBSQLParser, IBDatabaseInfo;
57  
58   const
59    BufferCacheSize    =  1000;  { Allocate cache in this many record chunks}
# Line 74 | Line 74 | type
74      procedure SetDataSet(ADataSet: TIBCustomDataSet); virtual; abstract;
75      procedure Apply(UpdateKind: TUpdateKind; buff: PChar); virtual; abstract;
76      function GetSQL(UpdateKind: TUpdateKind): TStrings; virtual; abstract;
77 <    procedure InternalSetParams(Query: TIBSQL; buff: PChar);
77 >    procedure InternalSetParams(Params: ISQLParams; buff: PChar); overload;
78 >    procedure InternalSetParams(Query: TIBSQL; buff: PChar); overload;
79 >    procedure UpdateRecordFromQuery(QryResults: IResults; Buffer: PChar);
80      property DataSet: TIBCustomDataSet read GetDataSet write SetDataSet;
81    public
82      constructor Create(AOwner: TComponent); override;
# Line 181 | Line 183 | type
183      FCharacterSetSize: integer;
184      FAutoFieldSize: boolean;
185      FCodePage: TSystemCodePage;
186 +    FDataSize: integer;
187    protected
188      procedure Bind(Binding: Boolean); override;
189      function GetDataSize: Integer; override;
# Line 206 | Line 209 | type
209       Note: y > 4 will default to Floats
210    }
211    TIBBCDField = class(TBCDField)
212 +  private
213 +    FIdentityColumn: boolean;
214    protected
215 +    procedure Bind(Binding: Boolean); override;
216      class procedure CheckTypeSize(Value: Integer); override;
217      function GetAsCurrency: Currency; override;
218      function GetAsString: string; override;
# Line 214 | Line 220 | type
220      function GetDataSize: Integer; override;
221    public
222      constructor Create(AOwner: TComponent); override;
223 +    property IdentityColumn: boolean read FIdentityColumn;
224    published
225      property Size default 8;
226    end;
227  
228 +  {The following integer field types extend the built in versions to enable IBX appplications
229 +   to check for an Identity column}
230 +
231 +  { TIBSmallintField }
232 +
233 +  TIBSmallintField = class(TSmallintField)
234 +  private
235 +    FIdentityColumn: boolean;
236 +  protected
237 +    procedure Bind(Binding: Boolean); override;
238 +  public
239 +    property IdentityColumn: boolean read FIdentityColumn;
240 +  end;
241 +
242 +  { TIBIntegerField }
243 +
244 +  TIBIntegerField = class(TIntegerField)
245 +  private
246 +    FIdentityColumn: boolean;
247 +  protected
248 +    procedure Bind(Binding: Boolean); override;
249 +  public
250 +    property IdentityColumn: boolean read FIdentityColumn;
251 +  end;
252 +
253 +  { TIBLargeIntField }
254 +
255 +  TIBLargeIntField = class(TLargeIntField)
256 +  private
257 +    FIdentityColumn: boolean;
258 +  protected
259 +    procedure Bind(Binding: Boolean); override;
260 +  public
261 +    property IdentityColumn: boolean read FIdentityColumn;
262 +  end;
263 +
264    {TIBMemoField}
265    {Allows us to show truncated text in DBGrids and anything else that uses
266     DisplayText}
# Line 358 | Line 401 | type
401      FQRefresh,
402      FQSelect,
403      FQModify: TIBSQL;
404 +    FDatabaseInfo: TIBDatabaseInfo;
405      FRecordBufferSize: Integer;
406      FRecordCount: Integer;
407      FRecordSize: Integer;
# Line 387 | Line 431 | type
431      FInTransactionEnd: boolean;
432      FIBLinks: TList;
433      FFieldColumns: PFieldColumns;
434 +    procedure ColumnDataToBuffer(QryResults: IResults; ColumnIndex,
435 +      FieldIndex: integer; Buffer: PChar);
436      procedure InitModelBuffer(Qry: TIBSQL; Buffer: PChar);
437      function GetSelectStmtIntf: IStatement;
438      procedure SetUpdateMode(const Value: TUpdateMode);
# Line 434 | Line 480 | type
480      procedure SetDatabase(Value: TIBDatabase);
481      procedure SetDeleteSQL(Value: TStrings);
482      procedure SetInsertSQL(Value: TStrings);
483 <    procedure SetInternalSQLParams(Qry: TIBSQL; Buffer: Pointer);
483 >    procedure SetInternalSQLParams(Params: ISQLParams; Buffer: Pointer);
484      procedure SetRefreshSQL(Value: TStrings);
485      procedure SetSelectSQL(Value: TStrings);
486      procedure SetModifySQL(Value: TStrings);
487      procedure SetTransaction(Value: TIBTransaction);
488      procedure SetUpdateRecordTypes(Value: TIBUpdateRecordTypes);
489      procedure SetUniDirectional(Value: Boolean);
490 +    procedure UpdateRecordFromQuery(QryResults: IResults; Buffer: PChar);
491      procedure RefreshParams;
492      function AdjustPosition(FCache: PChar; Offset: DWORD;
493                              Origin: Integer): DWORD;
# Line 789 | Line 836 | type
836      FCharacterSetName: RawByteString;
837      FCharacterSetSize: integer;
838      FCodePage: TSystemCodePage;
839 +    FIdentityColumn: boolean;
840      FRelationName: string;
841 +    FDataSize: integer;
842    published
843      property CharacterSetName: RawByteString read FCharacterSetName write FCharacterSetName;
844      property CharacterSetSize: integer read FCharacterSetSize write FCharacterSetSize;
845      property CodePage: TSystemCodePage read FCodePage write FCodePage;
846 +    property DataSize: integer read FDataSize write FDataSize;
847      property RelationName: string read FRelationName write FRelationName;
848      property ArrayDimensions: integer read FArrayDimensions write FArrayDimensions;
849      property ArrayBounds: TArrayBounds read FArrayBounds write FArrayBounds;
850 +    property IdentityColumn: boolean read FIdentityColumn write FIdentityColumn default false;
851    end;
852  
853   const
854   DefaultFieldClasses: array[TFieldType] of TFieldClass = (
855      nil,                { ftUnknown }
856      TIBStringField,     { ftString }
857 <    TSmallintField,     { ftSmallint }
858 <    TIntegerField,      { ftInteger }
857 >    TIBSmallintField,   { ftSmallint }
858 >    TIBIntegerField,      { ftInteger }
859      TWordField,         { ftWord }
860      TBooleanField,      { ftBoolean }
861      TFloatField,        { ftFloat }
# Line 826 | Line 877 | DefaultFieldClasses: array[TFieldType] o
877      nil,                { ftCursor }
878      TStringField,       { ftFixedChar }
879      nil,    { ftWideString }
880 <    TLargeIntField,     { ftLargeInt }
880 >    TIBLargeIntField,     { ftLargeInt }
881      nil,          { ftADT }
882      TIBArrayField,        { ftArray }
883      nil,    { ftReference }
# Line 870 | Line 921 | type
921      FieldName : String;
922      COMPUTED_BLR : Boolean;
923      DEFAULT_VALUE : boolean;
924 +    IDENTITY_COLUMN : boolean;
925      NextField : TFieldNode;
926    end;
927  
# Line 922 | Line 974 | type
974      Result := str;
975    end;
976  
977 + { TIBLargeIntField }
978 +
979 + procedure TIBLargeIntField.Bind(Binding: Boolean);
980 + begin
981 +  inherited Bind(Binding);
982 +  if Binding and (FieldDef <> nil) then
983 +     FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn;
984 + end;
985 +
986 + { TIBIntegerField }
987 +
988 + procedure TIBIntegerField.Bind(Binding: Boolean);
989 + begin
990 +  inherited Bind(Binding);
991 +  if Binding and (FieldDef <> nil) then
992 +     FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn;
993 + end;
994 +
995 + { TIBSmallintField }
996 +
997 + procedure TIBSmallintField.Bind(Binding: Boolean);
998 + begin
999 +  inherited Bind(Binding);
1000 +  if Binding and (FieldDef <> nil) then
1001 +     FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn;
1002 + end;
1003 +
1004   { TIBArray }
1005  
1006   procedure TIBArray.EventHandler(Sender: IArray; Reason: TArrayEventReason);
# Line 1031 | Line 1110 | begin
1110         {2: case 2 ignored. This should be handled by TIBWideMemo}
1111  
1112         3, {Assume UNICODE_FSS is really UTF8}
1113 <       4: {Include GB18030 - assuming UTF8 routine work for this codeset}
1113 >       4: {Include GB18030 - assuming UTF8 routines work for this codeset}
1114           if DisplayWidth = 0 then
1115             Result := ValidUTF8String(TextToSingleLine(Result))
1116           else
# Line 1141 | Line 1220 | begin
1220      IBFieldDef := FieldDef as TIBFieldDef;
1221      CharacterSetSize := IBFieldDef.CharacterSetSize;
1222      CharacterSetName := IBFieldDef.CharacterSetName;
1223 +    FDataSize := IBFieldDef.DataSize + 1;
1224      if AutoFieldSize then
1225        Size := IBFieldDef.Size;
1226      CodePage := IBFieldDef.CodePage;
# Line 1149 | Line 1229 | end;
1229  
1230   function TIBStringField.GetDataSize: Integer;
1231   begin
1232 <  Result := Size * CharacterSetSize + 1;
1232 >  Result := FDataSize;
1233   end;
1234  
1235   constructor TIBStringField.Create(aOwner: TComponent);
# Line 1232 | Line 1312 | begin
1312    Size := 8;
1313   end;
1314  
1315 + procedure TIBBCDField.Bind(Binding: Boolean);
1316 + begin
1317 +  inherited Bind(Binding);
1318 +  if Binding and (FieldDef <> nil) then
1319 +     FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn;
1320 + end;
1321 +
1322   class procedure TIBBCDField.CheckTypeSize(Value: Integer);
1323   begin
1324   { No need to check as the base type is currency, not BCD }
# Line 1317 | Line 1404 | constructor TIBCustomDataSet.Create(AOwn
1404   begin
1405    inherited Create(AOwner);
1406    FBase := TIBBase.Create(Self);
1407 +  FDatabaseInfo := TIBDatabaseInfo.Create(self);
1408    FIBLinks := TList.Create;
1409    FCurrentRecord := -1;
1410    FDeletedRecords := 0;
# Line 1955 | Line 2043 | begin
2043    end;
2044   end;
2045  
2046 + {Update Buffer Fields from Query Results}
2047 +
2048 + procedure TIBCustomDataSet.UpdateRecordFromQuery(QryResults: IResults;
2049 +  Buffer: PChar);
2050 + var i, j: integer;
2051 + begin
2052 +  for i := 0 to QryResults.Count - 1 do
2053 +  begin
2054 +    j := GetFieldPosition(QryResults[i].GetAliasName);
2055 +    if j > 0 then
2056 +      ColumnDataToBuffer(QryResults,i,j,Buffer);
2057 +  end;
2058 + end;
2059 +
2060 +
2061 + {Move column data returned from query to row buffer}
2062 +
2063 + procedure TIBCustomDataSet.ColumnDataToBuffer(QryResults: IResults;
2064 +               ColumnIndex, FieldIndex: integer; Buffer: PChar);
2065 + var
2066 +  LocalData: PByte;
2067 +  LocalDate, LocalDouble: Double;
2068 +  LocalInt: Integer;
2069 +  LocalBool: wordBool;
2070 +  LocalInt64: Int64;
2071 +  LocalCurrency: Currency;
2072 +  p: PRecordData;
2073 +  ColData: ISQLData;
2074 + begin
2075 +  p := PRecordData(Buffer);
2076 +  LocalData := nil;
2077 +  with p^.rdFields[FieldIndex], FFieldColumns^[FieldIndex] do
2078 +  begin
2079 +    QryResults.GetData(ColumnIndex,fdIsNull,fdDataLength,LocalData);
2080 +    if not fdIsNull then
2081 +    begin
2082 +      ColData := QryResults[ColumnIndex];
2083 +      case fdDataType of  {Get Formatted data for column types that need formatting}
2084 +        SQL_TIMESTAMP:
2085 +        begin
2086 +          LocalDate := TimeStampToMSecs(DateTimeToTimeStamp(ColData.AsDateTime));
2087 +          LocalData := PByte(@LocalDate);
2088 +        end;
2089 +        SQL_TYPE_DATE:
2090 +        begin
2091 +          LocalInt := DateTimeToTimeStamp(ColData.AsDateTime).Date;
2092 +          LocalData := PByte(@LocalInt);
2093 +        end;
2094 +        SQL_TYPE_TIME:
2095 +        begin
2096 +          LocalInt := DateTimeToTimeStamp(ColData.AsDateTime).Time;
2097 +          LocalData := PByte(@LocalInt);
2098 +        end;
2099 +        SQL_SHORT, SQL_LONG:
2100 +        begin
2101 +          if (fdDataScale = 0) then
2102 +          begin
2103 +            LocalInt := ColData.AsLong;
2104 +            LocalData := PByte(@LocalInt);
2105 +          end
2106 +          else
2107 +          if (fdDataScale >= (-4)) then
2108 +          begin
2109 +            LocalCurrency := ColData.AsCurrency;
2110 +            LocalData := PByte(@LocalCurrency);
2111 +          end
2112 +          else
2113 +          begin
2114 +           LocalDouble := ColData.AsDouble;
2115 +           LocalData := PByte(@LocalDouble);
2116 +          end;
2117 +        end;
2118 +        SQL_INT64:
2119 +        begin
2120 +          if (fdDataScale = 0) then
2121 +          begin
2122 +            LocalInt64 := ColData.AsInt64;
2123 +            LocalData := PByte(@LocalInt64);
2124 +          end
2125 +          else
2126 +          if (fdDataScale >= (-4)) then
2127 +          begin
2128 +            LocalCurrency := ColData.AsCurrency;
2129 +            LocalData := PByte(@LocalCurrency);
2130 +            end
2131 +            else
2132 +            begin
2133 +              LocalDouble := ColData.AsDouble;
2134 +              LocalData := PByte(@LocalDouble);
2135 +            end
2136 +        end;
2137 +        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
2138 +        begin
2139 +          LocalDouble := ColData.AsDouble;
2140 +          LocalData := PByte(@LocalDouble);
2141 +        end;
2142 +        SQL_BOOLEAN:
2143 +        begin
2144 +          LocalBool := ColData.AsBoolean;
2145 +          LocalData := PByte(@LocalBool);
2146 +        end;
2147 +      end;
2148 +
2149 +      if fdDataType = SQL_VARYING then
2150 +        Move(LocalData^, Buffer[fdDataOfs], fdDataLength)
2151 +      else
2152 +        Move(LocalData^, Buffer[fdDataOfs], fdDataSize)
2153 +    end
2154 +    else {Null column}
2155 +    if fdDataType = SQL_VARYING then
2156 +      FillChar(Buffer[fdDataOfs],fdDataLength,0)
2157 +    else
2158 +      FillChar(Buffer[fdDataOfs],fdDataSize,0);
2159 +  end;
2160 + end;
2161 +
2162   { Read the record from FQSelect.Current into the record buffer
2163    Then write the buffer to in memory cache }
2164   procedure TIBCustomDataSet.FetchCurrentRecordToBuffer(Qry: TIBSQL;
# Line 1963 | Line 2167 | var
2167    pbd: PBlobDataArray;
2168    pda: PArrayDataArray;
2169    i, j: Integer;
1966  LocalData: PByte;
1967  LocalDate, LocalDouble: Double;
1968  LocalInt: Integer;
1969  LocalBool: wordBool;
1970  LocalInt64: Int64;
1971  LocalCurrency: Currency;
2170    FieldsLoaded: Integer;
2171    p: PRecordData;
2172   begin
# Line 2019 | Line 2217 | begin
2217          continue;
2218        end;
2219      if j > 0 then
2220 <    begin
2023 <      LocalData := nil;
2024 <      with p^.rdFields[j], FFieldColumns^[j] do
2025 <      begin
2026 <        Qry.Current.GetData(i,fdIsNull,fdDataLength,LocalData);
2027 <        if not fdIsNull then
2028 <        begin
2029 <          case fdDataType of  {Get Formatted data for column types that need formatting}
2030 <            SQL_TIMESTAMP:
2031 <            begin
2032 <              LocalDate := TimeStampToMSecs(DateTimeToTimeStamp(Qry[i].AsDateTime));
2033 <              LocalData := PByte(@LocalDate);
2034 <            end;
2035 <            SQL_TYPE_DATE:
2036 <            begin
2037 <              LocalInt := DateTimeToTimeStamp(Qry[i].AsDateTime).Date;
2038 <              LocalData := PByte(@LocalInt);
2039 <            end;
2040 <            SQL_TYPE_TIME:
2041 <            begin
2042 <              LocalInt := DateTimeToTimeStamp(Qry[i].AsDateTime).Time;
2043 <              LocalData := PByte(@LocalInt);
2044 <            end;
2045 <            SQL_SHORT, SQL_LONG:
2046 <            begin
2047 <              if (fdDataScale = 0) then
2048 <              begin
2049 <                LocalInt := Qry[i].AsLong;
2050 <                LocalData := PByte(@LocalInt);
2051 <              end
2052 <              else
2053 <              if (fdDataScale >= (-4)) then
2054 <              begin
2055 <                LocalCurrency := Qry[i].AsCurrency;
2056 <                LocalData := PByte(@LocalCurrency);
2057 <              end
2058 <              else
2059 <              begin
2060 <               LocalDouble := Qry[i].AsDouble;
2061 <               LocalData := PByte(@LocalDouble);
2062 <              end;
2063 <            end;
2064 <            SQL_INT64:
2065 <            begin
2066 <              if (fdDataScale = 0) then
2067 <              begin
2068 <                LocalInt64 := Qry[i].AsInt64;
2069 <                LocalData := PByte(@LocalInt64);
2070 <              end
2071 <              else
2072 <              if (fdDataScale >= (-4)) then
2073 <              begin
2074 <                LocalCurrency := Qry[i].AsCurrency;
2075 <                LocalData := PByte(@LocalCurrency);
2076 <                end
2077 <                else
2078 <                begin
2079 <                  LocalDouble := Qry[i].AsDouble;
2080 <                  LocalData := PByte(@LocalDouble);
2081 <                end
2082 <            end;
2083 <            SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
2084 <            begin
2085 <              LocalDouble := Qry[i].AsDouble;
2086 <              LocalData := PByte(@LocalDouble);
2087 <            end;
2088 <            SQL_BOOLEAN:
2089 <            begin
2090 <              LocalBool := Qry[i].AsBoolean;
2091 <              LocalData := PByte(@LocalBool);
2092 <            end;
2093 <          end;
2094 <
2095 <          if fdDataType = SQL_VARYING then
2096 <            Move(LocalData^, Buffer[fdDataOfs], fdDataLength)
2097 <          else
2098 <            Move(LocalData^, Buffer[fdDataOfs], fdDataSize)
2099 <        end
2100 <        else {Null column}
2101 <        if fdDataType = SQL_VARYING then
2102 <          FillChar(Buffer[fdDataOfs],fdDataLength,0)
2103 <        else
2104 <          FillChar(Buffer[fdDataOfs],fdDataSize,0);
2105 <      end;
2106 <    end;
2220 >      ColumnDataToBuffer(Qry.Current,i,j,Buffer);
2221    end;
2222    WriteRecordCache(RecordNumber, Buffer);
2223   end;
# Line 2198 | Line 2312 | begin
2312      FUpdateObject.Apply(ukDelete,Buff)
2313    else
2314    begin
2315 <    SetInternalSQLParams(FQDelete, Buff);
2315 >    SetInternalSQLParams(FQDelete.Params, Buff);
2316      FQDelete.ExecQuery;
2317    end;
2318    with PRecordData(Buff)^ do
# Line 2347 | Line 2461 | begin
2461        FUpdateObject.Apply(ukModify,Buff);
2462    end
2463    else begin
2464 <    SetInternalSQLParams(Qry, Buff);
2464 >    SetInternalSQLParams(Qry.Params, Buff);
2465      Qry.ExecQuery;
2466    end;
2467 +  if Qry.FieldCount > 0 then {Has RETURNING Clause}
2468 +    UpdateRecordFromQuery(Qry.Current,Buff);
2469    PRecordData(Buff)^.rdUpdateStatus := usUnmodified;
2470    PRecordData(Buff)^.rdCachedUpdateStatus := cusUnmodified;
2471    SetModified(False);
# Line 2381 | Line 2497 | begin
2497          end
2498          else
2499            Qry := FQRefresh;
2500 <        SetInternalSQLParams(Qry, Buff);
2500 >        SetInternalSQLParams(Qry.Params, Buff);
2501          Qry.ExecQuery;
2502          try
2503            if (Qry.SQLStatementType = SQLExecProcedure) or Qry.Next then
# Line 2593 | Line 2709 | begin
2709    if (FBase.Database <> Value) then
2710    begin
2711      CheckDatasetClosed;
2712 +    InternalUnPrepare;
2713      FBase.Database := Value;
2714      FQDelete.Database := Value;
2715      FQInsert.Database := Value;
2716      FQRefresh.Database := Value;
2717      FQSelect.Database := Value;
2718      FQModify.Database := Value;
2719 +    FDatabaseInfo.Database := Value;
2720    end;
2721   end;
2722  
# Line 2620 | Line 2738 | begin
2738    end;
2739   end;
2740  
2741 < procedure TIBCustomDataSet.SetInternalSQLParams(Qry: TIBSQL; Buffer: Pointer);
2741 > procedure TIBCustomDataSet.SetInternalSQLParams(Params: ISQLParams; Buffer: Pointer);
2742   var
2743    i, j: Integer;
2744    cr, data: PChar;
# Line 2636 | Line 2754 | begin
2754      InternalPrepare;
2755    OldBuffer := nil;
2756    try
2757 <    for i := 0 to Qry.Params.GetCount - 1 do
2757 >    for i := 0 to Params.GetCount - 1 do
2758      begin
2759 <      Param := Qry.Params[i];
2759 >      Param := Params[i];
2760        fn := Param.Name;
2761        if (Pos('OLD_', fn) = 1) then {mbcs ok}
2762        begin
# Line 3668 | Line 3786 | const
3786                 'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize}
3787                 'and ((not F.RDB$COMPUTED_BLR is NULL) or ' + {do not localize}
3788                 '     (not F.RDB$DEFAULT_VALUE is NULL)) '; {do not localize}
3789 +
3790 +  DefaultSQLODS12 = 'Select F.RDB$COMPUTED_BLR, ' + {do not localize}
3791 +               'F.RDB$DEFAULT_VALUE, R.RDB$FIELD_NAME, R.RDB$IDENTITY_TYPE ' + {do not localize}
3792 +               'from RDB$RELATION_FIELDS R, RDB$FIELDS F ' + {do not localize}
3793 +               'where R.RDB$RELATION_NAME = :RELATION ' +  {do not localize}
3794 +               'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize}
3795 +               'and ((not F.RDB$COMPUTED_BLR is NULL) or ' + {do not localize}
3796 +               '     (not F.RDB$DEFAULT_VALUE is NULL) or ' + {do not localize}
3797 +               '     ( not R.RDB$IDENTITY_TYPE is NULL))' ; {do not localize}
3798 +
3799   var
3800    FieldType: TFieldType;
3801    FieldSize: Word;
3802 +  FieldDataSize: integer;
3803    charSetID: short;
3804    CharSetSize: integer;
3805    CharSetName: RawByteString;
# Line 3707 | Line 3836 | var
3836        FField.FieldName := Query.Fields[2].AsString;
3837        FField.DEFAULT_VALUE := not Query.Fields[1].IsNull;
3838        FField.COMPUTED_BLR := not Query.Fields[0].IsNull;
3839 +      FField.IDENTITY_COLUMN := (Query.FieldCount > 3) and not Query.Fields[3].IsNull;
3840        FField.NextField := Result.FieldNodes;
3841        Result.FieldNodes := FField;
3842        Query.Next;
# Line 3760 | Line 3890 | var
3890          FField := Ffield.NextField;
3891    end;
3892  
3893 +  function Is_IDENTITY_COLUMN(Relation, Field : String) : Boolean;
3894 +  var
3895 +    FRelation : TRelationNode;
3896 +    FField : TFieldNode;
3897 +  begin
3898 +    FRelation := FRelationNodes;
3899 +    while Assigned(FRelation) and
3900 +         (FRelation.RelationName <> Relation) do
3901 +      FRelation := FRelation.NextRelation;
3902 +    if not Assigned(FRelation) then
3903 +      FRelation := Add_Node(Relation, Field);
3904 +    Result := false;
3905 +    FField := FRelation.FieldNodes;
3906 +    while Assigned(FField) do
3907 +      if FField.FieldName = Field then
3908 +      begin
3909 +        Result := Ffield.IDENTITY_COLUMN;
3910 +        Exit;
3911 +      end
3912 +      else
3913 +        FField := Ffield.NextField;
3914 +  end;
3915 +
3916    Procedure FreeNodes;
3917    var
3918      FRelation : TRelationNode;
# Line 3793 | Line 3946 | begin
3946      FieldIndex := 0;
3947      if (Length(FMappedFieldPosition) < SourceQuery.MetaData.Count) then
3948        SetLength(FMappedFieldPosition, SourceQuery.MetaData.Count);
3949 <    Query.SQL.Text := DefaultSQL;
3949 >    if FDatabaseInfo.ODSMajorVersion >= 12 then
3950 >      Query.SQL.Text := DefaultSQLODS12
3951 >    else
3952 >      Query.SQL.Text := DefaultSQL;
3953      Query.Prepare;
3954      SetLength(FAliasNameMap, SourceQuery.MetaData.Count);
3955      SetLength(FAliasNameList, SourceQuery.MetaData.Count);
# Line 3807 | Line 3963 | begin
3963          FieldName := getSQLName;
3964          FAliasNameList[i] := DBAliasName;
3965          FieldSize := 0;
3966 +        FieldDataSize := GetSize;
3967          FieldPrecision := 0;
3968          FieldNullable := IsNullable;
3969          CharSetSize := 0;
# Line 3823 | Line 3980 | begin
3980                CharSetSize := 1;
3981              CharSetName := Database.Attachment.GetCharsetName(getCharSetID);
3982              Database.Attachment.CharSetID2CodePage(getCharSetID,FieldCodePage);
3983 <            FieldSize := GetSize div CharSetSize;
3983 >            FieldSize := FieldDataSize div CharSetSize;
3984              FieldType := ftString;
3985            end;
3986            { All Doubles/Floats should be cast to doubles }
# Line 3874 | Line 4031 | begin
4031                FieldSize := -getScale;
4032              end
4033              else
4034 <              FieldType := ftFloat
4034 >              FieldType := ftFloat;
4035            end;
4036            SQL_TIMESTAMP: FieldType := ftDateTime;
4037            SQL_TYPE_TIME: FieldType := ftTime;
# Line 3919 | Line 4076 | begin
4076              Name := FieldAliasName;
4077              FAliasNameMap[FieldNo-1] := DBAliasName;
4078              Size := FieldSize;
4079 +            DataSize := FieldDataSize;
4080              Precision := FieldPrecision;
4081              Required := not FieldNullable;
4082              RelationName := aRelationName;
# Line 3930 | Line 4088 | begin
4088              ArrayBounds := aArrayBounds;
4089              if (FieldName <> '') and (RelationName <> '') then
4090              begin
4091 +              IdentityColumn := Is_IDENTITY_COLUMN(RelationName, FieldName);
4092                if Has_COMPUTED_BLR(RelationName, FieldName) then
4093                begin
4094                  Attributes := [faReadOnly];
# Line 4674 | Line 4833 | begin
4833    Transaction.StartTransaction;
4834   end;
4835  
4836 < function TIBCustomDataSet.PSGetTableName: string;
4836 > function TIBCustomDataSet.PsGetTableName: string;
4837   begin
4838   //  if not FInternalPrepared then
4839   //    InternalPrepare;
# Line 4815 | Line 4974 | begin
4974    inherited Destroy;
4975   end;
4976  
4977 < procedure TIBDataSetUpdateObject.SetRefreshSQL(Value: TStrings);
4977 > procedure TIBDataSetUpdateObject.SetRefreshSQL(value: TStrings);
4978   begin
4979    FRefreshSQL.Assign(Value);
4980   end;
4981  
4982 + procedure TIBDataSetUpdateObject.InternalSetParams(Params: ISQLParams;
4983 +  buff: PChar);
4984 + begin
4985 +  if not Assigned(DataSet) then Exit;
4986 +  DataSet.SetInternalSQLParams(Params, buff);
4987 + end;
4988 +
4989   procedure TIBDataSetUpdateObject.InternalSetParams(Query: TIBSQL; buff: PChar);
4990   begin
4991 +  InternalSetParams(Query.Params,buff);
4992 + end;
4993 +
4994 + procedure TIBDataSetUpdateObject.UpdateRecordFromQuery(QryResults: IResults;
4995 +  Buffer: PChar);
4996 + begin
4997    if not Assigned(DataSet) then Exit;
4998 <  DataSet.SetInternalSQLParams(Query, buff);
4998 >  DataSet.UpdateRecordFromQuery(QryResults, Buffer);
4999   end;
5000  
5001   function TIBDSBlobStream.GetSize: Int64;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines