fbadmin.pp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. unit FBAdmin;
  2. { Interbase/Firebird Administration using the service manager
  3. Copyright (C) 2012 Ludo Brands
  4. This library is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU Library General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or (at your
  7. option) any later version with the following modification:
  8. As a special exception, the copyright holders of this library give you
  9. permission to link this library with independent modules to produce an
  10. executable, regardless of the license terms of these independent modules,and
  11. to copy and distribute the resulting executable under terms of your choice,
  12. provided that you also meet, for each linked independent module, the terms
  13. and conditions of the license of that module. An independent module is a
  14. module which is not derived from or based on this library. If you modify
  15. this library, you may extend this exception to your version of the library,
  16. but you are not obligated to do so. If you do not wish to do so, delete this
  17. exception statement from your version.
  18. This program is distributed in the hope that it will be useful, but WITHOUT
  19. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  20. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  21. for more details.
  22. You should have received a copy of the GNU Library General Public License
  23. along with this library; if not, write to the Free Software Foundation,
  24. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  25. }
  26. {$mode objfpc}{$H+}
  27. {$Define LinkDynamically}
  28. interface
  29. uses
  30. Classes, SysUtils,
  31. {$IfDef LinkDynamically}
  32. ibase60dyn,
  33. {$Else}
  34. ibase60,
  35. {$EndIf}
  36. IBConnection;
  37. type
  38. TIBBackupOption=(IBBkpVerbose,IBBkpIgnoreChecksums,IBBkpIgnoreLimbo,IBBkpMetadataOnly,
  39. IBBkpNoGarbageCollect,IBBkpOldDescriptions,IBBkpNonTransportable,IBBkpConvert,IBBkpWait);
  40. TIBBackupOptions= set of TIBBackupOption;
  41. TIBRestoreOption=(IBResVerbose,IBResDeactivateIdx,IBResNoShadow,IBResNoValidity,
  42. IBResOneAtaTime,IBResReplace,IBResCreate,IBResUseAllSpace,IBResAMReadOnly,IBResAMReadWrite,
  43. IBFixFssData, IBFixFssMeta,IBResWait);
  44. TIBRestoreOptions= set of TIBRestoreOption;
  45. TServiceProtocol=(IBSPLOCAL,IBSPTCPIP,IBSPNETBEUI,IBSPNAMEDPIPE);
  46. TIBOnOutput= procedure(Sender: TObject; msg: string; IBAdminAction: string) of object;
  47. TIBStatOption = (IBDataPages, IBDbLog, IBHeaderPages, IBIndexPages, IBSystemRelations,
  48. IBRecordVersions, IBStatTables);
  49. TIBStatOptions = set of TIBStatOption;
  50. { TFBAdmin }
  51. TFBAdmin=class(TComponent)
  52. private
  53. FErrorCode: longint;
  54. FErrorMsg: string;
  55. FFixFssDataCharSet: String;
  56. FHost: string;
  57. FOnOutput: TIBOnOutput;
  58. FOutput: TStringList;
  59. FPassword: string;
  60. FPort: word;
  61. FProtocol: TServiceProtocol;
  62. FServerImplementation: string;
  63. FServerLockDir: string;
  64. FServerMsgDir: string;
  65. FServerRootDir: string;
  66. FServerSecDBDir: string;
  67. FServerVersion: string;
  68. FStatus: array [0..19] of ISC_STATUS;
  69. FSvcHandle: isc_svc_handle;
  70. FUseExceptions: boolean;
  71. FUser: string;
  72. FWaitInterval: Integer;
  73. function CheckConnected(ProcName: string):boolean;
  74. procedure CheckError(ProcName : string; Status : PISC_STATUS);
  75. function GetDBInfo:boolean;
  76. function GetIBLongint(buffer:string; var bufptr:integer):longint;overload;
  77. function GetIBString(buffer:string; var bufptr:integer):string;overload;
  78. function GetOutput(IBAdminAction:string):boolean;
  79. function IBParamSerialize(isccode:byte;value:string):string;
  80. procedure IBRaiseError(GDSErrorCode:Longint; const msg : string; const args : array of const);
  81. function IBSPBParamSerialize(isccode:byte;value:string):string;
  82. function IBSPBParamSerialize(isccode:byte;value:longint):string;
  83. function MakeBackupOptions(options:TIBBackupOptions):longint;
  84. function MakeRestoreOptions(options:TIBRestoreOptions):longint;
  85. public
  86. constructor Create(AOwner: TComponent); override;
  87. destructor Destroy; override;
  88. //Connect to service manager. Specify User,Password and, for remote databases,
  89. //Host and, if not standard, Port
  90. function Connect:boolean;
  91. //Disconnect from service manager. Done automatically when destroying component
  92. function DisConnect:boolean;
  93. //Backup database to a single file on the server.
  94. //Include IBBkpVerbose in Options to get progress feedback through the OnOutput Handler
  95. function Backup(Database,Filename:string;Options:TIBBackupOptions;RoleName:string=''):boolean;
  96. //Backup database to multiple files with length FileSize on the server.
  97. //Filenames is the list of filenames to use. The last file specified has no size limit.
  98. //Include IBBkpVerbose in Options to get progress feedback through the OnOutput Handler
  99. function BackupMultiFile(Database:string;Filenames:TStrings;FileSize:longint;
  100. Options:TIBBackupOptions;RoleName:string=''):boolean;
  101. //Restore database from a single file on the server.
  102. //Include IBResReplace to restore in and existing database or IBResCreate
  103. //to create a a new one.
  104. //Include IBResVerbose in Options to get progress feedback through the OnOutput Handler
  105. function Restore(Database,Filename:string;Options:TIBRestoreOptions;RoleName:string=''):boolean;
  106. //Restore database from multiple files on the server.
  107. //Filenames is the list of files to use.
  108. //Include IBResReplace to restore in and existing database or IBResCreate
  109. //to create a a new one.
  110. //Include IBResVerbose in Options to get progress feedback through the OnOutput Handler
  111. function RestoreMultiFile(Database:string;Filenames:TStrings;
  112. Options:TIBRestoreOptions;RoleName:string=''):boolean;
  113. //Add a new user.
  114. function AddUser(UserName,Password:string;RoleName:string='';
  115. GroupName:string='';FirstName:string='';MiddleName:string='';
  116. LastName:string='';UserID: longint = 0; GroupID: longint = 0):boolean;
  117. //Modify an existing user.
  118. function ModifyUser(UserName,Password:string;RoleName:string='';
  119. GroupName:string='';FirstName:string='';MiddleName:string='';
  120. LastName:string='';UserID: longint = 0; GroupID: longint = 0):boolean;
  121. //Delete an existing user.
  122. function DeleteUser(UserName:string;RoleName:string=''):boolean;
  123. //Get the details of an existing user.
  124. function GetUser(UserName:string;var GroupName,FirstName,MiddleName,
  125. LastName:string;var UserID, GroupID: longint):boolean;
  126. //Get the list of all users
  127. function GetUsers(Users:TStrings):boolean;
  128. //Get database server log file
  129. function GetDatabaseLog:boolean;
  130. // For Backup, Restore this will check if the service call is still running.
  131. function ServiceRunning: Boolean;
  132. // Wait till the service stops running, or until aTimeout (in milliseconds) is reached.
  133. // Return true if the service stopped, false if timeout reached.
  134. // WaitInterval is the interval (in milliseconds) between ServiceRunning calls.
  135. function WaitForServiceCompletion(aTimeOut: Integer): Boolean;
  136. //Get database statistics
  137. function GetDatabaseStats(Database:string;Options:TIBStatOptions;TableNames:String = ''): boolean;
  138. //Database server version
  139. property ServerVersion:string read FServerVersion;
  140. //Implementation string of the database server
  141. property ServerImplementation:string read FServerImplementation;
  142. //Setting of $FIREBIRD or $INTERBASE
  143. property ServerRootDir:string read FServerRootDir;
  144. //Setting of $FIREBIRD_LCK or $INTERBASE_LCK
  145. property ServerLockDir:string read FServerLockDir;
  146. //Setting of $FIREBIRD_MSG or $INTERBASE_MSG
  147. property ServerMsgDir:string read FServerMsgDir;
  148. //Path to the security database in use by the server
  149. property ServerSecDBDir:string read FServerSecDBDir;
  150. // FixFxxData/FixFxxMetaData code page
  151. property FixFssDataCharSet: String read FFixFssDataCharSet write FFixFssDataCharSet;
  152. published
  153. //User name to connect to service manager
  154. property User: string read FUser write FUser;
  155. //User name to connect to service manager
  156. property Password: string read FPassword write FPassword;
  157. //Database Host
  158. property Host: string read FHost write FHost;
  159. //Database Port, Default:3050
  160. property Port: word read FPort write FPort default 3050;
  161. //Protocol used to connect to service manager. One of:
  162. //IBSPLOCAL: Host and port ignored
  163. //IBSPTCPIP: Connect to Host:Port
  164. //IBSPNETBEUI: Connect to \\Host\
  165. //IBSPNAMEDPIPE: Connect to //Host/
  166. property Protocol: TServiceProtocol read FProtocol write FProtocol;
  167. //Errorcode returned in status vector or 0 for TFBAdmin errors
  168. property ErrorCode:longint read FErrorCode;
  169. //Errormsg returned in status vector or by TFBAdmin
  170. property ErrorMsg:string read FErrorMsg;
  171. //Raise exceptions when error encounterd. Default: false
  172. property UseExceptions:boolean read FUseExceptions write FUseExceptions;
  173. //Service output messages
  174. //Result from Backup and Restore operations and GetLog
  175. property Output:TStringList read FOutput;
  176. //Event handler for Service output messages
  177. //Used in Backup and Restore operations and GetLog
  178. property OnOutput: TIBOnOutput read FOnOutput write FOnOutput;
  179. // Interval (in milliseconds) to sleep while waiting for the service operation to end.
  180. Property WaitInterval : Integer Read FWaitInterval Write FWaitInterval;
  181. end;
  182. implementation
  183. uses dateutils;
  184. resourcestring
  185. SErrNotConnected = '%s : %s : Not connected.';
  186. SErrError = '%s : %s : %s';
  187. SErrConnected = '%s : Connect : Already connected.';
  188. SErrRestoreOptionsError = '%s : Restore : Nothing to do. Specify IBResReplace or IBResCreate in Options.';
  189. SErrRestoreMultiOptionsError = '%s : RestoreMultiFile : Nothing to do. Specify IBResReplace or IBResCreate in Options.';
  190. SErrUserDoesNotExist = '%s : GetUser : User does not exist.';
  191. SErrUserInvalidReply = '%s : GetUser : Invalid reply (%d).';
  192. SErrUsersInvalidReply = '%s : GetUsers : Invalid reply (%d).';
  193. { TFBAdmin }
  194. function TFBAdmin.IBParamSerialize(isccode: byte; value: string): string;
  195. begin
  196. result:=chr(isccode)+chr(Length(value))+value;
  197. end;
  198. procedure TFBAdmin.IBRaiseError(GDSErrorCode: Longint; const msg: string;
  199. const args: array of const);
  200. begin
  201. FErrorMsg:=Format(msg,args);
  202. FErrorCode:=GDSErrorCode;
  203. if FUseExceptions then
  204. raise EIBDatabaseError.CreateFmt(msg,args,nil,GDSErrorCode,'');
  205. end;
  206. function TFBAdmin.IBSPBParamSerialize(isccode: byte; value: string): string;
  207. begin
  208. result:=chr(isccode)+chr(Length(value) and $ff)+chr((Length(value)shr 8) and $ff)+value;
  209. end;
  210. function TFBAdmin.IBSPBParamSerialize(isccode: byte; value: longint): string;
  211. begin
  212. result:=chr(isccode)+chr(value and $ff)+chr((value shr 8) and $ff)
  213. +chr((value shr 16) and $ff)+chr((value shr 24) and $ff);
  214. end;
  215. function TFBAdmin.MakeBackupOptions(options: TIBBackupOptions): longint;
  216. begin
  217. result:=0;
  218. if IBBkpConvert in Options then
  219. result:=result or isc_spb_bkp_convert;
  220. if IBBkpIgnoreChecksums in Options then
  221. result:=result or isc_spb_bkp_ignore_checksums;
  222. if IBBkpIgnoreLimbo in Options then
  223. result:=result or isc_spb_bkp_ignore_limbo;
  224. if IBBkpMetadataOnly in Options then
  225. result:=result or isc_spb_bkp_metadata_only;
  226. if IBBkpNoGarbageCollect in Options then
  227. result:=result or isc_spb_bkp_no_garbage_collect;
  228. if IBBkpNonTransportable in Options then
  229. result:=result or isc_spb_bkp_non_transportable;
  230. if IBBkpOldDescriptions in Options then
  231. result:=result or isc_spb_bkp_old_descriptions;
  232. end;
  233. function TFBAdmin.MakeRestoreOptions(options: TIBRestoreOptions): longint;
  234. begin
  235. result:=0;
  236. if IBResCreate in Options then
  237. result:=result or isc_spb_res_create;
  238. if IBResDeactivateIdx in Options then
  239. result:=result or isc_spb_res_deactivate_idx;
  240. if IBResNoShadow in Options then
  241. result:=result or isc_spb_res_no_shadow;
  242. if IBResNoValidity in Options then
  243. result:=result or isc_spb_res_no_validity;
  244. if IBResOneAtaTime in Options then
  245. result:=result or isc_spb_res_one_at_a_time;
  246. if IBResReplace in Options then
  247. result:=result or isc_spb_res_replace;
  248. if IBResUseAllSpace in Options then
  249. result:=result or isc_spb_res_use_all_space;
  250. end;
  251. function TFBAdmin.CheckConnected(ProcName: string): boolean;
  252. begin
  253. result:=false;
  254. if FSvcHandle=FB_API_NULLHANDLE then
  255. begin
  256. IBRaiseError(0,SErrNotConnected,[self.Name,ProcName]);
  257. exit;
  258. end;
  259. result:=true;
  260. end;
  261. procedure TFBAdmin.CheckError(ProcName: string; Status: PISC_STATUS);
  262. var
  263. buf : array [0..1023] of char;
  264. Msg : string;
  265. Err : longint;
  266. begin
  267. if ((Status[0] = 1) and (Status[1] <> 0)) then
  268. begin
  269. Err := Status[1];
  270. msg := '';
  271. while isc_interprete(Buf, @Status) > 0 do
  272. Msg := Msg + LineEnding +' -' + StrPas(Buf);
  273. IBRaiseError(Err,SErrError,[self.Name,ProcName,Msg]);
  274. end;
  275. end;
  276. function TFBAdmin.GetDBInfo: boolean;
  277. function QueryInfo(isc:byte):string;
  278. var
  279. spb:string;
  280. len:integer;
  281. begin
  282. result:='';
  283. spb:=chr(isc);
  284. setlength(result,255);
  285. if (isc_service_query(@FStatus[0], @FSvcHandle, nil, 0, nil, length(spb),
  286. @spb[1],255,@result[1])=0) and (result[1]=chr(isc)) then
  287. begin
  288. len:=isc_vax_integer(@result[2],2);
  289. delete(result,1,3); // remove cmd and len
  290. setlength(result,len);
  291. end;
  292. end;
  293. begin
  294. FServerImplementation:= QueryInfo(isc_info_svc_implementation);
  295. FServerLockDir:= QueryInfo(isc_info_svc_get_env_lock);
  296. FServerMsgDir:= QueryInfo(isc_info_svc_get_env_msg);
  297. FServerRootDir:= QueryInfo(isc_info_svc_get_env);
  298. FServerSecDBDir:= QueryInfo(isc_info_svc_user_dbpath);
  299. FServerVersion:= QueryInfo(isc_info_svc_server_version);
  300. end;
  301. function TFBAdmin.GetIBLongint(buffer: string; var bufptr: integer): longint;
  302. begin
  303. bufptr:=bufptr+1;
  304. result:=isc_vax_integer(@Buffer[bufptr], 4);
  305. bufptr:=bufptr+4;
  306. end;
  307. function TFBAdmin.GetIBString(buffer: string; var bufptr: integer): string;
  308. var
  309. len:integer;
  310. begin
  311. bufptr:=bufptr+1;
  312. len:=isc_vax_integer(@buffer[bufptr], 2);
  313. bufptr:=bufptr+2;
  314. result:=copy(buffer,bufptr,len);
  315. bufptr:=bufptr+len;
  316. end;
  317. function TFBAdmin.GetOutput(IBAdminAction: string): boolean;
  318. var
  319. len:integer;
  320. buffer:string;
  321. spb:string;
  322. const
  323. BUFFERSIZE=1000;
  324. begin
  325. len:=0;
  326. FOutput.Clear;
  327. spb:=chr(isc_info_svc_line);
  328. repeat
  329. setlength(buffer,BUFFERSIZE);
  330. result:=isc_service_query(@FStatus[0], @FSvcHandle, nil, 0, nil, length(spb),
  331. @spb[1],BUFFERSIZE,@buffer[1])=0;
  332. if not result then
  333. begin
  334. CheckError('GetOutput',FStatus);
  335. exit;
  336. end;
  337. if buffer[1]=chr(isc_info_svc_line) then
  338. begin
  339. len:=isc_vax_integer(@buffer[2],2);
  340. delete(buffer,1,3); // remove cmd and len
  341. setlength(buffer,len);
  342. FOutput.Add(buffer);
  343. if assigned(FOnOutput) then
  344. begin
  345. FOnOutput(Self,buffer,IBAdminAction);
  346. end;
  347. end;
  348. until len=0;
  349. end;
  350. constructor TFBAdmin.Create(AOwner: TComponent);
  351. begin
  352. inherited Create(AOwner);
  353. FPort:= 3050;
  354. FOutput:=TStringList.Create;
  355. FFixFssDataCharSet:= '';
  356. end;
  357. destructor TFBAdmin.Destroy;
  358. begin
  359. if FSvcHandle<>FB_API_NULLHANDLE then
  360. begin
  361. WaitInterval:=100;
  362. DisConnect;
  363. end;
  364. FOutput.Destroy;
  365. inherited Destroy;
  366. end;
  367. function TFBAdmin.Connect: boolean;
  368. var
  369. Service:string;
  370. spb:string;
  371. begin
  372. result:=false;
  373. {$IfDef LinkDynamically}
  374. result:=InitialiseIBase60<>0;
  375. {$EndIf}
  376. if FSvcHandle<>FB_API_NULLHANDLE then
  377. raise EIBDatabaseError.CreateFmt(SErrConnected,[Self.Name],nil,0,'');
  378. Service:='service_mgr';
  379. case FProtocol of
  380. IBSPTCPIP:if FPort=3050 then
  381. service:=FHost+':'+service
  382. else
  383. service:=FHost+'/'+IntTostr(FPort)+':'+service;
  384. IBSPNETBEUI:service:='\\'+FHost+'\'+service;
  385. IBSPNAMEDPIPE:service:='//'+FHost+'/'+service;
  386. end;
  387. spb:=chr(isc_spb_version)+chr(isc_spb_current_version)+
  388. IBParamSerialize(isc_spb_user_name,FUser)+
  389. IBParamSerialize(isc_spb_password,FPassword);
  390. result:=isc_service_attach(@FStatus[0], 0,PChar(Service), @FSvcHandle,
  391. length(spb), @spb[1]) = 0;
  392. if not result then
  393. CheckError('Connect',FStatus)
  394. else
  395. GetDBInfo;
  396. end;
  397. function TFBAdmin.DisConnect: boolean;
  398. begin
  399. result:=CheckConnected('DisConnect');
  400. result:= isc_service_detach(@FStatus[0], @FSvcHandle) = 0;
  401. if not result then
  402. CheckError('DisConnect',FStatus);
  403. FSvcHandle:=FB_API_NULLHANDLE;
  404. {$IfDef LinkDynamically}
  405. ReleaseIBase60;
  406. {$EndIf}
  407. result:=true;
  408. end;
  409. function TFBAdmin.Backup(Database, Filename: string; Options: TIBBackupOptions;
  410. RoleName: string): boolean;
  411. var
  412. spb:string;
  413. begin
  414. result:=CheckConnected('Backup');
  415. spb:=chr(isc_action_svc_backup)+IBSPBParamSerialize(isc_spb_dbname,Database)
  416. +IBSPBParamSerialize(isc_spb_bkp_file,Filename);
  417. if RoleName<>'' then
  418. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  419. if IBBkpVerbose in Options then
  420. spb:=spb+chr(isc_spb_verbose);
  421. spb:=spb+IBSPBParamSerialize(isc_spb_options,MakeBackupOptions(Options));
  422. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  423. @spb[1])=0;
  424. if not result then
  425. begin
  426. CheckError('Backup',FStatus);
  427. exit;
  428. end;
  429. if IBBkpVerbose in Options then
  430. result:=GetOutput('Backup')
  431. else if (IBBkpWait in Options) then
  432. WaitForServiceCompletion(0);
  433. end;
  434. function TFBAdmin.BackupMultiFile(Database: string; Filenames: TStrings;
  435. FileSize: longint; Options: TIBBackupOptions; RoleName: string): boolean;
  436. var
  437. spb:string;
  438. i:integer;
  439. begin
  440. result:=CheckConnected('BackupMultiFile');
  441. spb:=chr(isc_action_svc_backup)+IBSPBParamSerialize(isc_spb_dbname,Database);
  442. for i:=0 to Filenames.Count-1 do
  443. begin
  444. spb:=spb+IBSPBParamSerialize(isc_spb_bkp_file,Filenames[i]);
  445. spb:=spb+IBSPBParamSerialize(isc_spb_bkp_length,FileSize);
  446. end;
  447. if RoleName<>'' then
  448. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  449. if IBBkpVerbose in Options then
  450. spb:=spb+chr(isc_spb_verbose);
  451. spb:=spb+IBSPBParamSerialize(isc_spb_options,MakeBackupOptions(Options));
  452. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  453. @spb[1])=0;
  454. if not result then
  455. begin
  456. CheckError('BackupMultiFile',FStatus);
  457. exit;
  458. end;
  459. if IBBkpVerbose in Options then
  460. result:=GetOutput('BackupMultiFile')
  461. else if (IBBkpWait in Options) then
  462. WaitForServiceCompletion(0);
  463. end;
  464. Function TFBAdmin.ServiceRunning : Boolean;
  465. const
  466. BUFFERSIZE=1000;
  467. var
  468. res:integer;
  469. buffer: string;
  470. spb:string;
  471. begin
  472. FOutput.Clear;
  473. spb:=chr(isc_info_svc_running);
  474. setlength(buffer,BUFFERSIZE);
  475. result:=isc_service_query(@FStatus[0], @FSvcHandle, nil, 0, nil, length(spb),
  476. @spb[1],BUFFERSIZE,@buffer[1])=0;
  477. if Not Result then
  478. CheckError('ServiceRunning',FSTatus);
  479. if (Buffer[1]=Char(isc_info_svc_running)) then
  480. begin
  481. res:=isc_vax_integer(@Buffer[2],4);
  482. Result:=res=1;
  483. end
  484. else
  485. IBRaiseError(0,'%s: Service status detection returned wrong result',[self.Name]);
  486. end;
  487. Function TFBAdmin.WaitForServiceCompletion(aTimeOut : Integer) : Boolean;
  488. Var
  489. N : TDateTime;
  490. begin
  491. N:=Now;
  492. Repeat
  493. Sleep(WaitInterval);
  494. Result:=not ServiceRunning;
  495. until Result or ((aTimeOut<>0) and (MilliSecondsBetween(Now,N)>aTimeOut*WaitInterval));
  496. end;
  497. function TFBAdmin.Restore(Database, Filename: string;
  498. Options: TIBRestoreOptions; RoleName: string): boolean;
  499. var
  500. spb:string;
  501. begin
  502. result:=CheckConnected('Restore');
  503. if not ((IBResReplace in Options) or (IBResCreate in Options)) then
  504. begin
  505. result:=false;
  506. IBRaiseError(0,SErrRestoreOptionsError,[self.Name]);
  507. exit;
  508. end;
  509. spb:=chr(isc_action_svc_restore)+IBSPBParamSerialize(isc_spb_dbname,Database)
  510. +IBSPBParamSerialize(isc_spb_bkp_file,Filename);
  511. if RoleName<>'' then
  512. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  513. if IBResVerbose in Options then
  514. spb:=spb+chr(isc_spb_verbose);
  515. if (IBResAMReadOnly in Options) or (IBResAMReadWrite in Options) then
  516. begin
  517. if (IBResAMReadOnly in Options) then //ReadOnly overrides ReadWrite
  518. spb:=spb+chr(isc_spb_res_access_mode)+chr(isc_spb_res_am_readonly)
  519. else
  520. spb:=spb+chr(isc_spb_res_access_mode)+chr(isc_spb_res_am_readwrite);
  521. end;
  522. if (IBFixFssData in Options) and (FixFssDataCharSet > ' ') then
  523. spb:=spb+IBSPBParamSerialize(isc_spb_res_fix_fss_data, FixFssDataCharSet);
  524. if (IBFixFssMeta in Options) and (FixFssDataCharSet > ' ') then
  525. spb:=spb+IBSPBParamSerialize(isc_spb_res_fix_fss_metadata, FixFssDataCharSet);
  526. spb:=spb+IBSPBParamSerialize(isc_spb_options,MakeRestoreOptions(Options));
  527. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  528. @spb[1])=0;
  529. if not result then
  530. begin
  531. CheckError('Restore',FStatus);
  532. exit;
  533. end;
  534. if IBResVerbose in Options then
  535. result:=GetOutput('Restore')
  536. else if IBResWait in Options then
  537. WaitForServiceCompletion(0);
  538. end;
  539. function TFBAdmin.RestoreMultiFile(Database: string; Filenames: TStrings;
  540. Options: TIBRestoreOptions; RoleName: string): boolean;
  541. var
  542. spb:string;
  543. i:integer;
  544. begin
  545. result:=CheckConnected('RestoreMultiFile');
  546. if not ((IBResReplace in Options) or (IBResCreate in Options)) then
  547. begin
  548. result:=false;
  549. IBRaiseError(0,SErrRestoreMultiOptionsError,[self.Name]);
  550. exit;
  551. end;
  552. spb:=chr(isc_action_svc_restore)+IBSPBParamSerialize(isc_spb_dbname,Database);
  553. for i:=0 to Filenames.Count-1 do
  554. spb:=spb+IBSPBParamSerialize(isc_spb_bkp_file,Filenames[i]);
  555. if RoleName<>'' then
  556. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  557. if IBResVerbose in Options then
  558. spb:=spb+chr(isc_spb_verbose);
  559. if (IBResAMReadOnly in Options) or (IBResAMReadWrite in Options) then
  560. begin
  561. if (IBResAMReadOnly in Options) then //ReadOnly overrides ReadWrite
  562. spb:=spb+chr(isc_spb_res_access_mode)+chr(isc_spb_res_am_readonly)
  563. else
  564. spb:=spb+chr(isc_spb_res_access_mode)+chr(isc_spb_res_am_readwrite);
  565. end;
  566. spb:=spb+IBSPBParamSerialize(isc_spb_options,MakeRestoreOptions(Options));
  567. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  568. @spb[1])=0;
  569. if not result then
  570. begin
  571. CheckError('RestoreMultiFile',FStatus);
  572. exit;
  573. end;
  574. if IBResVerbose in Options then
  575. result:=GetOutput('RestoreMultiFile');
  576. end;
  577. function TFBAdmin.AddUser(UserName, Password: string; RoleName: string;
  578. GroupName: string; FirstName: string; MiddleName: string; LastName: string;
  579. UserID: longint; GroupID: longint): boolean;
  580. var
  581. spb:string;
  582. begin
  583. result:=CheckConnected('AddUser');
  584. spb:=chr(isc_action_svc_add_user)+IBSPBParamSerialize(isc_spb_sec_username,copy(UserName,1,31))+
  585. IBSPBParamSerialize(isc_spb_sec_password,copy(Password,1,8));
  586. if RoleName<>'' then
  587. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  588. if GroupName<>'' then
  589. spb:=spb+IBSPBParamSerialize(isc_spb_sec_groupname,copy(GroupName,1,31));
  590. if FirstName<>'' then
  591. spb:=spb+IBSPBParamSerialize(isc_spb_sec_firstname,copy(FirstName,1,255));
  592. if MiddleName<>'' then
  593. spb:=spb+IBSPBParamSerialize(isc_spb_sec_middlename,copy(MiddleName,1,255));
  594. if LastName<>'' then
  595. spb:=spb+IBSPBParamSerialize(isc_spb_sec_lastname,copy(LastName,1,255));
  596. if UserID<>0 then
  597. spb:=spb+IBSPBParamSerialize(isc_spb_sec_userid,UserID);
  598. if GroupID<>0 then
  599. spb:=spb+IBSPBParamSerialize(isc_spb_sec_groupid,GroupID);
  600. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  601. @spb[1])=0;
  602. if not result then
  603. CheckError('AddUser',FStatus);
  604. end;
  605. function TFBAdmin.ModifyUser(UserName, Password: string; RoleName: string;
  606. GroupName: string; FirstName: string; MiddleName: string; LastName: string;
  607. UserID: longint; GroupID: longint): boolean;
  608. var
  609. spb:string;
  610. begin
  611. result:=CheckConnected('ModifyUser');
  612. spb:=chr(isc_action_svc_modify_user)+IBSPBParamSerialize(isc_spb_sec_username,copy(UserName,1,31))+
  613. IBSPBParamSerialize(isc_spb_sec_password,copy(Password,1,8));
  614. if RoleName<>'' then
  615. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  616. if GroupName<>'' then
  617. spb:=spb+IBSPBParamSerialize(isc_spb_sec_groupname,copy(GroupName,1,31));
  618. if FirstName<>'' then
  619. spb:=spb+IBSPBParamSerialize(isc_spb_sec_firstname,copy(FirstName,1,255));
  620. if MiddleName<>'' then
  621. spb:=spb+IBSPBParamSerialize(isc_spb_sec_middlename,copy(MiddleName,1,255));
  622. if LastName<>'' then
  623. spb:=spb+IBSPBParamSerialize(isc_spb_sec_lastname,copy(LastName,1,255));
  624. if UserID<>0 then
  625. spb:=spb+IBSPBParamSerialize(isc_spb_sec_userid,UserID);
  626. if GroupID<>0 then
  627. spb:=spb+IBSPBParamSerialize(isc_spb_sec_groupid,GroupID);
  628. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  629. @spb[1])=0;
  630. if not result then
  631. CheckError('ModifyUser',FStatus);
  632. end;
  633. function TFBAdmin.DeleteUser(UserName: string; RoleName: string): boolean;
  634. var
  635. spb:string;
  636. begin
  637. result:=CheckConnected('DeleteUser');
  638. spb:=chr(isc_action_svc_delete_user)+IBSPBParamSerialize(isc_spb_sec_username,copy(UserName,1,31));
  639. if RoleName<>'' then
  640. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  641. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  642. @spb[1])=0;
  643. if not result then
  644. CheckError('DeleteUser',FStatus);
  645. end;
  646. function TFBAdmin.GetUser(UserName: string; var GroupName, FirstName,
  647. MiddleName, LastName: string; var UserID, GroupID: longint): boolean;
  648. var
  649. spb:string;
  650. buffer:string;
  651. bufptr:integer;
  652. const
  653. BUFFERSIZE=1000;
  654. begin
  655. result:=CheckConnected('GetUser');
  656. spb:=chr(isc_action_svc_display_user)+IBSPBParamSerialize(isc_spb_sec_username,copy(UserName,1,31));
  657. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  658. @spb[1])=0;
  659. if not result then
  660. begin
  661. CheckError('GetUser',FStatus);
  662. exit;
  663. end;
  664. //retrieve result
  665. spb:=chr(isc_info_svc_get_users);
  666. setlength(buffer,BUFFERSIZE);
  667. result:=isc_service_query(@FStatus[0], @FSvcHandle, nil, 0, nil, length(spb),
  668. @spb[1],BUFFERSIZE,@buffer[1])=0;
  669. if not result then
  670. begin
  671. CheckError('GetUser',FStatus);
  672. exit;
  673. end;
  674. bufptr:=4;
  675. if buffer[1]=chr(isc_info_svc_get_users) then
  676. begin
  677. if buffer[bufptr]=chr(isc_info_end) then
  678. begin
  679. result:=false;
  680. IBRaiseError(0,SErrUserDoesNotExist,[self.Name]);
  681. exit;
  682. end;
  683. while buffer[bufptr]<>chr(isc_info_end) do
  684. begin
  685. case buffer[bufptr] of
  686. chr(isc_spb_sec_username):GetIBString(buffer,bufptr); //trash result
  687. chr(isc_spb_sec_groupname):GroupName:=GetIBString(buffer,bufptr);
  688. chr(isc_spb_sec_firstname):FirstName:=GetIBString(buffer,bufptr);
  689. chr(isc_spb_sec_middlename):MiddleName:=GetIBString(buffer,bufptr);
  690. chr(isc_spb_sec_lastname):LastName:=GetIBString(buffer,bufptr);
  691. chr(isc_spb_sec_userid):UserID:=GetIBLongint(buffer,bufptr);
  692. chr(isc_spb_sec_groupid):GroupID:=GetIBLongint(buffer,bufptr);
  693. else
  694. begin
  695. result:=false;
  696. IBRaiseError(0,SErrUserInvalidReply,[self.Name,ord(buffer[bufptr])]);
  697. exit;
  698. end;
  699. end;
  700. end;
  701. end;
  702. end;
  703. function TFBAdmin.GetUsers(Users: TStrings): boolean;
  704. var
  705. spb:string;
  706. buffer:string;
  707. bufptr:integer;
  708. const
  709. BUFFERSIZE=1000;
  710. begin
  711. result:=CheckConnected('GetUsers');
  712. spb:=chr(isc_action_svc_display_user);
  713. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  714. @spb[1])=0;
  715. if not result then
  716. begin
  717. CheckError('GetUsers',FStatus);
  718. exit;
  719. end;
  720. //retrieve result
  721. spb:=chr(isc_info_svc_get_users);
  722. setlength(buffer,BUFFERSIZE);
  723. result:=isc_service_query(@FStatus[0], @FSvcHandle, nil, 0, nil, length(spb),
  724. @spb[1],BUFFERSIZE,@buffer[1])=0;
  725. if not result then
  726. begin
  727. CheckError('GetUsers',FStatus);
  728. exit;
  729. end;
  730. bufptr:=4;
  731. Users.Clear;
  732. if buffer[1]=chr(isc_info_svc_get_users) then
  733. begin
  734. while buffer[bufptr]<>chr(isc_info_end) do
  735. begin
  736. case buffer[bufptr] of
  737. chr(isc_spb_sec_username):Users.Add(GetIBString(buffer,bufptr));
  738. chr(isc_spb_sec_groupname),
  739. chr(isc_spb_sec_firstname),
  740. chr(isc_spb_sec_middlename),
  741. chr(isc_spb_sec_lastname):GetIBString(buffer,bufptr); //trash result
  742. chr(isc_spb_sec_userid),
  743. chr(isc_spb_sec_groupid):GetIBLongint(buffer,bufptr); //trash result
  744. else
  745. begin
  746. result:=false;
  747. IBRaiseError(0,SErrUsersInvalidReply,[self.Name,ord(buffer[bufptr])]);
  748. exit;
  749. end;
  750. end;
  751. end;
  752. end;
  753. end;
  754. function TFBAdmin.GetDatabaseLog: boolean;
  755. var
  756. spb:string;
  757. begin
  758. result:=CheckConnected('GetLogFile');
  759. spb:=chr(isc_action_svc_get_ib_log);
  760. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  761. @spb[1])=0;
  762. if not result then
  763. begin
  764. CheckError('GetLogFile',FStatus);
  765. exit;
  766. end;
  767. result:=GetOutput('GetLogFile');
  768. end;
  769. function TFBAdmin.GetDatabaseStats(Database:string;Options: TIBStatOptions; TableNames: String
  770. ): boolean;
  771. var
  772. spb:string;
  773. param: Integer;
  774. begin
  775. Result:=CheckConnected('GetDatabaseStats');
  776. param := 0;
  777. if (IBDataPages in Options) then
  778. param := param or isc_spb_sts_data_pages;
  779. if (IBDbLog in Options) then
  780. param := param or isc_spb_sts_db_log;
  781. if (IBHeaderPages in Options) then
  782. param := param or isc_spb_sts_hdr_pages;
  783. if (IBIndexPages in Options) then
  784. param := param or isc_spb_sts_idx_pages;
  785. if (IBSystemRelations in Options) then
  786. param := param or isc_spb_sts_sys_relations;
  787. if (IBRecordVersions in Options) then
  788. param := param or isc_spb_sts_record_versions;
  789. if (IBStatTables in Options) then
  790. param := param or isc_spb_sts_table;
  791. spb := Char(isc_action_svc_db_stats)+IBSPBParamSerialize(isc_spb_dbname,Database)+
  792. IBSPBParamSerialize(isc_spb_options, param);
  793. if (IBStatTables in Options) and (TableNames <> '') then
  794. spb := spb+IBSPBParamSerialize(isc_spb_command_line, TableNames);
  795. Result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  796. @spb[1])=0;
  797. if not Result then
  798. begin
  799. CheckError('GetDatabaseStats',FStatus);
  800. exit;
  801. end;
  802. Result:=GetOutput('GetDatabaseStats');
  803. end;
  804. end.