ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBDatabase.pas
Revision: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (7 years, 4 months ago) by tony
Content type: text/x-pascal
File size: 61732 byte(s)
Log Message:
Committing updates for Release R2-0-0

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