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

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