ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/nongui/IBTable.pas
Revision: 410
Committed: Thu Jun 22 13:52:39 2023 UTC (17 months ago) by tony
Content type: text/x-pascal
File size: 48480 byte(s)
Log Message:
Release 2.6.0 beta

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

Properties

Name Value
svn:eol-style native