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

Comparing ibx/trunk/runtime/IBTable.pas (file contents):
Revision 1 by tony, Mon Jul 31 16:43:00 2000 UTC vs.
Revision 143 by tony, Fri Feb 23 12:11:21 2018 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 - 2018                                               }
31 + {                                                                        }
32   {************************************************************************}
33  
34   unit IBTable;
35  
36 < interface
36 > {$Mode Delphi}
37 >
38 > {$codepage UTF8}
39  
40 < uses Windows, SysUtils, Graphics, Classes, Controls, Db, StdVCL,
34 <     IB, IBDatabase, IBCustomDataSet, IBHeader, IBSQL, IBUtils;
40 > interface
41  
42 + uses SysUtils, Classes, DB, IB,  IBCustomDataSet,
43 +     IBSQL, IBUtils;
44 +    
45   type
46  
47   { TIBTable }
# Line 50 | Line 59 | type
59      FMasterLink: TMasterDataLink;
60      FMasterFieldsList: TStringList;
61      FDetailFieldsList: TStringList;
53    FStoreDefs: Boolean;
62      FIndexDefs: TIndexDefs;
63      FDefaultIndex: Boolean;
64      FReadOnly: Boolean;
# Line 62 | Line 70 | type
70      FSwitchingIndex: Boolean;
71      FPrimaryIndexFields: string;
72      FTableTypes: TIBTableTypes;
73 +    FStoreDefs: boolean;
74      WhereAllRefreshSQL: TStrings;
75      WhereDBKeyRefreshSQL: TStrings;
76      WherePrimaryRefreshSQL: TStrings;
# Line 88 | Line 97 | type
97      function GetExists: Boolean;
98      procedure SetIndexDefs(Value: TIndexDefs);
99      procedure ExtractLinkFields;
91    function FieldDefsStored: Boolean;
100      function IndexDefsStored: Boolean;
101      function GetMasterFields: string;
102      procedure SetMasterFields(const Value: string);
# Line 103 | Line 111 | type
111      procedure Reopen;
112  
113    protected
106    { IProviderSupport }
107    function PSGetDefaultOrder: TIndexDef; override;
108    function PSGetKeyFields: string; override;
109    function PSGetTableName: string; override;
110    function PSGetIndexDefs(IndexTypes: TIndexOptions): TIndexDefs; override;
111    procedure PSSetCommandText(const CommandText: string); override;
112    procedure PSSetParams(AParams: TParams); override;
114  
115      procedure DoOnNewRecord; override;
116      procedure GetIndexParams(const IndexName: string; FieldsIndex: Boolean;
117        var IndexedName: string);
118      function GetCanModify: Boolean; override;
119      procedure UpdateIndexDefs; override;
120 <    procedure DataEvent(Event: TDataEvent; Info: Longint); override;
121 <    procedure DefChanged(Sender: TObject); override;
120 >    procedure DataEvent(Event: TDataEvent; Info: Ptrint); override;
121 >    procedure DefChanged(Sender: TObject); virtual;
122      function GetDataSource: TDataSource; override;
123      procedure InitFieldDefs; override;
124      procedure InternalClose; override;
# Line 137 | Line 138 | type
138      procedure DeleteIndex(const Name: string);
139      procedure DeleteTable;
140      procedure EmptyTable;
141 <    procedure GetDetailLinkFields(MasterFields, DetailFields: TList); override;
141 >    procedure GetDetailLinkFields(MasterFields, DetailFields: TList); virtual;
142      procedure GetIndexNames(List: TStrings);
143      procedure GotoCurrent(Table: TIBTable);
144      property CurrentDBKey: TIBDBKey read GetCurrentDBKey;
# Line 147 | Line 148 | type
148      property TableNames: TStrings read GetTableNames;
149  
150    published
151 +    property AutoCommit;
152      property Active;
153      property BufferChunks;
154      property CachedUpdates;
155 <    property Constraints stored ConstraintsStored;
155 >    property DataSetCloseAction;
156 > //    property Constraints stored ConstraintsStored;
157      property DefaultIndex: Boolean read FDefaultIndex write FDefaultIndex default True;
155    property FieldDefs stored FieldDefsStored;
158      property Filter;
159      property Filtered;
160 +    property GeneratorField;
161      property IndexDefs: TIndexDefs read FIndexDefs write SetIndexDefs stored IndexDefsStored;
162      property IndexFieldNames: string read GetIndexFieldNames write SetIndexFieldNames;
163      property IndexName: string read GetIndexName write SetIndexName;
# Line 178 | Line 181 | type
181  
182   implementation
183  
184 + uses FBMessages;
185 +
186   { TIBTable }
187  
188   constructor TIBTable.Create(AOwner: TComponent);
# Line 234 | Line 239 | begin
239        GenerateUpdateSQL;
240      FRegenerateSQL := False;
241    end;
242 + {  writeln(SelectSQL.Text);
243 +  writeln(InsertSQL.Text);
244 +  writeln(DeleteSQL.Text);
245 +  writeln(ModifySQL.Text); }
246    SetParams;
247    inherited InternalOpen;
248   end;
# Line 285 | Line 294 | begin
294      QRefresh.SQL.Assign(WherePrimaryRefreshSQL)
295    else
296      QRefresh.SQL.Assign(WhereAllRefreshSQL);
297 <  inherited;
297 >  inherited InternalRefreshRow;
298   end;
299  
300   procedure TIBTable.DefChanged(Sender: TObject);
# Line 295 | Line 304 | end;
304  
305   procedure TIBTable.InitFieldDefs;
306   var
307 <  sqlscale: Integer;
307 >  DidActivate: Boolean;
308    Query: TIBSQL;
309   begin
310    if FTableName = '' then IBError(ibxeNoTableName, [nil]);
311 <  if (InternalPrepared) then InternalInitFieldDefs else
311 >  if (InternalPrepared) then
312 >     InternalInitFieldDefs
313 >  else
314    begin
315 <    Database.InternalTransaction.StartTransaction;
315 >    {Get the field defs from a simple query on the table}
316 >    ActivateConnection;
317      Query := TIBSQL.Create(self);
318      try
319 <      Query.GoToFirstRecordOnExecute := False;
320 <      Query.Database := DataBase;
321 <      Query.Transaction := Database.InternalTransaction;
322 <      Query.SQL.Text := 'Select R.RDB$FIELD_NAME, R.RDB$FIELD_POSITION, ' + {do not localize}
323 <                        'F.RDB$COMPUTED_BLR, F.RDB$DEFAULT_VALUE, ' + {do not localize}
324 <                        'F.RDB$NULL_FLAG, ' + {do not localize}
325 <                        'F.RDB$FIELD_LENGTH, F.RDB$FIELD_SCALE, ' + {do not localize}
326 <                        'F.RDB$FIELD_TYPE, F.RDB$FIELD_SUB_TYPE, ' + {do not localize}
327 <                        'F.RDB$EXTERNAL_LENGTH, F.RDB$EXTERNAL_SCALE, F.RDB$EXTERNAL_TYPE ' + {do not localize}
328 <                        'from RDB$RELATION_FIELDS R, RDB$FIELDS F ' + {do not localize}
317 <                        'where R.RDB$RELATION_NAME = ' + {do not localize}
318 <                        '''' +
319 <                        FormatIdentifierValue(Database.SQLDialect, FTableName) +
320 <                        ''' ' +
321 <                        'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize}
322 <                        'order by R.RDB$FIELD_POSITION'; {do not localize}
323 <
324 <      Query.Prepare;
325 <      Query.ExecQuery;
326 <      FieldDefs.BeginUpdate;
327 <      FieldDefs.Clear;
328 <      while (not Query.EOF) and (Query.Next <> nil) do
329 <      begin
330 <          with FieldDefs.AddFieldDef do
331 <          begin
332 <            FieldNo := Query.Current.ByName('RDB$FIELD_POSITION').AsInteger; {do not localize}
333 <            Name := TrimRight(Query.Current.ByName('RDB$FIELD_NAME').AsString); {do not localize}
334 <            case Query.Current.ByName('RDB$FIELD_TYPE').AsInteger of {do not localize}
335 <              blr_varying, blr_text: begin
336 <                DataType := ftString;
337 <                Size := Query.Current.ByName('RDB$FIELD_LENGTH').AsInteger; {do not localize}
338 <              end;
339 <              blr_float, blr_double, blr_d_float: DataType := ftFloat;
340 <              blr_short: begin
341 <                sqlscale := Query.Current.ByName('RDB$FIELD_SCALE').AsInteger; {do not localize}
342 <                if (sqlscale = 0) then
343 <                  DataType := ftSmallInt
344 <                else begin
345 <                  DataType := ftBCD;
346 <                  Precision := 4;
347 <                end;
319 >         Query.Database := DataBase;
320 >         Query.Transaction := Database.InternalTransaction;
321 >         DidActivate := false;
322 >         Query.SQL.Text := 'Select * from ' + QuoteIdentifier(DataBase.SQLDialect, FTableName);
323 >         with Query.Transaction do
324 >         begin
325 >              if not InTransaction then
326 >              begin
327 >                StartTransaction;
328 >                DidActivate := true
329                end;
330 <              blr_long: begin
331 <                sqlscale := Query.Current.ByName('RDB$FIELD_SCALE').AsInteger; {do not localize}
332 <                if (sqlscale = 0) then
333 <                  DataType := ftInteger
334 <                else if (sqlscale >= (-4)) then begin
354 <                  DataType := ftBCD;
355 <                  Precision := 9;
356 <                end else
357 <                  DataType := ftFloat;
358 <              end;
359 <              blr_int64: begin
360 <                sqlscale := Query.Current.ByName('RDB$FIELD_SCALE').AsInteger; {do not localize}
361 <                if (sqlscale = 0) then
362 <                  DataType := ftLargeInt
363 <                else if (sqlscale >= (-4)) then begin
364 <                  DataType := ftBCD;
365 <                  Precision := 18;
366 <                end else
367 <                  DataType := ftFloat;
368 <              end;
369 <              blr_timestamp: DataType := ftDateTime;
370 <              blr_sql_time: DataType := ftTime;
371 <              blr_sql_date: DataType := ftDate;
372 <              blr_blob:
373 <                if (Query.Current.ByName('RDB$FIELD_SUB_TYPE').AsInteger = 1) then {do not localize}
374 <                  DataType := ftMemo
375 <                else
376 <                  DataType := ftBlob;
377 <              blr_quad: begin
378 <                DataType := ftUnknown;
379 <                Size := sizeof (TISC_QUAD);
380 <              end;
381 <              else
382 <                DataType := ftUnknown;
383 <            end;
384 <            if not (Query.Current.ByName('RDB$COMPUTED_BLR').IsNull) then {do not localize}
385 <            begin
386 <              Attributes := [faReadOnly];
387 <              InternalCalcField := True
388 <            end
389 <            else
390 <              InternalCalcField := False;
391 <            if ((not InternalCalcField) and
392 <                 Query.Current.ByName('RDB$DEFAULT_VALUE').IsNull and {do not localize}
393 <                 (Query.Current.ByName('RDB$NULL_FLAG').AsInteger = 1) )then begin {do not localize}
394 <              Attributes := [faRequired];
395 <              Required := True;
396 <            end;
397 <          end;
398 <      end;
399 <      FieldDefs.EndUpdate;
330 >         end;
331 >         Query.Prepare;
332 >         FieldDefsFromQuery(Query);
333 >         if DidActivate then
334 >            Query.Transaction.Rollback;
335      finally
336 <      Query.free;
402 <      Database.InternalTransaction.Commit;
336 >         Query.Free;
337      end;
338    end;
339   end;
# Line 425 | Line 359 | begin
359      if (ixPrimary in Options) then
360      begin
361       Query.SQL.Text := 'Alter Table ' + {do not localize}
362 <       FormatIdentifier(Database.SQLDialect, FTableName) +
362 >       QuoteIdentifier(Database.SQLDialect, FTableName) +
363         ' Add CONSTRAINT ' +   {do not localize}
364 <       FormatIdentifier(Database.SQLDialect, Name)
364 >       QuoteIdentifier(Database.SQLDialect, Name)
365         + ' Primary Key (' + {do not localize}
366         FormatFieldsList(Fields) +
367         ')';
368      end
369      else if ([ixUnique, ixDescending] * Options = [ixUnique, ixDescending]) then
370        Query.SQL.Text := 'Create unique Descending Index ' + {do not localize}
371 <                        FormatIdentifier(Database.SQLDialect, Name) +
371 >                        QuoteIdentifier(Database.SQLDialect, Name) +
372                          ' on ' + {do not localize}
373 <                        FormatIdentifier(Database.SQLDialect, FTableName) +
373 >                        QuoteIdentifier(Database.SQLDialect, FTableName) +
374                          ' (' + FieldList + ')'
375      else if (ixUnique in Options) then
376        Query.SQL.Text := 'Create unique Index ' + {do not localize}
377 <                        FormatIdentifier(Database.SQLDialect, Name) +
377 >                        QuoteIdentifier(Database.SQLDialect, Name) +
378                          ' on ' + {do not localize}
379 <                        FormatIdentifier(Database.SQLDialect, FTableName) +
379 >                        QuoteIdentifier(Database.SQLDialect, FTableName) +
380                          ' (' + FieldList + ')'
381      else if (ixDescending in Options) then
382        Query.SQL.Text := 'Create Descending Index ' + {do not localize}
383 <                        FormatIdentifier(Database.SQLDialect, Name) +
383 >                        QuoteIdentifier(Database.SQLDialect, Name) +
384                          ' on ' + {do not localize}
385 <                        FormatIdentifier(Database.SQLDialect, FTableName) +
385 >                        QuoteIdentifier(Database.SQLDialect, FTableName) +
386                          ' (' + FieldList + ')'
387      else
388        Query.SQL.Text := 'Create Index ' + {do not localize}
389 <                        FormatIdentifier(Database.SQLDialect, Name) +
389 >                        QuoteIdentifier(Database.SQLDialect, Name) +
390                          ' on ' + {do not localize}
391 <                        FormatIdentifier(Database.SQLDialect, FTableName) +
391 >                        QuoteIdentifier(Database.SQLDialect, FTableName) +
392                          ' (' + FieldList + ')';
393      Query.Prepare;
394      Query.ExecQuery;
# Line 475 | Line 409 | var
409        Query.Database := DataBase;
410        Query.Transaction := Transaction;
411        Query.SQL.Text := 'Drop index ' +  {do not localize}
412 <                         FormatIdentifier(Database.SQLDialect, Name);
412 >                         QuoteIdentifier(Database.SQLDialect, Name);
413        Query.Prepare;
414        Query.ExecQuery;
415        IndexDefs.Updated := False;
# Line 494 | Line 428 | var
428        Query.SQL.Text := 'Select ''foo'' from RDB$RELATION_CONSTRAINTS ' +
429          'where RDB$RELATION_NAME = ' +
430          '''' +
431 <        FormatIdentifierValue(Database.SQLDialect, FTableName) +
431 >        ExtractIdentifier(Database.SQLDialect,
432 >          QuoteIdentifier(DataBase.SQLDialect, FTableName)) +
433          ''' ' +
434          ' AND RDB$CONSTRAINT_NAME = ' +
435          '''' +
436 <        FormatIdentifierValue(Database.SQLDialect, Name) +
436 >        ExtractIdentifier(Database.SQLDialect,
437 >          QuoteIdentifier(DataBase.SQLDialect, Name)) +
438          ''' ' +
439          'AND RDB$CONSTRAINT_TYPE = ''PRIMARY KEY''';
440        Query.Prepare;
# Line 507 | Line 443 | var
443        begin
444          Query.Close;
445          Query.SQL.Text := 'Alter Table ' +  {do not localize}
446 <          FormatIdentifier(Database.SQLDialect, FTableName) +
446 >          QuoteIdentifier(DataBase.SQLDialect, FTableName) +
447            ' Drop Constraint ' +
448 <          FormatIdentifier(Database.SQLDialect, Name);
448 >          QuoteIdentifier(DataBase.SQLDialect, Name);
449          Query.Prepare;
450          Query.ExecQuery;
451          IndexDefs.Updated := False;
# Line 529 | Line 465 | var
465        Query.SQL.Text := 'Select RDB$CONSTRAINT_NAME from RDB$RELATION_CONSTRAINTS ' +
466          'where RDB$RELATION_NAME = ' +
467          '''' +
468 <        FormatIdentifierValue(Database.SQLDialect, FTableName) +
468 >        ExtractIdentifier(Database.SQLDialect,
469 >          QuoteIdentifier(DataBase.SQLDialect, FTableName)) +
470          ''' ' +
471          'AND RDB$INDEX_NAME = ' +
472          '''' +
473 <        FormatIdentifierValue(Database.SQLDialect, Name) +
473 >        ExtractIdentifier(Database.SQLDialect,
474 >          QuoteIdentifier(DataBase.SQLDialect, Name)) +
475          ''' ' +
476          'AND RDB$CONSTRAINT_TYPE = ''PRIMARY KEY''';
477        Query.Prepare;
# Line 542 | Line 480 | var
480        begin
481          Query.Close;
482          Query.SQL.Text := 'Alter Table ' +  {do not localize}
483 <          FormatIdentifier(Database.SQLDialect, FTableName) +
483 >          QuoteIdentifier(DataBase.SQLDialect, FTableName) +
484            ' Drop Constraint ' +
485 <          FormatIdentifier(Database.SQLDialect, Query.Current.ByName('RDB$CONSTRAINT_NAME').AsString);
485 >          QuoteIdentifier(DataBase.SQLDialect, Query.FieldByName('RDB$CONSTRAINT_NAME').AsString);
486          Query.Prepare;
487          Query.ExecQuery;
488          IndexDefs.Updated := False;
# Line 629 | Line 567 | var
567    Opts: TIndexOptions;
568    Flds: string;
569    Query, SubQuery: TIBSQL;
570 +  fn: string;
571 +  aField: TFieldDef;
572   begin
573    if not (csReading in ComponentState) then begin
574    if not Active and not FSwitchingIndex  then
# Line 646 | Line 586 | begin
586      'I.RDB$SEGMENT_COUNT, S.RDB$FIELD_NAME from RDB$INDICES I, ' + {do not localize}
587      'RDB$INDEX_SEGMENTS S where I.RDB$INDEX_NAME = S.RDB$INDEX_NAME '+ {do not localize}
588      'and I.RDB$RELATION_NAME = ' + '''' + {do not localize}
589 <     FormatIdentifierValue(Database.SQLDialect, FTableName) + '''';
589 >     ExtractIdentifier(Database.SQLDialect,
590 >       QuoteIdentifier(DataBase.SQLDialect, FTableName)) + '''';
591      Query.Prepare;
592      Query.ExecQuery;
593 <    while (not Query.EOF) and (Query.Next <> nil) do
593 >    while (not Query.EOF) and Query.Next do
594      begin
595        with IndexDefs.AddIndexDef do
596        begin
597 <        Name := TrimRight(Query.Current.ByName('RDB$INDEX_NAME').AsString); {do not localize}
597 >        Name := TrimRight(Query.FieldByName('RDB$INDEX_NAME').AsString); {do not localize}
598          Opts := [];
599          if Pos ('RDB$PRIMARY', Name) = 1 then Include(Opts, ixPrimary); {do not localize} {mbcs ok}
600 <        if Query.Current.ByName('RDB$UNIQUE_FLAG').AsInteger = 1 then Include(Opts, ixUnique); {do not localize}
601 <        if Query.Current.ByName('RDB$INDEX_TYPE').AsInteger = 2  then Include(Opts, ixDescending); {do not localize}
600 >        if Query.FieldByName('RDB$UNIQUE_FLAG').AsInteger = 1 then Include(Opts, ixUnique); {do not localize}
601 >        if Query.FieldByName('RDB$INDEX_TYPE').AsInteger = 2  then Include(Opts, ixDescending); {do not localize}
602          Options := Opts;
603 <        if (Query.Current.ByName('RDB$SEGMENT_COUNT').AsInteger = 1) then {do not localize}
604 <          Fields := Trim(Query.Current.ByName('RDB$FIELD_NAME').AsString) {do not localize}
603 >        if (Query.FieldByName('RDB$SEGMENT_COUNT').AsInteger = 1) then {do not localize}
604 >        begin
605 >          fn := Trim(Query.FieldByName('RDB$FIELD_NAME').AsString); {do not localize}
606 >          aField := GetFieldDefFromAlias(fn);
607 >          if assigned(aField) then
608 >             Fields := aField.Name
609 >          else
610 >              Fields := fn;
611 >        end
612          else begin
613            SubQuery := TIBSQL.Create(self);
614          try
# Line 670 | Line 618 | begin
618            SubQuery.SQL.Text :=
619           'Select RDB$FIELD_NAME from RDB$INDEX_SEGMENTS where RDB$INDEX_NAME = ' + {do not localize}
620            '''' +
621 <          FormatIdentifierValue(Database.SQLDialect, Name) +
621 >          ExtractIdentifier(Database.SQLDialect,
622 >            QuoteIdentifier(DataBase.SQLDialect, Name)) +
623            '''' + 'ORDER BY RDB$FIELD_POSITION'; {do not localize}
624            SubQuery.Prepare;
625            SubQuery.ExecQuery;
626            Flds := '';
627 <          while (not SubQuery.EOF) and (SubQuery.Next <> nil) do
627 >          while (not SubQuery.EOF) and SubQuery.Next do
628            begin
629 +            fn := TrimRight(SubQuery.FieldByName('RDB$FIELD_NAME').AsString); {do not localize}
630 +            aField := GetFieldDefFromAlias(fn);
631 +            if assigned(aField) then
632 +               fn := aField.Name;
633              if (Flds = '') then
634 <              Flds := TrimRight(SubQuery.Current.ByName('RDB$FIELD_NAME').AsString) {do not localize}
634 >               Flds := fn
635              else begin
636                Query.Next;
637 <              Flds := Flds + ';' + TrimRight(SubQuery.Current[0].AsString);
637 >              Flds := Flds + ';' + fn;
638              end;
639            end;
640            Fields := Flds;
# Line 716 | Line 669 | begin
669      Query.SQL.Text :=
670      'Select USER from RDB$RELATIONS where RDB$RELATION_NAME = ' + {do not localize}
671      '''' +
672 <    FormatIdentifierValue(Database.SQLDialect, FTableName) + '''';
672 >    ExtractIdentifier(Database.SQLDialect,
673 >      QuoteIdentifier(DataBase.SQLDialect, FTableName)) + '''';
674      Query.Prepare;
675      Query.ExecQuery;
676      Result := not Query.EOF;
# Line 758 | Line 712 | var
712          case DataType of
713            ftString:
714              FieldList := FieldList +
715 <              FormatIdentifier(Database.SQLDialect, Name) +
715 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
716                ' VARCHAR(' + IntToStr(Size) + ')'; {do not localize}
717            ftFixedChar:
718              FieldList := FieldList +
719 <              FormatIdentifier(Database.SQLDialect, Name) +
719 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
720                ' CHAR(' + IntToStr(Size) + ')'; {do not localize}
721 <          ftBoolean, ftSmallint, ftWord:
721 >          ftBoolean:
722              FieldList := FieldList +
723 <              FormatIdentifier(Database.SQLDialect, Name) +
723 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
724 >              ' BOOLEAN'; {do not localize}
725 >          ftSmallint, ftWord:
726 >            FieldList := FieldList +
727 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
728                ' SMALLINT'; {do not localize}
729            ftInteger:
730              FieldList := FieldList +
731 <              FormatIdentifier(Database.SQLDialect, Name) +
731 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
732                ' INTEGER'; {do not localize}
733            ftFloat, ftCurrency:
734              FieldList := FieldList +
735 <              FormatIdentifier(Database.SQLDialect, Name) +
735 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
736                ' DOUBLE PRECISION'; {do not localize}
737            ftBCD: begin
738              if (Database.SQLDialect = 1) then begin
# Line 785 | Line 743 | var
743              end;
744              if (Precision <= 4 ) then
745                FieldList := FieldList +
746 <                FormatIdentifier(Database.SQLDialect, Name) +
746 >                QuoteIdentifier(DataBase.SQLDialect, Name) +
747                  ' Numeric(18, 4)' {do not localize}
748              else
749                FieldList := FieldList +
750 <                FormatIdentifier(Database.SQLDialect, Name) +
750 >                QuoteIdentifier(DataBase.SQLDialect, Name) +
751                  ' Numeric(' + IntToStr(Precision) + ', 4)'; {do not localize}
752            end;
753            ftDate:
754              FieldList := FieldList +
755 <              FormatIdentifier(Database.SQLDialect, Name) +
755 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
756                ' DATE'; {do not localize}
757            ftTime:
758              FieldList := FieldList +
759 <              FormatIdentifier(Database.SQLDialect, Name) +
759 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
760                ' TIME'; {do not localize}
761            ftDateTime:
762              if (Database.SQLDialect = 1) then
763                FieldList := FieldList +
764 <              FormatIdentifier(Database.SQLDialect, Name) +
764 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
765                ' DATE' {do not localize}
766              else
767                FieldList := FieldList +
768 <              FormatIdentifier(Database.SQLDialect, Name) +
768 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
769                ' TIMESTAMP'; {do not localize}
770            ftLargeInt:
771              if (Database.SQLDialect = 1) then
772                IBError(ibxeFieldUnsupportedType,[nil])
773              else
774                FieldList := FieldList +
775 <                FormatIdentifier(Database.SQLDialect, Name) +
775 >                QuoteIdentifier(DataBase.SQLDialect, Name) +
776                  ' Numeric(18, 0)'; {do not localize}
777            ftBlob, ftMemo:
778              FieldList := FieldList +
779 <              FormatIdentifier(Database.SQLDialect, Name) +
779 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
780                ' BLOB SUB_TYPE 1'; {do not localize}
781            ftBytes, ftVarBytes, ftGraphic..ftTypedBinary:
782              FieldList := FieldList +
783 <              FormatIdentifier(Database.SQLDialect, Name) +
783 >              QuoteIdentifier(DataBase.SQLDialect, Name) +
784                ' BLOB SUB_TYPE 0'; {do not localize}
785            ftUnknown, ftADT, ftArray, ftReference, ftDataSet,
786            ftCursor, ftWideString, ftAutoInc:
# Line 848 | Line 806 | var
806        Query.Database := Database;
807        Query.transaction := Transaction;
808        Query.SQL.Text := 'Create Table ' +
809 <        FormatIdentifier(Database.SQLDialect, FTableName) +
809 >        QuoteIdentifier(DataBase.SQLDialect, FTableName) +
810          ' (' + FieldList; {do not localize}
811        for I := 0 to IndexDefs.Count - 1 do
812        with IndexDefs[I] do
813          if ixPrimary in Options then
814          begin
815            Query.SQL.Text := Query.SQL.Text + ', CONSTRAINT ' +
816 <            FormatIdentifier(Database.SQLDialect, Name) +
816 >            QuoteIdentifier(DataBase.SQLDialect, Name) +
817              ' Primary Key (' +
818              FormatFieldsList(Fields) +
819              ')';
# Line 895 | Line 853 | begin
853      Query.Database := DataBase;
854      Query.Transaction := Transaction;
855      Query.SQL.Text := 'drop table ' +  {do not localize}
856 <      FormatIdentifier(Database.SQLDialect, FTableName);
856 >      QuoteIdentifier(DataBase.SQLDialect, FTableName);
857      Query.Prepare;
858      Query.ExecQuery;
859    finally
# Line 914 | Line 872 | begin
872      Query.Database := DataBase;
873      Query.Transaction := Transaction;
874      Query.SQL.Text := 'delete from ' + {do not localize}
875 <      FormatIdentifier(Database.SQLDialect, FTableName);
875 >      QuoteIdentifier(DataBase.SQLDialect, FTableName);
876      Query.Prepare;
877      Query.ExecQuery;
878      if Active then
# Line 927 | Line 885 | begin
885    end;
886   end;
887  
888 < procedure TIBTable.DataEvent(Event: TDataEvent; Info: Longint);
888 > procedure TIBTable.DataEvent(Event: TDataEvent; Info: Ptrint);
889   begin
890    if Event = dePropertyChange then begin
891      IndexDefs.Updated := False;
# Line 958 | Line 916 | begin
916      Query.SQL.Text := 'Select RDB$SYSTEM_FLAG, RDB$DBKEY_LENGTH ' + {do not localize}
917                      'from RDB$RELATIONS where RDB$RELATION_NAME = ' + {do not localize}
918                      '''' +
919 <                    FormatIdentifierValue(Database.SQLDialect, FTableName) + '''';
919 >                    ExtractIdentifier(Database.SQLDialect,
920 >                      QuoteIdentifier(DataBase.SQLDialect, FTableName)) + '''';
921      Query.Prepare;
922      Query.ExecQuery;
923 <    if (Query.Current[0].AsInteger <> 0) or
924 <       (Query.Current[1].AsInteger <> 8) then
923 >    if (Query.Fields[0].AsInteger <> 0) or
924 >       (Query.Fields[1].AsInteger <> 8) then
925        Result := False
926      else
927        Result := True;
# Line 972 | Line 931 | begin
931    end;
932   end;
933  
975 function TIBTable.FieldDefsStored: Boolean;
976 begin
977  Result := StoreDefs and (FieldDefs.Count > 0);
978 end;
979
934   function TIBTable.IndexDefsStored: Boolean;
935   begin
936    Result := StoreDefs and (IndexDefs.Count > 0);
# Line 1048 | Line 1002 | var
1002    i: Integer;
1003   begin
1004    if Database.SQLDialect = 1 then begin
1005 <    Value := FormatIdentifier(Database.SQLDialect, Value);
1005 >    Value := QuoteIdentifier(Database.SQLDialect, Value);
1006      Result := StringReplace (Value, ';', ', ', [rfReplaceAll]);
1007    end
1008    else begin
# Line 1058 | Line 1012 | begin
1012      begin
1013        FieldName := ExtractFieldName(Value, i);
1014        if Result = '' then
1015 <        Result := FormatIdentifier(Database.SQLDialect, FieldName)
1015 >        Result := QuoteIdentifier(Database.SQLDialect, FieldName)
1016        else
1017 <        Result := Result + ', ' + FormatIdentifier(Database.SQLDialect, FieldName);
1017 >        Result := Result + ', ' + QuoteIdentifier(Database.SQLDialect, FieldName);
1018      end;
1019    end;
1020   end;
# Line 1245 | Line 1199 | begin
1199                            ' where RDB$VIEW_BLR is NULL and RDB$SYSTEM_FLAG = 0'; {do not localize}
1200        Query.Prepare;
1201        Query.ExecQuery;
1202 <      while (not Query.EOF) and (Query.Next <> nil) do
1203 <        FNameList.Add (TrimRight(Query.Current[0].AsString));
1202 >      while (not Query.EOF) and Query.Next  do
1203 >        FNameList.Add (TrimRight(Query.Fields[0].AsString));
1204      finally
1205        Query.Free;
1206        Database.InternalTransaction.Commit;
# Line 1279 | Line 1233 | var
1233    SQL: TStrings;
1234    OrderByStr: string;
1235    bWhereClausePresent: Boolean;
1236 +  fn: string;
1237 +  aField: TFieldDef;
1238   begin
1239    bWhereClausePresent := False;
1240    Database.CheckActive;
# Line 1293 | Line 1249 | begin
1249      OrderByStr := FormatFieldsList(FPrimaryIndexFields);
1250    SQL := TStringList.Create;
1251    SQL.Text := 'select ' + {do not localize}
1252 <    FormatIdentifier(Database.SQLDialect, FTableName) + '.*, '
1252 >    QuoteIdentifier(DataBase.SQLDialect, FTableName) + '.*, ' {do not localize}
1253      + 'RDB$DB_KEY as IBX_INTERNAL_DBKEY from ' {do not localize}
1254 <    + FormatIdentifier(Database.SQLDialect, FTableName);
1254 >    + QuoteIdentifier(DataBase.SQLDialect, FTableName);
1255    if Filtered and (Filter <> '') then
1256    begin
1257      SQL.Text := SQL.Text + ' where ' + Filter; {do not localize}
# Line 1314 | Line 1270 | begin
1270      begin
1271        if i > 0 then
1272          SQL.Text := SQL.Text + 'AND ';
1273 +      aField := FieldDefs.Find(FDetailFieldsList.Strings[i]);
1274 +      if assigned(aField) then
1275 +         fn := GetDBAliasName(aField.FieldNo)
1276 +      else
1277 +          fn := FDetailFieldsList.Strings[i]; {something wrong if we get here - but should word}
1278        SQL.Text := SQL.Text +
1279 <        FormatIdentifier(Database.SQLDialect, FDetailFieldsList.Strings[i]) +
1319 <        ' = :' +
1320 <        FormatIdentifier(Database.SQLDialect, FMasterFieldsList.Strings[i]);
1279 >        QuoteIdentifier(DataBase.SQLDialect, fn) + ' = :' + FMasterFieldsList.Strings[i];
1280      end;
1281    end;
1282    if OrderByStr <> '' then
1283      SQL.Text := SQL.Text + ' order by ' + OrderByStr; {do not localize}
1284    SelectSQL.Assign(SQL);
1285    RefreshSQL.Text := 'select ' + {do not localize}
1286 <    FormatIdentifier(Database.SQLDialect, FTableName) + '.*, '
1286 >    QuoteIdentifier(DataBase.SQLDialect, FTableName) + '.*, ' {do not localize}
1287      + 'RDB$DB_KEY as IBX_INTERNAL_DBKEY from ' {do not localize}
1288 <    + FormatIdentifier(Database.SQLDialect, FTableName) +
1288 >    + QuoteIdentifier(DataBase.SQLDialect, FTableName) +
1289      ' where RDB$DB_KEY = :IBX_INTERNAL_DBKEY'; {do not localize}
1290    WhereDBKeyRefreshSQL.Assign(RefreshSQL);
1291    InternalPrepare;
# Line 1336 | Line 1295 | end;
1295   procedure TIBTable.GenerateUpdateSQL;
1296   var
1297    InsertFieldList, InsertParamList, UpdateFieldList: string;
1298 <  WherePrimaryFieldList, WhereAllFieldList: string;
1298 >  WherePrimaryFieldList, WhereAllFieldList,
1299 >    InsertReturningFieldList, UpdateReturningFieldList: string;
1300  
1301    procedure GenerateFieldLists;
1302    var
1303      I: Integer;
1304 +    AllowReturningClause: boolean;
1305    begin
1306 +     {Is database Firebird 2.1 or later?}
1307 +    AllowReturningClause := (DatabaseInfo.ODSMajorVersion > 11) or
1308 +        ((DatabaseInfo.ODSMajorVersion = 11) and (DatabaseInfo.ODSMinorVersion >= 1));
1309      for I := 0 to FieldDefs.Count - 1 do begin
1310 <      with FieldDefs[I] do begin
1310 >      with TIBFieldDef(FieldDefs[I]) do begin
1311 >        if AllowReturningClause then
1312 >        begin
1313 >          if (faReadOnly in Attributes) or IdentityColumn then
1314 >          begin
1315 >            if InsertReturningFieldList <> '' then
1316 >              InsertReturningFieldList := InsertReturningFieldList + ', ' +
1317 >                       QuoteIdentifier(DataBase.SQLDialect, GetDBAliasName(FieldNo))
1318 >            else
1319 >              InsertReturningFieldList := ' RETURNING ' +
1320 >                QuoteIdentifier(DataBase.SQLDialect, GetDBAliasName(FieldNo))
1321 >          end;
1322 >          if (faReadOnly in Attributes)  then
1323 >          begin
1324 >            if UpdateReturningFieldList <> '' then
1325 >              UpdateReturningFieldList := UpdateReturningFieldList + ', ' +
1326 >                       QuoteIdentifier(DataBase.SQLDialect, GetDBAliasName(FieldNo))
1327 >            else
1328 >              UpdateReturningFieldList := ' RETURNING ' +
1329 >                QuoteIdentifier(DataBase.SQLDialect, GetDBAliasName(FieldNo))
1330 >          end;
1331 >        end;
1332          if not (InternalCalcField or (faReadOnly in Attributes) or
1333 <          (DataType = ftUnknown)) then
1333 >           (DataType = ftUnknown)) then
1334          begin
1335 <          if ( InsertFieldList <> '' ) then begin
1336 <            InsertFieldList := InsertFieldList + ', ';
1337 <            InsertParamList := InsertParamList + ', ';
1335 >          if not IdentityColumn then
1336 >          begin
1337 >            if ( InsertFieldList <> '' ) then begin
1338 >              InsertFieldList := InsertFieldList + ', ';
1339 >              InsertParamList := InsertParamList + ', ';
1340 >            end;
1341 >            InsertFieldList := InsertFieldList +
1342 >              QuoteIdentifier(DataBase.SQLDialect, GetDBAliasName(FieldNo));
1343 >            InsertParamList := InsertParamList + ':' +  Name;
1344 >          end;
1345 >          if (UpdateFieldList <> '') then begin
1346              UpdateFieldList := UpdateFieldList + ', ';
1347              if (DataType <> ftBlob) and (DataType <>ftMemo) then
1348                WhereAllFieldList := WhereAllFieldList + ' AND ';
1349            end;
1357          InsertFieldList := InsertFieldList +
1358            FormatIdentifier(Database.SQLDialect, Name);
1359          InsertParamList := InsertParamList + ':' +
1360            FormatIdentifier(Database.SQLDialect, Name);
1350            UpdateFieldList := UpdateFieldList +
1351 <            FormatIdentifier(Database.SQLDialect, Name) +
1352 <            ' = :' +
1364 <            FormatIdentifier(Database.SQLDialect, Name);
1351 >            QuoteIdentifier(DataBase.SQLDialect, GetDBAliasName(FieldNo)) +
1352 >            ' = :' + Name;
1353            if (DataType <> ftBlob) and (DataType <>ftMemo) then
1354              WhereAllFieldList := WhereAllFieldList +
1355 <              FormatIdentifier(Database.SQLDialect, Name) + ' = :' +
1368 <              FormatIdentifier(Database.SQLDialect, Name);{do not localize}
1355 >              QuoteIdentifier(DataBase.SQLDialect, GetDBAliasName(FieldNo)) + ' = :' +  Name;
1356          end;
1357        end;
1358      end;
# Line 1374 | Line 1361 | var
1361    procedure GenerateWherePrimaryFieldList;
1362    var
1363      i: Integer;
1364 <    tmp: String;
1364 >    tmp, fn: String;
1365 >    aField: TFieldDef;
1366    begin
1367      i := 1;
1368      while i <= Length(FPrimaryIndexFields) do
1369      begin
1370        tmp := ExtractFieldName(FPrimaryIndexFields, i);
1371 +      aField := FieldDefs.Find(tmp);
1372 +      if assigned(aField) then
1373 +         fn := GetDBAliasName(aField.FieldNo)
1374 +      else
1375 +         fn := tmp; {something wrong if we get here - but will work in most cases}
1376        tmp :=
1377 <        FormatIdentifier(Database.SQLDialect, tmp) +  ' = :' +
1378 <        FormatIdentifier(Database.SQLDialect, tmp);{do not localize}
1377 >        QuoteIdentifier(DataBase.SQLDialect, fn) +  ' = :' +
1378 >        QuoteIdentifier(DataBase.SQLDialect, tmp);{do not localize}
1379        if WherePrimaryFieldList <> '' then
1380          WherePrimaryFieldList :=
1381            WherePrimaryFieldList + ' AND ' + tmp
# Line 1397 | Line 1390 | begin
1390    else
1391    begin
1392      DeleteSQL.Text := 'delete from ' + {do not localize}
1393 <      FormatIdentifier(Database.SQLDialect, FTableName) +
1393 >      QuoteIdentifier(DataBase.SQLDialect, FTableName) +
1394        ' where RDB$DB_KEY = ' + ':IBX_INTERNAL_DBKEY'; {do not localize}
1395      GenerateFieldLists;
1396      InsertSQL.Text := 'insert into ' + {do not localize}
1397 <      FormatIdentifier(Database.SQLDialect, FTableName) +
1397 >      QuoteIdentifier(DataBase.SQLDialect, FTableName) +
1398      ' (' + InsertFieldList + {do not localize}
1399 <      ') values (' + InsertParamList + ')'; {do not localize}
1399 >      ') values (' + InsertParamList + ')' + InsertReturningFieldList; {do not localize}
1400      ModifySQL.Text := 'update ' +
1401 <      FormatIdentifier(Database.SQLDialect, FTableName) +
1401 >      QuoteIdentifier(DataBase.SQLDialect, FTableName) +
1402        ' set ' + UpdateFieldList + {do not localize}
1403 <      ' where RDB$DB_KEY = :IBX_INTERNAL_DBKEY'; {do not localize}
1403 >      ' where RDB$DB_KEY = :IBX_INTERNAL_DBKEY' + UpdateReturningFieldList; {do not localize}
1404      WhereAllRefreshSQL.Text := 'select ' +  {do not localize}
1405 <      FormatIdentifier(Database.SQLDialect, FTableName) + '.*, '
1405 >      QuoteIdentifier(DataBase.SQLDialect, FTableName) + '.*, '
1406        + 'RDB$DB_KEY as IBX_INTERNAL_DBKEY from ' {do not localize}
1407 <      + FormatIdentifier(Database.SQLDialect, FTableName) +
1408 <      ' where ' + WhereAllFieldList; {do not localize}
1407 >      + QuoteIdentifier(DataBase.SQLDialect, FTableName) +
1408 >      ' where ' + WhereAllFieldList ; {do not localize}
1409      if FPrimaryIndexFields <> '' then
1410      begin
1411        GenerateWherePrimaryFieldList;
1412        WherePrimaryRefreshSQL.Text := 'select ' + {do not localize}
1413 <        FormatIdentifier(Database.SQLDialect, FTableName) + '.*, ' {do not localize}
1413 >        QuoteIdentifier(DataBase.SQLDialect, FTableName) + '.*, ' {do not localize}
1414          + 'RDB$DB_KEY as IBX_INTERNAL_DBKEY from ' {do not localize}
1415 <        + FormatIdentifier(Database.SQLDialect, FTableName) +
1415 >        + QuoteIdentifier(DataBase.SQLDialect, FTableName) +
1416          ' where ' + WherePrimaryFieldList; {do not localize}
1417      end;
1418      try
# Line 1499 | Line 1492 | begin
1492      begin
1493        SetState(dsInactive);
1494        CloseCursor;
1495 <      OpenCursor;
1495 >      OpenCursor(false);
1496        SetState(dsBrowse);
1497      end;
1498    finally
# Line 1507 | Line 1500 | begin
1500    end;
1501   end;
1502  
1510 { TIBTable IProviderSupport }
1511
1512 function TIBTable.PSGetDefaultOrder: TIndexDef;
1513
1514  function GetIdx(IdxType: TIndexOption): TIndexDef;
1515  var
1516    i: Integer;
1517  begin
1518    Result := nil;
1519    for i := 0 to IndexDefs.Count - 1 do
1520      if IdxType in IndexDefs[i].Options then
1521      try
1522        Result := IndexDefs[i];
1523        GetFieldList(nil, Result.Fields);
1524        break;
1525      except
1526        Result := nil;
1527      end;
1528  end;
1529
1530 var
1531  DefIdx: TIndexDef;
1532 begin
1533  DefIdx := nil;
1534  IndexDefs.Update;
1535  try
1536    if IndexName <> '' then
1537      DefIdx := IndexDefs.Find(IndexName)
1538    else if IndexFieldNames <> '' then
1539      DefIdx := IndexDefs.FindIndexForFields(IndexFieldNames);
1540    if Assigned(DefIdx) then
1541      GetFieldList(nil, DefIdx.Fields);
1542  except
1543    DefIdx := nil;
1544  end;
1545  if not Assigned(DefIdx) then
1546    DefIdx := GetIdx(ixPrimary);
1547  if not Assigned(DefIdx) then
1548    DefIdx := GetIdx(ixUnique);
1549  if Assigned(DefIdx) then
1550  begin
1551    Result := TIndexDef.Create(nil);
1552    Result.Assign(DefIdx);
1553  end else
1554    Result := nil;
1555 end;
1556
1557 function TIBTable.PSGetIndexDefs(IndexTypes: TIndexOptions): TIndexDefs;
1558 begin
1559  Result := GetIndexDefs(IndexDefs, IndexTypes);
1560 end;
1561
1562 function TIBTable.PSGeTTableName: string;
1563 begin
1564  Result := FTableName;
1565 end;
1566
1567 procedure TIBTable.PSSetParams(AParams: TParams);
1568 begin
1569  if AParams.Count > 0 then
1570    Open;
1571  PSReset;
1572 end;
1573
1574 procedure TIBTable.PSSetCommandText(const CommandText: string);
1575 begin
1576  if CommandText <> '' then
1577    TableName := CommandText;
1578 end;
1579
1580 function TIBTable.PSGetKeyFields: string;
1581 var
1582  i, Idx: Integer;
1583  IndexFound: Boolean;
1584 begin
1585  Result := inherited PSGetKeyFields;
1586  if Result = '' then
1587  begin
1588    if not Exists then Exit;
1589    IndexFound := False;
1590    IndexDefs.Update;
1591    FieldDefs.Update;
1592    for i := 0 to IndexDefs.Count - 1 do
1593      if ixUnique in IndexDefs[I].Options then
1594      begin
1595        Idx := 1;
1596        Result := IndexDefs[I].Fields;
1597        IndexFound := False;
1598        while Idx <= Length(Result) do
1599        begin
1600          IndexFound := FindField(ExtractFieldName(Result, Idx)) <> nil;
1601          if not IndexFound then Break;
1602        end;
1603        if IndexFound then Break;
1604      end;
1605    if not IndexFound then
1606      Result := '';
1607  end;
1608 end;
1609
1503   end.

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines