/Gedemin/IBX/IBDatabase.pas

http://gedemin.googlecode.com/ · Pascal · 2276 lines · 1958 code · 164 blank · 154 comment · 238 complexity · 742150ae1c849dd259184b9b54b98409 MD5 · raw file

Large files are truncated click here to view the full file

  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 TIBDatab