ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBDatabase.pas
Revision: 27
Committed: Tue Apr 14 13:10:23 2015 UTC (9 years, 7 months ago) by tony
Content type: text/x-pascal
File size: 65403 byte(s)
Log Message:
Committing updates for Release R1-2-3

File Contents

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