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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines