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