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

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines