ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBTable.pas
Revision: 143
Committed: Fri Feb 23 12:11:21 2018 UTC (6 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 46106 byte(s)
Log Message:
Fixes Merged

File Contents

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