ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBDatabase.pas
Revision: 39
Committed: Tue May 17 08:14:52 2016 UTC (8 years, 6 months ago) by tony
Content type: text/x-pascal
File size: 69819 byte(s)
Log Message:
Committing updates for Release R1-4-1

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