fbadmin.pp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  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. WaitInterval:=100;
  361. DisConnect;
  362. FOutput.Destroy;
  363. inherited Destroy;
  364. end;
  365. function TFBAdmin.Connect: boolean;
  366. var
  367. Service:string;
  368. spb:string;
  369. begin
  370. result:=false;
  371. {$IfDef LinkDynamically}
  372. result:=InitialiseIBase60<>0;
  373. {$EndIf}
  374. if FSvcHandle<>FB_API_NULLHANDLE then
  375. raise EIBDatabaseError.CreateFmt(SErrConnected,[Self.Name],nil,0,'');
  376. Service:='service_mgr';
  377. case FProtocol of
  378. IBSPTCPIP:if FPort=3050 then
  379. service:=FHost+':'+service
  380. else
  381. service:=FHost+'/'+IntTostr(FPort)+':'+service;
  382. IBSPNETBEUI:service:='\\'+FHost+'\'+service;
  383. IBSPNAMEDPIPE:service:='//'+FHost+'/'+service;
  384. end;
  385. spb:=chr(isc_spb_version)+chr(isc_spb_current_version)+
  386. IBParamSerialize(isc_spb_user_name,FUser)+
  387. IBParamSerialize(isc_spb_password,FPassword);
  388. result:=isc_service_attach(@FStatus[0], 0,PChar(Service), @FSvcHandle,
  389. length(spb), @spb[1]) = 0;
  390. if not result then
  391. CheckError('Connect',FStatus)
  392. else
  393. GetDBInfo;
  394. end;
  395. function TFBAdmin.DisConnect: boolean;
  396. begin
  397. result:=CheckConnected('DisConnect');
  398. result:= isc_service_detach(@FStatus[0], @FSvcHandle) = 0;
  399. if not result then
  400. CheckError('DisConnect',FStatus);
  401. FSvcHandle:=FB_API_NULLHANDLE;
  402. {$IfDef LinkDynamically}
  403. ReleaseIBase60;
  404. {$EndIf}
  405. result:=true;
  406. end;
  407. function TFBAdmin.Backup(Database, Filename: string; Options: TIBBackupOptions;
  408. RoleName: string): boolean;
  409. var
  410. spb:string;
  411. begin
  412. result:=CheckConnected('Backup');
  413. spb:=chr(isc_action_svc_backup)+IBSPBParamSerialize(isc_spb_dbname,Database)
  414. +IBSPBParamSerialize(isc_spb_bkp_file,Filename);
  415. if RoleName<>'' then
  416. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  417. if IBBkpVerbose in Options then
  418. spb:=spb+chr(isc_spb_verbose);
  419. spb:=spb+IBSPBParamSerialize(isc_spb_options,MakeBackupOptions(Options));
  420. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  421. @spb[1])=0;
  422. if not result then
  423. begin
  424. CheckError('Backup',FStatus);
  425. exit;
  426. end;
  427. if IBBkpVerbose in Options then
  428. result:=GetOutput('Backup')
  429. else if (IBBkpWait in Options) then
  430. WaitForServiceCompletion(0);
  431. end;
  432. function TFBAdmin.BackupMultiFile(Database: string; Filenames: TStrings;
  433. FileSize: longint; Options: TIBBackupOptions; RoleName: string): boolean;
  434. var
  435. spb:string;
  436. i:integer;
  437. begin
  438. result:=CheckConnected('BackupMultiFile');
  439. spb:=chr(isc_action_svc_backup)+IBSPBParamSerialize(isc_spb_dbname,Database);
  440. for i:=0 to Filenames.Count-1 do
  441. begin
  442. spb:=spb+IBSPBParamSerialize(isc_spb_bkp_file,Filenames[i]);
  443. spb:=spb+IBSPBParamSerialize(isc_spb_bkp_length,FileSize);
  444. end;
  445. if RoleName<>'' then
  446. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  447. if IBBkpVerbose in Options then
  448. spb:=spb+chr(isc_spb_verbose);
  449. spb:=spb+IBSPBParamSerialize(isc_spb_options,MakeBackupOptions(Options));
  450. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  451. @spb[1])=0;
  452. if not result then
  453. begin
  454. CheckError('BackupMultiFile',FStatus);
  455. exit;
  456. end;
  457. if IBBkpVerbose in Options then
  458. result:=GetOutput('BackupMultiFile')
  459. else if (IBBkpWait in Options) then
  460. WaitForServiceCompletion(0);
  461. end;
  462. Function TFBAdmin.ServiceRunning : Boolean;
  463. const
  464. BUFFERSIZE=1000;
  465. var
  466. res:integer;
  467. buffer: string;
  468. spb:string;
  469. begin
  470. FOutput.Clear;
  471. spb:=chr(isc_info_svc_running);
  472. setlength(buffer,BUFFERSIZE);
  473. result:=isc_service_query(@FStatus[0], @FSvcHandle, nil, 0, nil, length(spb),
  474. @spb[1],BUFFERSIZE,@buffer[1])=0;
  475. if Not Result then
  476. CheckError('ServiceRunning',FSTatus);
  477. if (Buffer[1]=Char(isc_info_svc_running)) then
  478. begin
  479. res:=isc_vax_integer(@Buffer[2],4);
  480. Result:=res=1;
  481. end
  482. else
  483. IBRaiseError(0,'%s: Service status detection returned wrong result',[self.Name]);
  484. end;
  485. Function TFBAdmin.WaitForServiceCompletion(aTimeOut : Integer) : Boolean;
  486. Var
  487. N : TDateTime;
  488. begin
  489. N:=Now;
  490. Repeat
  491. Sleep(WaitInterval);
  492. Result:=not ServiceRunning;
  493. until Result or ((aTimeOut<>0) and (MilliSecondsBetween(Now,N)>aTimeOut*WaitInterval));
  494. end;
  495. function TFBAdmin.Restore(Database, Filename: string;
  496. Options: TIBRestoreOptions; RoleName: string): boolean;
  497. var
  498. spb:string;
  499. begin
  500. result:=CheckConnected('Restore');
  501. if not ((IBResReplace in Options) or (IBResCreate in Options)) then
  502. begin
  503. result:=false;
  504. IBRaiseError(0,SErrRestoreOptionsError,[self.Name]);
  505. exit;
  506. end;
  507. spb:=chr(isc_action_svc_restore)+IBSPBParamSerialize(isc_spb_dbname,Database)
  508. +IBSPBParamSerialize(isc_spb_bkp_file,Filename);
  509. if RoleName<>'' then
  510. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  511. if IBResVerbose in Options then
  512. spb:=spb+chr(isc_spb_verbose);
  513. if (IBResAMReadOnly in Options) or (IBResAMReadWrite in Options) then
  514. begin
  515. if (IBResAMReadOnly in Options) then //ReadOnly overrides ReadWrite
  516. spb:=spb+chr(isc_spb_res_access_mode)+chr(isc_spb_res_am_readonly)
  517. else
  518. spb:=spb+chr(isc_spb_res_access_mode)+chr(isc_spb_res_am_readwrite);
  519. end;
  520. if (IBFixFssData in Options) and (FixFssDataCharSet > ' ') then
  521. spb:=spb+IBSPBParamSerialize(isc_spb_res_fix_fss_data, FixFssDataCharSet);
  522. if (IBFixFssMeta in Options) and (FixFssDataCharSet > ' ') then
  523. spb:=spb+IBSPBParamSerialize(isc_spb_res_fix_fss_metadata, FixFssDataCharSet);
  524. spb:=spb+IBSPBParamSerialize(isc_spb_options,MakeRestoreOptions(Options));
  525. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  526. @spb[1])=0;
  527. if not result then
  528. begin
  529. CheckError('Restore',FStatus);
  530. exit;
  531. end;
  532. if IBResVerbose in Options then
  533. result:=GetOutput('Restore')
  534. else if IBResWait in Options then
  535. WaitForServiceCompletion(0);
  536. end;
  537. function TFBAdmin.RestoreMultiFile(Database: string; Filenames: TStrings;
  538. Options: TIBRestoreOptions; RoleName: string): boolean;
  539. var
  540. spb:string;
  541. i:integer;
  542. begin
  543. result:=CheckConnected('RestoreMultiFile');
  544. if not ((IBResReplace in Options) or (IBResCreate in Options)) then
  545. begin
  546. result:=false;
  547. IBRaiseError(0,SErrRestoreMultiOptionsError,[self.Name]);
  548. exit;
  549. end;
  550. spb:=chr(isc_action_svc_restore)+IBSPBParamSerialize(isc_spb_dbname,Database);
  551. for i:=0 to Filenames.Count-1 do
  552. spb:=spb+IBSPBParamSerialize(isc_spb_bkp_file,Filenames[i]);
  553. if RoleName<>'' then
  554. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  555. if IBResVerbose in Options then
  556. spb:=spb+chr(isc_spb_verbose);
  557. if (IBResAMReadOnly in Options) or (IBResAMReadWrite in Options) then
  558. begin
  559. if (IBResAMReadOnly in Options) then //ReadOnly overrides ReadWrite
  560. spb:=spb+chr(isc_spb_res_access_mode)+chr(isc_spb_res_am_readonly)
  561. else
  562. spb:=spb+chr(isc_spb_res_access_mode)+chr(isc_spb_res_am_readwrite);
  563. end;
  564. spb:=spb+IBSPBParamSerialize(isc_spb_options,MakeRestoreOptions(Options));
  565. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  566. @spb[1])=0;
  567. if not result then
  568. begin
  569. CheckError('RestoreMultiFile',FStatus);
  570. exit;
  571. end;
  572. if IBResVerbose in Options then
  573. result:=GetOutput('RestoreMultiFile');
  574. end;
  575. function TFBAdmin.AddUser(UserName, Password: string; RoleName: string;
  576. GroupName: string; FirstName: string; MiddleName: string; LastName: string;
  577. UserID: longint; GroupID: longint): boolean;
  578. var
  579. spb:string;
  580. begin
  581. result:=CheckConnected('AddUser');
  582. spb:=chr(isc_action_svc_add_user)+IBSPBParamSerialize(isc_spb_sec_username,copy(UserName,1,31))+
  583. IBSPBParamSerialize(isc_spb_sec_password,copy(Password,1,8));
  584. if RoleName<>'' then
  585. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  586. if GroupName<>'' then
  587. spb:=spb+IBSPBParamSerialize(isc_spb_sec_groupname,copy(GroupName,1,31));
  588. if FirstName<>'' then
  589. spb:=spb+IBSPBParamSerialize(isc_spb_sec_firstname,copy(FirstName,1,255));
  590. if MiddleName<>'' then
  591. spb:=spb+IBSPBParamSerialize(isc_spb_sec_middlename,copy(MiddleName,1,255));
  592. if LastName<>'' then
  593. spb:=spb+IBSPBParamSerialize(isc_spb_sec_lastname,copy(LastName,1,255));
  594. if UserID<>0 then
  595. spb:=spb+IBSPBParamSerialize(isc_spb_sec_userid,UserID);
  596. if GroupID<>0 then
  597. spb:=spb+IBSPBParamSerialize(isc_spb_sec_groupid,GroupID);
  598. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  599. @spb[1])=0;
  600. if not result then
  601. CheckError('AddUser',FStatus);
  602. end;
  603. function TFBAdmin.ModifyUser(UserName, Password: string; RoleName: string;
  604. GroupName: string; FirstName: string; MiddleName: string; LastName: string;
  605. UserID: longint; GroupID: longint): boolean;
  606. var
  607. spb:string;
  608. begin
  609. result:=CheckConnected('ModifyUser');
  610. spb:=chr(isc_action_svc_modify_user)+IBSPBParamSerialize(isc_spb_sec_username,copy(UserName,1,31))+
  611. IBSPBParamSerialize(isc_spb_sec_password,copy(Password,1,8));
  612. if RoleName<>'' then
  613. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  614. if GroupName<>'' then
  615. spb:=spb+IBSPBParamSerialize(isc_spb_sec_groupname,copy(GroupName,1,31));
  616. if FirstName<>'' then
  617. spb:=spb+IBSPBParamSerialize(isc_spb_sec_firstname,copy(FirstName,1,255));
  618. if MiddleName<>'' then
  619. spb:=spb+IBSPBParamSerialize(isc_spb_sec_middlename,copy(MiddleName,1,255));
  620. if LastName<>'' then
  621. spb:=spb+IBSPBParamSerialize(isc_spb_sec_lastname,copy(LastName,1,255));
  622. if UserID<>0 then
  623. spb:=spb+IBSPBParamSerialize(isc_spb_sec_userid,UserID);
  624. if GroupID<>0 then
  625. spb:=spb+IBSPBParamSerialize(isc_spb_sec_groupid,GroupID);
  626. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  627. @spb[1])=0;
  628. if not result then
  629. CheckError('ModifyUser',FStatus);
  630. end;
  631. function TFBAdmin.DeleteUser(UserName: string; RoleName: string): boolean;
  632. var
  633. spb:string;
  634. begin
  635. result:=CheckConnected('DeleteUser');
  636. spb:=chr(isc_action_svc_delete_user)+IBSPBParamSerialize(isc_spb_sec_username,copy(UserName,1,31));
  637. if RoleName<>'' then
  638. spb:=spb+IBSPBParamSerialize(isc_spb_sql_role_name,copy(RoleName,1,31));
  639. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  640. @spb[1])=0;
  641. if not result then
  642. CheckError('DeleteUser',FStatus);
  643. end;
  644. function TFBAdmin.GetUser(UserName: string; var GroupName, FirstName,
  645. MiddleName, LastName: string; var UserID, GroupID: longint): boolean;
  646. var
  647. spb:string;
  648. buffer:string;
  649. bufptr:integer;
  650. const
  651. BUFFERSIZE=1000;
  652. begin
  653. result:=CheckConnected('GetUser');
  654. spb:=chr(isc_action_svc_display_user)+IBSPBParamSerialize(isc_spb_sec_username,copy(UserName,1,31));
  655. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  656. @spb[1])=0;
  657. if not result then
  658. begin
  659. CheckError('GetUser',FStatus);
  660. exit;
  661. end;
  662. //retrieve result
  663. spb:=chr(isc_info_svc_get_users);
  664. setlength(buffer,BUFFERSIZE);
  665. result:=isc_service_query(@FStatus[0], @FSvcHandle, nil, 0, nil, length(spb),
  666. @spb[1],BUFFERSIZE,@buffer[1])=0;
  667. if not result then
  668. begin
  669. CheckError('GetUser',FStatus);
  670. exit;
  671. end;
  672. bufptr:=4;
  673. if buffer[1]=chr(isc_info_svc_get_users) then
  674. begin
  675. if buffer[bufptr]=chr(isc_info_end) then
  676. begin
  677. result:=false;
  678. IBRaiseError(0,SErrUserDoesNotExist,[self.Name]);
  679. exit;
  680. end;
  681. while buffer[bufptr]<>chr(isc_info_end) do
  682. begin
  683. case buffer[bufptr] of
  684. chr(isc_spb_sec_username):GetIBString(buffer,bufptr); //trash result
  685. chr(isc_spb_sec_groupname):GroupName:=GetIBString(buffer,bufptr);
  686. chr(isc_spb_sec_firstname):FirstName:=GetIBString(buffer,bufptr);
  687. chr(isc_spb_sec_middlename):MiddleName:=GetIBString(buffer,bufptr);
  688. chr(isc_spb_sec_lastname):LastName:=GetIBString(buffer,bufptr);
  689. chr(isc_spb_sec_userid):UserID:=GetIBLongint(buffer,bufptr);
  690. chr(isc_spb_sec_groupid):GroupID:=GetIBLongint(buffer,bufptr);
  691. else
  692. begin
  693. result:=false;
  694. IBRaiseError(0,SErrUserInvalidReply,[self.Name,ord(buffer[bufptr])]);
  695. exit;
  696. end;
  697. end;
  698. end;
  699. end;
  700. end;
  701. function TFBAdmin.GetUsers(Users: TStrings): boolean;
  702. var
  703. spb:string;
  704. buffer:string;
  705. bufptr:integer;
  706. const
  707. BUFFERSIZE=1000;
  708. begin
  709. result:=CheckConnected('GetUsers');
  710. spb:=chr(isc_action_svc_display_user);
  711. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  712. @spb[1])=0;
  713. if not result then
  714. begin
  715. CheckError('GetUsers',FStatus);
  716. exit;
  717. end;
  718. //retrieve result
  719. spb:=chr(isc_info_svc_get_users);
  720. setlength(buffer,BUFFERSIZE);
  721. result:=isc_service_query(@FStatus[0], @FSvcHandle, nil, 0, nil, length(spb),
  722. @spb[1],BUFFERSIZE,@buffer[1])=0;
  723. if not result then
  724. begin
  725. CheckError('GetUsers',FStatus);
  726. exit;
  727. end;
  728. bufptr:=4;
  729. Users.Clear;
  730. if buffer[1]=chr(isc_info_svc_get_users) then
  731. begin
  732. while buffer[bufptr]<>chr(isc_info_end) do
  733. begin
  734. case buffer[bufptr] of
  735. chr(isc_spb_sec_username):Users.Add(GetIBString(buffer,bufptr));
  736. chr(isc_spb_sec_groupname),
  737. chr(isc_spb_sec_firstname),
  738. chr(isc_spb_sec_middlename),
  739. chr(isc_spb_sec_lastname):GetIBString(buffer,bufptr); //trash result
  740. chr(isc_spb_sec_userid),
  741. chr(isc_spb_sec_groupid):GetIBLongint(buffer,bufptr); //trash result
  742. else
  743. begin
  744. result:=false;
  745. IBRaiseError(0,SErrUsersInvalidReply,[self.Name,ord(buffer[bufptr])]);
  746. exit;
  747. end;
  748. end;
  749. end;
  750. end;
  751. end;
  752. function TFBAdmin.GetDatabaseLog: boolean;
  753. var
  754. spb:string;
  755. begin
  756. result:=CheckConnected('GetLogFile');
  757. spb:=chr(isc_action_svc_get_ib_log);
  758. result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  759. @spb[1])=0;
  760. if not result then
  761. begin
  762. CheckError('GetLogFile',FStatus);
  763. exit;
  764. end;
  765. result:=GetOutput('GetLogFile');
  766. end;
  767. function TFBAdmin.GetDatabaseStats(Database:string;Options: TIBStatOptions; TableNames: String
  768. ): boolean;
  769. var
  770. spb:string;
  771. param: Integer;
  772. begin
  773. Result:=CheckConnected('GetDatabaseStats');
  774. param := 0;
  775. if (IBDataPages in Options) then
  776. param := param or isc_spb_sts_data_pages;
  777. if (IBDbLog in Options) then
  778. param := param or isc_spb_sts_db_log;
  779. if (IBHeaderPages in Options) then
  780. param := param or isc_spb_sts_hdr_pages;
  781. if (IBIndexPages in Options) then
  782. param := param or isc_spb_sts_idx_pages;
  783. if (IBSystemRelations in Options) then
  784. param := param or isc_spb_sts_sys_relations;
  785. if (IBRecordVersions in Options) then
  786. param := param or isc_spb_sts_record_versions;
  787. if (IBStatTables in Options) then
  788. param := param or isc_spb_sts_table;
  789. spb := Char(isc_action_svc_db_stats)+IBSPBParamSerialize(isc_spb_dbname,Database)+
  790. IBSPBParamSerialize(isc_spb_options, param);
  791. if (IBStatTables in Options) and (TableNames <> '') then
  792. spb := spb+IBSPBParamSerialize(isc_spb_command_line, TableNames);
  793. Result:=isc_service_start(@FStatus[0], @FSvcHandle, nil, length(spb),
  794. @spb[1])=0;
  795. if not Result then
  796. begin
  797. CheckError('GetDatabaseStats',FStatus);
  798. exit;
  799. end;
  800. Result:=GetOutput('GetDatabaseStats');
  801. end;
  802. end.