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 27 by tony, Tue Apr 14 13:10:23 2015 UTC vs.
Revision 143 by tony, Fri Feb 23 12:11:21 2018 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines