ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/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
File size: 68596 byte(s)
Log Message:
Fixes Merged

File Contents

# User Rev Content
1 tony 209 {************************************************************************}
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 tony 263 FFirebirdLibraryPathName: TIBFileName;
192 tony 209 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 tony 229 FUseHiddenPassword: boolean;
212 tony 263 FFirebirdAPI: IFirebirdAPI;
213 tony 266 FWireCompression: boolean;
214 tony 209 procedure EnsureInactive;
215     function GetAuthenticationMethod: string;
216     function GetDBSQLDialect: Integer;
217     function GetDefaultCharSetID: integer;
218     function GetDefaultCharSetName: AnsiString;
219     function GetDefaultCodePage: TSystemCodePage;
220 tony 263 function GetFirebirdAPI: IFirebirdAPI;
221 tony 209 function GetRemoteProtocol: string;
222     function GetSQLObjectsCount: Integer;
223 tony 263 procedure SetFirebirdLibraryPathName(AValue: TIBFileName);
224 tony 209 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 tony 229 procedure ReConnect;
278 tony 209 procedure RemoveTransaction(Idx: Integer);
279     procedure RemoveTransactions;
280    
281     property Attachment: IAttachment read FAttachment;
282 tony 263 property FirebirdAPI: IFirebirdAPI read GetFirebirdAPI;
283 tony 209 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 tony 263 property FirebirdLibraryPathName: TIBFileName read FFirebirdLibraryPathName
304     write SetFirebirdLibraryPathName;
305 tony 209 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 tony 266 property WireCompression: boolean read FWireCompression write FWireCompression;
316 tony 209 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 tony 263 property OnDialectDowngradeWarning: TNotifyEvent read FOnDialectDowngradeWarning
324     write FOnDialectDowngradeWarning;
325 tony 209 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 tony 266 function GenerateDPB(FirebirdAPI: IFirebirdAPI; sl: TStrings; WireCompression: boolean): IDPB;
509 tony 263 function GenerateTPB(FirebirdAPI: IFirebirdAPI; sl: TStrings): ITPB;
510 tony 209
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 tony 263 FFirebirdAPI := nil;
566 tony 209 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 tony 229 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 tony 209 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 tony 229 FHiddenPassword := '';
845 tony 209 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 tony 229 if (not LoginPrompt) and (FHiddenPassword <> '') and not FUseHiddenPassword then
1062 tony 209 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 tony 229 if not FUseHiddenPassword and (not LoginPrompt and not (csDesigning in ComponentState)) or (FHiddenPassword = '') then
1099 tony 266 DPB := GenerateDPB(FirebirdAPI,TempDBParams,WireCompression)
1100 tony 209 else
1101     begin
1102     TempDBParams.Values['password'] := FHiddenPassword;
1103 tony 266 DPB := GenerateDPB(FirebirdAPI,TempDBParams,WireCompression);
1104 tony 209 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 tony 263 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 tony 209 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 tony 263 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 tony 209 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 tony 263 FTPB := GenerateTPB(Databases[0].FirebirdAPI,FTRParams);
2101 tony 209 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 tony 263 FTransactionIntf := Databases[0].FirebirdAPI.StartTransaction(Attachments,FTPB,DefaultAction);
2117 tony 209 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 tony 266 function GenerateDPB(FirebirdAPI: IFirebirdAPI; sl: TStrings; WireCompression: boolean): IDPB;
2322 tony 209 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 tony 266 if WireCompression then
2393     Result.Add(isc_dpb_config).SetAsString('WireCompression=true');
2394 tony 209 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 tony 263 function GenerateTPB(FirebirdAPI: IFirebirdAPI; sl: TStrings): ITPB;
2402 tony 209 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