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

File Contents

# Content
1 {************************************************************************}
2 { }
3 { Borland Delphi Visual Component Library }
4 { InterBase Express core components }
5 { }
6 { Copyright (c) 1998-2000 Inprise Corporation }
7 { }
8 { InterBase Express is based in part on the product }
9 { Free IB Components, written by Gregory H. Deatz for }
10 { Hoagland, Longo, Moran, Dunst & Doukas Company. }
11 { Free IB Components is used under license. }
12 { }
13 { The contents of this file are subject to the InterBase }
14 { Public License Version 1.0 (the "License"); you may not }
15 { use this file except in compliance with the License. You }
16 { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
17 { Software distributed under the License is distributed on }
18 { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
19 { express or implied. See the License for the specific language }
20 { governing rights and limitations under the License. }
21 { The Original Code was created by InterBase Software Corporation }
22 { and its successors. }
23 { Portions created by Inprise Corporation are Copyright (C) Inprise }
24 { Corporation. All Rights Reserved. }
25 { Contributor(s): Jeff Overcash }
26 { }
27 { IBX For Lazarus (Firebird Express) }
28 { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
29 { Portions created by MWA Software are copyright McCallum Whyman }
30 { Associates Ltd 2011 - 2018 }
31 { }
32 {************************************************************************}
33
34 unit IBDatabase;
35
36 {$Mode Delphi}
37
38 {$codepage UTF8}
39
40 interface
41
42 uses
43 {$IFDEF WINDOWS }
44 Windows,
45 {$ELSE}
46 unix,
47 {$ENDIF}
48 SysUtils, Classes, FPTimer, IBExternals, DB, IB, CustApp, IBTypes;
49
50 const
51 DPBPrefix = 'isc_dpb_';
52 DPBConstantNames: array[1..isc_dpb_last_dpb_constant] of string = (
53 'cdd_pathname',
54 'allocation',
55 'journal',
56 'page_size',
57 'num_buffers',
58 'buffer_length',
59 'debug',
60 'garbage_collect',
61 'verify',
62 'sweep',
63 'enable_journal',
64 'disable_journal',
65 'dbkey_scope',
66 'number_of_users',
67 'trace',
68 'no_garbage_collect',
69 'damaged',
70 'license',
71 'sys_user_name',
72 'encrypt_key',
73 'activate_shadow',
74 'sweep_interval',
75 'delete_shadow',
76 'force_write',
77 'begin_log',
78 'quit_log',
79 'no_reserve',
80 'user_name',
81 'password',
82 'password_enc',
83 'sys_user_name_enc',
84 'interp',
85 'online_dump',
86 'old_file_size',
87 'old_num_files',
88 'old_file',
89 'old_start_page',
90 'old_start_seqno',
91 'old_start_file',
92 'drop_walfile',
93 'old_dump_id',
94 'wal_backup_dir',
95 'wal_chkptlen',
96 'wal_numbufs',
97 'wal_bufsize',
98 'wal_grp_cmt_wait',
99 'lc_messages',
100 'lc_ctype',
101 'cache_manager',
102 'shutdown',
103 'online',
104 'shutdown_delay',
105 'reserved',
106 'overwrite',
107 'sec_attach',
108 'disable_wal',
109 'connect_timeout',
110 'dummy_packet_interval',
111 'gbak_attach',
112 'sql_role_name',
113 'set_page_buffers',
114 'working_directory',
115 'sql_dialect',
116 'set_db_readonly',
117 'set_db_sql_dialect',
118 'gfix_attach',
119 'gstat_attach',
120 'set_db_charset',
121 'gsec_attach',
122 'address_path' ,
123 'process_id',
124 'no_db_triggers',
125 'trusted_auth',
126 'process_name',
127 'trusted_role',
128 'org_filename',
129 'utf8_ilename',
130 'ext_call_depth',
131 'auth_block',
132 'client_version',
133 'remote_protocol',
134 'host_name',
135 'os_user',
136 'specific_auth_data',
137 'auth_plugin_list',
138 'auth_plugin_name',
139 'config',
140 'nolinger',
141 'reset_icu',
142 'map_attach'
143 );
144
145 TPBPrefix = 'isc_tpb_';
146 TPBConstantNames: array[1..isc_tpb_last_tpb_constant] of string = (
147 'consistency',
148 'concurrency',
149 'shared',
150 'protected',
151 'exclusive',
152 'wait',
153 'nowait',
154 'read',
155 'write',
156 'lock_read',
157 'lock_write',
158 'verb_time',
159 'commit_time',
160 'ignore_limbo',
161 'read_committed',
162 'autocommit',
163 'rec_version',
164 'no_rec_version',
165 'restart_requests',
166 'no_auto_undo',
167 'lock_timeout'
168 );
169
170 type
171
172 TIBDatabase = class;
173 TIBTransaction = class;
174 TIBBase = class;
175
176 TIBDatabaseLoginEvent = procedure(Database: TIBDatabase;
177 LoginParams: TStrings) of object;
178
179 TIBFileName = type string;
180 { TIBDatabase }
181 TIBDataBase = class(TCustomConnection)
182 private
183 FAttachment: IAttachment;
184 FCreateDatabase: boolean;
185 FCreateIfNotExists: boolean;
186 FAllowStreamedConnected: boolean;
187 FHiddenPassword: string;
188 FOnCreateDatabase: TNotifyEvent;
189 FOnLogin: TIBDatabaseLoginEvent;
190 FSQLHourGlass: Boolean;
191 FTraceFlags: TTraceFlags;
192 FSQLDialect: Integer;
193 FOnDialectDowngradeWarning: TNotifyEvent;
194 FSQLObjects: TList;
195 FTransactions: TList;
196 FDBName: TIBFileName;
197 FDBParams: TStrings;
198 FDBParamsChanged: Boolean;
199 FOnIdleTimer: TNotifyEvent;
200 FDefaultTransaction: TIBTransaction;
201 FInternalTransaction: TIBTransaction;
202 FTimer: TFPTimer;
203 FUserNames: TStringList;
204 FDataSets: TList;
205 FLoginCalled: boolean;
206 FUseDefaultSystemCodePage: boolean;
207 procedure EnsureInactive;
208 function GetAuthenticationMethod: string;
209 function GetDBSQLDialect: Integer;
210 function GetDefaultCharSetID: integer;
211 function GetDefaultCharSetName: AnsiString;
212 function GetDefaultCodePage: TSystemCodePage;
213 function GetRemoteProtocol: string;
214 procedure SetSQLDialect(const Value: Integer);
215 procedure ValidateClientSQLDialect;
216 procedure DBParamsChange(Sender: TObject);
217 procedure DBParamsChanging(Sender: TObject);
218 function GetSQLObject(Index: Integer): TIBBase;
219 function GetSQLObjectCount: Integer;
220 function GetIdleTimer: Integer;
221 function GetTransaction(Index: Integer): TIBTransaction;
222 function GetTransactionCount: Integer;
223 function Login(var aDatabaseName: string): Boolean;
224 procedure SetDatabaseName(const Value: TIBFileName);
225 procedure SetDBParamByDPB(const Idx: Integer; Value: String);
226 procedure SetDBParams(Value: TStrings);
227 procedure SetDefaultTransaction(Value: TIBTransaction);
228 procedure SetIdleTimer(Value: Integer);
229 procedure TimeoutConnection(Sender: TObject);
230 function GetIsReadOnly: Boolean;
231 function AddSQLObject(ds: TIBBase): Integer;
232 procedure RemoveSQLObject(Idx: Integer);
233 procedure RemoveSQLObjects;
234 procedure InternalClose(Force: Boolean);
235
236 protected
237 procedure DoConnect; override;
238 procedure DoDisconnect; override;
239 function GetConnected: Boolean; override;
240 procedure CheckStreamConnect;
241 procedure HandleException(Sender: TObject);
242 procedure Notification( AComponent: TComponent; Operation: TOperation); override;
243 function GetDataset(Index : longint) : TDataset; override;
244 function GetDataSetCount : Longint; override;
245 procedure ReadState(Reader: TReader); override;
246 procedure SetConnected (Value : boolean); override;
247 public
248 constructor Create(AOwner: TComponent); override;
249 destructor Destroy; override;
250 procedure ApplyUpdates(const DataSets: array of TDataSet);
251 procedure CloseDataSets;
252 procedure CheckActive;
253 procedure CheckInactive;
254 procedure CreateDatabase; overload;
255 procedure CreateDatabase(createDatabaseSQL: string); overload;
256 procedure DropDatabase;
257 procedure ForceClose;
258 procedure GetFieldNames(const TableName: string; List: TStrings);
259 procedure GetTableNames(List: TStrings; SystemTables: Boolean = False);
260 function IndexOfDBConst(st: String): Integer;
261 function TestConnected: Boolean;
262 procedure CheckDatabaseName;
263 function AddTransaction(TR: TIBTransaction): Integer;
264 function FindTransaction(TR: TIBTransaction): Integer;
265 function FindDefaultTransaction(): TIBTransaction;
266 procedure RemoveTransaction(Idx: Integer);
267 procedure RemoveTransactions;
268
269 property Attachment: IAttachment read FAttachment;
270 property DBSQLDialect : Integer read GetDBSQLDialect;
271 property IsReadOnly: Boolean read GetIsReadOnly;
272 property SQLObjectCount: Integer read GetSQLObjectCount;
273 property SQLObjects[Index: Integer]: TIBBase read GetSQLObject;
274 property TransactionCount: Integer read GetTransactionCount;
275 property Transactions[Index: Integer]: TIBTransaction read GetTransaction;
276 property InternalTransaction: TIBTransaction read FInternalTransaction;
277 property DefaultCharSetName: AnsiString read GetDefaultCharSetName;
278 property DefaultCharSetID: integer read GetDefaultCharSetID;
279 property DefaultCodePage: TSystemCodePage read GetDefaultCodePage;
280 property AuthenticationMethod: string read GetAuthenticationMethod;
281 property RemoteProtocol: string read GetRemoteProtocol;
282
283 published
284 property Connected;
285 property CreateIfNotExists: boolean read FCreateIfNotExists write FCreateIfNotExists;
286 property AllowStreamedConnected: boolean read FAllowStreamedConnected
287 write FAllowStreamedConnected;
288 property DatabaseName: TIBFileName read FDBName write SetDatabaseName;
289 property Params: TStrings read FDBParams write SetDBParams;
290 property LoginPrompt default True;
291 property DefaultTransaction: TIBTransaction read FDefaultTransaction
292 write SetDefaultTransaction;
293 property IdleTimer: Integer read GetIdleTimer write SetIdleTimer;
294 property SQLDialect : Integer read FSQLDialect write SetSQLDialect default 3;
295 property SQLHourGlass: Boolean read FSQLHourGlass write FSQLHourGlass default true;
296 property TraceFlags: TTraceFlags read FTraceFlags write FTraceFlags;
297 property UseDefaultSystemCodePage: boolean read FUseDefaultSystemCodePage
298 write FUseDefaultSystemCodePage;
299 property AfterConnect;
300 property AfterDisconnect;
301 property BeforeConnect;
302 property BeforeDisconnect;
303 property OnCreateDatabase: TNotifyEvent read FOnCreateDatabase write FOnCreateDatabase;
304 property OnLogin: TIBDatabaseLoginEvent read FOnLogin write FOnLogin;
305 property OnIdleTimer: TNotifyEvent read FOnIdleTimer write FOnIdleTimer;
306 property OnDialectDowngradeWarning: TNotifyEvent read FOnDialectDowngradeWarning write FOnDialectDowngradeWarning;
307 end;
308
309 TDefaultEndAction = TARollback..TACommit;
310
311 { TIBTransaction }
312
313 TIBTransaction = class(TComponent)
314 private
315 FTransactionIntf: ITransaction;
316 FAfterDelete: TNotifyEvent;
317 FAfterEdit: TNotifyEvent;
318 FAfterExecQuery: TNotifyEvent;
319 FAfterInsert: TNotifyEvent;
320 FAfterPost: TNotifyEvent;
321 FAfterTransactionEnd: TNotifyEvent;
322 FBeforeTransactionEnd: TNotifyEvent;
323 FDatabases : TList;
324 FOnStartTransaction: TNotifyEvent;
325 FSQLObjects : TList;
326 FDefaultDatabase : TIBDatabase;
327 FOnIdleTimer : TNotifyEvent;
328 FStreamedActive : Boolean;
329 FTPB : ITPB;
330 FTimer : TFPTimer;
331 FDefaultAction : TDefaultEndAction;
332 FTRParams : TStrings;
333 FTRParamsChanged : Boolean;
334 FInEndTransaction : boolean;
335 FEndAction : TTransactionAction;
336 procedure DoBeforeTransactionEnd;
337 procedure DoAfterTransactionEnd;
338 procedure DoOnStartTransaction;
339 procedure DoAfterExecQuery(Sender: TObject);
340 procedure DoAfterEdit(Sender: TObject);
341 procedure DoAfterDelete(Sender: TObject);
342 procedure DoAfterInsert(Sender: TObject);
343 procedure DoAfterPost(Sender: TObject);
344 procedure EnsureNotInTransaction;
345 procedure EndTransaction(Action: TTransactionAction; Force: Boolean);
346 function GetDatabase(Index: Integer): TIBDatabase;
347 function GetDatabaseCount: Integer;
348 function GetSQLObject(Index: Integer): TIBBase;
349 function GetSQLObjectCount: Integer;
350 function GetInTransaction: Boolean;
351 function GetIdleTimer: Integer;
352 procedure BeforeDatabaseDisconnect(DB: TIBDatabase);
353 procedure SetActive(Value: Boolean);
354 procedure SetDefaultDatabase(Value: TIBDatabase);
355 procedure SetIdleTimer(Value: Integer);
356 procedure SetTRParams(Value: TStrings);
357 procedure TimeoutTransaction(Sender: TObject);
358 procedure TRParamsChange(Sender: TObject);
359 procedure TRParamsChanging(Sender: TObject);
360 function AddSQLObject(ds: TIBBase): Integer;
361 procedure RemoveSQLObject(Idx: Integer);
362 procedure RemoveSQLObjects;
363
364 protected
365 procedure Loaded; override;
366 procedure Notification( AComponent: TComponent; Operation: TOperation); override;
367
368 public
369 constructor Create(AOwner: TComponent); override;
370 destructor Destroy; override;
371 procedure Commit;
372 procedure CommitRetaining;
373 procedure Rollback;
374 procedure RollbackRetaining;
375 procedure StartTransaction;
376 procedure CheckInTransaction;
377 procedure CheckNotInTransaction;
378
379 function AddDatabase(db: TIBDatabase): Integer;
380 function FindDatabase(db: TIBDatabase): Integer;
381 function FindDefaultDatabase: TIBDatabase;
382 function GetEndAction: TTransactionAction;
383 procedure RemoveDatabase(Idx: Integer);
384 procedure RemoveDatabases;
385 procedure CheckDatabasesInList;
386
387 property DatabaseCount: Integer read GetDatabaseCount;
388 property Databases[Index: Integer]: TIBDatabase read GetDatabase;
389 property SQLObjectCount: Integer read GetSQLObjectCount;
390 property SQLObjects[Index: Integer]: TIBBase read GetSQLObject;
391 property InTransaction: Boolean read GetInTransaction;
392 property TransactionIntf: ITransaction read FTransactionIntf;
393 property TPB: ITPB read FTPB;
394 published
395 property Active: Boolean read GetInTransaction write SetActive;
396 property DefaultDatabase: TIBDatabase read FDefaultDatabase
397 write SetDefaultDatabase;
398 property IdleTimer: Integer read GetIdleTimer write SetIdleTimer default 0;
399 property DefaultAction: TDefaultEndAction read FDefaultAction write FDefaultAction default taCommit;
400 property Params: TStrings read FTRParams write SetTRParams;
401 property OnIdleTimer: TNotifyEvent read FOnIdleTimer write FOnIdleTimer;
402 property BeforeTransactionEnd: TNotifyEvent read FBeforeTransactionEnd
403 write FBeforeTransactionEnd;
404 property AfterTransactionEnd: TNotifyEvent read FAfterTransactionEnd
405 write FAfterTransactionEnd;
406 property OnStartTransaction: TNotifyEvent read FOnStartTransaction
407 write FOnStartTransaction;
408 property AfterExecQuery: TNotifyEvent read FAfterExecQuery
409 write FAfterExecQuery;
410 property AfterEdit: TNotifyEvent read FAfterEdit write FAfterEdit;
411 property AfterDelete: TNotifyEvent read FAfterDelete write FAfterDelete;
412 property AfterInsert: TNotifyEvent read FAfterInsert write FAfterInsert;
413 property AfterPost: TNotifyEvent read FAfterPost write FAfterPost;
414 end;
415
416 TTransactionEndEvent = procedure(Sender:TObject; Action: TTransactionAction) of object;
417 TBeforeDatabaseConnectEvent = procedure (Sender: TObject; DBParams: TStrings;
418 var DBName: string) of object;
419
420 { TIBBase }
421
422 { Virtually all components in IB are "descendents" of TIBBase.
423 It is to more easily manage the database and transaction
424 connections. }
425 TIBBase = class(TObject)
426 protected
427 FBeforeDatabaseConnect: TBeforeDatabaseConnectEvent;
428 FDatabase: TIBDatabase;
429 FIndexInDatabase: Integer;
430 FTransaction: TIBTransaction;
431 FIndexInTransaction: Integer;
432 FOwner: TObject;
433 FBeforeDatabaseDisconnect: TNotifyEvent;
434 FAfterDatabaseDisconnect: TNotifyEvent;
435 FAfterDatabaseConnect: TNotifyEvent;
436 FOnDatabaseFree: TNotifyEvent;
437 FBeforeTransactionEnd: TTransactionEndEvent;
438 FAfterTransactionEnd: TNotifyEvent;
439 FOnTransactionFree: TNotifyEvent;
440
441 procedure DoBeforeDatabaseConnect(DBParams: TStrings;
442 var DBName: string); virtual;
443 procedure DoAfterDatabaseConnect; virtual;
444 procedure DoBeforeDatabaseDisconnect; virtual;
445 procedure DoAfterDatabaseDisconnect; virtual;
446 procedure DoDatabaseFree; virtual;
447 procedure DoBeforeTransactionEnd(Action: TTransactionAction); virtual;
448 procedure DoAfterTransactionEnd; virtual;
449 procedure DoTransactionFree; virtual;
450 procedure SetDatabase(Value: TIBDatabase); virtual;
451 procedure SetTransaction(Value: TIBTransaction); virtual;
452 public
453 constructor Create(AOwner: TObject);
454 destructor Destroy; override;
455 procedure CheckDatabase; virtual;
456 procedure CheckTransaction; virtual;
457 procedure DoAfterExecQuery(Sender: TObject); virtual;
458 procedure DoAfterEdit(Sender: TObject); virtual;
459 procedure DoAfterDelete(Sender: TObject); virtual;
460 procedure DoAfterInsert(Sender: TObject); virtual;
461 procedure DoAfterPost(Sender: TObject); virtual;
462 procedure HandleException(Sender: TObject);
463 procedure SetCursor;
464 procedure RestoreCursor;
465 public
466 property BeforeDatabaseConnect: TBeforeDatabaseConnectEvent read FBeforeDatabaseConnect
467 write FBeforeDatabaseConnect;
468 property AfterDatabaseConnect: TNotifyEvent read FAfterDatabaseConnect
469 write FAfterDatabaseConnect;
470 property BeforeDatabaseDisconnect: TNotifyEvent read FBeforeDatabaseDisconnect
471 write FBeforeDatabaseDisconnect;
472 property AfterDatabaseDisconnect: TNotifyEvent read FAfterDatabaseDisconnect
473 write FAfterDatabaseDisconnect;
474 property OnDatabaseFree: TNotifyEvent read FOnDatabaseFree write FOnDatabaseFree;
475 property BeforeTransactionEnd: TTransactionEndEvent read FBeforeTransactionEnd write FBeforeTransactionEnd;
476 property AfterTransactionEnd: TNotifyEvent read FAfterTransactionEnd write FAfterTransactionEnd;
477 property OnTransactionFree: TNotifyEvent read FOnTransactionFree write FOnTransactionFree;
478 property Database: TIBDatabase read FDatabase
479 write SetDatabase;
480 property Owner: TObject read FOwner;
481 property Transaction: TIBTransaction read FTransaction
482 write SetTransaction;
483 end;
484
485 function GenerateDPB(sl: TStrings): IDPB;
486 function GenerateTPB(sl: TStrings): ITPB;
487
488
489 implementation
490
491 uses IBSQLMonitor, IBCustomDataSet, IBDatabaseInfo, IBSQL, IBUtils,
492 typInfo, FBMessages, IBErrorCodes {$IFDEF WINDOWS}, Windirs {$ENDIF};
493
494 { TIBDatabase }
495
496 constructor TIBDataBase.Create(AOwner: TComponent);
497 begin
498 inherited Create(AOwner);
499 LoginPrompt := True;
500 FSQLObjects := TList.Create;
501 FTransactions := TList.Create;
502 FDBName := '';
503 FDBParams := TStringList.Create;
504 FSQLHourGlass := true;
505 if (AOwner <> nil) and
506 (AOwner is TCustomApplication) and
507 TCustomApplication(AOWner).ConsoleApplication then
508 LoginPrompt := false;
509 FDBParamsChanged := True;
510 TStringList(FDBParams).OnChange := DBParamsChange;
511 TStringList(FDBParams).OnChanging := DBParamsChanging;
512 FUserNames := nil;
513 FInternalTransaction := TIBTransaction.Create(self);
514 FInternalTransaction.DefaultDatabase := Self;
515 FTimer := TFPTimer.Create(Self);
516 FTimer.Enabled := False;
517 FTimer.Interval := 0;
518 FTimer.OnTimer := TimeoutConnection;
519 FSQLDialect := 3;
520 FTraceFlags := [];
521 FDataSets := TList.Create;
522 CheckStreamConnect;
523 end;
524
525 destructor TIBDataBase.Destroy;
526 var
527 i: Integer;
528 begin
529 IdleTimer := 0;
530 if FAttachment <> nil then
531 ForceClose;
532 for i := 0 to FSQLObjects.Count - 1 do
533 if FSQLObjects[i] <> nil then
534 SQLObjects[i].DoDatabaseFree;
535 RemoveSQLObjects;
536 RemoveTransactions;
537 FInternalTransaction.Free;
538 FDBParams.Free;
539 FSQLObjects.Free;
540 FUserNames.Free;
541 FTransactions.Free;
542 FDataSets.Free;
543 inherited Destroy;
544 end;
545
546 procedure TIBDataBase.CheckActive;
547 begin
548 if StreamedConnected and (not Connected) then
549 Loaded;
550 if FAttachment = nil then
551 IBError(ibxeDatabaseClosed, [nil]);
552 end;
553
554 procedure TIBDataBase.EnsureInactive;
555 begin
556 if csDesigning in ComponentState then
557 begin
558 if FAttachment <> nil then
559 Close;
560 end
561 end;
562
563 function TIBDataBase.GetAuthenticationMethod: string;
564 begin
565 CheckActive;
566 Result := Attachment.GetAuthenticationMethod;
567 end;
568
569 procedure TIBDataBase.CheckInactive;
570 begin
571 if FAttachment <> nil then
572 IBError(ibxeDatabaseOpen, [nil]);
573 end;
574
575 procedure TIBDataBase.CheckDatabaseName;
576 begin
577 if (Trim(FDBName) = '') then
578 IBError(ibxeDatabaseNameMissing, [nil]);
579 end;
580
581 function TIBDataBase.AddSQLObject(ds: TIBBase): Integer;
582 begin
583 result := 0;
584 if (ds.Owner is TIBCustomDataSet) then
585 FDataSets.Add(ds.Owner);
586 while (result < FSQLObjects.Count) and (FSQLObjects[result] <> nil) do
587 Inc(result);
588 if (result = FSQLObjects.Count) then
589 FSQLObjects.Add(ds)
590 else
591 FSQLObjects[result] := ds;
592 end;
593
594 function TIBDataBase.AddTransaction(TR: TIBTransaction): Integer;
595 begin
596 result := FindTransaction(TR);
597 if result <> -1 then
598 begin
599 result := -1;
600 exit;
601 end;
602 result := 0;
603 while (result < FTransactions.Count) and (FTransactions[result] <> nil) do
604 Inc(result);
605 if (result = FTransactions.Count) then
606 FTransactions.Add(TR)
607 else
608 FTransactions[result] := TR;
609 end;
610
611 procedure TIBDataBase.DoDisconnect;
612 begin
613 if Connected then
614 InternalClose(False);
615 end;
616
617 procedure TIBDataBase.CreateDatabase;
618 begin
619 CheckInactive;
620 CheckDatabaseName;
621 FCreateDatabase := true;
622 Connected := true;
623 end;
624
625 procedure TIBDataBase.CreateDatabase(createDatabaseSQL: string);
626 begin
627 CheckInactive;
628 FAttachment := FirebirdAPI.CreateDatabase(createDatabaseSQL,SQLDialect);
629 FDBName := Attachment.GetConnectString;
630 if assigned(FOnCreateDatabase) and (FAttachment <> nil) then
631 OnCreateDatabase(self);
632 end;
633
634 procedure TIBDataBase.DropDatabase;
635 begin
636 CheckActive;
637 FAttachment.DropDatabase;
638 FAttachment := nil;
639 end;
640
641 procedure TIBDataBase.DBParamsChange(Sender: TObject);
642 begin
643 FDBParamsChanged := True;
644 end;
645
646 procedure TIBDataBase.DBParamsChanging(Sender: TObject);
647 begin
648 EnsureInactive;
649 CheckInactive;
650 end;
651
652 function TIBDataBase.FindTransaction(TR: TIBTransaction): Integer;
653 var
654 i: Integer;
655 begin
656 result := -1;
657 for i := 0 to FTransactions.Count - 1 do
658 if TR = Transactions[i] then
659 begin
660 result := i;
661 break;
662 end;
663 end;
664
665 function TIBDataBase.FindDefaultTransaction(): TIBTransaction;
666 var
667 i: Integer;
668 begin
669 result := FDefaultTransaction;
670 if result = nil then
671 begin
672 for i := 0 to FTransactions.Count - 1 do
673 if (Transactions[i] <> nil) and
674 (TIBTransaction(Transactions[i]).DefaultDatabase = self) and
675 (TIBTransaction(Transactions[i]) <> FInternalTransaction) then
676 begin
677 result := TIBTransaction(Transactions[i]);
678 break;
679 end;
680 end;
681 end;
682
683 procedure TIBDataBase.ForceClose;
684 begin
685 if Connected then
686 InternalClose(True);
687 end;
688
689 function TIBDataBase.GetConnected: Boolean;
690 begin
691 result := (FAttachment <> nil) and FAttachment.IsConnected;
692 end;
693
694 function TIBDataBase.GetSQLObject(Index: Integer): TIBBase;
695 begin
696 result := FSQLObjects[Index];
697 end;
698
699 function TIBDataBase.GetSQLObjectCount: Integer;
700 var
701 i: Integer;
702 begin
703 result := 0;
704 for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
705 Inc(result);
706 end;
707
708 function TIBDataBase.GetIdleTimer: Integer;
709 begin
710 result := FTimer.Interval;
711 end;
712
713 function TIBDataBase.GetTransaction(Index: Integer): TIBTransaction;
714 begin
715 result := FTransactions[Index];
716 end;
717
718 function TIBDataBase.GetTransactionCount: Integer;
719 var
720 i: Integer;
721 begin
722 result := 0;
723 for i := 0 to FTransactions.Count - 1 do
724 if FTransactions[i] <> nil then
725 Inc(result);
726 end;
727
728 function TIBDataBase.IndexOfDBConst(st: String): Integer;
729 var
730 i, pos_of_str: Integer;
731 begin
732 result := -1;
733 for i := 0 to Params.Count - 1 do
734 begin
735 pos_of_str := Pos(st, AnsiLowerCase(Params[i])); {mbcs ok}
736 if (pos_of_str = 1) or (pos_of_str = Length(DPBPrefix) + 1) then
737 begin
738 result := i;
739 break;
740 end;
741 end;
742 end;
743
744 procedure TIBDataBase.InternalClose(Force: Boolean);
745 var
746 i: Integer;
747 begin
748 CheckActive;
749 { Tell all connected transactions that we're disconnecting.
750 This is so transactions can commit/rollback, accordingly
751 }
752 for i := 0 to FTransactions.Count - 1 do
753 begin
754 try
755 if FTransactions[i] <> nil then
756 Transactions[i].BeforeDatabaseDisconnect(Self);
757 except
758 if not Force then
759 raise;
760 end;
761 end;
762 for i := 0 to FSQLObjects.Count - 1 do
763 begin
764 try
765 if FSQLObjects[i] <> nil then
766 SQLObjects[i].DoBeforeDatabaseDisconnect;
767 except
768 if not Force then
769 raise;
770 end;
771 end;
772
773 FAttachment.Disconnect(Force);
774 FAttachment := nil;
775
776 if not (csDesigning in ComponentState) then
777 MonitorHook.DBDisconnect(Self);
778
779 for i := 0 to FSQLObjects.Count - 1 do
780 if FSQLObjects[i] <> nil then
781 SQLObjects[i].DoAfterDatabaseDisconnect;
782 end;
783
784 procedure TIBDataBase.CheckStreamConnect;
785 var
786 i: integer;
787 begin
788 try
789 if not (csDesigning in ComponentState) and StreamedConnected and (not Connected) then
790 begin
791 for i := 0 to FTransactions.Count - 1 do
792 if FTransactions[i] <> nil then
793 begin
794 with TIBTransaction(FTransactions[i]) do
795 if not Active then
796 if FStreamedActive and not InTransaction then
797 begin
798 StartTransaction;
799 FStreamedActive := False;
800 end;
801 end;
802 if (FDefaultTransaction <> nil) and
803 (FDefaultTransaction.FStreamedActive) and
804 (not FDefaultTransaction.InTransaction) then
805 FDefaultTransaction.StartTransaction;
806 StreamedConnected := False;
807 end;
808 except
809 if csDesigning in ComponentState then
810 HandleException(Self)
811 else
812 raise;
813 end;
814 end;
815
816 procedure TIBDataBase.HandleException(Sender: TObject);
817 var aParent: TComponent;
818 begin
819 aParent := Owner;
820 while aParent <> nil do
821 begin
822 if aParent is TCustomApplication then
823 begin
824 TCustomApplication(aParent).HandleException(Sender);
825 Exit;
826 end;
827 aParent := aParent.Owner;
828 end;
829 SysUtils.ShowException(ExceptObject,ExceptAddr);
830 end;
831
832 procedure TIBDataBase.Notification(AComponent: TComponent;
833 Operation: TOperation);
834 var
835 i: Integer;
836 begin
837 inherited Notification( AComponent, Operation);
838 if (Operation = opRemove) and (AComponent = FDefaultTransaction) then
839 begin
840 i := FindTransaction(FDefaultTransaction);
841 if (i <> -1) then
842 RemoveTransaction(i);
843 FDefaultTransaction := nil;
844 end;
845 end;
846
847 function TIBDataBase.Login(var aDatabaseName: string): Boolean;
848 var
849 IndexOfUser, IndexOfPassword: Integer;
850 Username, Password, OldPassword: String;
851 LoginParams: TStrings;
852
853 procedure HidePassword;
854 var
855 I: Integer;
856 IndexAt: Integer;
857 begin
858 IndexAt := 0;
859 for I := 0 to Params.Count -1 do
860 if Pos('password', LowerCase(Trim(Params.Names[i]))) = 1 then {mbcs ok}
861 begin
862 FHiddenPassword := Params.Values[Params.Names[i]];
863 IndexAt := I;
864 break;
865 end;
866 if IndexAt <> 0 then
867 Params.Delete(IndexAt);
868 end;
869
870 begin
871 Result := false;
872 if FLoginCalled then Exit;
873 FLoginCalled := true;
874 try
875 if Assigned(FOnLogin) and not (csDesigning in ComponentState) then
876 begin
877 result := True;
878 LoginParams := TStringList.Create;
879 try
880 LoginParams.Assign(Params);
881 FOnLogin(Self, LoginParams);
882 Params.Assign (LoginParams);
883 aDatabaseName := FDBName;
884 HidePassword;
885 finally
886 LoginParams.Free;
887 end;
888 end
889 else
890 if assigned(IBGUIInterface) then
891 begin
892 IndexOfUser := IndexOfDBConst(DPBConstantNames[isc_dpb_user_name]);
893 if IndexOfUser <> -1 then
894 Username := Copy(Params[IndexOfUser],
895 Pos('=', Params[IndexOfUser]) + 1, {mbcs ok}
896 Length(Params[IndexOfUser]));
897 IndexOfPassword := IndexOfDBConst(DPBConstantNames[isc_dpb_password]);
898 if IndexOfPassword <> -1 then
899 begin
900 Password := Copy(Params[IndexOfPassword],
901 Pos('=', Params[IndexOfPassword]) + 1, {mbcs ok}
902 Length(Params[IndexOfPassword]));
903 OldPassword := password;
904 end;
905
906 result := IBGUIInterface.LoginDialogEx(aDatabaseName, Username, Password, False);
907 if result then
908 begin
909 if Username <> '' then
910 begin
911 if IndexOfUser = -1 then
912 Params.Add(DPBConstantNames[isc_dpb_user_name] + '=' + Username)
913 else
914 Params[IndexOfUser] := DPBConstantNames[isc_dpb_user_name] +
915 '=' + Username;
916 end
917 else
918 if IndexOfUser <> -1 then
919 Params.Delete(IndexOfUser);
920 if (Password = OldPassword) then
921 FHiddenPassword := ''
922 else
923 begin
924 FHiddenPassword := Password;
925 if OldPassword <> '' then
926 HidePassword;
927 end;
928 end;
929 end
930 else
931 if LoginPrompt then
932 IBError(ibxeNoLoginDialog,[]);
933 finally
934 FLoginCalled := false
935 end;
936 end;
937
938 procedure TIBDataBase.DoConnect;
939
940 function ExpandDBName(aDBName: string): string;
941 const
942 TmpPrefix = '$TEMP$';
943 DataPrefix = '$DATADIR$';
944 var
945 LocalDirName: string;
946 begin
947 if Pos(TmpPrefix,aDBName) = 1 then
948 begin
949 system.Delete(aDBName,1,Length(TmpPrefix));
950 Result := GetTempDir + aDBName
951 end
952 else
953 if Pos(DataPrefix,aDBName) = 1 then
954 begin
955 system.Delete(aDBName,1,Length(DataPrefix));
956 if Sysutils.VendorName <> '' then
957 LocalDirName := Sysutils.VendorName
958 else
959 LocalDirName := 'IBX';
960 {$IFDEF UNIX}
961 LocalDirName := GetUserDir + '.' + LocalDirName;
962 {$ENDIF}
963 {$IFDEF WINDOWS}
964 LocalDirName := GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA) + LocalDirName;
965 {$ENDIF}
966 CreateDir(LocalDirName);
967 Result := LocalDirName + DirectorySeparator + aDBName;
968 end
969 else
970 Result := aDBName;
971 end;
972
973 var
974 TempDBParams: TStrings;
975 I: integer;
976 aDBName: string;
977 Status: IStatus;
978 CharSetID: integer;
979 CharSetName: AnsiString;
980 DPB: IDPB;
981 PW: IDPBItem;
982 begin
983 DPB := nil;
984 CheckInactive;
985 CheckDatabaseName;
986 if (not LoginPrompt) and (FHiddenPassword <> '') then
987 begin
988 FHiddenPassword := '';
989 FDBParamsChanged := True;
990 end;
991 { Use builtin login prompt if requested }
992 aDBName := ExpandDBName(FDBName);
993
994 if (LoginPrompt or (csDesigning in ComponentState)) and not Login(aDBName) then
995 IBError(ibxeOperationCancelled, [nil]);
996
997 TempDBParams := TStringList.Create;
998 try
999 TempDBParams.Assign(FDBParams);
1000 {$ifdef UNIX}
1001 {See below for WINDOWS UseDefaultSystemCodePage}
1002 if UseDefaultSystemCodePage then
1003 TempDBParams.Values['lc_ctype'] :='UTF8';
1004 {$endif}
1005 {Opportunity to override defaults}
1006 for i := 0 to FSQLObjects.Count - 1 do
1007 begin
1008 if FSQLObjects[i] <> nil then
1009 SQLObjects[i].DoBeforeDatabaseConnect(TempDBParams,aDBName);
1010 end;
1011
1012 repeat
1013 { Generate a new DPB if necessary }
1014 if (DPB = nil) or FDBParamsChanged or (TempDBParams.Text <> FDBParams.Text) then
1015 begin
1016 FDBParamsChanged := False;
1017 if (not LoginPrompt and not (csDesigning in ComponentState)) or (FHiddenPassword = '') then
1018 DPB := GenerateDPB(TempDBParams)
1019 else
1020 begin
1021 TempDBParams.Values['password'] := FHiddenPassword;
1022 DPB := GenerateDPB(TempDBParams);
1023 end;
1024 end;
1025
1026 if FCreateDatabase then
1027 begin
1028 FCreateDatabase := false;
1029 DPB.Add(isc_dpb_set_db_SQL_dialect).AsByte := SQLDialect; {create with this SQL Dialect}
1030 FAttachment := FirebirdAPI.CreateDatabase(aDBName,DPB, false);
1031 if FAttachment = nil then
1032 DPB := nil;
1033 if assigned(FOnCreateDatabase) and (FAttachment <> nil) then
1034 OnCreateDatabase(self);
1035 end
1036 else
1037 FAttachment := FirebirdAPI.OpenDatabase(aDBName,DPB,false);
1038
1039 if FAttachment = nil then
1040 begin
1041 Status := FirebirdAPI.GetStatus;
1042 {$IFDEF UNIX}
1043 if GetProtocol(aDBName) = Local then
1044 begin
1045 if ((Status.GetSQLCode = -901) and (Status.GetIBErrorCode = isc_random)) {Access permissions on firebird temp}
1046 or
1047 ((Status.GetSQLCode = -902) and (Status.GetIBErrorCode = isc_sys_request)) {Security DB Problem}
1048 or
1049 ((Status.GetSQLCode = -902) and (Status.GetIBErrorCode = isc_psw_attach)) {Security DB Problem}
1050 or
1051 ((Status.GetSQLCode = -904) and (Status.GetIBErrorCode = isc_lock_dir_access)) {Lock File Problem}
1052 then
1053 begin
1054 aDBName := 'localhost:' + aDBName;
1055 Continue;
1056 end
1057 end;
1058 {$ENDIF}
1059 if ((Status.GetSQLCode = -902) and (Status.GetIBErrorCode = isc_io_error)) {Database not found}
1060 and CreateIfNotExists and not (csDesigning in ComponentState) then
1061 FCreateDatabase := true
1062 else
1063 raise EIBInterBaseError.Create(Status);
1064 end;
1065
1066 if UseDefaultSystemCodePage and (FAttachment <> nil) then
1067 {Only now can we check the codepage in use by the Attachment.
1068 If not that required then re-open with required LCLType.}
1069 begin
1070 {$ifdef WINDOWS}
1071 if Attachment.CodePage2CharSetID(GetACP,CharSetID) then
1072 {$else}
1073 if Attachment.CodePage2CharSetID(DefaultSystemCodePage,CharSetID) then
1074 {$endif}
1075 begin
1076 CharSetName := Attachment.GetCharsetName(CharSetID);
1077 if CharSetName <> AnsiUpperCase(TempDBParams.Values['lc_ctype']) then
1078 begin
1079 TempDBParams.Values['lc_ctype'] := CharSetName;
1080 FDBParamsChanged := True;
1081 FAttachment := nil;
1082 end
1083 end
1084 end;
1085
1086 until FAttachment <> nil;
1087
1088 finally
1089 TempDBParams.Free;
1090 end;
1091 PW := Attachment.getDPB.Find(isc_dpb_password);
1092 if PW <> nil then PW.AsString := 'xxxxxxxx'; {Hide password}
1093
1094 if not (csDesigning in ComponentState) then
1095 FDBName := aDBName; {Synchronise at run time}
1096 ValidateClientSQLDialect;
1097 for i := 0 to FSQLObjects.Count - 1 do
1098 begin
1099 if FSQLObjects[i] <> nil then
1100 SQLObjects[i].DoAfterDatabaseConnect;
1101 end;
1102 if not (csDesigning in ComponentState) then
1103 MonitorHook.DBConnect(Self);
1104 end;
1105
1106 procedure TIBDataBase.RemoveSQLObject(Idx: Integer);
1107 var
1108 ds: TIBBase;
1109 begin
1110 if (Idx >= 0) and (FSQLObjects[Idx] <> nil) then
1111 begin
1112 ds := SQLObjects[Idx];
1113 FSQLObjects[Idx] := nil;
1114 ds.Database := nil;
1115 if (ds.owner is TDataSet) then
1116 FDataSets.Remove(TDataSet(ds.Owner));
1117 end;
1118 end;
1119
1120 procedure TIBDataBase.RemoveSQLObjects;
1121 var
1122 i: Integer;
1123 begin
1124 for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
1125 begin
1126 RemoveSQLObject(i);
1127 if (TIBBase(FSQLObjects[i]).owner is TDataSet) then
1128 FDataSets.Remove(TDataSet(TIBBase(FSQLObjects[i]).owner));
1129 end;
1130 end;
1131
1132 procedure TIBDataBase.RemoveTransaction(Idx: Integer);
1133 var
1134 TR: TIBTransaction;
1135 begin
1136 if ((Idx >= 0) and (FTransactions[Idx] <> nil)) then
1137 begin
1138 TR := Transactions[Idx];
1139 FTransactions[Idx] := nil;
1140 TR.RemoveDatabase(TR.FindDatabase(Self));
1141 if TR = FDefaultTransaction then
1142 FDefaultTransaction := nil;
1143 end;
1144 end;
1145
1146 procedure TIBDataBase.RemoveTransactions;
1147 var
1148 i: Integer;
1149 begin
1150 for i := 0 to FTransactions.Count - 1 do if FTransactions[i] <> nil then
1151 RemoveTransaction(i);
1152 end;
1153
1154 procedure TIBDataBase.SetDatabaseName( const Value: TIBFileName);
1155 begin
1156 if FDBName <> Value then
1157 begin
1158 EnsureInactive;
1159 CheckInactive;
1160 FDBName := Value;
1161 end;
1162 end;
1163
1164 procedure TIBDataBase.SetDBParamByDPB( const Idx: Integer; Value: String);
1165 var
1166 ConstIdx: Integer;
1167 begin
1168 ConstIdx := IndexOfDBConst(DPBConstantNames[Idx]);
1169 if (Value = '') then
1170 begin
1171 if ConstIdx <> -1 then
1172 Params.Delete(ConstIdx);
1173 end
1174 else
1175 begin
1176 if (ConstIdx = -1) then
1177 Params.Add(DPBConstantNames[Idx] + '=' + Value)
1178 else
1179 Params[ConstIdx] := DPBConstantNames[Idx] + '=' + Value;
1180 end;
1181 end;
1182
1183 procedure TIBDataBase.SetDBParams(Value: TStrings);
1184 begin
1185 FDBParams.Assign(Value);
1186 end;
1187
1188 procedure TIBDataBase.SetDefaultTransaction(Value: TIBTransaction);
1189 var
1190 i: Integer;
1191 begin
1192 if (FDefaultTransaction <> nil) and (FDefaultTransaction <> Value) then
1193 begin
1194 i := FindTransaction(FDefaultTransaction);
1195 if (i <> -1) and (FDefaultTransaction.DefaultDatabase <> self) then
1196 RemoveTransaction(i);
1197 end;
1198 if (Value <> nil) and (FDefaultTransaction <> Value) then
1199 begin
1200 Value.AddDatabase(Self);
1201 AddTransaction(Value);
1202 end;
1203 FDefaultTransaction := Value;
1204 end;
1205
1206 procedure TIBDataBase.SetIdleTimer(Value: Integer);
1207 begin
1208 if Value < 0 then
1209 IBError(ibxeTimeoutNegative, [nil])
1210 else
1211 if (Value = 0) then
1212 begin
1213 FTimer.Enabled := False;
1214 FTimer.Interval := 0;
1215 end
1216 else
1217 if (Value > 0) then
1218 begin
1219 FTimer.Interval := Value;
1220 if not (csDesigning in ComponentState) then
1221 FTimer.Enabled := True;
1222 end;
1223 end;
1224
1225 function TIBDataBase.TestConnected: Boolean;
1226 var
1227 DatabaseInfo: TIBDatabaseInfo;
1228 begin
1229 result := Connected;
1230 if result then
1231 begin
1232 DatabaseInfo := TIBDatabaseInfo.Create(self);
1233 try
1234 DatabaseInfo.Database := self;
1235 { poke the server to see if connected }
1236 if DatabaseInfo.BaseLevel = 0 then ;
1237 DatabaseInfo.Free;
1238 except
1239 ForceClose;
1240 result := False;
1241 DatabaseInfo.Free;
1242 end;
1243 end;
1244 end;
1245
1246 procedure TIBDataBase.TimeoutConnection(Sender: TObject);
1247 begin
1248 if Connected then
1249 begin
1250 if not FAttachment.HasActivity then
1251 begin
1252 ForceClose;
1253 if Assigned(FOnIdleTimer) then
1254 FOnIdleTimer(Self);
1255 end
1256 end;
1257 end;
1258
1259 function TIBDataBase.GetIsReadOnly: Boolean;
1260 var
1261 DatabaseInfo: TIBDatabaseInfo;
1262 begin
1263 DatabaseInfo := TIBDatabaseInfo.Create(self);
1264 DatabaseInfo.Database := self;
1265 if (DatabaseInfo.ODSMajorVersion < 10) then
1266 result := false
1267 else
1268 begin
1269 if (DatabaseInfo.ReadOnly = 0) then
1270 result := false
1271 else
1272 result := true;
1273 end;
1274 DatabaseInfo.Free;
1275 end;
1276
1277
1278 procedure TIBDataBase.SetSQLDialect( const Value: Integer);
1279 begin
1280 if (Value < 1) then IBError(ibxeSQLDialectInvalid, [nil]);
1281 if (Attachment = nil) or (Value <= DBSQLDialect) then
1282 FSQLDialect := Value
1283 else
1284 IBError(ibxeSQLDialectInvalid, [nil]);
1285 end;
1286
1287 function TIBDataBase.GetDBSQLDialect: Integer;
1288 begin
1289 CheckActive;
1290 Result := Attachment.GetSQLDialect;
1291 end;
1292
1293 function TIBDataBase.GetDefaultCharSetID: integer;
1294 begin
1295 if (Attachment <> nil) and Attachment.HasDefaultCharSet then
1296 Result := Attachment.GetDefaultCharSetID
1297 else
1298 Result := 0;
1299 end;
1300
1301 function TIBDataBase.GetDefaultCharSetName: AnsiString;
1302 begin
1303 if Attachment <> nil then
1304 Result := Attachment.GetCharsetName(DefaultCharSetID)
1305 else
1306 Result := '';
1307 end;
1308
1309 function TIBDataBase.GetDefaultCodePage: TSystemCodePage;
1310 begin
1311 if Attachment <> nil then
1312 Attachment.CharSetID2CodePage(DefaultCharSetID,Result)
1313 else
1314 Result := CP_NONE;
1315 end;
1316
1317 function TIBDataBase.GetRemoteProtocol: string;
1318 begin
1319 CheckActive;
1320 Result := Attachment.GetRemoteProtocol;
1321 end;
1322
1323 procedure TIBDataBase.ValidateClientSQLDialect;
1324 begin
1325 if (DBSQLDialect < FSQLDialect) then
1326 begin
1327 FSQLDialect := DBSQLDialect;
1328 if Assigned (FOnDialectDowngradeWarning) then
1329 FOnDialectDowngradeWarning(self);
1330 end;
1331 end;
1332
1333 procedure TIBDataBase.ApplyUpdates( const DataSets: array of TDataSet);
1334 var
1335 I: Integer;
1336 DS: TIBCustomDataSet;
1337 TR: TIBTransaction;
1338 begin
1339 TR := nil;
1340 for I := 0 to High(DataSets) do
1341 begin
1342 DS := TIBCustomDataSet(DataSets[I]);
1343 if DS.Database <> Self then
1344 IBError(ibxeUpdateWrongDB, [nil]);
1345 if TR = nil then
1346 TR := DS.Transaction;
1347 if (DS.Transaction <> TR) or (TR = nil) then
1348 IBError(ibxeUpdateWrongTR, [nil]);
1349 end;
1350 TR.CheckInTransaction;
1351 for I := 0 to High(DataSets) do
1352 begin
1353 DS := TIBCustomDataSet(DataSets[I]);
1354 DS.ApplyUpdates;
1355 end;
1356 TR.CommitRetaining;
1357 end;
1358
1359 procedure TIBDataBase.CloseDataSets;
1360 var
1361 i: Integer;
1362 begin
1363 for i := 0 to DataSetCount - 1 do
1364 if (DataSets[i] <> nil) then
1365 DataSets[i].close;
1366 end;
1367
1368 function TIBDataBase.GetDataset(Index: longint): TDataset;
1369 begin
1370 if (Index >= 0) and (Index < FDataSets.Count) then
1371 Result := TDataSet(FDataSets[Index])
1372 else
1373 raise Exception.Create('Invalid Index to DataSets');
1374 end;
1375
1376 function TIBDataBase.GetDataSetCount: Longint;
1377 begin
1378 Result := FDataSets.Count;
1379 end;
1380
1381 procedure TIBDataBase.ReadState(Reader: TReader);
1382 begin
1383 FDBParams.Clear;
1384 inherited ReadState(Reader);
1385 end;
1386
1387 procedure TIBDataBase.SetConnected(Value: boolean);
1388 begin
1389 if StreamedConnected and not AllowStreamedConnected then
1390 begin
1391 StreamedConnected := false;
1392 Value := false
1393 end;
1394 inherited SetConnected(Value);
1395 end;
1396
1397 procedure TIBDataBase.GetFieldNames( const TableName: string; List: TStrings);
1398 var
1399 Query: TIBSQL;
1400 begin
1401 if TableName = '' then
1402 IBError(ibxeNoTableName, [nil]);
1403 if not Connected then
1404 Open;
1405 if not FInternalTransaction.Active then
1406 FInternalTransaction.StartTransaction;
1407 Query := TIBSQL.Create(self);
1408 try
1409 Query.GoToFirstRecordOnExecute := False;
1410 Query.Database := Self;
1411 Query.Transaction := FInternalTransaction;
1412 Query.SQL.Text := 'Select R.RDB$FIELD_NAME ' + {do not localize}
1413 'from RDB$RELATION_FIELDS R ' + {do not localize}
1414 'where R.RDB$RELATION_NAME = ' + {do not localize}
1415 '''' + ExtractIdentifier(DBSQLDialect, TableName) +
1416 ''' and Exists(Select * From RDB$FIELDS F Where R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME)' ; {do not localize}
1417 Query.Prepare;
1418 Query.ExecQuery;
1419 with List do
1420 begin
1421 BeginUpdate;
1422 try
1423 Clear;
1424 while (not Query.EOF) and Query.Next do
1425 List.Add(TrimRight(Query.FieldByName('RDB$FIELD_NAME').AsString)); {do not localize}
1426 finally
1427 EndUpdate;
1428 end;
1429 end;
1430 finally
1431 Query.free;
1432 FInternalTransaction.Commit;
1433 end;
1434 end;
1435
1436 procedure TIBDataBase.GetTableNames(List: TStrings; SystemTables: Boolean);
1437 var
1438 Query : TIBSQL;
1439 begin
1440 if not (csReading in ComponentState) then
1441 begin
1442 if not Connected then
1443 Open;
1444 if not FInternalTransaction.Active then
1445 FInternalTransaction.StartTransaction;
1446 Query := TIBSQL.Create(self);
1447 try
1448 Query.GoToFirstRecordOnExecute := False;
1449 Query.Database := Self;
1450 Query.Transaction := FInternalTransaction;
1451 if SystemTables then
1452 Query.SQL.Text := 'Select RDB$RELATION_NAME from RDB$RELATIONS' + {do not localize}
1453 ' where RDB$VIEW_BLR is NULL' {do not localize}
1454 else
1455 Query.SQL.Text := 'Select RDB$RELATION_NAME from RDB$RELATIONS' + {do not localize}
1456 ' where RDB$VIEW_BLR is NULL and RDB$SYSTEM_FLAG = 0'; {do not localize}
1457 Query.Prepare;
1458 Query.ExecQuery;
1459 with List do
1460 begin
1461 BeginUpdate;
1462 try
1463 Clear;
1464 while (not Query.EOF) and Query.Next do
1465 List.Add(TrimRight(Query.Fields[0].AsString));
1466 finally
1467 EndUpdate;
1468 end;
1469 end;
1470 finally
1471 Query.Free;
1472 FInternalTransaction.Commit;
1473 end;
1474 end;
1475 end;
1476
1477 { TIBTransaction }
1478
1479 constructor TIBTransaction.Create(AOwner: TComponent);
1480 begin
1481 inherited Create(AOwner);
1482 FDatabases := TList.Create;
1483 FSQLObjects := TList.Create;
1484 FTPB := nil;
1485 FTRParams := TStringList.Create;
1486 FTRParamsChanged := True;
1487 TStringList(FTRParams).OnChange := TRParamsChange;
1488 TStringList(FTRParams).OnChanging := TRParamsChanging;
1489 FTimer := TFPTimer.Create(Self);
1490 FTimer.Enabled := False;
1491 FTimer.Interval := 0;
1492 FTimer.OnTimer := TimeoutTransaction;
1493 FDefaultAction := taCommit;
1494 end;
1495
1496 destructor TIBTransaction.Destroy;
1497 var
1498 i: Integer;
1499 begin
1500 if InTransaction then
1501 EndTransaction(FDefaultAction, True);
1502 for i := 0 to FSQLObjects.Count - 1 do
1503 if FSQLObjects[i] <> nil then
1504 SQLObjects[i].DoTransactionFree;
1505 RemoveSQLObjects;
1506 RemoveDatabases;
1507 FTPB := nil;
1508 FTRParams.Free;
1509 FSQLObjects.Free;
1510 FDatabases.Free;
1511 inherited Destroy;
1512 end;
1513
1514 procedure TIBTransaction.CheckDatabasesInList;
1515 begin
1516 if GetDatabaseCount = 0 then
1517 IBError(ibxeNoDatabasesInTransaction, [nil]);
1518 end;
1519
1520 procedure TIBTransaction.CheckInTransaction;
1521 begin
1522 if FStreamedActive and (not InTransaction) then
1523 Loaded;
1524 if (TransactionIntf = nil) then
1525 IBError(ibxeNotInTransaction, [nil]);
1526 end;
1527
1528 procedure TIBTransaction.DoBeforeTransactionEnd;
1529 begin
1530 if Assigned(FBeforeTransactionEnd) then
1531 FBeforeTransactionEnd(self);
1532 end;
1533
1534 procedure TIBTransaction.DoAfterTransactionEnd;
1535 begin
1536 if Assigned(FAfterTransactionEnd) then
1537 FAfterTransactionEnd(self);
1538 end;
1539
1540 procedure TIBTransaction.DoOnStartTransaction;
1541 begin
1542 if assigned(FOnStartTransaction) then
1543 OnStartTransaction(self);
1544 end;
1545
1546 procedure TIBTransaction.DoAfterExecQuery(Sender: TObject);
1547 begin
1548 if assigned(FAfterExecQuery) then
1549 AfterExecQuery(Sender);
1550 end;
1551
1552 procedure TIBTransaction.DoAfterEdit(Sender: TObject);
1553 begin
1554 if assigned(FAfterEdit) then
1555 AfterEdit(Sender);
1556 end;
1557
1558 procedure TIBTransaction.DoAfterDelete(Sender: TObject);
1559 begin
1560 if assigned(FAfterDelete) then
1561 AfterDelete(Sender);
1562 end;
1563
1564 procedure TIBTransaction.DoAfterInsert(Sender: TObject);
1565 begin
1566 if assigned(FAfterInsert) then
1567 AfterInsert(Sender);
1568 end;
1569
1570 procedure TIBTransaction.DoAfterPost(Sender: TObject);
1571 begin
1572 if assigned(FAfterPost) then
1573 AfterPost(Sender);
1574 end;
1575
1576 procedure TIBTransaction.EnsureNotInTransaction;
1577 begin
1578 if csDesigning in ComponentState then
1579 begin
1580 if TransactionIntf <> nil then
1581 Rollback;
1582 end;
1583 end;
1584
1585 procedure TIBTransaction.CheckNotInTransaction;
1586 begin
1587 if (TransactionIntf <> nil) and TransactionIntf.InTransaction then
1588 IBError(ibxeInTransaction, [nil]);
1589 end;
1590
1591 function TIBTransaction.AddDatabase(db: TIBDatabase): Integer;
1592 var
1593 i: Integer;
1594 NilFound: Boolean;
1595 begin
1596 EnsureNotInTransaction;
1597 CheckNotInTransaction;
1598 FTransactionIntf := nil;
1599
1600 i := FindDatabase(db);
1601 if i <> -1 then
1602 begin
1603 result := i;
1604 exit;
1605 end;
1606 NilFound := False;
1607 i := 0;
1608 while (not NilFound) and (i < FDatabases.Count) do
1609 begin
1610 NilFound := (FDatabases[i] = nil);
1611 if (not NilFound) then
1612 Inc(i);
1613 end;
1614 if (NilFound) then
1615 begin
1616 FDatabases[i] := db;
1617 result := i;
1618 end
1619 else
1620 begin
1621 result := FDatabases.Count;
1622 FDatabases.Add(db);
1623 end;
1624 end;
1625
1626 function TIBTransaction.AddSQLObject(ds: TIBBase): Integer;
1627 begin
1628 result := 0;
1629 while (result < FSQLObjects.Count) and (FSQLObjects[result] <> nil) do
1630 Inc(result);
1631 if (result = FSQLObjects.Count) then
1632 FSQLObjects.Add(ds)
1633 else
1634 FSQLObjects[result] := ds;
1635 end;
1636
1637 procedure TIBTransaction.Commit;
1638 begin
1639 EndTransaction(TACommit, False);
1640 end;
1641
1642 procedure TIBTransaction.CommitRetaining;
1643 begin
1644 EndTransaction(TACommitRetaining, False);
1645 end;
1646
1647 procedure TIBTransaction.EndTransaction(Action: TTransactionAction;
1648 Force: Boolean);
1649 var
1650 i: Integer;
1651 begin
1652 CheckInTransaction;
1653 if FInEndTransaction then Exit;
1654 FInEndTransaction := true;
1655 FEndAction := Action;
1656 try
1657 case Action of
1658 TARollback, TACommit:
1659 begin
1660 try
1661 DoBeforeTransactionEnd;
1662 except on E: EIBInterBaseError do
1663 begin
1664 if not Force then
1665 raise;
1666 end;
1667 end;
1668
1669 for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
1670 try
1671 SQLObjects[i].DoBeforeTransactionEnd(Action);
1672 except on E: EIBInterBaseError do
1673 begin
1674 if not Force then
1675 raise;
1676 end;
1677 end;
1678
1679 if InTransaction then
1680 begin
1681 if (Action = TARollback) then
1682 FTransactionIntf.Rollback(Force)
1683 else
1684 try
1685 FTransactionIntf.Commit;
1686 except on E: EIBInterBaseError do
1687 begin
1688 if Force then
1689 FTransactionIntf.Rollback(Force)
1690 else
1691 raise;
1692 end;
1693 end;
1694
1695 for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
1696 try
1697 SQLObjects[i].DoAfterTransactionEnd;
1698 except on E: EIBInterBaseError do
1699 begin
1700 if not Force then
1701 raise;
1702 end;
1703 end;
1704 try
1705 DoAfterTransactionEnd;
1706 except on E: EIBInterBaseError do
1707 begin
1708 if not Force then
1709 raise;
1710 end;
1711 end;
1712 end;
1713 end;
1714 TACommitRetaining:
1715 FTransactionIntf.CommitRetaining;
1716
1717 TARollbackRetaining:
1718 FTransactionIntf.RollbackRetaining;
1719 end;
1720 if not (csDesigning in ComponentState) then
1721 begin
1722 case Action of
1723 TACommit:
1724 MonitorHook.TRCommit(Self);
1725 TARollback:
1726 MonitorHook.TRRollback(Self);
1727 TACommitRetaining:
1728 MonitorHook.TRCommitRetaining(Self);
1729 TARollbackRetaining:
1730 MonitorHook.TRRollbackRetaining(Self);
1731 end;
1732 end;
1733 finally
1734 FInEndTransaction := false
1735 end;
1736 end;
1737
1738 function TIBTransaction.GetDatabase(Index: Integer): TIBDatabase;
1739 begin
1740 result := FDatabases[Index];
1741 end;
1742
1743 function TIBTransaction.GetDatabaseCount: Integer;
1744 var
1745 i, Cnt: Integer;
1746 begin
1747 result := 0;
1748 Cnt := FDatabases.Count - 1;
1749 for i := 0 to Cnt do if FDatabases[i] <> nil then
1750 Inc(result);
1751 end;
1752
1753 function TIBTransaction.GetSQLObject(Index: Integer): TIBBase;
1754 begin
1755 result := FSQLObjects[Index];
1756 end;
1757
1758 function TIBTransaction.GetSQLObjectCount: Integer;
1759 var
1760 i, Cnt: Integer;
1761 begin
1762 result := 0;
1763 Cnt := FSQLObjects.Count - 1;
1764 for i := 0 to Cnt do if FSQLObjects[i] <> nil then
1765 Inc(result);
1766 end;
1767
1768 function TIBTransaction.GetInTransaction: Boolean;
1769 begin
1770 result := (TransactionIntf <> nil) and TransactionIntf.InTransaction;
1771 end;
1772
1773 function TIBTransaction.FindDatabase(db: TIBDatabase): Integer;
1774 var
1775 i: Integer;
1776 begin
1777 result := -1;
1778 for i := 0 to FDatabases.Count - 1 do
1779 if db = TIBDatabase(FDatabases[i]) then
1780 begin
1781 result := i;
1782 break;
1783 end;
1784 end;
1785
1786 function TIBTransaction.FindDefaultDatabase: TIBDatabase;
1787 var
1788 i: Integer;
1789 begin
1790 result := FDefaultDatabase;
1791 if result = nil then
1792 begin
1793 for i := 0 to FDatabases.Count - 1 do
1794 if (TIBDatabase(FDatabases[i]) <> nil) and
1795 (TIBDatabase(FDatabases[i]).DefaultTransaction = self) then
1796 begin
1797 result := TIBDatabase(FDatabases[i]);
1798 break;
1799 end;
1800 end;
1801 end;
1802
1803 function TIBTransaction.GetEndAction: TTransactionAction;
1804 begin
1805 if FInEndTransaction then
1806 Result := FEndAction
1807 else
1808 IBError(ibxeIB60feature, [nil])
1809 end;
1810
1811
1812 function TIBTransaction.GetIdleTimer: Integer;
1813 begin
1814 result := FTimer.Interval;
1815 end;
1816
1817 procedure TIBTransaction.Loaded;
1818 begin
1819 inherited Loaded;
1820 end;
1821
1822 procedure TIBTransaction.BeforeDatabaseDisconnect(DB: TIBDatabase);
1823 begin
1824 if InTransaction then
1825 EndTransaction(FDefaultAction, True);
1826 FTransactionIntf := nil;
1827 end;
1828
1829 procedure TIBTransaction.RemoveDatabase(Idx: Integer);
1830 var
1831 DB: TIBDatabase;
1832 begin
1833 if ((Idx >= 0) and (FDatabases[Idx] <> nil)) then
1834 begin
1835 EnsureNotInTransaction;
1836 CheckNotInTransaction;
1837 FTransactionIntf := nil;
1838
1839 DB := Databases[Idx];
1840 FDatabases[Idx] := nil;
1841 DB.RemoveTransaction(DB.FindTransaction(Self));
1842 if DB = FDefaultDatabase then
1843 FDefaultDatabase := nil;
1844 end;
1845 end;
1846
1847 procedure TIBTransaction.RemoveDatabases;
1848 var
1849 i: Integer;
1850 begin
1851 EnsureNotInTransaction;
1852 CheckNotInTransaction;
1853 FTransactionIntf := nil;
1854
1855 for i := 0 to FDatabases.Count - 1 do if FDatabases[i] <> nil then
1856 RemoveDatabase(i);
1857 end;
1858
1859 procedure TIBTransaction.RemoveSQLObject(Idx: Integer);
1860 var
1861 ds: TIBBase;
1862 begin
1863 if ((Idx >= 0) and (FSQLObjects[Idx] <> nil)) then
1864 begin
1865 ds := SQLObjects[Idx];
1866 FSQLObjects[Idx] := nil;
1867 ds.Transaction := nil;
1868 end;
1869 end;
1870
1871 procedure TIBTransaction.RemoveSQLObjects;
1872 var
1873 i: Integer;
1874 begin
1875 for i := 0 to FSQLObjects.Count - 1 do if FSQLObjects[i] <> nil then
1876 RemoveSQLObject(i);
1877 end;
1878
1879 procedure TIBTransaction.Rollback;
1880 begin
1881 EndTransaction(TARollback, False);
1882 end;
1883
1884 procedure TIBTransaction.RollbackRetaining;
1885 begin
1886 EndTransaction(TARollbackRetaining, False);
1887 end;
1888
1889 procedure TIBTransaction.SetActive(Value: Boolean);
1890 begin
1891 if csReading in ComponentState then
1892 FStreamedActive := Value
1893 else
1894 if Value and not InTransaction then
1895 StartTransaction
1896 else
1897 if not Value and InTransaction then
1898 Rollback;
1899 end;
1900
1901 procedure TIBTransaction.SetDefaultDatabase(Value: TIBDatabase);
1902 var
1903 i: integer;
1904 begin
1905 if (FDefaultDatabase <> nil) and (FDefaultDatabase <> Value) then
1906 begin
1907 i := FDefaultDatabase.FindTransaction(self);
1908 if (i <> -1) then
1909 FDefaultDatabase.RemoveTransaction(i);
1910 end;
1911 if (Value <> nil) and (FDefaultDatabase <> Value) then
1912 begin
1913 Value.AddTransaction(Self);
1914 AddDatabase(Value);
1915 for i := 0 to FSQLObjects.Count - 1 do
1916 if (FSQLObjects[i] <> nil) and
1917 (TIBBase(FSQLObjects[i]).Database = nil) then
1918 SetObjectProp(TIBBase(FSQLObjects[i]).Owner, 'Database', Value);
1919 end;
1920 FDefaultDatabase := Value;
1921 end;
1922
1923 procedure TIBTransaction.Notification( AComponent: TComponent;
1924 Operation: TOperation);
1925 var
1926 i: Integer;
1927 begin
1928 inherited Notification( AComponent, Operation);
1929 if (Operation = opRemove) and (AComponent = FDefaultDatabase) then
1930 begin
1931 i := FindDatabase(FDefaultDatabase);
1932 if (i <> -1) then
1933 RemoveDatabase(i);
1934 FDefaultDatabase := nil;
1935 end;
1936 end;
1937
1938 procedure TIBTransaction.SetIdleTimer(Value: Integer);
1939 begin
1940 if Value < 0 then
1941 IBError(ibxeTimeoutNegative, [nil])
1942 else
1943 if (Value = 0) then
1944 begin
1945 FTimer.Enabled := False;
1946 FTimer.Interval := 0;
1947 end
1948 else
1949 if (Value > 0) then
1950 begin
1951 FTimer.Interval := Value;
1952 if not (csDesigning in ComponentState) then
1953 FTimer.Enabled := True;
1954 end;
1955 end;
1956
1957 procedure TIBTransaction.SetTRParams(Value: TStrings);
1958 begin
1959 FTRParams.Assign(Value);
1960 end;
1961
1962 procedure TIBTransaction.StartTransaction;
1963 var
1964 i: Integer;
1965 Attachments: array of IAttachment;
1966 ValidDatabaseCount: integer;
1967 begin
1968 CheckNotInTransaction;
1969 CheckDatabasesInList;
1970 if TransactionIntf <> nil then
1971 begin
1972 TransactionIntf.Start(DefaultAction);
1973 Exit;
1974 end;
1975
1976 for i := 0 to FDatabases.Count - 1 do
1977 if FDatabases[i] <> nil then
1978 begin
1979 with TIBDatabase(FDatabases[i]) do
1980 if not Connected then
1981 if StreamedConnected then
1982 begin
1983 Open;
1984 StreamedConnected := False;
1985 end
1986 else
1987 IBError(ibxeDatabaseClosed, [nil]);
1988 end;
1989 if FTRParamsChanged then
1990 begin
1991 FTRParamsChanged := False;
1992 FTPB := GenerateTPB(FTRParams);
1993 end;
1994
1995 ValidDatabaseCount := 0;
1996 for i := 0 to DatabaseCount - 1 do
1997 if Databases[i] <> nil then Inc(ValidDatabaseCount);
1998
1999 if ValidDatabaseCount = 1 then
2000 FTransactionIntf := Databases[0].Attachment.StartTransaction(FTPB,DefaultAction)
2001 else
2002 begin
2003 SetLength(Attachments,ValidDatabaseCount);
2004 for i := 0 to DatabaseCount - 1 do
2005 if Databases[i] <> nil then
2006 Attachments[i] := Databases[i].Attachment;
2007
2008 FTransactionIntf := FirebirdAPI.StartTransaction(Attachments,FTPB,DefaultAction);
2009 end;
2010
2011 if not (csDesigning in ComponentState) then
2012 MonitorHook.TRStart(Self);
2013 DoOnStartTransaction;
2014 end;
2015
2016 procedure TIBTransaction.TimeoutTransaction(Sender: TObject);
2017 begin
2018 if InTransaction then
2019 begin
2020 if not TransactionIntf.HasActivity then
2021 begin
2022 EndTransaction(FDefaultAction, True);
2023 if Assigned(FOnIdleTimer) then
2024 FOnIdleTimer(Self);
2025 end
2026 end;
2027 end;
2028
2029 procedure TIBTransaction.TRParamsChange(Sender: TObject);
2030 begin
2031 FTRParamsChanged := True;
2032 end;
2033
2034 procedure TIBTransaction.TRParamsChanging(Sender: TObject);
2035 begin
2036 EnsureNotInTransaction;
2037 CheckNotInTransaction;
2038 FTransactionIntf := nil;
2039 end;
2040
2041 { TIBBase }
2042 constructor TIBBase.Create(AOwner: TObject);
2043 begin
2044 FOwner := AOwner;
2045 end;
2046
2047 destructor TIBBase.Destroy;
2048 begin
2049 SetDatabase(nil);
2050 SetTransaction(nil);
2051 inherited Destroy;
2052 end;
2053
2054 procedure TIBBase.HandleException(Sender: TObject);
2055 begin
2056 if assigned(Database) then
2057 Database.HandleException(Sender)
2058 else
2059 SysUtils.ShowException(ExceptObject,ExceptAddr);
2060 end;
2061
2062 procedure TIBBase.SetCursor;
2063 begin
2064 if Assigned(Database) and not Database.SQLHourGlass then
2065 Exit;
2066 if assigned(IBGUIInterface) then
2067 IBGUIInterface.SetCursor;
2068 end;
2069
2070 procedure TIBBase.RestoreCursor;
2071 begin
2072 if Assigned(Database) and not Database.SQLHourGlass then
2073 Exit;
2074 if assigned(IBGUIInterface) then
2075 IBGUIInterface.RestoreCursor;
2076 end;
2077
2078 procedure TIBBase.CheckDatabase;
2079 begin
2080 if (FDatabase = nil) then
2081 IBError(ibxeDatabaseNotAssigned, [nil]);
2082 FDatabase.CheckActive;
2083 end;
2084
2085 procedure TIBBase.CheckTransaction;
2086 begin
2087 if FTransaction = nil then
2088 IBError(ibxeTransactionNotAssigned, [nil]);
2089 FTransaction.CheckInTransaction;
2090 end;
2091
2092 procedure TIBBase.DoBeforeDatabaseConnect(DBParams: TStrings; var DBName: string
2093 );
2094 begin
2095 if assigned(FBeforeDatabaseConnect) then
2096 BeforeDatabaseConnect(self,DBParams,DBName);
2097 end;
2098
2099 procedure TIBBase.DoAfterDatabaseConnect;
2100 begin
2101 if assigned(FAfterDatabaseConnect) then
2102 AfterDatabaseConnect(self);
2103 end;
2104
2105 procedure TIBBase.DoBeforeDatabaseDisconnect;
2106 begin
2107 if Assigned(BeforeDatabaseDisconnect) then
2108 BeforeDatabaseDisconnect(Self);
2109 end;
2110
2111 procedure TIBBase.DoAfterDatabaseDisconnect;
2112 begin
2113 if Assigned(AfterDatabaseDisconnect) then
2114 AfterDatabaseDisconnect(Self);
2115 end;
2116
2117 procedure TIBBase.DoDatabaseFree;
2118 begin
2119 if Assigned(OnDatabaseFree) then
2120 OnDatabaseFree(Self);
2121 SetDatabase(nil);
2122 SetTransaction(nil);
2123 end;
2124
2125 procedure TIBBase.DoBeforeTransactionEnd(Action: TTransactionAction);
2126 begin
2127 if Assigned(BeforeTransactionEnd) then
2128 BeforeTransactionEnd(Self,Action);
2129 end;
2130
2131 procedure TIBBase.DoAfterTransactionEnd;
2132 begin
2133 if Assigned(AfterTransactionEnd) then
2134 AfterTransactionEnd(Self);
2135 end;
2136
2137 procedure TIBBase.DoTransactionFree;
2138 begin
2139 if Assigned(OnTransactionFree) then
2140 OnTransactionFree(Self);
2141 FTransaction := nil;
2142 end;
2143
2144 procedure TIBBase.DoAfterExecQuery(Sender: TObject);
2145 begin
2146 if FTransaction <> nil then
2147 FTransaction.DoAfterExecQuery(Sender);
2148 end;
2149
2150 procedure TIBBase.DoAfterEdit(Sender: TObject);
2151 begin
2152 if FTransaction <> nil then
2153 FTransaction.DoAfterEdit(Sender);
2154 end;
2155
2156 procedure TIBBase.DoAfterDelete(Sender: TObject);
2157 begin
2158 if FTransaction <> nil then
2159 FTransaction.DoAfterDelete(Sender);
2160 end;
2161
2162 procedure TIBBase.DoAfterInsert(Sender: TObject);
2163 begin
2164 if FTransaction <> nil then
2165 FTransaction.DoAfterInsert(Sender);
2166 end;
2167
2168 procedure TIBBase.DoAfterPost(Sender: TObject);
2169 begin
2170 if FTransaction <> nil then
2171 FTransaction.DoAfterPost(Sender);
2172 end;
2173
2174 procedure TIBBase.SetDatabase(Value: TIBDatabase);
2175 begin
2176 if (FDatabase <> nil) then
2177 FDatabase.RemoveSQLObject(FIndexInDatabase);
2178 FDatabase := Value;
2179 if (FDatabase <> nil) then
2180 begin
2181 FIndexInDatabase := FDatabase.AddSQLObject(Self);
2182 if (FTransaction = nil) then
2183 Transaction := FDatabase.FindDefaultTransaction;
2184 end;
2185 end;
2186
2187 procedure TIBBase.SetTransaction(Value: TIBTransaction);
2188 begin
2189 if (FTransaction <> nil) then
2190 FTransaction.RemoveSQLObject(FIndexInTransaction);
2191 FTransaction := Value;
2192 if (FTransaction <> nil) then
2193 begin
2194 FIndexInTransaction := FTransaction.AddSQLObject(Self);
2195 if (FDatabase = nil) then
2196 Database := FTransaction.FindDefaultDatabase;
2197 end;
2198 end;
2199
2200 { GenerateDPB -
2201 Given a string containing a textual representation
2202 of the database parameters, generate a database
2203 parameter buffer, and return it and its length
2204 in DPB and DPBLength, respectively. }
2205
2206 function GenerateDPB(sl: TStrings): IDPB;
2207 var
2208 i, j: Integer;
2209 DPBVal: UShort;
2210 ParamName, ParamValue: string;
2211 begin
2212 Result := FirebirdAPI.AllocateDPB;
2213
2214 {Iterate through the textual database parameters, constructing
2215 a DPB on-the-fly }
2216 for i := 0 to sl.Count - 1 do
2217 begin
2218 { Get the parameter's name and value from the list,
2219 and make sure that the name is all lowercase with
2220 no leading 'isc_dpb_' prefix
2221 }
2222 if (Trim(sl.Names[i]) = '') then
2223 continue;
2224 ParamName := LowerCase(sl.Names[i]); {mbcs ok}
2225 ParamValue := Copy(sl[i], Pos('=', sl[i]) + 1, Length(sl[i])); {mbcs ok}
2226 if (Pos(DPBPrefix, ParamName) = 1) then {mbcs ok}
2227 Delete(ParamName, 1, Length(DPBPrefix));
2228 { We want to translate the parameter name to some Integer
2229 value. We do this by scanning through a list of known
2230 database parameter names (DPBConstantNames, defined above) }
2231 DPBVal := 0;
2232 { Find the parameter }
2233 for j := 1 to isc_dpb_last_dpb_constant do
2234 if (ParamName = DPBConstantNames[j]) then
2235 begin
2236 DPBVal := j;
2237 break;
2238 end;
2239 { A database parameter either contains a string value (case 1)
2240 or an Integer value (case 2)
2241 or no value at all (case 3)
2242 or an error needs to be generated (case else) }
2243 case DPBVal of
2244 isc_dpb_user_name, isc_dpb_password, isc_dpb_password_enc,
2245 isc_dpb_sys_user_name, isc_dpb_license, isc_dpb_encrypt_key,
2246 isc_dpb_lc_messages, isc_dpb_lc_ctype, isc_dpb_page_size,
2247 isc_dpb_sql_role_name, isc_dpb_sql_dialect:
2248 begin
2249 if DPBVal = isc_dpb_sql_dialect then
2250 ParamValue[1] := Char(Ord(ParamValue[1]) - 48);
2251 Result.Add(DPBVal).SetAsString(ParamValue);
2252 end;
2253
2254 isc_dpb_num_buffers, isc_dpb_dbkey_scope, isc_dpb_force_write,
2255 isc_dpb_no_reserve, isc_dpb_damaged, isc_dpb_verify:
2256 Result.Add(DPBVal).SetAsByte(byte(ParamValue[1]));
2257
2258 isc_dpb_sweep:
2259 Result.Add(DPBVal).SetAsByte(isc_dpb_records);
2260
2261 isc_dpb_sweep_interval:
2262 Result.Add(DPBVal).SetAsInteger(StrToInt(ParamValue));
2263
2264 isc_dpb_activate_shadow, isc_dpb_delete_shadow, isc_dpb_begin_log,
2265 isc_dpb_map_attach, isc_dpb_quit_log:
2266 Result.Add(DPBVal).SetAsByte(0);
2267 else
2268 begin
2269 if (DPBVal > 0) and
2270 (DPBVal <= isc_dpb_last_dpb_constant) then
2271 IBError(ibxeDPBConstantNotSupported, [DPBConstantNames[DPBVal]])
2272 else
2273 IBError(ibxeDPBConstantUnknownEx, [sl.Names[i]]);
2274 end;
2275 end;
2276 end;
2277 end;
2278
2279 { GenerateTPB -
2280 Given a string containing a textual representation
2281 of the transaction parameters, generate a transaction
2282 parameter buffer, and return it and its length in
2283 TPB and TPBLength, respectively. }
2284 function GenerateTPB(sl: TStrings): ITPB;
2285 var
2286 i, j, TPBVal: Integer;
2287 ParamName, ParamValue: string;
2288 begin
2289 Result := FirebirdAPI.AllocateTPB;
2290 for i := 0 to sl.Count - 1 do
2291 begin
2292 if (Trim(sl[i]) = '') then
2293 Continue;
2294
2295 if (Pos('=', sl[i]) = 0) then {mbcs ok}
2296 ParamName := LowerCase(sl[i]) {mbcs ok}
2297 else
2298 begin
2299 ParamName := LowerCase(sl.Names[i]); {mbcs ok}
2300 ParamValue := Copy(sl[i], Pos('=', sl[i]) + 1, Length(sl[i])); {mbcs ok}
2301 end;
2302 if (Pos(TPBPrefix, ParamName) = 1) then {mbcs ok}
2303 Delete(ParamName, 1, Length(TPBPrefix));
2304 TPBVal := 0;
2305 { Find the parameter }
2306 for j := 1 to isc_tpb_last_tpb_constant do
2307 if (ParamName = TPBConstantNames[j]) then
2308 begin
2309 TPBVal := j;
2310 break;
2311 end;
2312 { Now act on it }
2313 case TPBVal of
2314 isc_tpb_consistency, isc_tpb_exclusive, isc_tpb_protected,
2315 isc_tpb_concurrency, isc_tpb_shared, isc_tpb_wait, isc_tpb_nowait,
2316 isc_tpb_read, isc_tpb_write, isc_tpb_ignore_limbo,
2317 isc_tpb_read_committed, isc_tpb_rec_version, isc_tpb_no_rec_version:
2318 Result.Add(TPBVal);
2319
2320 isc_tpb_lock_read, isc_tpb_lock_write:
2321 Result.Add(TPBVal).SetAsString(ParamValue);
2322
2323 else
2324 begin
2325 if (TPBVal > 0) and
2326 (TPBVal <= isc_tpb_last_tpb_constant) then
2327 IBError(ibxeTPBConstantNotSupported, [TPBConstantNames[TPBVal]])
2328 else
2329 IBError(ibxeTPBConstantUnknownEx, [sl.Names[i]]);
2330 end;
2331 end;
2332 end;
2333 end;
2334
2335 end.
2336
2337
2338
2339
2340