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