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