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 80 by tony, Mon Jan 1 11:31:07 2018 UTC vs.
Revision 104 by tony, Thu Jan 18 14:37:29 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 76 | Line 76 | type
76      function GetSQL(UpdateKind: TUpdateKind): TStrings; virtual; abstract;
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 208 | 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 216 | 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 274 | Line 315 | type
315      FFieldName: string;
316      FGeneratorName: string;
317      FIncrement: integer;
318 +    FQuery: TIBSQL;
319 +    function GetDatabase: TIBDatabase;
320 +    function GetTransaction: TIBTransaction;
321 +    procedure SetDatabase(AValue: TIBDatabase);
322 +    procedure SetGeneratorName(AValue: string);
323      procedure SetIncrement(const AValue: integer);
324 +    procedure SetTransaction(AValue: TIBTransaction);
325 +    procedure SetQuerySQL;
326    protected
327 <    function GetNextValue(ADatabase: TIBDatabase; ATransaction: TIBTransaction): integer;
327 >    function GetNextValue: integer;
328    public
329      constructor Create(Owner: TIBCustomDataSet);
330 +    destructor Destroy; override;
331      procedure Apply;
332      property Owner: TIBCustomDataSet read FOwner;
333 +    property Database: TIBDatabase read GetDatabase write SetDatabase;
334 +    property Transaction: TIBTransaction read GetTransaction write SetTransaction;
335    published
336 <    property Generator: string read FGeneratorName write FGeneratorName;
336 >    property Generator: string read FGeneratorName write SetGeneratorName;
337      property Field: string read FFieldName write FFieldName;
338      property Increment: integer read FIncrement write SetIncrement default 1;
339      property ApplyOnEvent: TIBGeneratorApplyOnEvent read FApplyOnEvent write FApplyOnEvent;
# Line 360 | Line 411 | type
411      FQRefresh,
412      FQSelect,
413      FQModify: TIBSQL;
414 +    FDatabaseInfo: TIBDatabaseInfo;
415      FRecordBufferSize: Integer;
416      FRecordCount: Integer;
417      FRecordSize: Integer;
# Line 389 | Line 441 | type
441      FInTransactionEnd: boolean;
442      FIBLinks: TList;
443      FFieldColumns: PFieldColumns;
444 +    procedure ColumnDataToBuffer(QryResults: IResults; ColumnIndex,
445 +      FieldIndex: integer; Buffer: PChar);
446      procedure InitModelBuffer(Qry: TIBSQL; Buffer: PChar);
447      function GetSelectStmtIntf: IStatement;
448      procedure SetUpdateMode(const Value: TUpdateMode);
# Line 443 | Line 497 | type
497      procedure SetTransaction(Value: TIBTransaction);
498      procedure SetUpdateRecordTypes(Value: TIBUpdateRecordTypes);
499      procedure SetUniDirectional(Value: Boolean);
500 +    procedure UpdateRecordFromQuery(QryResults: IResults; Buffer: PChar);
501      procedure RefreshParams;
502      function AdjustPosition(FCache: PChar; Offset: DWORD;
503                              Origin: Integer): DWORD;
# Line 791 | Line 846 | type
846      FCharacterSetName: RawByteString;
847      FCharacterSetSize: integer;
848      FCodePage: TSystemCodePage;
849 +    FIdentityColumn: boolean;
850      FRelationName: string;
851      FDataSize: integer;
852    published
# Line 801 | Line 857 | type
857      property RelationName: string read FRelationName write FRelationName;
858      property ArrayDimensions: integer read FArrayDimensions write FArrayDimensions;
859      property ArrayBounds: TArrayBounds read FArrayBounds write FArrayBounds;
860 +    property IdentityColumn: boolean read FIdentityColumn write FIdentityColumn default false;
861    end;
862  
863   const
864   DefaultFieldClasses: array[TFieldType] of TFieldClass = (
865      nil,                { ftUnknown }
866      TIBStringField,     { ftString }
867 <    TSmallintField,     { ftSmallint }
868 <    TIntegerField,      { ftInteger }
867 >    TIBSmallintField,   { ftSmallint }
868 >    TIBIntegerField,      { ftInteger }
869      TWordField,         { ftWord }
870      TBooleanField,      { ftBoolean }
871      TFloatField,        { ftFloat }
# Line 830 | Line 887 | DefaultFieldClasses: array[TFieldType] o
887      nil,                { ftCursor }
888      TStringField,       { ftFixedChar }
889      nil,    { ftWideString }
890 <    TLargeIntField,     { ftLargeInt }
890 >    TIBLargeIntField,     { ftLargeInt }
891      nil,          { ftADT }
892      TIBArrayField,        { ftArray }
893      nil,    { ftReference }
# Line 874 | Line 931 | type
931      FieldName : String;
932      COMPUTED_BLR : Boolean;
933      DEFAULT_VALUE : boolean;
934 +    IDENTITY_COLUMN : boolean;
935      NextField : TFieldNode;
936    end;
937  
# Line 926 | Line 984 | type
984      Result := str;
985    end;
986  
987 + { TIBLargeIntField }
988 +
989 + procedure TIBLargeIntField.Bind(Binding: Boolean);
990 + begin
991 +  inherited Bind(Binding);
992 +  if Binding and (FieldDef <> nil) then
993 +     FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn;
994 + end;
995 +
996 + { TIBIntegerField }
997 +
998 + procedure TIBIntegerField.Bind(Binding: Boolean);
999 + begin
1000 +  inherited Bind(Binding);
1001 +  if Binding and (FieldDef <> nil) then
1002 +     FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn;
1003 + end;
1004 +
1005 + { TIBSmallintField }
1006 +
1007 + procedure TIBSmallintField.Bind(Binding: Boolean);
1008 + begin
1009 +  inherited Bind(Binding);
1010 +  if Binding and (FieldDef <> nil) then
1011 +     FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn;
1012 + end;
1013 +
1014   { TIBArray }
1015  
1016   procedure TIBArray.EventHandler(Sender: IArray; Reason: TArrayEventReason);
# Line 1035 | Line 1120 | begin
1120         {2: case 2 ignored. This should be handled by TIBWideMemo}
1121  
1122         3, {Assume UNICODE_FSS is really UTF8}
1123 <       4: {Include GB18030 - assuming UTF8 routine work for this codeset}
1123 >       4: {Include GB18030 - assuming UTF8 routines work for this codeset}
1124           if DisplayWidth = 0 then
1125             Result := ValidUTF8String(TextToSingleLine(Result))
1126           else
# Line 1237 | Line 1322 | begin
1322    Size := 8;
1323   end;
1324  
1325 + procedure TIBBCDField.Bind(Binding: Boolean);
1326 + begin
1327 +  inherited Bind(Binding);
1328 +  if Binding and (FieldDef <> nil) then
1329 +     FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn;
1330 + end;
1331 +
1332   class procedure TIBBCDField.CheckTypeSize(Value: Integer);
1333   begin
1334   { No need to check as the base type is currency, not BCD }
# Line 1322 | Line 1414 | constructor TIBCustomDataSet.Create(AOwn
1414   begin
1415    inherited Create(AOwner);
1416    FBase := TIBBase.Create(Self);
1417 +  FDatabaseInfo := TIBDatabaseInfo.Create(self);
1418    FIBLinks := TList.Create;
1419    FCurrentRecord := -1;
1420    FDeletedRecords := 0;
# Line 1960 | Line 2053 | begin
2053    end;
2054   end;
2055  
2056 + {Update Buffer Fields from Query Results}
2057 +
2058 + procedure TIBCustomDataSet.UpdateRecordFromQuery(QryResults: IResults;
2059 +  Buffer: PChar);
2060 + var i, j: integer;
2061 + begin
2062 +  for i := 0 to QryResults.Count - 1 do
2063 +  begin
2064 +    j := GetFieldPosition(QryResults[i].GetAliasName);
2065 +    if j > 0 then
2066 +      ColumnDataToBuffer(QryResults,i,j,Buffer);
2067 +  end;
2068 + end;
2069 +
2070 +
2071 + {Move column data returned from query to row buffer}
2072 +
2073 + procedure TIBCustomDataSet.ColumnDataToBuffer(QryResults: IResults;
2074 +               ColumnIndex, FieldIndex: integer; Buffer: PChar);
2075 + var
2076 +  LocalData: PByte;
2077 +  LocalDate, LocalDouble: Double;
2078 +  LocalInt: Integer;
2079 +  LocalBool: wordBool;
2080 +  LocalInt64: Int64;
2081 +  LocalCurrency: Currency;
2082 +  p: PRecordData;
2083 +  ColData: ISQLData;
2084 + begin
2085 +  p := PRecordData(Buffer);
2086 +  LocalData := nil;
2087 +  with p^.rdFields[FieldIndex], FFieldColumns^[FieldIndex] do
2088 +  begin
2089 +    QryResults.GetData(ColumnIndex,fdIsNull,fdDataLength,LocalData);
2090 +    if not fdIsNull then
2091 +    begin
2092 +      ColData := QryResults[ColumnIndex];
2093 +      case fdDataType of  {Get Formatted data for column types that need formatting}
2094 +        SQL_TIMESTAMP:
2095 +        begin
2096 +          LocalDate := TimeStampToMSecs(DateTimeToTimeStamp(ColData.AsDateTime));
2097 +          LocalData := PByte(@LocalDate);
2098 +        end;
2099 +        SQL_TYPE_DATE:
2100 +        begin
2101 +          LocalInt := DateTimeToTimeStamp(ColData.AsDateTime).Date;
2102 +          LocalData := PByte(@LocalInt);
2103 +        end;
2104 +        SQL_TYPE_TIME:
2105 +        begin
2106 +          LocalInt := DateTimeToTimeStamp(ColData.AsDateTime).Time;
2107 +          LocalData := PByte(@LocalInt);
2108 +        end;
2109 +        SQL_SHORT, SQL_LONG:
2110 +        begin
2111 +          if (fdDataScale = 0) then
2112 +          begin
2113 +            LocalInt := ColData.AsLong;
2114 +            LocalData := PByte(@LocalInt);
2115 +          end
2116 +          else
2117 +          if (fdDataScale >= (-4)) then
2118 +          begin
2119 +            LocalCurrency := ColData.AsCurrency;
2120 +            LocalData := PByte(@LocalCurrency);
2121 +          end
2122 +          else
2123 +          begin
2124 +           LocalDouble := ColData.AsDouble;
2125 +           LocalData := PByte(@LocalDouble);
2126 +          end;
2127 +        end;
2128 +        SQL_INT64:
2129 +        begin
2130 +          if (fdDataScale = 0) then
2131 +          begin
2132 +            LocalInt64 := ColData.AsInt64;
2133 +            LocalData := PByte(@LocalInt64);
2134 +          end
2135 +          else
2136 +          if (fdDataScale >= (-4)) then
2137 +          begin
2138 +            LocalCurrency := ColData.AsCurrency;
2139 +            LocalData := PByte(@LocalCurrency);
2140 +            end
2141 +            else
2142 +            begin
2143 +              LocalDouble := ColData.AsDouble;
2144 +              LocalData := PByte(@LocalDouble);
2145 +            end
2146 +        end;
2147 +        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
2148 +        begin
2149 +          LocalDouble := ColData.AsDouble;
2150 +          LocalData := PByte(@LocalDouble);
2151 +        end;
2152 +        SQL_BOOLEAN:
2153 +        begin
2154 +          LocalBool := ColData.AsBoolean;
2155 +          LocalData := PByte(@LocalBool);
2156 +        end;
2157 +      end;
2158 +
2159 +      if fdDataType = SQL_VARYING then
2160 +        Move(LocalData^, Buffer[fdDataOfs], fdDataLength)
2161 +      else
2162 +        Move(LocalData^, Buffer[fdDataOfs], fdDataSize)
2163 +    end
2164 +    else {Null column}
2165 +    if fdDataType = SQL_VARYING then
2166 +      FillChar(Buffer[fdDataOfs],fdDataLength,0)
2167 +    else
2168 +      FillChar(Buffer[fdDataOfs],fdDataSize,0);
2169 +  end;
2170 + end;
2171 +
2172   { Read the record from FQSelect.Current into the record buffer
2173    Then write the buffer to in memory cache }
2174   procedure TIBCustomDataSet.FetchCurrentRecordToBuffer(Qry: TIBSQL;
# Line 1968 | Line 2177 | var
2177    pbd: PBlobDataArray;
2178    pda: PArrayDataArray;
2179    i, j: Integer;
1971  LocalData: PByte;
1972  LocalDate, LocalDouble: Double;
1973  LocalInt: Integer;
1974  LocalBool: wordBool;
1975  LocalInt64: Int64;
1976  LocalCurrency: Currency;
2180    FieldsLoaded: Integer;
2181    p: PRecordData;
2182   begin
# Line 2024 | Line 2227 | begin
2227          continue;
2228        end;
2229      if j > 0 then
2230 <    begin
2028 <      LocalData := nil;
2029 <      with p^.rdFields[j], FFieldColumns^[j] do
2030 <      begin
2031 <        Qry.Current.GetData(i,fdIsNull,fdDataLength,LocalData);
2032 <        if not fdIsNull then
2033 <        begin
2034 <          case fdDataType of  {Get Formatted data for column types that need formatting}
2035 <            SQL_TIMESTAMP:
2036 <            begin
2037 <              LocalDate := TimeStampToMSecs(DateTimeToTimeStamp(Qry[i].AsDateTime));
2038 <              LocalData := PByte(@LocalDate);
2039 <            end;
2040 <            SQL_TYPE_DATE:
2041 <            begin
2042 <              LocalInt := DateTimeToTimeStamp(Qry[i].AsDateTime).Date;
2043 <              LocalData := PByte(@LocalInt);
2044 <            end;
2045 <            SQL_TYPE_TIME:
2046 <            begin
2047 <              LocalInt := DateTimeToTimeStamp(Qry[i].AsDateTime).Time;
2048 <              LocalData := PByte(@LocalInt);
2049 <            end;
2050 <            SQL_SHORT, SQL_LONG:
2051 <            begin
2052 <              if (fdDataScale = 0) then
2053 <              begin
2054 <                LocalInt := Qry[i].AsLong;
2055 <                LocalData := PByte(@LocalInt);
2056 <              end
2057 <              else
2058 <              if (fdDataScale >= (-4)) then
2059 <              begin
2060 <                LocalCurrency := Qry[i].AsCurrency;
2061 <                LocalData := PByte(@LocalCurrency);
2062 <              end
2063 <              else
2064 <              begin
2065 <               LocalDouble := Qry[i].AsDouble;
2066 <               LocalData := PByte(@LocalDouble);
2067 <              end;
2068 <            end;
2069 <            SQL_INT64:
2070 <            begin
2071 <              if (fdDataScale = 0) then
2072 <              begin
2073 <                LocalInt64 := Qry[i].AsInt64;
2074 <                LocalData := PByte(@LocalInt64);
2075 <              end
2076 <              else
2077 <              if (fdDataScale >= (-4)) then
2078 <              begin
2079 <                LocalCurrency := Qry[i].AsCurrency;
2080 <                LocalData := PByte(@LocalCurrency);
2081 <                end
2082 <                else
2083 <                begin
2084 <                  LocalDouble := Qry[i].AsDouble;
2085 <                  LocalData := PByte(@LocalDouble);
2086 <                end
2087 <            end;
2088 <            SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
2089 <            begin
2090 <              LocalDouble := Qry[i].AsDouble;
2091 <              LocalData := PByte(@LocalDouble);
2092 <            end;
2093 <            SQL_BOOLEAN:
2094 <            begin
2095 <              LocalBool := Qry[i].AsBoolean;
2096 <              LocalData := PByte(@LocalBool);
2097 <            end;
2098 <          end;
2099 <
2100 <          if fdDataType = SQL_VARYING then
2101 <            Move(LocalData^, Buffer[fdDataOfs], fdDataLength)
2102 <          else
2103 <            Move(LocalData^, Buffer[fdDataOfs], fdDataSize)
2104 <        end
2105 <        else {Null column}
2106 <        if fdDataType = SQL_VARYING then
2107 <          FillChar(Buffer[fdDataOfs],fdDataLength,0)
2108 <        else
2109 <          FillChar(Buffer[fdDataOfs],fdDataSize,0);
2110 <      end;
2111 <    end;
2230 >      ColumnDataToBuffer(Qry.Current,i,j,Buffer);
2231    end;
2232    WriteRecordCache(RecordNumber, Buffer);
2233   end;
# Line 2355 | Line 2474 | begin
2474      SetInternalSQLParams(Qry.Params, Buff);
2475      Qry.ExecQuery;
2476    end;
2477 +  if Qry.FieldCount > 0 then {Has RETURNING Clause}
2478 +    UpdateRecordFromQuery(Qry.Current,Buff);
2479    PRecordData(Buff)^.rdUpdateStatus := usUnmodified;
2480    PRecordData(Buff)^.rdCachedUpdateStatus := cusUnmodified;
2481    SetModified(False);
# Line 2605 | Line 2726 | begin
2726      FQRefresh.Database := Value;
2727      FQSelect.Database := Value;
2728      FQModify.Database := Value;
2729 +    FDatabaseInfo.Database := Value;
2730 +    FGeneratorField.Database := Value;
2731    end;
2732   end;
2733  
# Line 2773 | Line 2896 | begin
2896      FQRefresh.Transaction := Value;
2897      FQSelect.Transaction := Value;
2898      FQModify.Transaction := Value;
2899 +    FGeneratorField.Transaction := Value;
2900    end;
2901   end;
2902  
# Line 3674 | Line 3798 | const
3798                 'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize}
3799                 'and ((not F.RDB$COMPUTED_BLR is NULL) or ' + {do not localize}
3800                 '     (not F.RDB$DEFAULT_VALUE is NULL)) '; {do not localize}
3801 +
3802 +  DefaultSQLODS12 = 'Select F.RDB$COMPUTED_BLR, ' + {do not localize}
3803 +               'F.RDB$DEFAULT_VALUE, R.RDB$FIELD_NAME, R.RDB$IDENTITY_TYPE ' + {do not localize}
3804 +               'from RDB$RELATION_FIELDS R, RDB$FIELDS F ' + {do not localize}
3805 +               'where R.RDB$RELATION_NAME = :RELATION ' +  {do not localize}
3806 +               'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize}
3807 +               'and ((not F.RDB$COMPUTED_BLR is NULL) or ' + {do not localize}
3808 +               '     (not F.RDB$DEFAULT_VALUE is NULL) or ' + {do not localize}
3809 +               '     ( not R.RDB$IDENTITY_TYPE is NULL))' ; {do not localize}
3810 +
3811   var
3812    FieldType: TFieldType;
3813    FieldSize: Word;
# Line 3714 | Line 3848 | var
3848        FField.FieldName := Query.Fields[2].AsString;
3849        FField.DEFAULT_VALUE := not Query.Fields[1].IsNull;
3850        FField.COMPUTED_BLR := not Query.Fields[0].IsNull;
3851 +      FField.IDENTITY_COLUMN := (Query.FieldCount > 3) and not Query.Fields[3].IsNull;
3852        FField.NextField := Result.FieldNodes;
3853        Result.FieldNodes := FField;
3854        Query.Next;
# Line 3767 | Line 3902 | var
3902          FField := Ffield.NextField;
3903    end;
3904  
3905 +  function Is_IDENTITY_COLUMN(Relation, Field : String) : Boolean;
3906 +  var
3907 +    FRelation : TRelationNode;
3908 +    FField : TFieldNode;
3909 +  begin
3910 +    FRelation := FRelationNodes;
3911 +    while Assigned(FRelation) and
3912 +         (FRelation.RelationName <> Relation) do
3913 +      FRelation := FRelation.NextRelation;
3914 +    if not Assigned(FRelation) then
3915 +      FRelation := Add_Node(Relation, Field);
3916 +    Result := false;
3917 +    FField := FRelation.FieldNodes;
3918 +    while Assigned(FField) do
3919 +      if FField.FieldName = Field then
3920 +      begin
3921 +        Result := Ffield.IDENTITY_COLUMN;
3922 +        Exit;
3923 +      end
3924 +      else
3925 +        FField := Ffield.NextField;
3926 +  end;
3927 +
3928    Procedure FreeNodes;
3929    var
3930      FRelation : TRelationNode;
# Line 3800 | Line 3958 | begin
3958      FieldIndex := 0;
3959      if (Length(FMappedFieldPosition) < SourceQuery.MetaData.Count) then
3960        SetLength(FMappedFieldPosition, SourceQuery.MetaData.Count);
3961 <    Query.SQL.Text := DefaultSQL;
3961 >    if FDatabaseInfo.ODSMajorVersion >= 12 then
3962 >      Query.SQL.Text := DefaultSQLODS12
3963 >    else
3964 >      Query.SQL.Text := DefaultSQL;
3965      Query.Prepare;
3966      SetLength(FAliasNameMap, SourceQuery.MetaData.Count);
3967      SetLength(FAliasNameList, SourceQuery.MetaData.Count);
# Line 3939 | Line 4100 | begin
4100              ArrayBounds := aArrayBounds;
4101              if (FieldName <> '') and (RelationName <> '') then
4102              begin
4103 +              IdentityColumn := Is_IDENTITY_COLUMN(RelationName, FieldName);
4104                if Has_COMPUTED_BLR(RelationName, FieldName) then
4105                begin
4106                  Attributes := [faReadOnly];
# Line 4841 | Line 5003 | begin
5003    InternalSetParams(Query.Params,buff);
5004   end;
5005  
5006 + procedure TIBDataSetUpdateObject.UpdateRecordFromQuery(QryResults: IResults;
5007 +  Buffer: PChar);
5008 + begin
5009 +  if not Assigned(DataSet) then Exit;
5010 +  DataSet.UpdateRecordFromQuery(QryResults, Buffer);
5011 + end;
5012 +
5013   function TIBDSBlobStream.GetSize: Int64;
5014   begin
5015    Result := FBlobStream.BlobSize;
# Line 4901 | Line 5070 | end;
5070  
5071   procedure TIBGenerator.SetIncrement(const AValue: integer);
5072   begin
5073 +  if FIncrement = AValue then Exit;
5074    if AValue < 0 then
5075 <     raise Exception.Create('A Generator Increment cannot be negative');
5076 <  FIncrement := AValue
5075 >    IBError(ibxeNegativeGenerator,[]);
5076 >  FIncrement := AValue;
5077 >  SetQuerySQL;
5078   end;
5079  
5080 < function TIBGenerator.GetNextValue(ADatabase: TIBDatabase;
4910 <  ATransaction: TIBTransaction): integer;
5080 > procedure TIBGenerator.SetTransaction(AValue: TIBTransaction);
5081   begin
5082 <  with TIBSQL.Create(nil) do
5083 <  try
5084 <    Database := ADatabase;
5085 <    Transaction := ATransaction;
5086 <    if not assigned(Database) then
5087 <       IBError(ibxeCannotSetDatabase,[]);
5088 <    if not assigned(Transaction) then
5089 <       IBError(ibxeCannotSetTransaction,[]);
5090 <    with Transaction do
5091 <      if not InTransaction then StartTransaction;
5092 <    SQL.Text := Format('Select Gen_ID(%s,%d) as ID From RDB$Database',[FGeneratorName,Increment]);
5093 <    Prepare;
5082 >  FQuery.Transaction := AValue;
5083 > end;
5084 >
5085 > procedure TIBGenerator.SetQuerySQL;
5086 > begin
5087 >  FQuery.SQL.Text := Format('Select Gen_ID(%s,%d) From RDB$Database',[FGeneratorName,Increment]);
5088 > end;
5089 >
5090 > function TIBGenerator.GetDatabase: TIBDatabase;
5091 > begin
5092 >  Result := FQuery.Database;
5093 > end;
5094 >
5095 > function TIBGenerator.GetTransaction: TIBTransaction;
5096 > begin
5097 >  Result := FQuery.Transaction;
5098 > end;
5099 >
5100 > procedure TIBGenerator.SetDatabase(AValue: TIBDatabase);
5101 > begin
5102 >  FQuery.Database := AValue;
5103 > end;
5104 >
5105 > procedure TIBGenerator.SetGeneratorName(AValue: string);
5106 > begin
5107 >  if FGeneratorName = AValue then Exit;
5108 >  FGeneratorName := AValue;
5109 >  SetQuerySQL;
5110 > end;
5111 >
5112 > function TIBGenerator.GetNextValue: integer;
5113 > begin
5114 >  with FQuery do
5115 >  begin
5116 >    Transaction.Active := true;
5117      ExecQuery;
5118      try
5119 <      Result := FieldByName('ID').AsInteger
5119 >      Result := Fields[0].AsInteger
5120      finally
5121        Close
5122      end;
4930  finally
4931    Free
5123    end;
5124   end;
5125  
# Line 4936 | Line 5127 | constructor TIBGenerator.Create(Owner: T
5127   begin
5128    FOwner := Owner;
5129    FIncrement := 1;
5130 +  FQuery := TIBSQL.Create(nil);
5131 + end;
5132 +
5133 + destructor TIBGenerator.Destroy;
5134 + begin
5135 +  if assigned(FQuery) then FQuery.Free;
5136 +  inherited Destroy;
5137   end;
5138  
5139  
5140   procedure TIBGenerator.Apply;
5141   begin
5142 <  if (FGeneratorName <> '') and (FFieldName <> '') and Owner.FieldByName(FFieldName).IsNull then
5143 <    Owner.FieldByName(FFieldName).AsInteger := GetNextValue(Owner.Database,Owner.Transaction);
5142 >  if assigned(Database) and assigned(Transaction) and
5143 >       (FGeneratorName <> '') and (FFieldName <> '') and Owner.FieldByName(FFieldName).IsNull then
5144 >    Owner.FieldByName(FFieldName).AsInteger := GetNextValue;
5145   end;
5146  
5147  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines