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

File Contents

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