home *** CD-ROM | disk | FTP | other *** search
/ Delphi Anthology / aDELPHI.iso / Runimage / Delphi50 / Source / Vcl / ibtable.pas < prev    next >
Pascal/Delphi Source File  |  1999-08-11  |  49KB  |  1,578 lines

  1. {********************************************************}
  2. {                                                        }
  3. {       Borland Delphi Visual Component Library          }
  4. {       InterBase Express core components                }
  5. {                                                        }
  6. {       Copyright (c) 1998-1999 Inprise Corporation      }
  7. {                                                        }
  8. {    InterBase Express is based in part on the product   }
  9. {    Free IB Components, written by Gregory H. Deatz for }
  10. {    Hoagland, Longo, Moran, Dunst & Doukas Company.     }
  11. {    Free IB Components is used under license.           }
  12. {                                                        }
  13. {********************************************************}
  14.  
  15. unit IBTable;
  16.  
  17. interface
  18.  
  19. uses Windows, SysUtils, Graphics, Classes, Controls, Db, StdVCL,
  20.      IB, IBDatabase, IBCustomDataSet, IBHeader, IBSQL, IBUtils;
  21.  
  22. type
  23.  
  24. { TIBTable }
  25.  
  26.   TBatchMode = (batAppend, batUpdate, batAppendUpdate, batDelete, batCopy);
  27.   TIBTableType = (ttSystem, ttView);
  28.   TIBTableTypes = set of TIBTableType;
  29.   TIndexName = String;
  30.  
  31.   TIBTable = class;
  32.  
  33.   TIBTable = class(TIBCustomDataSet)
  34.   private
  35.     FSystemTable: Boolean;
  36.     FMultiTableView: Boolean;
  37.     FMasterLink: TMasterDataLink;
  38.     FMasterFieldsList: TStringList;
  39.     FDetailFieldsList: TStringList;
  40.     FStoreDefs: Boolean;
  41.     FIndexDefs: TIndexDefs;
  42.     FDefaultIndex: Boolean;
  43.     FReadOnly: Boolean;
  44.     FFieldsIndex: Boolean;
  45.     FTableName: String;
  46.     FIndexName: TIndexName;
  47.     FRegenerateSQL: Boolean;
  48.     FNameList: TStrings;
  49.     FSwitchingIndex: Boolean;
  50.     FPrimaryIndexFields: string;
  51.     FTableTypes: TIBTableTypes;
  52.     WhereAllRefreshSQL: TStrings;
  53.     WhereDBKeyRefreshSQL: TStrings;
  54.     WherePrimaryRefreshSQL: TStrings;
  55.  
  56.     function GetIndexFieldCount: Integer;
  57.     function GetIndexField(Index: Integer): TField;
  58.     procedure MasterChanged(Sender: TObject);
  59.     procedure MasterDisabled(Sender: TObject);
  60.     procedure SetDataSource(Value: TDataSource);
  61.     procedure SetIndexField(Index: Integer; Value: TField);
  62.     procedure SetIndexFieldNames(const Value: string);
  63.     procedure GenerateSQL;
  64.     procedure GenerateUpdateSQL;
  65.     procedure SwitchToIndex();
  66.     procedure InternalTableRefresh();
  67.     function GetTableNames: TStrings;
  68.     procedure GetTableNamesFromServer;
  69.     procedure SetTableTypes(
  70.     const Value: TIBTableTypes);
  71.     function InternalGotoDBKey(DBKey: TIBDBKey): Boolean;
  72.     function FormatFieldsList(Value: string): string;
  73.     function GetCurrentDBKey: TIBDBKey;
  74.     function InternalGetUpdatable: Boolean;
  75.     function GetExists: Boolean;
  76.     procedure SetIndexDefs(Value: TIndexDefs);
  77.     procedure ExtractLinkFields;
  78.     function FieldDefsStored: Boolean;
  79.     function IndexDefsStored: Boolean;
  80.     function GetMasterFields: string;
  81.     procedure SetMasterFields(const Value: string);
  82.     function GetIndexFieldNames: string;
  83.     function GetIndexName: string;
  84.     procedure SetIndexName(const Value: string);
  85.     procedure SetParams;
  86.     procedure SetReadOnly(Value: Boolean);
  87.     procedure SetTableName(Value: String);
  88.     procedure SetIndex(const Value: string; FieldsIndex: Boolean);
  89.     procedure ResetSQLStatements;
  90.     procedure Reopen;
  91.     
  92.   protected
  93.     { IProviderSupport }
  94.     function PSGetDefaultOrder: TIndexDef; override;
  95.     function PSGetKeyFields: string; override;
  96.     function PSGetTableName: string; override;
  97.     function PSGetIndexDefs(IndexTypes: TIndexOptions): TIndexDefs; override;
  98.     procedure PSSetCommandText(const CommandText: string); override;
  99.     procedure PSSetParams(AParams: TParams); override;
  100.  
  101.     procedure DoOnNewRecord; override;
  102.     procedure GetIndexParams(const IndexName: string; FieldsIndex: Boolean;
  103.       var IndexedName: string);
  104.     function GetCanModify: Boolean; override;
  105.     procedure UpdateIndexDefs; override;
  106.     procedure DataEvent(Event: TDataEvent; Info: Longint); override;
  107.     procedure DefChanged(Sender: TObject); override;
  108.     function GetDataSource: TDataSource; override;
  109.     procedure InitFieldDefs; override;
  110.     procedure InternalClose; override;
  111.     procedure InternalOpen; override;
  112.     procedure SetFiltered(Value: Boolean); override;
  113.     procedure SetFilterText(const Value: string); override;
  114.     procedure SetFilterOptions(Value: TFilterOptions); override;
  115.     procedure InternalRefreshRow; override;
  116.  
  117.   public
  118.     constructor Create(AOwner: TComponent); override;
  119.     destructor Destroy; override;
  120.     procedure AddIndex(const Name, Fields: string; Options: TIndexOptions;
  121.       const DescFields: string = '');
  122.     procedure CreateTable;
  123.     procedure DeleteIndex(const Name: string);
  124.     procedure DeleteTable;
  125.     procedure EmptyTable;
  126.     procedure GetDetailLinkFields(MasterFields, DetailFields: TList); override;
  127.     procedure GetIndexNames(List: TStrings);
  128.     procedure GotoCurrent(Table: TIBTable);
  129.     property CurrentDBKey: TIBDBKey read GetCurrentDBKey;
  130.     property Exists: Boolean read GetExists;
  131.     property IndexFieldCount: Integer read GetIndexFieldCount;
  132.     property IndexFields[Index: Integer]: TField read GetIndexField write SetIndexField;
  133.     property TableNames: TStrings read GetTableNames;
  134.     property BufferChunks;
  135.     property UniDirectional;
  136.  
  137.   published
  138.     property CachedUpdates;
  139.     property Constraints stored ConstraintsStored;
  140.     property DefaultIndex: Boolean read FDefaultIndex write FDefaultIndex default True;
  141.     property FieldDefs stored FieldDefsStored;
  142.     property Filter;
  143.     property Filtered;
  144.     property IndexDefs: TIndexDefs read FIndexDefs write SetIndexDefs stored IndexDefsStored;
  145.     property IndexFieldNames: string read GetIndexFieldNames write SetIndexFieldNames;
  146.     property IndexName: string read GetIndexName write SetIndexName;
  147.     property MasterFields: string read GetMasterFields write SetMasterFields;
  148.     property MasterSource: TDataSource read GetDataSource write SetDataSource;
  149.     property ReadOnly: Boolean read FReadOnly write SetReadOnly default False;
  150.     property StoreDefs: Boolean read FStoreDefs write FStoreDefs default False;
  151.     property TableName: String read FTableName write SetTableName;
  152.     property UpdateObject;
  153.     property TableTypes: TIBTableTypes read FTableTypes write SetTableTypes default [];
  154.   end;
  155.  
  156. implementation
  157.  
  158. { TIBTable }
  159.  
  160. constructor TIBTable.Create(AOwner: TComponent);
  161. begin
  162.   inherited Create(AOwner);
  163.   FNameList := TStringList.Create;
  164.   FSwitchingIndex := False;
  165.   FIndexDefs := TIndexDefs.Create(Self);
  166.   WhereAllRefreshSQL := TStringList.Create;
  167.   WhereDBKeyRefreshSQL := TStringList.Create;
  168.   WherePrimaryRefreshSQL := TStringList.Create;
  169.   FDefaultIndex := True;
  170.   FRegenerateSQL := True;
  171.   FMasterFieldsList := TStringList.Create;
  172.   FDetailFieldsList := TStringList.Create;
  173.   FMasterLink := TMasterDataLink.Create(Self);
  174.   FMasterLink.OnMasterChange := MasterChanged;
  175.   FMasterLink.OnMasterDisable := MasterDisabled;
  176.   QRefresh.OnSQLChanging := nil;
  177.   QDelete.OnSQLChanging := nil;
  178.   QInsert.OnSQLChanging := nil;
  179.   QModify.OnSQLChanging := nil;
  180. end;
  181.  
  182. destructor TIBTable.Destroy;
  183. begin
  184.   FNameList.Free;
  185.   FIndexDefs.Free;
  186.   FMasterFieldsList.Free;
  187.   FDetailFieldsList.Free;
  188.   FMasterLink.Free;
  189.   WhereAllRefreshSQL.Free;
  190.   WhereDBKeyRefreshSQL.Free;
  191.   WherePrimaryRefreshSQL.Free;
  192.   inherited Destroy;
  193. end;
  194.  
  195. procedure TIBTable.InternalClose;
  196. begin
  197.   DataEvent(dePropertyChange, 0);
  198.   inherited InternalClose;
  199. end;
  200.  
  201. procedure TIBTable.InternalOpen;
  202. begin
  203.   if FTableName = '' then IBError(ibxeNoTableName, [nil]);
  204.   ActivateConnection;
  205.   ActivateTransaction;
  206.   if FRegenerateSQL then
  207.   begin
  208.     InternalUnprepare;
  209.     GenerateSQL;
  210.     if not FReadOnly then
  211.       GenerateUpdateSQL;
  212.     FRegenerateSQL := False;
  213.   end;
  214.   SetParams;
  215.   inherited InternalOpen;
  216. end;
  217.  
  218. procedure TIBTable.SetFiltered(Value: Boolean);
  219. begin
  220.   if(Filtered <> Value) then
  221.   begin
  222.     inherited SetFiltered(value);
  223.     if Active then
  224.       InternalTableRefresh;
  225.   end
  226.   else
  227.     inherited SetFiltered(value);
  228. end;
  229.  
  230. procedure TIBTable.SetFilterText(const Value: string);
  231. begin
  232.   if Filtered and (Value <> Filter) then
  233.   begin
  234.     inherited SetFilterText(value);
  235.     InternalTableRefresh;
  236.   end
  237.   else
  238.     inherited SetFilterText(value);
  239. end;
  240.  
  241. procedure TIBTable.SetFilterOptions(Value: TFilterOptions);
  242. begin
  243.   if Value <> [] then
  244.     IBError(ibxeNotSupported, [nil]);
  245. end;
  246.  
  247. procedure TIBTable.InternalRefreshRow;
  248. begin
  249.   if CurrentDBKey.DBKey[0] <> 0 then
  250.     QRefresh.SQL.Assign(WhereDBKeyRefreshSQL)
  251.   else if WherePrimaryRefreshSQL.Text <> '' then
  252.     QRefresh.SQL.Assign(WherePrimaryRefreshSQL)
  253.   else
  254.     QRefresh.SQL.Assign(WhereAllRefreshSQL);
  255.   inherited;
  256.  
  257. end;
  258.  
  259. procedure TIBTable.DefChanged(Sender: TObject);
  260. begin
  261.   StoreDefs := True;
  262. end;
  263.  
  264. procedure TIBTable.InitFieldDefs;
  265. var
  266.   sqlscale: Integer;
  267.   Query: TIBSQL;
  268. begin
  269.   if FTableName = '' then IBError(ibxeNoTableName, [nil]);
  270.   if (InternalPrepared) then InternalInitFieldDefs else
  271.   begin
  272.     Database.InternalTransaction.StartTransaction;
  273.     Query := TIBSQL.Create(self);
  274.     try
  275.       Query.GoToFirstRecordOnExecute := False;
  276.       Query.Database := DataBase;
  277.       Query.Transaction := Database.InternalTransaction;
  278.       Query.SQL.Text := 'Select R.RDB$FIELD_NAME, R.RDB$FIELD_POSITION, ' + {do not localize}
  279.                         'F.RDB$COMPUTED_BLR, F.RDB$DEFAULT_VALUE, ' + {do not localize}
  280.                         'F.RDB$NULL_FLAG, ' + {do not localize}
  281.                         'F.RDB$FIELD_LENGTH, F.RDB$FIELD_SCALE, ' + {do not localize}
  282.                         'F.RDB$FIELD_TYPE, F.RDB$FIELD_SUB_TYPE, ' + {do not localize}
  283.                         'F.RDB$EXTERNAL_LENGTH, F.RDB$EXTERNAL_SCALE, F.RDB$EXTERNAL_TYPE ' + {do not localize}
  284.                         'from RDB$RELATION_FIELDS R, RDB$FIELDS F ' + {do not localize}
  285.                         'where R.RDB$RELATION_NAME = ' + {do not localize}
  286.                         '''' +
  287.                         FormatIdentifierValue(Database.SQLDialect, FTableName) +
  288.                         ''' ' +
  289.                         'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize}
  290.                         'order by R.RDB$FIELD_POSITION'; {do not localize}
  291.  
  292.       Query.Prepare;
  293.       Query.ExecQuery;
  294.       FieldDefs.BeginUpdate;
  295.       FieldDefs.Clear;
  296.       while (not Query.EOF) and (Query.Next <> nil) do
  297.       begin
  298.           with FieldDefs.AddFieldDef do
  299.           begin
  300.             FieldNo := Query.Current.ByName('RDB$FIELD_POSITION').AsInteger; {do not localize}
  301.             Name := TrimRight(Query.Current.ByName('RDB$FIELD_NAME').AsString); {do not localize}
  302.             case Query.Current.ByName('RDB$FIELD_TYPE').AsInteger of {do not localize}
  303.               blr_varying, blr_text: begin
  304.                 DataType := ftString;
  305.                 Size := Query.Current.ByName('RDB$FIELD_LENGTH').AsInteger; {do not localize}
  306.               end;
  307.               blr_float, blr_double, blr_d_float: DataType := ftFloat;
  308.               blr_short: begin
  309.                 sqlscale := Query.Current.ByName('RDB$FIELD_SCALE').AsInteger; {do not localize}
  310.                 if (sqlscale = 0) then
  311.                   DataType := ftSmallInt
  312.                 else begin
  313.                   DataType := ftBCD;
  314.                   Precision := 4;
  315.                 end;
  316.               end;
  317.               blr_long: begin
  318.                 sqlscale := Query.Current.ByName('RDB$FIELD_SCALE').AsInteger; {do not localize}
  319.                 if (sqlscale = 0) then
  320.                   DataType := ftInteger
  321.                 else if (sqlscale >= (-4)) then begin
  322.                   DataType := ftBCD;
  323.                   Precision := 9;
  324.                 end else
  325.                   DataType := ftFloat;
  326.               end;
  327.               blr_int64: begin
  328.                 sqlscale := Query.Current.ByName('RDB$FIELD_SCALE').AsInteger; {do not localize}
  329.                 if (sqlscale = 0) then
  330.                   DataType := ftLargeInt
  331.                 else if (sqlscale >= (-4)) then begin
  332.                   DataType := ftBCD;
  333.                   Precision := 18;
  334.                 end else
  335.                   DataType := ftFloat;
  336.               end;
  337.               blr_timestamp: DataType := ftDateTime;
  338.               blr_sql_time: DataType := ftTime;
  339.               blr_sql_date: DataType := ftDate;
  340.               blr_blob:
  341.                 if (Query.Current.ByName('RDB$FIELD_SUB_TYPE').AsInteger = 1) then {do not localize}
  342.                   DataType := ftMemo
  343.                 else
  344.                   DataType := ftBlob;
  345.               blr_quad: begin
  346.                 DataType := ftUnknown;
  347.                 Size := sizeof (TISC_QUAD);
  348.               end;
  349.               else
  350.                 DataType := ftUnknown;
  351.             end;
  352.             if not (Query.Current.ByName('RDB$COMPUTED_BLR').IsNull) then {do not localize}
  353.             begin
  354.               Attributes := [faReadOnly];
  355.               InternalCalcField := True
  356.             end
  357.             else
  358.               InternalCalcField := False;
  359.             if ((not InternalCalcField) and
  360.                  Query.Current.ByName('RDB$DEFAULT_VALUE').IsNull and {do not localize}
  361.                  (Query.Current.ByName('RDB$NULL_FLAG').AsInteger = 1) )then begin {do not localize}
  362.               Attributes := [faRequired];
  363.               Required := True;
  364.             end;
  365.           end;
  366.       end;
  367.       FieldDefs.EndUpdate;
  368.     finally
  369.       Query.free;
  370.       Database.InternalTransaction.Commit;
  371.     end;
  372.   end;
  373. end;
  374.  
  375. { Index / Ranges / Keys }
  376.  
  377. procedure TIBTable.AddIndex(const Name, Fields: string; Options: TIndexOptions;
  378.   const DescFields: string);
  379. var
  380.   Query: TIBSQL;
  381.   FieldList: string;
  382. begin
  383.   FieldDefs.Update;
  384.   if Active then begin
  385.     CheckBrowseMode;
  386.     CursorPosChanged;
  387.   end;
  388.   Query := TIBSQL.Create(self);
  389.   try
  390.     Query.Database := DataBase;
  391.     Query.Transaction := Transaction;
  392.     FieldList := FormatFieldsList(Fields);
  393.     if (ixPrimary in Options) then
  394.     begin
  395.      Query.SQL.Text := 'Alter Table ' + {do not localize}
  396.        FormatIdentifier(Database.SQLDialect, FTableName) +
  397.        ' Add CONSTRAINT ' +   {do not localize}
  398.        FormatIdentifier(Database.SQLDialect, Name)
  399.        + ' Primary Key (' + {do not localize}
  400.        FormatFieldsList(Fields) +
  401.        ')';
  402.     end
  403.     else if ([ixUnique, ixDescending] * Options = [ixUnique, ixDescending]) then
  404.       Query.SQL.Text := 'Create unique Descending Index ' + {do not localize}
  405.                         FormatIdentifier(Database.SQLDialect, Name) +
  406.                         ' on ' + {do not localize}
  407.                         FormatIdentifier(Database.SQLDialect, FTableName) +
  408.                         ' (' + FieldList + ')'
  409.     else if (ixUnique in Options) then
  410.       Query.SQL.Text := 'Create unique Index ' + {do not localize}
  411.                         FormatIdentifier(Database.SQLDialect, Name) +
  412.                         ' on ' + {do not localize}
  413.                         FormatIdentifier(Database.SQLDialect, FTableName) +
  414.                         ' (' + FieldList + ')'
  415.     else if (ixDescending in Options) then
  416.       Query.SQL.Text := 'Create Descending Index ' + {do not localize}
  417.                         FormatIdentifier(Database.SQLDialect, Name) +
  418.                         ' on ' + {do not localize}
  419.                         FormatIdentifier(Database.SQLDialect, FTableName) +
  420.                         ' (' + FieldList + ')'
  421.     else
  422.       Query.SQL.Text := 'Create Index ' + {do not localize}
  423.                         FormatIdentifier(Database.SQLDialect, Name) +
  424.                         ' on ' + {do not localize}
  425.                         FormatIdentifier(Database.SQLDialect, FTableName) +
  426.                         ' (' + FieldList + ')';
  427.     Query.Prepare;
  428.     Query.ExecQuery;
  429.     IndexDefs.Updated := False;
  430.   finally
  431.     Query.free
  432.   end;
  433. end;
  434.  
  435. procedure TIBTable.DeleteIndex(const Name: string);
  436. var
  437.   Query: TIBSQL;
  438.  
  439.   procedure DeleteByIndex;
  440.   begin
  441.     Query := TIBSQL.Create(self);
  442.     try
  443.       Query.Database := DataBase;
  444.       Query.Transaction := Transaction;
  445.       Query.SQL.Text := 'Drop index ' +  {do not localize}
  446.                          FormatIdentifier(Database.SQLDialect, Name);
  447.       Query.Prepare;
  448.       Query.ExecQuery;
  449.       IndexDefs.Updated := False;
  450.     finally
  451.       Query.Free;
  452.     end;
  453.   end;
  454.  
  455.   function DeleteByConstraint: Boolean;
  456.   begin
  457.     Result := False;
  458.     Query := TIBSQL.Create(self);
  459.     try
  460.       Query.Database := DataBase;
  461.       Query.Transaction := Transaction;
  462.       Query.SQL.Text := 'Select ''foo'' from RDB$RELATION_CONSTRAINTS ' +
  463.         'where RDB$RELATION_NAME = ' +
  464.         '''' +
  465.         FormatIdentifierValue(Database.SQLDialect, FTableName) +
  466.         ''' ' +
  467.         ' AND RDB$CONSTRAINT_NAME = ' +
  468.         '''' +
  469.         FormatIdentifierValue(Database.SQLDialect, Name) +
  470.         ''' ' +
  471.         'AND RDB$CONSTRAINT_TYPE = ''PRIMARY KEY''';
  472.       Query.Prepare;
  473.       Query.ExecQuery;
  474.       if not Query.EOF then
  475.       begin
  476.         Query.Close;
  477.         Query.SQL.Text := 'Alter Table ' +  {do not localize}
  478.           FormatIdentifier(Database.SQLDialect, FTableName) +
  479.           ' Drop Constraint ' +
  480.           FormatIdentifier(Database.SQLDialect, Name);
  481.         Query.Prepare;
  482.         Query.ExecQuery;
  483.         IndexDefs.Updated := False;
  484.         Result := True;
  485.       end;
  486.     finally
  487.       Query.Free;
  488.     end;
  489.   end;
  490.  
  491.   procedure DeleteByKey;
  492.   begin
  493.     Query := TIBSQL.Create(self);
  494.     try
  495.       Query.Database := DataBase;
  496.       Query.Transaction := Transaction;
  497.       Query.SQL.Text := 'Select RDB$CONSTRAINT_NAME from RDB$RELATION_CONSTRAINTS ' +
  498.         'where RDB$RELATION_NAME = ' +
  499.         '''' +
  500.         FormatIdentifierValue(Database.SQLDialect, FTableName) +
  501.         ''' ' +
  502.         'AND RDB$INDEX_NAME = ' +
  503.         '''' +
  504.         FormatIdentifierValue(Database.SQLDialect, Name) +
  505.         ''' ' +
  506.         'AND RDB$CONSTRAINT_TYPE = ''PRIMARY KEY''';
  507.       Query.Prepare;
  508.       Query.ExecQuery;
  509.       if not Query.EOF then
  510.       begin
  511.         Query.Close;
  512.         Query.SQL.Text := 'Alter Table ' +  {do not localize}
  513.           FormatIdentifier(Database.SQLDialect, FTableName) +
  514.           ' Drop Constraint ' +
  515.           FormatIdentifier(Database.SQLDialect, Query.Current.ByName('RDB$CONSTRAINT_NAME').AsString);
  516.         Query.Prepare;
  517.         Query.ExecQuery;
  518.         IndexDefs.Updated := False;
  519.       end;
  520.     finally
  521.       Query.Free;
  522.     end;
  523.   end;
  524.  
  525. begin
  526.   if Active then
  527.     CheckBrowseMode;
  528.   IndexDefs.Update;
  529.   if (Pos('RDB$PRIMARY', Name) <> 0 ) then {do not localize} {mbcs ok}
  530.     DeleteByKey
  531.   else if not DeleteByConstraint then
  532.     DeleteByIndex;
  533. end;
  534.  
  535. function TIBTable.GetIndexFieldNames: string;
  536. begin
  537.   if FFieldsIndex then Result := FIndexName else Result := '';
  538. end;
  539.  
  540. function TIBTable.GetIndexName: string;
  541. begin
  542.   if FFieldsIndex then Result := '' else Result := FIndexName;
  543. end;
  544.  
  545. procedure TIBTable.GetIndexNames(List: TStrings);
  546. begin
  547.   IndexDefs.Update;
  548.   IndexDefs.GetItemNames(List);
  549. end;
  550.  
  551. procedure TIBTable.GetIndexParams(const IndexName: string;
  552.   FieldsIndex: Boolean; var IndexedName: string);
  553. var
  554.   IndexStr: TIndexName;
  555. begin
  556.   if IndexName <> '' then
  557.   begin
  558.     IndexDefs.Update;
  559.     IndexStr := IndexName;
  560.     if FieldsIndex then
  561.       IndexStr := IndexDefs.FindIndexForFields(IndexName).Name;
  562.   end;
  563.   IndexedName := IndexStr;
  564. end;
  565.  
  566. procedure TIBTable.SetIndexDefs(Value: TIndexDefs);
  567. begin
  568.   IndexDefs.Assign(Value);
  569. end;
  570.  
  571. procedure TIBTable.SetIndex(const Value: string; FieldsIndex: Boolean);
  572. begin
  573.   if Active then CheckBrowseMode;
  574.   if (FIndexName <> Value) or (FFieldsIndex <> FieldsIndex) then
  575.   begin
  576.     FIndexName := Value;
  577.     FFieldsIndex := FieldsIndex;
  578.     if Active then
  579.     begin
  580.       SwitchToIndex;
  581.     end;
  582.   end;
  583. end;
  584.  
  585. procedure TIBTable.SetIndexFieldNames(const Value: string);
  586. begin
  587.   SetIndex(Value, Value <> '');
  588. end;
  589.  
  590. procedure TIBTable.SetIndexName(const Value: string);
  591. begin
  592.   SetIndex(Value, False);
  593. end;
  594.  
  595. procedure TIBTable.UpdateIndexDefs;
  596. var
  597.   Opts: TIndexOptions;
  598.   Flds: string;
  599.   Query, SubQuery: TIBSQL;
  600. begin
  601.   if not (csReading in ComponentState) then begin
  602.   if not Active and not FSwitchingIndex  then
  603.     FieldDefs.Update;
  604.   IndexDefs.Clear;
  605.   Database.InternalTransaction.StartTransaction;
  606.   Query := TIBSQL.Create(self);
  607.   try
  608.     FPrimaryIndexFields := '';
  609.     Query.GoToFirstRecordOnExecute := False;
  610.     Query.Database := DataBase;
  611.     Query.Transaction := Database.InternalTransaction;
  612.     Query.SQL.Text :=
  613.     'Select I.RDB$INDEX_NAME, I.RDB$UNIQUE_FLAG, I.RDB$INDEX_TYPE, ' + {do not localize}
  614.     'I.RDB$SEGMENT_COUNT, S.RDB$FIELD_NAME from RDB$INDICES I, ' + {do not localize}
  615.     'RDB$INDEX_SEGMENTS S where I.RDB$INDEX_NAME = S.RDB$INDEX_NAME '+ {do not localize}
  616.     'and I.RDB$RELATION_NAME = ' + '''' + {do not localize}
  617.      FormatIdentifierValue(Database.SQLDialect, FTableName) + '''';
  618.     Query.Prepare;
  619.     Query.ExecQuery;
  620.     while (not Query.EOF) and (Query.Next <> nil) do
  621.     begin
  622.       with IndexDefs.AddIndexDef do
  623.       begin
  624.         Name := TrimRight(Query.Current.ByName('RDB$INDEX_NAME').AsString); {do not localize}
  625.         Opts := [];
  626.         if Pos ('RDB$PRIMARY', Name) = 1 then Include(Opts, ixPrimary); {do not localize} {mbcs ok}
  627.         if Query.Current.ByName('RDB$UNIQUE_FLAG').AsInteger = 1 then Include(Opts, ixUnique); {do not localize}
  628.         if Query.Current.ByName('RDB$INDEX_TYPE').AsInteger = 2  then Include(Opts, ixDescending); {do not localize}
  629.         Options := Opts;
  630.         if (Query.Current.ByName('RDB$SEGMENT_COUNT').AsInteger = 1) then {do not localize}
  631.           Fields := Trim(Query.Current.ByName('RDB$FIELD_NAME').AsString) {do not localize}
  632.         else begin
  633.           SubQuery := TIBSQL.Create(self);
  634.         try
  635.           SubQuery.GoToFirstRecordOnExecute := False;
  636.           SubQuery.Database := DataBase;
  637.           SubQuery.Transaction := Database.InternalTransaction;
  638.           SubQuery.SQL.Text :=
  639.          'Select RDB$FIELD_NAME from RDB$INDEX_SEGMENTS where RDB$INDEX_NAME = ' + {do not localize}
  640.           '''' +
  641.           FormatIdentifierValue(Database.SQLDialect, Name) +
  642.           '''' + 'ORDER BY RDB$FIELD_POSITION'; {do not localize}
  643.           SubQuery.Prepare;
  644.           SubQuery.ExecQuery;
  645.           Flds := '';
  646.           while (not SubQuery.EOF) and (SubQuery.Next <> nil) do
  647.           begin
  648.             if (Flds = '') then
  649.               Flds := TrimRight(SubQuery.Current.ByName('RDB$FIELD_NAME').AsString) {do not localize}
  650.             else begin
  651.               Query.Next;
  652.               Flds := Flds + ';' + TrimRight(SubQuery.Current[0].AsString);
  653.             end;
  654.           end;
  655.           Fields := Flds;
  656.         finally
  657.           SubQuery.Free;
  658.         end;
  659.         end;
  660.         if (ixDescending in Opts) then
  661.           DescFields := Fields;
  662.         if ixPrimary in Opts then
  663.           FPrimaryIndexFields := Fields;
  664.       end;
  665.     end;
  666.   finally
  667.     Query.Free;
  668.     Database.InternalTransaction.Commit;
  669.   end;
  670.   end;
  671. end;
  672.  
  673. function TIBTable.GetExists: Boolean;
  674. var
  675.   Query: TIBSQL;
  676. begin
  677.   Result := Active;
  678.   if Result or (TableName = '') then Exit;
  679.   Database.InternalTransaction.StartTransaction;
  680.   Query := TIBSQL.Create(self);
  681.   try
  682.     Query.Database := DataBase;
  683.     Query.Transaction := Database.InternalTransaction;
  684.     Query.SQL.Text :=
  685.     'Select USER from RDB$RELATIONS where RDB$RELATION_NAME = ' + {do not localize}
  686.     '''' +
  687.     FormatIdentifierValue(Database.SQLDialect, FTableName) + '''';
  688.     Query.Prepare;
  689.     Query.ExecQuery;
  690.     Result := not Query.EOF;
  691.   finally
  692.     Query.Free;
  693.     Database.InternalTransaction.Commit;
  694.   end;
  695. end;
  696.  
  697. procedure TIBTable.GotoCurrent(Table: TIBTable);
  698. begin
  699.   CheckBrowseMode;
  700.   Table.CheckBrowseMode;
  701.   if (Database <> Table.Database) or
  702.     (CompareText(TableName, Table.TableName) <> 0) then
  703.     IBError(ibxeTableNameMismatch, [nil]);
  704.   Table.UpdateCursorPos;
  705.   InternalGotoDBKey(Table.CurrentDBKey);
  706.   DoBeforeScroll;
  707.   Resync([rmExact, rmCenter]);
  708.   DoAfterScroll;
  709. end;
  710.  
  711.  
  712. procedure TIBTable.CreateTable;
  713. var
  714.   FieldList: string;
  715.  
  716.   procedure InitFieldsList;
  717.   var
  718.     I: Integer;
  719.   begin
  720.     InitFieldDefsFromFields;
  721.     for I := 0 to FieldDefs.Count - 1 do begin
  722.       if ( I > 0) then
  723.         FieldList := FieldList + ', ';
  724.       with FieldDefs[I] do
  725.       begin
  726.         case DataType of
  727.           ftString:
  728.             FieldList := FieldList +
  729.               FormatIdentifier(Database.SQLDialect, Name) +
  730.               ' VARCHAR(' + IntToStr(Size) + ')'; {do not localize}
  731.           ftFixedChar:
  732.             FieldList := FieldList +
  733.               FormatIdentifier(Database.SQLDialect, Name) +
  734.               ' CHAR(' + IntToStr(Size) + ')'; {do not localize}
  735.           ftBoolean, ftSmallint, ftWord:
  736.             FieldList := FieldList +
  737.               FormatIdentifier(Database.SQLDialect, Name) +
  738.               ' SMALLINT'; {do not localize}
  739.           ftInteger:
  740.             FieldList := FieldList +
  741.               FormatIdentifier(Database.SQLDialect, Name) +
  742.               ' INTEGER'; {do not localize}
  743.           ftFloat, ftCurrency:
  744.             FieldList := FieldList +
  745.               FormatIdentifier(Database.SQLDialect, Name) +
  746.               ' DOUBLE PRECISION'; {do not localize}
  747.           ftBCD: begin
  748.             if (Database.SQLDialect = 1) then begin
  749.               if (Precision > 9) then
  750.                 IBError(ibxeFieldUnsupportedType,[nil]);
  751.               if (Precision <= 4) then
  752.                 Precision := 9;
  753.             end;
  754.             if (Precision <= 4 ) then
  755.               FieldList := FieldList +
  756.                 FormatIdentifier(Database.SQLDialect, Name) +
  757.                 ' Numeric(18, 4)' {do not localize}
  758.             else
  759.               FieldList := FieldList +
  760.                 FormatIdentifier(Database.SQLDialect, Name) +
  761.                 ' Numeric(' + IntToStr(Precision) + ', 4)'; {do not localize}
  762.           end;
  763.           ftDate:
  764.             FieldList := FieldList +
  765.               FormatIdentifier(Database.SQLDialect, Name) +
  766.               ' DATE'; {do not localize}
  767.           ftTime:
  768.             FieldList := FieldList +
  769.               FormatIdentifier(Database.SQLDialect, Name) +
  770.               ' TIME'; {do not localize}
  771.           ftDateTime:
  772.             if (Database.SQLDialect = 1) then
  773.               FieldList := FieldList +
  774.               FormatIdentifier(Database.SQLDialect, Name) +
  775.               ' DATE' {do not localize}
  776.             else
  777.               FieldList := FieldList +
  778.               FormatIdentifier(Database.SQLDialect, Name) +
  779.               ' TIMESTAMP'; {do not localize}
  780.           ftLargeInt:
  781.             if (Database.SQLDialect = 1) then
  782.               IBError(ibxeFieldUnsupportedType,[nil])
  783.             else
  784.               FieldList := FieldList +
  785.                 FormatIdentifier(Database.SQLDialect, Name) +
  786.                 ' Numeric(18, 0)'; {do not localize}
  787.           ftBlob, ftMemo:
  788.             FieldList := FieldList +
  789.               FormatIdentifier(Database.SQLDialect, Name) +
  790.               ' BLOB SUB_TYPE 1'; {do not localize}
  791.           ftBytes, ftVarBytes, ftGraphic..ftTypedBinary:
  792.             FieldList := FieldList +
  793.               FormatIdentifier(Database.SQLDialect, Name) +
  794.               ' BLOB SUB_TYPE 0'; {do not localize}
  795.           ftUnknown, ftADT, ftArray, ftReference, ftDataSet,
  796.           ftCursor, ftWideString, ftAutoInc:
  797.             IBError(ibxeFieldUnsupportedType,[nil]);
  798.           else
  799.             IBError(ibxeFieldUnsupportedType,[nil]);
  800.         end;
  801.         if faRequired in Attributes then
  802.           FieldList := FieldList + ' NOT NULL'; {do not localize}
  803.       end;
  804.     end;
  805.   end;
  806.  
  807.   procedure InternalCreateTable;
  808.   var
  809.     I: Integer;
  810.     Query: TIBSQL;
  811.   begin
  812.     if (FieldList = '') then
  813.       IBError(ibxeFieldUnsupportedType,[nil]);
  814.     Query := TIBSQL.Create(self);
  815.     try
  816.       Query.Database := Database;
  817.       Query.transaction := Transaction;
  818.       Query.SQL.Text := 'Create Table ' +
  819.         FormatIdentifier(Database.SQLDialect, FTableName) +
  820.         ' (' + FieldList; {do not localize}
  821.       for I := 0 to IndexDefs.Count - 1 do
  822.       with IndexDefs[I] do
  823.         if ixPrimary in Options then
  824.         begin
  825.           Query.SQL.Text := Query.SQL.Text + ', CONSTRAINT ' +
  826.             FormatIdentifier(Database.SQLDialect, Name) +
  827.             ' Primary Key (' +
  828.             FormatFieldsList(Fields) +
  829.             ')';
  830.         end;
  831.       Query.SQL.Text := Query.SQL.Text + ')';
  832.       Query.Prepare;
  833.       Query.ExecQuery;
  834.     finally
  835.       Query.Free;
  836.     end;
  837.   end;
  838.  
  839.   procedure InternalCreateIndex;
  840.   var
  841.     I: Integer;
  842.   begin
  843.     for I := 0 to IndexDefs.Count - 1 do
  844.     with IndexDefs[I] do
  845.       if not (ixPrimary in Options) then
  846.         AddIndex(Name, Fields, Options);
  847.   end;
  848.  
  849. begin
  850.   CheckInactive;
  851.   InitFieldsList;
  852.   InternalCreateTable;
  853.   InternalCreateIndex;
  854. end;
  855.  
  856. procedure TIBTable.DeleteTable;
  857. var
  858.   Query: TIBSQL;
  859. begin
  860.   CheckInactive;
  861.   Query := TIBSQL.Create(self);
  862.   try
  863.     Query.Database := DataBase;
  864.     Query.Transaction := Transaction;
  865.     Query.SQL.Text := 'drop table ' +  {do not localize}
  866.       FormatIdentifier(Database.SQLDialect, FTableName);
  867.     Query.Prepare;
  868.     Query.ExecQuery;
  869.   finally
  870.     Query.Free;
  871.   end;
  872. end;
  873.  
  874. procedure TIBTable.EmptyTable;
  875. var
  876.   Query: TIBSQL;
  877. begin
  878.   if Active then
  879.     CheckBrowseMode;
  880.   Query := TIBSQL.Create(self);
  881.   try
  882.     Query.Database := DataBase;
  883.     Query.Transaction := Transaction;
  884.     Query.SQL.Text := 'delete from ' + {do not localize}
  885.       FormatIdentifier(Database.SQLDialect, FTableName);
  886.     Query.Prepare;
  887.     Query.ExecQuery;
  888.     if Active then
  889.     begin
  890.       ClearBuffers;
  891.       DataEvent(deDataSetChange, 0);
  892.     end;
  893.   finally
  894.     Query.Free;
  895.   end;
  896. end;
  897.  
  898. procedure TIBTable.DataEvent(Event: TDataEvent; Info: Longint);
  899. begin
  900.   if Event = dePropertyChange then begin
  901.     IndexDefs.Updated := False;
  902.     FRegenerateSQL := True;
  903.   end;
  904.   inherited DataEvent(Event, Info);
  905. end;
  906.  
  907. { Informational & Property }
  908.  
  909. function TIBTable.GetCanModify: Boolean;
  910. begin
  911.   Result := True;
  912.   if (FTableName = '') or FReadOnly
  913.     or FSystemTable or FMultiTableView then
  914.     Result := False;
  915. end;
  916.  
  917. function TIBTable.InternalGetUpdatable: Boolean;
  918. var
  919.   Query : TIBSQL;
  920. begin
  921.   Database.InternalTransaction.StartTransaction;
  922.   Query := TIBSQL.Create(self);
  923.   try
  924.     Query.Database := DataBase;
  925.     Query.Transaction := Database.InternalTransaction;
  926.     Query.SQL.Text := 'Select RDB$SYSTEM_FLAG, RDB$DBKEY_LENGTH ' + {do not localize}
  927.                     'from RDB$RELATIONS where RDB$RELATION_NAME = ' + {do not localize}
  928.                     '''' +
  929.                     FormatIdentifierValue(Database.SQLDialect, FTableName) + '''';
  930.     Query.Prepare;
  931.     Query.ExecQuery;
  932.     if (Query.Current[0].AsInteger <> 0) or
  933.        (Query.Current[1].AsInteger <> 8) then
  934.       Result := False
  935.     else
  936.       Result := True;
  937.   finally
  938.     Query.Free;
  939.     Database.InternalTransaction.Commit;
  940.   end;
  941. end;
  942.  
  943. function TIBTable.FieldDefsStored: Boolean;
  944. begin
  945.   Result := StoreDefs and (FieldDefs.Count > 0);
  946. end;
  947.  
  948. function TIBTable.IndexDefsStored: Boolean;
  949. begin
  950.   Result := StoreDefs and (IndexDefs.Count > 0);
  951. end;
  952.  
  953. procedure TIBTable.SetParams;
  954. var
  955.   i: Integer;
  956. begin
  957.   if (MasterSource = nil) or (MasterSource.DataSet = nil) or
  958.   (not MasterSource.DataSet.Active) or (FMasterFieldsList.Count = 0) then
  959.     exit;
  960.   for i := 0 to FMasterFieldsList.Count - 1 do
  961.     QSelect.Params.ByName(FMasterFieldsList.Strings[i]).Value :=
  962.     MasterSource.DataSet.FieldByName(FMasterFieldsList.Strings[i]).Value;
  963. end;
  964.  
  965. procedure TIBTable.MasterChanged(Sender: TObject);
  966. begin
  967.   CheckBrowseMode;
  968.   SetParams;
  969.   ReQuery;
  970. end;
  971.  
  972. procedure TIBTable.MasterDisabled(Sender: TObject);
  973. begin
  974.   DataEvent(dePropertyChange, 0);
  975.   ReQuery;
  976. end;
  977.  
  978. function TIBTable.GetDataSource: TDataSource;
  979. begin
  980.   Result := FMasterLink.DataSource;
  981. end;
  982.  
  983. procedure TIBTable.SetDataSource(Value: TDataSource);
  984. begin
  985.   if IsLinkedTo(Value) then IBError(ibxeCircularDataLink, [Self]);
  986.   if FMasterLink.DataSource <> Value then
  987.     DataEvent(dePropertyChange, 0);
  988.   FMasterLink.DataSource := Value;
  989. end;
  990.  
  991. function TIBTable.GetMasterFields: string;
  992. begin
  993.   Result := FMasterLink.FieldNames;
  994. end;
  995.  
  996. procedure TIBTable.SetMasterFields(const Value: string);
  997. begin
  998.   if FMasterLink.FieldNames <> Value then
  999.     DataEvent(dePropertyChange, 0);
  1000.   FMasterLink.FieldNames := Value;
  1001. end;
  1002.  
  1003. procedure TIBTable.DoOnNewRecord;
  1004. var
  1005.   I: Integer;
  1006. begin
  1007.   if FMasterLink.Active and (FMasterLink.Fields.Count > 0) then
  1008.     for I := 0 to FMasterLink.Fields.Count - 1 do
  1009.       IndexFields[I] := TField(FMasterLink.Fields[I]);
  1010.   inherited DoOnNewRecord;
  1011. end;
  1012.  
  1013. function TIBTable.FormatFieldsList(Value: String): String;
  1014. var
  1015.   FieldName: string;
  1016.   i: Integer;
  1017. begin
  1018.   if Database.SQLDialect = 1 then begin
  1019.     Value := FormatIdentifier(Database.SQLDialect, Value);
  1020.     Result := StringReplace (Value, ';', ', ', [rfReplaceAll]);
  1021.   end
  1022.   else begin
  1023.     i := 1;
  1024.     Result := '';
  1025.     while i <= Length(Value) do
  1026.     begin
  1027.       FieldName := ExtractFieldName(Value, i);
  1028.       if Result = '' then
  1029.         Result := FormatIdentifier(Database.SQLDialect, FieldName)
  1030.       else
  1031.         Result := Result + ', ' + FormatIdentifier(Database.SQLDialect, FieldName);
  1032.     end;
  1033.   end;
  1034. end;
  1035.  
  1036. procedure TIBTable.ExtractLinkFields;
  1037. var
  1038.   i: Integer;
  1039.   DetailFieldNames: String;
  1040. begin
  1041.   FMasterFieldsList.Clear;
  1042.   FDetailFieldsList.Clear;
  1043.   i := 1;
  1044.   while i <= Length(MasterFields) do
  1045.     FMasterFieldsList.Add(ExtractFieldName(MasterFields, i));
  1046.   i := 1;
  1047.   if IndexFieldNames = '' then
  1048.     DetailFieldNames := FPrimaryIndexFields
  1049.   else
  1050.     DetailFieldNames := IndexFieldNames;
  1051.   while i <= Length(DetailFieldNames) do
  1052.     FDetailFieldsList.Add(ExtractFieldName(DetailFieldNames, i));
  1053. end;
  1054.  
  1055. procedure TIBTable.GetDetailLinkFields(MasterFields, DetailFields: TList);
  1056. var
  1057.   i: Integer;
  1058.   Idx: TIndexDef;
  1059. begin
  1060.   MasterFields.Clear;
  1061.   DetailFields.Clear;
  1062.   if (MasterSource <> nil) and (MasterSource.DataSet <> nil) and
  1063.      (Self.MasterFields <> '') then
  1064.   begin
  1065.     Idx := nil;
  1066.     MasterSource.DataSet.GetFieldList(MasterFields, Self.MasterFields);
  1067.     UpdateIndexDefs;
  1068.     if IndexName <> '' then
  1069.       Idx := IndexDefs.Find(IndexName)
  1070.     else if IndexFieldNames <> '' then
  1071.       Idx := IndexDefs.GetIndexForFields(IndexFieldNames, False)
  1072.     else
  1073.       for i := 0 to IndexDefs.Count - 1 do
  1074.         if ixPrimary in IndexDefs[i].Options then
  1075.         begin
  1076.           Idx := IndexDefs[i];
  1077.           break;
  1078.         end;
  1079.     if Idx <> nil then
  1080.       GetFieldList(DetailFields, Idx.Fields);
  1081.   end;
  1082. end;
  1083.  
  1084. procedure TIBTable.SetReadOnly(Value: Boolean);
  1085. begin
  1086.   CheckInactive;
  1087.   FReadOnly := Value;
  1088. end;
  1089.  
  1090. procedure TIBTable.SetTableName(Value: String);
  1091. begin
  1092.   if not (csReading in ComponentState) then
  1093.   begin
  1094.     CheckInactive;
  1095.     if Value <> FTableName then
  1096.     begin
  1097.       ResetSQLStatements;
  1098.       FRegenerateSQL := True;
  1099.       FTableName := Value;
  1100.       IndexName := '';
  1101.       IndexFieldNames := '';
  1102.       FPrimaryIndexFields := '';
  1103.       DataEvent(dePropertyChange, 0);
  1104.     end;
  1105.   end
  1106.   else if Value <> FTableName then
  1107.     FTableName := Value;
  1108. end;
  1109.  
  1110. function TIBTable.GetIndexField(Index: Integer): TField;
  1111. var
  1112.   I, Count: Integer;
  1113.   FieldNames, FieldName: String;
  1114. begin
  1115.   Result := nil;
  1116.   FieldName := '';
  1117.   FieldNames := IndexFieldNames;
  1118.   if FieldNames = '' then
  1119.   begin
  1120.     for I := 0 to IndexDefs.Count - 1 do
  1121.       if (IndexDefs[i].Name = FIndexName) then
  1122.       begin
  1123.         FieldNames := IndexDefs[i].Fields;
  1124.         break;
  1125.       end;
  1126.   end;
  1127.   for I := 0 to Index do
  1128.   begin
  1129.     Count := Pos(';', FieldNames); {mbcs OK}
  1130.     if Count = 0 then
  1131.       FieldName := FieldNames
  1132.     else begin
  1133.       FieldName := Copy(FieldNames, 0, Count - 1);
  1134.       System.Delete(FieldNames, 1, Count);
  1135.     end;
  1136.   end;
  1137.   if FieldName <> '' then
  1138.     Result := FieldByName(FieldName)
  1139.   else
  1140.     IBError(ibxeIndexFieldMissing, [nil]);
  1141. end;
  1142.  
  1143.  
  1144. procedure TIBTable.SetIndexField(Index: Integer; Value: TField);
  1145. begin
  1146.   GetIndexField(Index).Assign(Value);
  1147. end;
  1148.  
  1149. function TIBTable.GetIndexFieldCount: Integer;
  1150. var
  1151.   I, Index: Integer;
  1152.   FieldNames: String;
  1153.   done: Boolean;
  1154. begin
  1155.   FieldNames := IndexFieldNames;
  1156.   if FieldNames = '' then
  1157.   begin
  1158.     for I := 0 to IndexDefs.Count - 1 do
  1159.       if (IndexDefs[i].Name = FIndexName) then
  1160.       begin
  1161.         FieldNames := IndexDefs[i].Fields;
  1162.         break;
  1163.       end;
  1164.   end;
  1165.   if FieldNames = '' then
  1166.     Result := 0
  1167.   else
  1168.   begin
  1169.     done := False;
  1170.     Result := 1;
  1171.     while not done do
  1172.     begin
  1173.       Index := Pos(';', FieldNames); {mbcs ok}
  1174.       if Index <> 0 then
  1175.       begin
  1176.         System.Delete(FieldNames, 1, Index);
  1177.         Inc(Result);
  1178.       end else
  1179.         done := True;
  1180.     end;
  1181.   end;
  1182. end;
  1183.  
  1184. function TIBTable.GetTableNames: TStrings;
  1185. begin
  1186.   FNameList.clear;
  1187.   GetTableNamesFromServer;
  1188.   Result := FNameList;
  1189. end;
  1190.  
  1191. procedure TIBTable.GetTableNamesFromServer;
  1192. var
  1193.   Query : TIBSQL;
  1194. begin
  1195.   if not (csReading in ComponentState) then begin
  1196.     ActivateConnection;
  1197.     Database.InternalTransaction.StartTransaction;
  1198.     Query := TIBSQL.Create(self);
  1199.     try
  1200.       Query.GoToFirstRecordOnExecute := False;
  1201.       Query.Database := DataBase;
  1202.       Query.Transaction := Database.InternalTransaction;
  1203.       if (TableTypes * [ttSystem, ttView] = [ttSystem, ttView]) then
  1204.         Query.SQL.Text := 'Select RDB$RELATION_NAME from RDB$RELATIONS' {do not localize}
  1205.       else if ttSystem in TableTypes then
  1206.         Query.SQL.Text := 'Select RDB$RELATION_NAME from RDB$RELATIONS' + {do not localize}
  1207.                           ' where RDB$VIEW_BLR is NULL' {do not localize}
  1208.       else if ttView in TableTypes then
  1209.         Query.SQL.Text := 'Select RDB$RELATION_NAME from RDB$RELATIONS' + {do not localize}
  1210.                           ' where RDB$SYSTEM_FLAG = 0' {do not localize}
  1211.       else
  1212.         Query.SQL.Text := 'Select RDB$RELATION_NAME from RDB$RELATIONS' + {do not localize}
  1213.                           ' where RDB$VIEW_BLR is NULL and RDB$SYSTEM_FLAG = 0'; {do not localize}
  1214.       Query.Prepare;
  1215.       Query.ExecQuery;
  1216.       while (not Query.EOF) and (Query.Next <> nil) do
  1217.         FNameList.Add (TrimRight(Query.Current[0].AsString));
  1218.     finally
  1219.       Query.Free;
  1220.       Database.InternalTransaction.Commit;
  1221.     end;
  1222.   end;
  1223. end;
  1224.  
  1225. procedure TIBTable.SwitchToIndex();
  1226. begin
  1227.   FSwitchingIndex := True;
  1228.   InternalTableRefresh;
  1229.   FSwitchingIndex := False;
  1230. end;
  1231.  
  1232. procedure TIBTable.InternalTableRefresh();
  1233. var
  1234.   DBKey: TIBDBKey;
  1235. begin
  1236.   CheckActive;
  1237.   DBKey := CurrentDBKey;
  1238.   FRegenerateSQL := True;
  1239.   Reopen;
  1240.   if DBKey.DBKey[0] <> 0 then
  1241.     InternalGotoDBKey(DBKey);
  1242. end;
  1243.  
  1244. procedure TIBTable.GenerateSQL;
  1245. var
  1246.   i: Integer;
  1247.   SQL: TStrings;
  1248.   OrderByStr: string;
  1249.   bWhereClausePresent: Boolean;
  1250. begin
  1251.   bWhereClausePresent := False;
  1252.   Database.CheckActive;
  1253.   Transaction.CheckInTransaction;
  1254.   if IndexDefs.Updated = False then
  1255.     IndexDefs.Update;
  1256.   if IndexFieldNames <> '' then
  1257.     OrderByStr := FormatFieldsList(IndexFieldNames)
  1258.   else if IndexName <> '' then
  1259.     OrderByStr := FormatFieldsList(IndexDefs[IndexDefs.Indexof (IndexName)].Fields)
  1260.   else if FDefaultIndex and (FPrimaryIndexFields <> '') then
  1261.     OrderByStr := FormatFieldsList(FPrimaryIndexFields);
  1262.   SQL := TStringList.Create;
  1263.   SQL.Text := 'select ' + {do not localize}
  1264.     FormatIdentifier(Database.SQLDialect, FTableName) + '.*, '
  1265.     + 'RDB$DB_KEY as IBX_INTERNAL_DBKEY from ' {do not localize}
  1266.     + FormatIdentifier(Database.SQLDialect, FTableName);
  1267.   if Filtered and (Filter <> '') then
  1268.   begin
  1269.     SQL.Text := SQL.Text + ' where ' + Filter; {do not localize}
  1270.     bWhereClausePresent := True;
  1271.   end;
  1272.   if (MasterSource <> nil) and (MasterSource.DataSet <> nil) and (MasterFields <> '') then
  1273.   begin
  1274.     if bWhereClausePresent then
  1275.       SQL.Text := SQL.Text + ' AND ' {do not localize}
  1276.     else
  1277.       SQL.Text := SQL.Text + ' WHERE '; {do not localize}
  1278.     ExtractLinkfields;
  1279.     if FDetailFieldsList.Count < FMasterFieldsList.Count then
  1280.       IBError(ibxeUnknownError, [nil]);
  1281.     for i := 0 to FMasterFieldsList.Count - 1 do
  1282.     begin
  1283.       if i > 0 then
  1284.         SQL.Text := SQL.Text + 'AND ';
  1285.       SQL.Text := SQL.Text +
  1286.         FormatIdentifier(Database.SQLDialect, FDetailFieldsList.Strings[i]) +
  1287.         ' = :' +
  1288.         FormatIdentifier(Database.SQLDialect, FMasterFieldsList.Strings[i]);
  1289.     end;
  1290.   end;
  1291.   if OrderByStr <> '' then
  1292.     SQL.Text := SQL.Text + ' order by ' + OrderByStr; {do not localize}
  1293.   SelectSQL.Assign(SQL);
  1294.   RefreshSQL.Text := 'select ' + {do not localize}
  1295.     FormatIdentifier(Database.SQLDialect, FTableName) + '.*, '
  1296.     + 'RDB$DB_KEY as IBX_INTERNAL_DBKEY from ' {do not localize}
  1297.     + FormatIdentifier(Database.SQLDialect, FTableName) +
  1298.     ' where RDB$DB_KEY = :IBX_INTERNAL_DBKEY'; {do not localize}
  1299.   WhereDBKeyRefreshSQL.Assign(RefreshSQL);
  1300.   InternalPrepare;
  1301.   SQL.Free;
  1302. end;
  1303.  
  1304. procedure TIBTable.GenerateUpdateSQL;
  1305. var
  1306.   InsertFieldList, InsertParamList, UpdateFieldList: string;
  1307.   WherePrimaryFieldList, WhereAllFieldList: string;
  1308.  
  1309.   procedure GenerateFieldLists;
  1310.   var
  1311.     I: Integer;
  1312.   begin
  1313.     for I := 0 to FieldDefs.Count - 1 do begin
  1314.       with FieldDefs[I] do begin
  1315.         if not (InternalCalcField or (faReadOnly in Attributes) or
  1316.           (DataType = ftUnknown)) then
  1317.         begin
  1318.           if ( InsertFieldList <> '' ) then begin
  1319.             InsertFieldList := InsertFieldList + ', ';
  1320.             InsertParamList := InsertParamList + ', ';
  1321.             UpdateFieldList := UpdateFieldList + ', ';
  1322.             if (DataType <> ftBlob) and (DataType <>ftMemo) then
  1323.               WhereAllFieldList := WhereAllFieldList + ' AND ';
  1324.           end;
  1325.           InsertFieldList := InsertFieldList +
  1326.             FormatIdentifier(Database.SQLDialect, Name);
  1327.           InsertParamList := InsertParamList + ':' +
  1328.             FormatIdentifier(Database.SQLDialect, Name);
  1329.           UpdateFieldList := UpdateFieldList +
  1330.             FormatIdentifier(Database.SQLDialect, Name) +
  1331.             ' = :' +
  1332.             FormatIdentifier(Database.SQLDialect, Name);
  1333.           if (DataType <> ftBlob) and (DataType <>ftMemo) then
  1334.             WhereAllFieldList := WhereAllFieldList +
  1335.               FormatIdentifier(Database.SQLDialect, Name) + ' = :' +
  1336.               FormatIdentifier(Database.SQLDialect, Name);{do not localize}
  1337.         end;
  1338.       end;
  1339.     end;
  1340.   end;
  1341.  
  1342.   procedure GenerateWherePrimaryFieldList;
  1343.   var
  1344.     i: Integer;
  1345.     tmp: String;
  1346.   begin
  1347.     i := 1;
  1348.     while i <= Length(FPrimaryIndexFields) do
  1349.     begin
  1350.       tmp := ExtractFieldName(FPrimaryIndexFields, i);
  1351.       tmp :=
  1352.         FormatIdentifier(Database.SQLDialect, tmp) +  ' = :' +
  1353.         FormatIdentifier(Database.SQLDialect, tmp);{do not localize}
  1354.       if WherePrimaryFieldList <> '' then
  1355.         WherePrimaryFieldList :=
  1356.           WherePrimaryFieldList + ' AND ' + tmp
  1357.       else
  1358.         WherePrimaryFieldList := tmp;
  1359.     end;
  1360.   end;
  1361.  
  1362. begin
  1363.   if InternalGetUpdatable = False  then
  1364.     FReadOnly := True
  1365.   else begin
  1366.     DeleteSQL.Text := 'delete from ' + {do not localize}
  1367.       FormatIdentifier(Database.SQLDialect, FTableName) +
  1368.       ' where RDB$DB_KEY = ' + ':IBX_INTERNAL_DBKEY'; {do not localize}
  1369.     GenerateFieldLists;
  1370.     InsertSQL.Text := 'insert into ' + {do not localize}
  1371.       FormatIdentifier(Database.SQLDialect, FTableName) +
  1372.     ' (' + InsertFieldList + {do not localize}
  1373.       ') values (' + InsertParamList + ')'; {do not localize}
  1374.     ModifySQL.Text := 'update ' +
  1375.       FormatIdentifier(Database.SQLDialect, FTableName) +
  1376.       ' set ' + UpdateFieldList + {do not localize}
  1377.       ' where RDB$DB_KEY = :IBX_INTERNAL_DBKEY'; {do not localize}
  1378.     WhereAllRefreshSQL.Text := 'select ' +  {do not localize}
  1379.       FormatIdentifier(Database.SQLDialect, FTableName) + '.*, '
  1380.       + 'RDB$DB_KEY as IBX_INTERNAL_DBKEY from ' {do not localize}
  1381.       + FormatIdentifier(Database.SQLDialect, FTableName) +
  1382.       ' where ' + WhereAllFieldList; {do not localize}
  1383.     if FPrimaryIndexFields <> '' then
  1384.     begin
  1385.       GenerateWherePrimaryFieldList;
  1386.       WherePrimaryRefreshSQL.Text := 'select ' + {do not localize}
  1387.         FormatIdentifier(Database.SQLDialect, FTableName) + '.*, ' {do not localize}
  1388.         + 'RDB$DB_KEY as IBX_INTERNAL_DBKEY from ' {do not localize}
  1389.         + FormatIdentifier(Database.SQLDialect, FTableName) +
  1390.         ' where ' + WherePrimaryFieldList; {do not localize}
  1391.     end;
  1392.     try
  1393.       InternalPrepare;
  1394.     except
  1395.       FReadonly := True;
  1396.     end;
  1397.   end;
  1398. end;
  1399.  
  1400. procedure TIBTable.ResetSQLStatements;
  1401. begin
  1402.   SelectSQL.Text := '';
  1403.   DeleteSQL.Text := '';
  1404.   InsertSQL.Text := '';
  1405.   ModifySQL.Text := '';
  1406.   RefreshSQL.Text := '';
  1407. end;
  1408.  
  1409. procedure TIBTable.SetTableTypes(
  1410.   const Value: TIBTableTypes);
  1411. begin
  1412.   FTableTypes := Value;
  1413. end;
  1414.  
  1415. function TIBTable.InternalGotoDBKey(DBKey: TIBDBKey): Boolean;
  1416.  
  1417.   function DBKeyCompare (DBKey1, DBKey2: TIBDBKey): Boolean;
  1418.   var
  1419.   I: Integer;
  1420.   begin
  1421.     for I := 0 to 7 do
  1422.       if (DBKey1.DBKey[i] <> DBKey2.DBKey[i]) then begin
  1423.         result := False;
  1424.         exit;
  1425.       end;
  1426.     result := True;
  1427.   end;
  1428. begin
  1429.   CheckActive;
  1430.   DisableControls;
  1431.  try
  1432.     result := False;
  1433.     First;
  1434.     while ((not result) and (not EOF)) do begin
  1435.       if (DBKeyCompare (DBKey, PRecordData(GetActiveBuf)^.rdDBKey)) then
  1436.         result := True
  1437.       else
  1438.         Next;
  1439.     end;
  1440.     if not result then
  1441.       First
  1442.     else
  1443.       CursorPosChanged;
  1444.   finally
  1445.     EnableControls;
  1446.   end;
  1447. end;
  1448.  
  1449. function TIBTable.GetCurrentDBKey: TIBDBKey;
  1450. var
  1451.   Buf: pChar;
  1452. begin
  1453.   CheckActive;
  1454.   buf := GetActiveBuf;
  1455.   if Buf <> nil then
  1456.     Result := PRecordData(Buf)^.rdDBKey
  1457.   else
  1458.     Result.DBKey[0] := 0;
  1459. end;
  1460.  
  1461. procedure TIBTable.Reopen;
  1462. begin
  1463.   DisableControls;
  1464.   try
  1465.     if Active then
  1466.     begin
  1467.       SetState(dsInactive);
  1468.       CloseCursor;
  1469.       OpenCursor;
  1470.       SetState(dsBrowse);
  1471.     end;
  1472.   finally
  1473.     EnableControls;
  1474.   end;
  1475. end;
  1476.  
  1477. { TIBTable IProviderSupport }
  1478.  
  1479. function TIBTable.PSGetDefaultOrder: TIndexDef;
  1480.  
  1481.   function GetIdx(IdxType: TIndexOption): TIndexDef;
  1482.   var
  1483.     i: Integer;
  1484.   begin
  1485.     Result := nil;
  1486.     for i := 0 to IndexDefs.Count - 1 do
  1487.       if IdxType in IndexDefs[i].Options then
  1488.       try
  1489.         Result := IndexDefs[i];
  1490.         GetFieldList(nil, Result.Fields);
  1491.         break;
  1492.       except
  1493.         Result := nil;
  1494.       end;
  1495.   end;
  1496.  
  1497. var
  1498.   DefIdx: TIndexDef;
  1499. begin
  1500.   DefIdx := nil;
  1501.   IndexDefs.Update;
  1502.   try
  1503.     if IndexName <> '' then
  1504.       DefIdx := IndexDefs.Find(IndexName)
  1505.     else if IndexFieldNames <> '' then
  1506.       DefIdx := IndexDefs.FindIndexForFields(IndexFieldNames);
  1507.     if Assigned(DefIdx) then
  1508.       GetFieldList(nil, DefIdx.Fields);
  1509.   except
  1510.     DefIdx := nil;
  1511.   end;
  1512.   if not Assigned(DefIdx) then
  1513.     DefIdx := GetIdx(ixPrimary);
  1514.   if not Assigned(DefIdx) then
  1515.     DefIdx := GetIdx(ixUnique);
  1516.   if Assigned(DefIdx) then
  1517.   begin
  1518.     Result := TIndexDef.Create(nil);
  1519.     Result.Assign(DefIdx);
  1520.   end else
  1521.     Result := nil;
  1522. end;
  1523.  
  1524. function TIBTable.PSGetIndexDefs(IndexTypes: TIndexOptions): TIndexDefs;
  1525. begin
  1526.   Result := GetIndexDefs(IndexDefs, IndexTypes);
  1527. end;
  1528.  
  1529. function TIBTable.PSGeTTableName: string;
  1530. begin
  1531.   Result := FTableName;
  1532. end;
  1533.  
  1534. procedure TIBTable.PSSetParams(AParams: TParams);
  1535. begin
  1536.   if AParams.Count > 0 then
  1537.     Open;
  1538.   PSReset;
  1539. end;
  1540.  
  1541. procedure TIBTable.PSSetCommandText(const CommandText: string);
  1542. begin
  1543.   if CommandText <> '' then
  1544.     TableName := CommandText;
  1545. end;
  1546.  
  1547. function TIBTable.PSGetKeyFields: string;
  1548. var
  1549.   i, Idx: Integer;
  1550.   IndexFound: Boolean;
  1551. begin
  1552.   Result := inherited PSGetKeyFields;
  1553.   if Result = '' then
  1554.   begin
  1555.     if not Exists then Exit;
  1556.     IndexFound := False;
  1557.     IndexDefs.Update;
  1558.     FieldDefs.Update;
  1559.     for i := 0 to IndexDefs.Count - 1 do
  1560.       if ixUnique in IndexDefs[I].Options then
  1561.       begin
  1562.         Idx := 1;
  1563.         Result := IndexDefs[I].Fields;
  1564.         IndexFound := False;
  1565.         while Idx <= Length(Result) do
  1566.         begin
  1567.           IndexFound := FindField(ExtractFieldName(Result, Idx)) <> nil;
  1568.           if not IndexFound then Break;
  1569.         end;
  1570.         if IndexFound then Break;
  1571.       end;
  1572.     if not IndexFound then
  1573.       Result := '';
  1574.   end;
  1575. end;
  1576.  
  1577. end.
  1578.