ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/nongui/IBTable.pas
Revision: 315
Committed: Thu Feb 25 11:56:36 2021 UTC (3 years, 8 months ago) by tony
Content type: text/x-pascal
File size: 48508 byte(s)
Log Message:
Updated for IBX 4 release

File Contents

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