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

# Content
1 {************************************************************************}
2 { }
3 { Borland Delphi Visual Component Library }
4 { InterBase Express core components }
5 { }
6 { Copyright (c) 1998-2000 Inprise Corporation }
7 { }
8 { InterBase Express is based in part on the product }
9 { Free IB Components, written by Gregory H. Deatz for }
10 { Hoagland, Longo, Moran, Dunst & Doukas Company. }
11 { Free IB Components is used under license. }
12 { }
13 { The contents of this file are subject to the InterBase }
14 { Public License Version 1.0 (the "License"); you may not }
15 { use this file except in compliance with the License. You }
16 { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
17 { Software distributed under the License is distributed on }
18 { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
19 { express or implied. See the License for the specific language }
20 { governing rights and limitations under the License. }
21 { The Original Code was created by InterBase Software Corporation }
22 { and its successors. }
23 { Portions created by Inprise Corporation are Copyright (C) Inprise }
24 { Corporation. All Rights Reserved. }
25 { Contributor(s): Jeff Overcash }
26 { }
27 { IBX For Lazarus (Firebird Express) }
28 { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
29 { Portions created by MWA Software are copyright McCallum Whyman }
30 { Associates Ltd 2011 - 2018 }
31 { }
32 {************************************************************************}
33
34 unit IBTable;
35
36 {$Mode Delphi}
37
38 {$codepage UTF8}
39
40 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 FStoreDefs: boolean;
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 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 property GeneratorField;
161 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 uses FBMessages;
185
186 { 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 FieldDefsFromQuery(Query);
333 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 ExtractIdentifier(Database.SQLDialect,
432 QuoteIdentifier(DataBase.SQLDialect, FTableName)) +
433 ''' ' +
434 ' AND RDB$CONSTRAINT_NAME = ' +
435 '''' +
436 ExtractIdentifier(Database.SQLDialect,
437 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 ExtractIdentifier(Database.SQLDialect,
469 QuoteIdentifier(DataBase.SQLDialect, FTableName)) +
470 ''' ' +
471 'AND RDB$INDEX_NAME = ' +
472 '''' +
473 ExtractIdentifier(Database.SQLDialect,
474 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 QuoteIdentifier(DataBase.SQLDialect, Query.FieldByName('RDB$CONSTRAINT_NAME').AsString);
486 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 ExtractIdentifier(Database.SQLDialect,
590 QuoteIdentifier(DataBase.SQLDialect, FTableName)) + '''';
591 Query.Prepare;
592 Query.ExecQuery;
593 while (not Query.EOF) and Query.Next do
594 begin
595 with IndexDefs.AddIndexDef do
596 begin
597 Name := TrimRight(Query.FieldByName('RDB$INDEX_NAME').AsString); {do not localize}
598 Opts := [];
599 if Pos ('RDB$PRIMARY', Name) = 1 then Include(Opts, ixPrimary); {do not localize} {mbcs ok}
600 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 Options := Opts;
603 if (Query.FieldByName('RDB$SEGMENT_COUNT').AsInteger = 1) then {do not localize}
604 begin
605 fn := Trim(Query.FieldByName('RDB$FIELD_NAME').AsString); {do not localize}
606 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 ExtractIdentifier(Database.SQLDialect,
622 QuoteIdentifier(DataBase.SQLDialect, Name)) +
623 '''' + 'ORDER BY RDB$FIELD_POSITION'; {do not localize}
624 SubQuery.Prepare;
625 SubQuery.ExecQuery;
626 Flds := '';
627 while (not SubQuery.EOF) and SubQuery.Next do
628 begin
629 fn := TrimRight(SubQuery.FieldByName('RDB$FIELD_NAME').AsString); {do not localize}
630 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 ExtractIdentifier(Database.SQLDialect,
673 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 ExtractIdentifier(Database.SQLDialect,
920 QuoteIdentifier(DataBase.SQLDialect, FTableName)) + '''';
921 Query.Prepare;
922 Query.ExecQuery;
923 if (Query.Fields[0].AsInteger <> 0) or
924 (Query.Fields[1].AsInteger <> 8) then
925 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 while (not Query.EOF) and Query.Next do
1203 FNameList.Add (TrimRight(Query.Fields[0].AsString));
1204 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 WherePrimaryFieldList, WhereAllFieldList,
1299 InsertReturningFieldList, UpdateReturningFieldList: string;
1300
1301 procedure GenerateFieldLists;
1302 var
1303 I: Integer;
1304 AllowReturningClause: boolean;
1305 begin
1306 {Is database Firebird 2.1 or later?}
1307 AllowReturningClause := (DatabaseInfo.ODSMajorVersion > 11) or
1308 ((DatabaseInfo.ODSMajorVersion = 11) and (DatabaseInfo.ODSMinorVersion >= 1));
1309 for I := 0 to FieldDefs.Count - 1 do begin
1310 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 if not (InternalCalcField or (faReadOnly in Attributes) or
1333 (DataType = ftUnknown)) then
1334 begin
1335 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 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 ') values (' + InsertParamList + ')' + InsertReturningFieldList; {do not localize}
1400 ModifySQL.Text := 'update ' +
1401 QuoteIdentifier(DataBase.SQLDialect, FTableName) +
1402 ' set ' + UpdateFieldList + {do not localize}
1403 ' where RDB$DB_KEY = :IBX_INTERNAL_DBKEY' + UpdateReturningFieldList; {do not localize}
1404 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 ' where ' + WhereAllFieldList ; {do not localize}
1409 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.