PageRenderTime 65ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/Gedemin/IBX/IBDatabase.pas

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