ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBDatabase.pas
Revision: 31
Committed: Tue Jul 14 15:31:25 2015 UTC (8 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 67822 byte(s)
Log Message:
Committing updates for Release R1-3-0

File Contents

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