ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/nongui/IBXServices.pas
Revision: 267
Committed: Fri Dec 28 10:44:23 2018 UTC (5 years, 4 months ago) by tony
Content type: text/x-pascal
File size: 92436 byte(s)
Log Message:
Fixes Merged

File Contents

# User Rev Content
1 tony 209 {************************************************************************}
2     { }
3     { Borland Delphi Visual Component Library }
4     { InterBase Express core components }
5     { }
6     { Copyright (c) 1998-2000 Inprise Corporation }
7     { }
8     { InterBase Express is based in part on the product }
9     { Free IB Components, written by Gregory H. Deatz for }
10     { Hoagland, Longo, Moran, Dunst & Doukas Company. }
11     { Free IB Components is used under license. }
12     { }
13     { The contents of this file are subject to the InterBase }
14     { Public License Version 1.0 (the "License"); you may not }
15     { use this file except in compliance with the License. You }
16     { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
17     { Software distributed under the License is distributed on }
18     { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
19     { express or implied. See the License for the specific language }
20     { governing rights and limitations under the License. }
21     { The Original Code was created by InterBase Software Corporation }
22     { and its successors. }
23     { Portions created by Inprise Corporation are Copyright (C) Inprise }
24     { Corporation. All Rights Reserved. }
25     { Contributor(s): Jeff Overcash }
26     { }
27     { IBX For Lazarus (Firebird Express) }
28     { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
29     { Portions created by MWA Software are copyright McCallum Whyman }
30     { Associates Ltd 2011 - 2018 }
31     { }
32     {************************************************************************}
33    
34     unit IBXServices;
35    
36     {$mode objfpc}{$H+}
37    
38     interface
39    
40     uses
41     Classes, SysUtils, DB, IB, IBDatabase, IBTypes, IBSQLMonitor, IBExternals, memds;
42    
43     type
44     TIBXCustomService = class;
45     TIBXControlService = class;
46     TIBXServicesConnection = class;
47    
48     IIBXServicesClient = interface
49     procedure OnAfterConnect(Sender: TIBXServicesConnection; aDatabaseName: string);
50     procedure OnBeforeDisconnect(Sender: TIBXServicesConnection);
51     end;
52    
53     TSecContextAction = (scRaiseError, scReconnect);
54    
55     TIBXServicesLoginEvent = procedure(Service: TIBXServicesConnection; var aServerName: string; LoginParams: TStrings) of object;
56     TIBXServicesSecContextEvent = procedure(Service: TIBXServicesConnection; var aAction: TSecContextAction) of object;
57    
58     { TIBXServicesConnection }
59    
60     TIBXServicesConnection = class(TIBXMonitoredConnection)
61     private
62 tony 267 FConfigOverrides: TStrings;
63 tony 209 FDatabase: TIBDatabase;
64 tony 263 FFirebirdAPI: IFirebirdAPI;
65 tony 209 FConnectString: string;
66 tony 263 FFirebirdLibraryPathName: TIBFileName;
67 tony 209 FOnSecurityContextException: TIBXServicesSecContextEvent;
68     FParams: TStrings;
69     FIBXServices: array of IIBXServicesClient;
70     FOnLogin: TIBXServicesLoginEvent;
71     FService: IServiceManager;
72     FPortNo: string;
73     FServerName: string;
74     FProtocol: TProtocol;
75     FServerVersionNo: array [1..4] of integer;
76     FExpectedDB: string;
77     procedure CheckActive;
78     procedure CheckInactive;
79     procedure CheckServerName;
80     function GenerateSPB(sl: TStrings): ISPB;
81 tony 263 function GetFirebirdAPI: IFirebirdAPI;
82 tony 209 function GetServerVersionNo(index: integer): integer;
83     function GetSPBConstName(action: byte): string;
84 tony 267 function GetWireCompression: boolean;
85 tony 209 procedure HandleException(Sender: TObject);
86     procedure HandleSecContextException(Sender: TIBXControlService; var action: TSecContextAction);
87     function Login(var aServerName: string; LoginParams: TStrings): Boolean;
88     procedure ParamsChanging(Sender: TObject);
89 tony 267 procedure SetConfigOverrides(AValue: TStrings);
90 tony 209 procedure SetConnectString(AValue: string);
91 tony 263 procedure SetFirebirdLibraryPathName(AValue: TIBFileName);
92 tony 209 procedure SetParams(AValue: TStrings);
93     procedure SetPortNo(AValue: string);
94     procedure SetProtocol(AValue: TProtocol);
95     procedure SetServerName(AValue: string);
96 tony 267 procedure SetWireCompression(AValue: boolean);
97 tony 209 protected
98     procedure DoConnect; override;
99     procedure DoDisconnect; override;
100     function GetConnected: Boolean; override;
101     function GetDataset(Index : longint) : TDataset; override;
102     function GetDataSetCount : Longint; override;
103     procedure ReadState(Reader: TReader); override;
104     procedure RegisterIntf(intf: IIBXServicesClient);
105     procedure UnRegisterIntf(intf: IIBXServicesClient);
106     public
107     constructor Create(AOwner: TComponent); override;
108     destructor Destroy; override;
109     procedure ConnectUsing(aDatabase: TIBDatabase);
110     {Copies database parameters as give in the DBParams to the Services connection
111     omitting any parameters not appropriate for Services API. Typically, the
112     DBParams are TIBDatabase.Params}
113     procedure SetDBParams(DBParams: TStrings);
114 tony 263 property FirebirdAPI: IFirebirdAPI read GetFirebirdAPI;
115 tony 209 property ServerVersionNo[index: integer]: integer read GetServerVersionNo;
116     property ServiceIntf: IServiceManager read FService;
117     published
118     property Connected;
119     property ConnectString: string read FConnectString write SetConnectString;
120 tony 267 property ConfigOverrides: TStrings read FConfigOverrides write SetConfigOverrides;
121 tony 263 property FirebirdLibraryPathName: TIBFileName read FFirebirdLibraryPathName
122     write SetFirebirdLibraryPathName;
123 tony 209 property LoginPrompt default True;
124     property Protocol: TProtocol read FProtocol write SetProtocol default Local;
125     property PortNo: string read FPortNo write SetPortNo;
126     property Params: TStrings read FParams write SetParams;
127     property ServerName: string read FServerName write SetServerName;
128     property TraceFlags;
129 tony 267 property WireCompression: boolean read GetWireCompression write SetWireCompression
130     stored false;
131 tony 209 property AfterConnect;
132     property AfterDisconnect;
133     property BeforeConnect;
134     property BeforeDisconnect;
135     property OnLogin: TIBXServicesLoginEvent read FOnLogin write FOnLogin;
136     property OnSecurityContextException: TIBXServicesSecContextEvent read FOnSecurityContextException
137     write FOnSecurityContextException;
138     end;
139    
140     { TIBXCustomService }
141    
142     TIBXCustomService = class(TIBXMonitoredService,IIBXServicesClient)
143     private
144     FSRB: ISRB;
145     FSQPB: ISQPB;
146     FServiceQueryResults: IServiceQueryResults;
147     FServicesConnection: TIBXServicesConnection;
148     procedure CheckActive;
149     function GetSQPB: ISQPB;
150     function GetSRB: ISRB;
151     procedure SetServicesConnection(AValue: TIBXServicesConnection);
152     protected
153     procedure Clear; virtual;
154     procedure OnAfterConnect(Sender: TIBXServicesConnection; aDatabaseName: string); virtual;
155     procedure OnBeforeDisconnect(Sender: TIBXServicesConnection); virtual;
156     procedure InternalServiceQuery(RaiseExceptionOnError: boolean=true);
157     procedure DoServiceQuery; virtual;
158     procedure Notification( AComponent: TComponent; Operation: TOperation); override;
159     property SRB: ISRB read GetSRB;
160     property SQPB: ISQPB read GetSQPB;
161     property ServiceQueryResults: IServiceQueryResults read FServiceQueryResults;
162     public
163     constructor Create(AOwner: TComponent); override;
164     destructor Destroy; override;
165     procedure Assign(Source: TPersistent); override;
166     published
167     property ServicesConnection: TIBXServicesConnection read FServicesConnection
168     write SetServicesConnection;
169     property TraceFlags;
170     end;
171    
172     { TDatabaseInfo }
173    
174     TDatabaseInfo = class
175     public
176     NoOfAttachments: Integer;
177     NoOfDatabases: Integer;
178     DbName: array of string;
179     constructor Create;
180     destructor Destroy; override;
181     end;
182    
183     { TConfigFileData }
184    
185     TConfigFileData = class
186     public
187     ConfigFileValue: array of integer;
188     ConfigFileKey: array of integer;
189     constructor Create;
190     destructor Destroy; override;
191     end;
192    
193     { TConfigParams }
194    
195     TConfigParams = class
196     public
197     ConfigFileData: TConfigFileData;
198     ConfigFileParams: array of string;
199     BaseLocation: string;
200     LockFileLocation: string;
201     MessageFileLocation: string;
202     SecurityDatabaseLocation: string;
203     constructor Create;
204     destructor Destroy; override;
205     end;
206    
207     TVersionInfo = class
208     ServerVersion: String;
209     ServerImplementation: string;
210     ServiceVersion: Integer;
211     end;
212    
213     { TIBXServerProperties }
214    
215     TIBXServerProperties = class(TIBXCustomService)
216     private
217     FDatabaseInfo: TDatabaseInfo;
218     FVersionInfo: TVersionInfo;
219     FConfigParams: TConfigParams;
220     function GetConfigParams: TConfigParams;
221     function GetDatabaseInfo: TDatabaseInfo;
222     function GetVersionInfo: TVersionInfo;
223     protected
224     procedure Clear; override;
225     public
226     property DatabaseInfo: TDatabaseInfo read GetDatabaseInfo;
227     property VersionInfo: TVersionInfo read GetVersionInfo;
228     property ConfigParams: TConfigParams read GetConfigParams;
229     end;
230    
231     { TIBXControlService }
232    
233     TIBXControlService = class(TIBXCustomService)
234     private
235     FDatabaseName: string;
236     FAction: TSecContextAction;
237     FLastStartSRB: ISRB;
238     function GetIsServiceRunning: Boolean;
239     procedure HandleSecContextErr;
240     procedure CallSecContextException;
241     procedure SetDatabaseName(AValue: string);
242     protected
243     procedure DatabaseNameChanged; virtual;
244     procedure OnAfterConnect(Sender: TIBXServicesConnection; aDatabaseName: string); override;
245     procedure AddDBNameToSRB;
246     procedure CheckServiceNotRunning;
247     procedure InternalServiceStart;
248     procedure DoServiceQuery; override;
249     procedure SetServiceStartOptions; virtual;
250     procedure ServiceStart; virtual;
251     property DatabaseName: string read FDatabaseName write SetDatabaseName;
252     public
253     procedure Assign(Source: TPersistent); override;
254     property IsServiceRunning : Boolean read GetIsServiceRunning;
255     end;
256    
257     TIBXOnGetNextLine = procedure(Sender: TObject; var Line: string) of object;
258    
259     { TIBXControlAndQueryService }
260    
261     TIBXControlAndQueryService = class (TIBXControlService)
262     private
263     FEof: Boolean;
264     FSendBytes: integer;
265     FOnGetNextLine: TIBXOnGetNextLine;
266     FServiceStarted: boolean;
267     FDataSets: TList;
268     protected
269     function GetNextLine : String;
270     function GetNextChunk : String;
271     procedure ServiceStart; override;
272     function ReceiveNextChunk(stream: TStream): integer;
273     function SendNextChunk(stream: TStream; var line: String): integer;
274     procedure DoOnGetNextLine(Line: string);
275     procedure OnBeforeDisconnect(Sender: TIBXServicesConnection); override;
276     procedure Notification( AComponent: TComponent; Operation: TOperation); override;
277     procedure RegisterDataSet(aDataSet: TDataSet);
278     procedure UnRegisterDataSet(aDataSet: TDataSet);
279     public
280     constructor Create(aOwner: TComponent); override;
281     destructor Destroy; override;
282     procedure Execute(OutputLog: TStrings); virtual;
283     property Eof: boolean read FEof;
284     published
285     property OnGetNextLine: TIBXOnGetNextLine read FOnGetNextLine write FOnGetNextLine;
286     end;
287    
288     { TIBXLogService }
289    
290     TIBXLogService = class(TIBXControlAndQueryService)
291     protected
292     procedure SetServiceStartOptions; override;
293     end;
294    
295     TDBShutdownMode = (Forced, DenyTransaction, DenyAttachment);
296    
297     { TIBXConfigService }
298    
299     TIBXConfigService = class(TIBXControlService)
300     public
301     procedure ShutdownDatabase (Options: TDBShutdownMode; Wait: Integer);
302     procedure SetSweepInterval (Value: Integer);
303     procedure SetDBSqlDialect (Value: Integer);
304     procedure SetPageBuffers (Value: Integer);
305     procedure ActivateShadow;
306     procedure BringDatabaseOnline;
307     procedure SetReserveSpace (Value: Boolean);
308     procedure SetAsyncMode (Value: Boolean);
309     procedure SetReadOnly (Value: Boolean);
310     procedure SetNoLinger;
311     published
312     property DatabaseName;
313     end;
314    
315     TStatOption = (DataPages, HeaderPages, IndexPages, SystemRelations);
316     TStatOptions = set of TStatOption;
317    
318     { TIBXStatisticalService }
319    
320     TIBXStatisticalService = class(TIBXControlAndQueryService)
321     private
322     FOptions: TStatOptions;
323     protected
324     procedure SetServiceStartOptions; override;
325     published
326     property DatabaseName;
327     property Options: TStatOptions read FOptions write FOptions;
328     end;
329    
330     TBackupStatsOption = (bsTotalTime,bsTimeDelta,bsPageReads,bsPageWrites);
331     TBackupStatsOptions = set of TBackupStatsOption;
332    
333     { TIBXBackupRestoreService }
334    
335     TIBXBackupRestoreService = class(TIBXControlAndQueryService)
336     private
337     FStatisticsRequested: TBackupStatsOptions;
338     FVerbose: Boolean;
339     protected
340     procedure SetServiceStartOptions; override;
341     property Verbose : Boolean read FVerbose write FVerbose default False;
342     property StatisticsRequested: TBackupStatsOptions read FStatisticsRequested write FStatisticsRequested;
343     published
344     end;
345    
346     TBackupOption = (IgnoreChecksums, IgnoreLimbo, MetadataOnly, NoGarbageCollection,
347     OldMetadataDesc, NonTransportable, ConvertExtTables, NoDBTriggers);
348     TBackupOptions = set of TBackupOption;
349    
350     { TIBXBackupService }
351    
352     TIBXBackupService = class (TIBXBackupRestoreService)
353     private
354     FOptions: TBackupOptions;
355     FBlockingFactor: Integer;
356     protected
357     procedure SetServiceStartOptions; override;
358     procedure SetBackupTarget; virtual; abstract;
359     published
360     property BlockingFactor: Integer read FBlockingFactor write FBlockingFactor;
361     property DatabaseName;
362     property Options : TBackupOptions read FOptions write FOptions;
363     end;
364    
365     { TIBXClientSideBackupService }
366    
367     TIBXClientSideBackupService = class(TIBXBackupService)
368     protected
369     procedure Execute(OutputLog: TStrings); override;
370     procedure SetBackupTarget; override;
371     public
372     procedure BackupToStream(S: TStream; var BytesWritten: integer);
373     procedure BackupToFile(aFileName: string; var BytesWritten: integer);
374     end;
375    
376     { TIBXServerSideBackupService }
377    
378     TIBXServerSideBackupService = class(TIBXBackupService)
379     private
380     FBackupFiles: TStrings;
381     procedure SetBackupFile(const Value: TStrings);
382     protected
383     procedure SetBackupTarget; override;
384     public
385     constructor Create(AOwner: TComponent); override;
386     destructor Destroy; override;
387     {Use inherited Execute method to perform backup}
388     published
389     { a name=value pair of filename and length }
390     property BackupFiles: TStrings read FBackupFiles write SetBackupFile;
391     property StatisticsRequested;
392     property Verbose;
393     end;
394    
395     TRestoreOption = (DeactivateIndexes, NoShadow, NoValidityCheck, OneRelationAtATime,
396     Replace, CreateNewDB, UseAllSpace, RestoreMetaDataOnly);
397    
398     TRestoreOptions = set of TRestoreOption;
399    
400     { TIBXRestoreService }
401    
402     TIBXRestoreService = class (TIBXBackupRestoreService)
403     private
404     FDatabaseFiles: TStrings;
405     FOptions: TRestoreOptions;
406     FPageSize: Integer;
407     FPageBuffers: Integer;
408     procedure SetDatabaseFiles(const Value: TStrings);
409     protected
410     procedure DatabaseNameChanged; override;
411     procedure SetServiceStartOptions; override;
412     procedure SetArchiveSource; virtual; abstract;
413     public
414     constructor Create(AOwner: TComponent); override;
415     destructor Destroy; override;
416     published
417     { a name=value pair of filename and length }
418     property DatabaseFiles: TStrings read FDatabaseFiles write SetDatabaseFiles;
419     property PageSize: Integer read FPageSize write FPageSize;
420     property PageBuffers: Integer read FPageBuffers write FPageBuffers;
421     property Options : TRestoreOptions read FOptions write FOptions default [CreateNewDB];
422     property StatisticsRequested;
423     property Verbose;
424     end;
425    
426     { TIBXClientSideRestoreService }
427    
428     TIBXClientSideRestoreService = class(TIBXRestoreService)
429     protected
430     procedure Execute(OutputLog: TStrings); override;
431     procedure SetArchiveSource; override;
432     public
433     procedure RestoreFromStream(S: TStream; OutputLog: TStrings);
434     procedure RestoreFromFile(aFileName: string; OutputLog: TStrings);
435     procedure RestoreFromFiles(FileList: TStrings; OutputLog: TStrings);
436     end;
437    
438     { TIBXServerSideRestoreService }
439    
440     TIBXServerSideRestoreService = class(TIBXRestoreService)
441     private
442     FBackupFiles: TStrings;
443     procedure SetBackupFiles(const Value: TStrings);
444     protected
445     procedure SetArchiveSource; override;
446     public
447     constructor Create(AOwner: TComponent); override;
448     destructor Destroy; override;
449     {use inherited Execute method to perform restore}
450     published
451     property BackupFiles: TStrings read FBackupFiles write SetBackupFiles;
452     end;
453    
454     { TIBXOnlineValidationService }
455    
456     TIBXOnlineValidationService = class(TIBXControlAndQueryService)
457     private
458     FExcludeIndexes: string;
459     FExcludeTables: string;
460     FIncludeIndexes: string;
461     FIncludeTables: string;
462     FLockTimeout: integer;
463     protected
464     procedure SetServiceStartOptions; override;
465     procedure ServiceStart; override;
466     public
467     constructor Create(AOwner: TComponent); override;
468     published
469     property IncludeTables: string read FIncludeTables write FIncludeTables;
470     property ExcludeTables: string read FExcludeTables write FExcludeTables;
471     property IncludeIndexes: string read FIncludeIndexes write FIncludeIndexes;
472     property ExcludeIndexes: string read FExcludeIndexes write FExcludeIndexes;
473     property LockTimeout: integer read FLockTimeout write FLockTimeout default 10;
474     property DatabaseName;
475     end;
476    
477     TValidateOption = (CheckDB, IgnoreChecksum, KillShadows, MendDB,
478     SweepDB, ValidateDB, ValidateFull);
479     TValidateOptions = set of TValidateOption;
480    
481     { TIBXValidationService }
482    
483     TIBXValidationService = class(TIBXControlAndQueryService)
484     private
485     FOptions: TValidateOptions;
486     protected
487     procedure SetServiceStartOptions; override;
488     public
489     {use inherited Execute method to perform validation}
490     published
491     property DatabaseName;
492     property Options: TValidateOptions read FOptions write FOptions;
493     end;
494    
495     TUserInfo = class
496     public
497     UserName: string;
498     FirstName: string;
499     MiddleName: string;
500     LastName: string;
501     GroupID: Integer;
502     UserID: Integer;
503     AdminRole: boolean;
504     end;
505    
506     TSecurityAction = (ActionAddUser, ActionDeleteUser, ActionModifyUser, ActionDisplayUser);
507     TSecurityModifyParam = (ModifyFirstName, ModifyMiddleName, ModifyLastName, ModifyUserId,
508     ModifyGroupId, ModifyPassword, ModifyAdminRole);
509     TSecurityModifyParams = set of TSecurityModifyParam;
510    
511     { TIBXSecurityService }
512    
513     TIBXSecurityService = class(TIBXControlAndQueryService)
514     private
515     FAdminRole: boolean;
516     FUserID: Integer;
517     FGroupID: Integer;
518     FFirstName: string;
519     FUserName: string;
520     FPassword: string;
521     FSQLRole: string;
522     FLastName: string;
523     FMiddleName: string;
524     FUserInfo: array of TUserInfo;
525     FSecurityAction: TSecurityAction;
526     FModifyParams: TSecurityModifyParams;
527     procedure ClearParams;
528     procedure SetAdminRole(AValue: boolean);
529     procedure SetSecurityAction (Value: TSecurityAction);
530     procedure SetFirstName (Value: String);
531     procedure SetMiddleName (Value: String);
532     procedure SetLastName (Value: String);
533     procedure SetPassword (Value: String);
534     procedure SetUserId (Value: Integer);
535     procedure SetGroupId (Value: Integer);
536    
537     procedure FetchUserInfo;
538     function GetUserInfo(Index: Integer): TUserInfo;
539     function GetUserInfoCount: Integer;
540    
541     protected
542     procedure Execute(OutputLog: TStrings); override;
543     procedure Loaded; override;
544     procedure SetServiceStartOptions; override;
545     property SecurityAction: TSecurityAction read FSecurityAction
546     write SetSecurityAction;
547     public
548     constructor Create(AOwner: TComponent); override;
549     destructor Destroy; override;
550     procedure DisplayUsers;
551     procedure DisplayUser(aUserName: string);
552     procedure AddUser;
553     procedure DeleteUser;
554     procedure ModifyUser;
555     function HasAdminRole: boolean;
556     procedure SetAutoAdmin(Value: Boolean);
557     property UserInfo[Index: Integer]: TUserInfo read GetUserInfo;
558     property UserInfoCount: Integer read GetUserInfoCount;
559    
560     published
561     property SQlRole : string read FSQLRole write FSQLrole;
562     property UserName : string read FUserName write FUserName;
563     property FirstName : string read FFirstName write SetFirstName;
564     property MiddleName : string read FMiddleName write SetMiddleName;
565     property LastName : string read FLastName write SetLastName;
566     property UserID : Integer read FUserID write SetUserID;
567     property GroupID : Integer read FGroupID write SetGroupID;
568     property Password : string read FPassword write setPassword;
569     property AdminRole: boolean read FAdminRole write SetAdminRole;
570     end;
571    
572     TTransactionGlobalAction = (CommitGlobal, RollbackGlobal, RecoverTwoPhaseGlobal,
573     NoGlobalAction);
574     TTransactionState = (LimboState, CommitState, RollbackState, UnknownState);
575     TTransactionAdvise = (CommitAdvise, RollbackAdvise, UnknownAdvise);
576     TTransactionAction = (CommitAction, RollbackAction);
577    
578     TLimboTransactionInfo = class
579     public
580     MultiDatabase: Boolean;
581     ID: Integer;
582     HostSite: String;
583     RemoteSite: String;
584     RemoteDatabasePath: String;
585     State: TTransactionState;
586     Advise: TTransactionAdvise;
587     Action: TTransactionAction;
588     end;
589    
590     { TIBXLimboTransactionResolutionService }
591    
592     TIBXLimboTransactionResolutionService = class(TIBXControlAndQueryService)
593     private
594     FLimboTransactionInfo: array of TLimboTransactionInfo;
595     FGlobalAction: TTransactionGlobalAction;
596     function GetLimboTransactionInfo(index: integer): TLimboTransactionInfo;
597     function GetLimboTransactionInfoCount: integer;
598     function FetchLimboTransactionInfo: integer;
599    
600     protected
601     procedure SetServiceStartOptions; override;
602     public
603     destructor Destroy; override;
604     procedure Clear; override;
605     procedure Execute(OutputLog: TStrings); override;
606     property LimboTransactionInfo[Index: integer]: TLimboTransactionInfo read GetLimboTransactionInfo;
607     property LimboTransactionInfoCount: Integer read GetLimboTransactionInfoCount;
608    
609     published
610     property DatabaseName;
611     property GlobalAction: TTransactionGlobalAction read FGlobalAction
612     write FGlobalAction;
613    
614     end;
615    
616     TRequiredSources = class of TIBXControlAndQueryService;
617    
618     { TIBXServicesDataSet }
619    
620     TIBXServicesDataSet = class(TMemDataSet)
621     private
622     FSource: TIBXControlAndQueryService;
623     procedure SetSource(AValue: TIBXControlAndQueryService);
624     protected
625     FRequiredSource: TRequiredSources;
626     procedure DoBeforeClose; override;
627     procedure Notification( AComponent: TComponent; Operation: TOperation); override;
628     public
629     destructor Destroy; override;
630     published
631     property Source: TIBXControlAndQueryService read FSource write SetSource;
632     end;
633    
634     { TIBXServicesUserList }
635    
636     TIBXServicesUserList = class(TIBXServicesDataSet)
637     private
638     FLoading: boolean;
639     protected
640     procedure DoBeforePost; override;
641     procedure DoAfterInsert; override;
642     procedure DoAfterPost; override;
643     procedure DoAfterOpen; override;
644     procedure InternalDelete; override;
645     public
646     constructor Create(AOwner:TComponent); override;
647     end;
648    
649     { TIBXServicesLimboTransactionsList }
650    
651     TIBXServicesLimboTransactionsList = class(TIBXServicesDataSet)
652     private
653     FLoading: boolean;
654     protected
655     procedure DoBeforeInsert; override;
656     procedure DoAfterOpen; override;
657 tony 210 procedure DoAfterPost; override;
658 tony 209 procedure DoBeforePost; override;
659     public
660     constructor Create(AOwner:TComponent); override;
661     procedure Delete; override;
662     procedure FixErrors(GlobalAction: TTransactionGlobalAction; OutputLog: TStrings);
663     end;
664    
665     implementation
666    
667     uses FBMessages, IBUtils, RegExpr, CustApp, IBErrorCodes;
668    
669     const
670     SPBPrefix = 'isc_spb_';
671     isc_spb_last_spb_constant = 13;
672     SPBConstantNames: array[1..isc_spb_last_spb_constant] of String = (
673     'user_name',
674     'sys_user_name',
675     'sys_user_name_enc',
676     'password',
677     'password_enc',
678     'command_line',
679     'db_name',
680     'verbose',
681     'options',
682     'connect_timeout',
683     'dummy_packet_interval',
684     'sql_role_name',
685     'expected_db'
686     );
687    
688     SPBConstantValues: array[1..isc_spb_last_spb_constant] of Integer = (
689     isc_spb_user_name,
690     isc_spb_sys_user_name,
691     isc_spb_sys_user_name_enc,
692     isc_spb_password,
693     isc_spb_password_enc,
694     isc_spb_command_line,
695     isc_spb_dbname,
696     isc_spb_verbose,
697     isc_spb_options,
698     isc_spb_connect_timeout,
699     isc_spb_dummy_packet_interval,
700     isc_spb_sql_role_name,
701     isc_spb_expected_db
702     );
703    
704     { TIBXClientSideRestoreService }
705    
706     procedure TIBXClientSideRestoreService.Execute(OutputLog: TStrings);
707     begin
708     // Do nothing
709     end;
710    
711     procedure TIBXClientSideRestoreService.SetArchiveSource;
712     begin
713     SRB.Add(isc_spb_bkp_file).AsString := 'stdin';
714     end;
715    
716     procedure TIBXClientSideRestoreService.RestoreFromStream(S: TStream;
717     OutputLog: TStrings);
718     var line: string;
719     begin
720     ServiceStart;
721     try
722     while not Eof do
723     begin
724     SendNextChunk(S,line);
725     if line <> '' then
726     begin
727     DoOnGetNextLine(line);
728     if OutputLog <> nil then
729     OutputLog.Add(line);
730     end;
731     end;
732     finally
733     while IsServiceRunning do; {flush}
734     end;
735     end;
736    
737     procedure TIBXClientSideRestoreService.RestoreFromFile(aFileName: string;
738     OutputLog: TStrings);
739     var F: TFileStream;
740     begin
741     F := TFileStream.Create(aFileName,fmOpenRead);
742     try
743     RestoreFromStream(F,OutputLog)
744     finally
745     F.Free;
746     end;
747     end;
748    
749     procedure TIBXClientSideRestoreService.RestoreFromFiles(FileList: TStrings;
750     OutputLog: TStrings);
751     var i: integer;
752     F: TFileStream;
753     line: string;
754     begin
755     ServiceStart;
756     for i := 0 to FileList.Count - 1 do
757     begin
758     F := TFileStream.Create(FileList[i],fmOpenRead);
759     try
760     while Eof do
761     begin
762     SendNextChunk(F,line);
763     if line <> '' then
764     begin
765     DoOnGetNextLine(line);
766     if OutputLog <> nil then
767     OutputLog.Add(line);
768     end;
769     end;
770     finally
771     F.Free;
772     while IsServiceRunning do; {flush}
773     FEof := false;
774     end;
775     end;
776     end;
777    
778     { TIBXClientSideBackupService }
779    
780     procedure TIBXClientSideBackupService.Execute(OutputLog: TStrings);
781     begin
782     //Do nothing
783     end;
784    
785     procedure TIBXClientSideBackupService.SetBackupTarget;
786     begin
787     SRB.Add(isc_spb_bkp_file).AsString := 'stdout';
788     end;
789    
790     procedure TIBXClientSideBackupService.BackupToStream(S: TStream;
791     var BytesWritten: integer);
792     var InitialSize: integer;
793     begin
794     InitialSize := S.Size;
795     ServiceStart;
796     while not Eof do
797     ReceiveNextChunk(S);
798     BytesWritten := S.Size - InitialSize;
799     end;
800    
801     procedure TIBXClientSideBackupService.BackupToFile(aFileName: string;
802     var BytesWritten: integer);
803     var F: TFileStream;
804     begin
805     F := TFileStream.Create(aFileName,fmCreate);
806     try
807     BackupToStream(F,BytesWritten);
808     finally
809     F.Free;
810     end;
811     end;
812    
813     { TIBXServicesLimboTransactionsList }
814    
815     procedure TIBXServicesLimboTransactionsList.DoBeforeInsert;
816     begin
817     inherited DoBeforeInsert;
818     if not FLoading then
819     IBError(ibxeNoLimboTransactionInsert,[nil]);
820     end;
821    
822     procedure TIBXServicesLimboTransactionsList.DoAfterOpen;
823    
824     function TypeToStr(MultiDatabase: boolean): string;
825     begin
826     if MultiDatabase then
827     Result := 'Multi DB'
828     else
829     Result := 'Single DB';
830     end;
831    
832     function StateToStr(State: TTransactionState): string;
833     begin
834     case State of
835     LimboState:
836     Result := 'Limbo';
837     CommitState:
838     Result := 'Commit';
839     RollbackState:
840     Result := 'Rollback';
841     else
842     Result := 'Unknown';
843     end;
844     end;
845    
846     function AdviseToStr(Advise: TTransactionAdvise): string;
847     begin
848     case Advise of
849     CommitAdvise:
850     Result := 'Commit';
851     RollbackAdvise:
852     Result := 'Rollback';
853     else
854     Result := 'Unknown';
855     end;
856     end;
857    
858     function ActionToStr(anAction: TTransactionAction): string;
859     begin
860     case anAction of
861     CommitAction:
862     Result := 'Commit';
863     RollbackAction:
864     Result := 'Rollback';
865     end;
866     end;
867    
868     var i: integer;
869     begin
870     if FLoading then Exit;
871     FLoading := true;
872     with FSource as TIBXLimboTransactionResolutionService do
873     try
874     for i := 0 to LimboTransactionInfoCount - 1 do
875     with LimboTransactionInfo[i] do
876     begin
877     Append;
878     FieldByName('TransactionID').AsInteger := ID;
879     FieldByName('TransactionType').AsString := TypeToStr(MultiDatabase);
880     FieldByName('HostSite').AsString := HostSite;
881     FieldByName('RemoteSite').AsString := RemoteSite;
882     FieldByName('DatabasePath').AsString := RemoteDatabasePath;
883     FieldByName('State').AsString := StateToStr(State);
884     FieldByName('RecommendedAction').AsString := AdviseToStr(Advise);
885     FieldByName('RequestedAction').AsString := ActionToStr(Action);
886     Post;
887     end;
888     finally
889     FLoading := false;
890     end;
891     inherited DoAfterOpen;
892     end;
893    
894 tony 210 procedure TIBXServicesLimboTransactionsList.DoAfterPost;
895     begin
896     if not FLoading then
897     inherited DoAfterPost;
898     end;
899    
900 tony 209 procedure TIBXServicesLimboTransactionsList.DoBeforePost;
901     var i: integer;
902     begin
903     inherited DoBeforePost;
904     if FLoading then Exit;
905     with FSource as TIBXLimboTransactionResolutionService do
906     for i := 0 to LimboTransactionInfoCount - 1 do
907     with LimboTransactionInfo[i] do
908     begin
909     if ID = FieldByName('TransactionID').AsInteger then
910     begin
911     if FieldByName('RequestedAction').AsString = 'Commit' then
912     Action := CommitAction
913     else
914     if FieldByName('RequestedAction').AsString = 'Rollback' then
915     Action := RollbackAction;
916     break;
917     end;
918     end;
919     end;
920    
921    
922     constructor TIBXServicesLimboTransactionsList.Create(AOwner: TComponent);
923     var i: integer;
924     begin
925     inherited Create(AOwner);
926     FRequiredSource := TIBXLimboTransactionResolutionService;
927     with FieldDefs do
928     if Count = 0 then
929     begin
930     Add('TransactionID',ftInteger);
931     Add('TransactionType',ftString,16);
932     Add('HostSite',ftString,256);
933     Add('RemoteSite',ftString,256);
934     Add('DatabasePath',ftString,256);
935     Add('State',ftString,32);
936     Add('RecommendedAction',ftString,32);
937     Add('RequestedAction',ftString,32);
938     for i := 0 to Count - 2 do
939     Items[i].Attributes := Items[i].Attributes + [faReadOnly];
940     end;
941     end;
942    
943     procedure TIBXServicesLimboTransactionsList.Delete;
944     begin
945     //Do nothing
946     end;
947    
948     procedure TIBXServicesLimboTransactionsList.FixErrors(
949     GlobalAction: TTransactionGlobalAction; OutputLog: TStrings);
950     begin
951     if State = dsEdit then Post;
952     (FSource as TIBXLimboTransactionResolutionService).GlobalAction := GlobalAction;
953     (FSource as TIBXLimboTransactionResolutionService).Execute(OutputLog);
954     Active := false;
955     Active := true;
956     end;
957    
958     { TIBXServicesUserList }
959    
960     procedure TIBXServicesUserList.DoBeforePost;
961     procedure SetParams;
962     begin
963     with FSource as TIBXSecurityService do
964     begin
965     UserID := FieldByName('UserID').AsInteger;
966     GroupID := FieldByName('GroupID').AsInteger;
967     UserName := FieldByName('SEC$USER_NAME').AsString;
968     FirstName := FieldByName('SEC$FIRST_NAME').AsString;
969     MiddleName := FieldByName('SEC$MIDDLE_NAME').AsString;
970     LastName := FieldByName('SEC$LAST_NAME').AsString;
971     if not FieldByName('SEC$PASSWORD').IsNull then
972     Password := FieldByName('SEC$PASSWORD').AsString;
973     AdminRole := FieldByName('SEC$ADMIN').AsBoolean;
974     end;
975     end;
976    
977     begin
978     inherited DoBeforePost;
979     if FLoading then Exit;
980     case State of
981     dsEdit:
982     begin
983     SetParams;
984     (FSource as TIBXSecurityService).ModifyUser;
985     end;
986     dsInsert:
987     begin
988     SetParams;
989     (FSource as TIBXSecurityService).AddUser;
990     end;
991     end;
992     end;
993    
994     procedure TIBXServicesUserList.DoAfterInsert;
995     begin
996     FieldByName('UserID').AsInteger := 0;
997     FieldByName('GroupID').AsInteger := 0;
998     FieldByName('SEC$PASSWORD').Clear;
999     FieldByName('SEC$ADMIN').AsBoolean := false;
1000     inherited DoAfterInsert;
1001     end;
1002    
1003     procedure TIBXServicesUserList.DoAfterPost;
1004     begin
1005     {Refresh}
1006     if not FLoading then
1007     begin
1008 tony 210 inherited DoAfterPost;
1009     with FSource as TIBXSecurityService do
1010 tony 209 begin
1011 tony 210 DisplayUser(FieldByName('SEC$USER_NAME').AsString);
1012     if UserInfoCount > 0 then
1013     with UserInfo[0] do
1014     begin
1015     FieldByName('UserID').AsInteger := UserID;
1016     FieldByName('GroupID').AsInteger := GroupID;
1017     FieldByName('SEC$USER_NAME').AsString := UserName;
1018     FieldByName('SEC$FIRST_NAME').AsString := FirstName;
1019     FieldByName('SEC$MIDDLE_NAME').AsString := MiddleName;
1020     FieldByName('SEC$LAST_NAME').AsString := LastName;
1021     FieldByName('SEC$PASSWORD').Clear;
1022     FieldByName('SEC$ADMIN').AsBoolean := AdminRole;
1023     end;
1024 tony 209 end;
1025     end;
1026     end;
1027    
1028     procedure TIBXServicesUserList.DoAfterOpen;
1029     var i: integer;
1030     Buf: TStringList;
1031     begin
1032     buf := TStringList.Create; {Used to sort user info}
1033     try
1034     with FSource as TIBXSecurityService do
1035     begin
1036     buf.Sorted := true;
1037     DisplayUsers;
1038     FLoading := true;
1039     try
1040     for i := 0 to UserInfoCount - 1 do
1041     buf.AddObject(UserInfo[i].UserName,UserInfo[i]);
1042    
1043     for i := 0 to buf.Count - 1 do
1044     with TUserInfo(buf.Objects[i]) do
1045     begin
1046     Append;
1047     FieldByName('UserID').AsInteger := UserID;
1048     FieldByName('GroupID').AsInteger := GroupID;
1049     FieldByName('SEC$USER_NAME').AsString := UserName;
1050     FieldByName('SEC$FIRST_NAME').AsString := FirstName;
1051     FieldByName('SEC$MIDDLE_NAME').AsString := MiddleName;
1052     FieldByName('SEC$LAST_NAME').AsString := LastName;
1053     FieldByName('SEC$PASSWORD').Clear;
1054     FieldByName('SEC$ADMIN').AsBoolean := AdminRole;
1055     Post;
1056     end;
1057     finally
1058     FLoading := false;
1059     end;
1060     end;
1061     finally
1062     Buf.Free;
1063     end;
1064     inherited DoAfterOpen;
1065     end;
1066    
1067     procedure TIBXServicesUserList.InternalDelete;
1068     begin
1069     with FSource as TIBXSecurityService do
1070     begin
1071     UserName := FieldByName('SEC$USER_NAME').AsString;
1072     DeleteUser;
1073     end;
1074     inherited InternalDelete;
1075     end;
1076    
1077     constructor TIBXServicesUserList.Create(AOwner: TComponent);
1078     begin
1079     inherited Create(AOwner);
1080     FRequiredSource := TIBXSecurityService;
1081     with FieldDefs do
1082     if Count = 0 then
1083     begin
1084     Add('UserID',ftInteger);
1085     Add('GroupID',ftInteger);
1086     Add('SEC$USER_NAME',ftString,31);
1087     Add('SEC$FIRST_NAME',ftString,32);
1088     Add('SEC$MIDDLE_NAME',ftString,32);
1089     Add('SEC$LAST_NAME',ftString,32);
1090     Add('SEC$PASSWORD',ftString,32);
1091     Add('SEC$ADMIN',ftBoolean);
1092     end;
1093     end;
1094    
1095     { TIBXServicesDataSet }
1096    
1097     procedure TIBXServicesDataSet.SetSource(AValue: TIBXControlAndQueryService);
1098     begin
1099     if FSource = AValue then Exit;
1100     if (AValue <> nil) and not (AValue is FRequiredSource) then
1101     IBError(ibxeNotRequiredDataSetSource,[AValue.ClassName]);
1102     if FSource <> nil then
1103     begin
1104     FSource.UnRegisterDataSet(self);
1105     RemoveFreeNotification(FSource);
1106     end;
1107     FSource := AValue;
1108     if FSource <> nil then
1109     begin
1110     FSource.RegisterDataSet(self);
1111     FreeNotification(FSource);
1112     end;
1113     end;
1114    
1115     procedure TIBXServicesDataSet.DoBeforeClose;
1116     begin
1117     if csDestroying in ComponentState then Exit;
1118     if State in [dsEdit,dsInsert] then Post;
1119     Clear(false);
1120     inherited DoBeforeClose;
1121     end;
1122    
1123     procedure TIBXServicesDataSet.Notification(AComponent: TComponent;
1124     Operation: TOperation);
1125     begin
1126     inherited Notification(AComponent, Operation);
1127     if (Operation = opRemove) and (AComponent = FSource) then
1128     FSource := nil;
1129     end;
1130    
1131     destructor TIBXServicesDataSet.Destroy;
1132     begin
1133     Source := nil;
1134     inherited Destroy;
1135     end;
1136    
1137     { TIBXLimboTransactionResolutionService }
1138    
1139     function TIBXLimboTransactionResolutionService.GetLimboTransactionInfo(
1140     index: integer): TLimboTransactionInfo;
1141     begin
1142     if index < GetLimboTransactionInfoCount then
1143     Result := FLimboTransactionInfo[index]
1144     else
1145     Result := nil;
1146     end;
1147    
1148     function TIBXLimboTransactionResolutionService.GetLimboTransactionInfoCount: integer;
1149     begin
1150     Result := Length(FLimboTransactionInfo);
1151     if Result = 0 then
1152     Result := FetchLimboTransactionInfo;
1153     end;
1154    
1155     procedure TIBXLimboTransactionResolutionService.SetServiceStartOptions;
1156     var i: integer;
1157     begin
1158     SRB.Add(isc_action_svc_repair);
1159     AddDBNameToSRB;
1160     if Length(FLimboTransactionInfo) = 0 then
1161     SRB.Add(isc_spb_options).AsInteger := isc_spb_rpr_list_limbo_trans
1162     else
1163     {Fixing existing transactions}
1164     begin
1165     case FGlobalAction of
1166     NoGlobalAction:
1167     begin
1168     for i := 0 to LimboTransactionInfoCount - 1 do
1169     begin
1170     if (FLimboTransactionInfo[i].Action = CommitAction) then
1171     SRB.Add(isc_spb_rpr_commit_trans).AsInteger := FLimboTransactionInfo[i].ID
1172     else
1173     SRB.Add(isc_spb_rpr_rollback_trans).AsInteger := FLimboTransactionInfo[i].ID;
1174     end;
1175     end;
1176    
1177     CommitGlobal:
1178     begin
1179     for i := 0 to LimboTransactionInfoCount - 1 do
1180     SRB.Add(isc_spb_rpr_commit_trans).AsInteger := FLimboTransactionInfo[i].ID;
1181     end;
1182    
1183     RollbackGlobal:
1184     begin
1185     for i := 0 to LimboTransactionInfoCount - 1 do
1186     SRB.Add(isc_spb_rpr_rollback_trans).AsInteger := FLimboTransactionInfo[i].ID;
1187     end;
1188    
1189     RecoverTwoPhaseGlobal:
1190     begin
1191     for i := 0 to LimboTransactionInfoCount - 1 do
1192     SRB.Add(isc_spb_rpr_recover_two_phase).AsInteger := FLimboTransactionInfo[i].ID;
1193     end;
1194     end;
1195     end;
1196     end;
1197    
1198     destructor TIBXLimboTransactionResolutionService.Destroy;
1199     begin
1200     Clear;
1201     inherited Destroy;
1202     end;
1203    
1204     procedure TIBXLimboTransactionResolutionService.Clear;
1205     var
1206     i : Integer;
1207     begin
1208     for i := 0 to High(FLimboTransactionInfo) do
1209     FLimboTransactionInfo[i].Free;
1210     SetLength(FLimboTransactionInfo,0);
1211     end;
1212    
1213    
1214     function TIBXLimboTransactionResolutionService.FetchLimboTransactionInfo: integer;
1215    
1216     procedure NextLimboTransaction(index: integer);
1217     begin
1218     SetLength(FLimboTransactionInfo, index+1);
1219     FLimboTransactionInfo[index] := TLimboTransactionInfo.Create;
1220     { if no advice commit as default }
1221     FLimboTransactionInfo[index].Advise := UnknownAdvise;
1222     FLimboTransactionInfo[index].Action:= CommitAction;
1223     end;
1224    
1225     var
1226     i,j, k: Integer;
1227     begin
1228     Clear;
1229     Result := 0;
1230     ServiceStart;
1231     SRB.Add(isc_info_svc_limbo_trans);
1232     InternalServiceQuery;
1233    
1234     k := -1;
1235     for i := 0 to FServiceQueryResults.Count - 1 do
1236     with FServiceQueryResults[i] do
1237     case getItemType of
1238     isc_info_svc_limbo_trans:
1239     begin
1240     if FServiceQueryResults[i].Count = 0 then continue;
1241     NextLimboTransaction(0);
1242     for j := 0 to FServiceQueryResults[i].Count - 1 do
1243     begin
1244     with FServiceQueryResults[i][j] do
1245     begin
1246     case getItemType of
1247     isc_spb_single_tra_id:
1248     begin
1249     Inc(k);
1250     if k > 0 then
1251     NextLimboTransaction(k);
1252     FLimboTransactionInfo[k].MultiDatabase := False;
1253     FLimboTransactionInfo[k].ID := AsInteger;
1254     end;
1255    
1256     isc_spb_multi_tra_id:
1257     begin
1258     Inc(k);
1259     if k > 0 then
1260     NextLimboTransaction(k);
1261     FLimboTransactionInfo[k].MultiDatabase := True;
1262     FLimboTransactionInfo[k].ID := AsInteger;
1263     end;
1264    
1265     isc_spb_tra_host_site:
1266     FLimboTransactionInfo[k].HostSite := AsString;
1267    
1268     isc_spb_tra_state:
1269     case AsByte of
1270     isc_spb_tra_state_limbo:
1271     FLimboTransactionInfo[k].State := LimboState;
1272    
1273     isc_spb_tra_state_commit:
1274     FLimboTransactionInfo[k].State := CommitState;
1275    
1276     isc_spb_tra_state_rollback:
1277     FLimboTransactionInfo[k].State := RollbackState;
1278    
1279     else
1280     FLimboTransactionInfo[k].State := UnknownState;
1281     end;
1282    
1283     isc_spb_tra_remote_site:
1284     FLimboTransactionInfo[k].RemoteSite := AsString;
1285    
1286     isc_spb_tra_db_path:
1287     FLimboTransactionInfo[k].RemoteDatabasePath := AsString;
1288    
1289     isc_spb_tra_advise:
1290     with FLimboTransactionInfo[k] do
1291     begin
1292     case (AsByte) of
1293     isc_spb_tra_advise_commit:
1294     begin
1295     Advise := CommitAdvise;
1296     Action:= CommitAction;
1297     end;
1298    
1299     isc_spb_tra_advise_rollback:
1300     begin
1301     Advise := RollbackAdvise;
1302     Action := RollbackAction;
1303     end;
1304    
1305     else
1306     Advise := UnknownAdvise;
1307     end;
1308     end;
1309    
1310     else
1311     IBError(ibxeOutputParsingError, [getItemType]);
1312     end;
1313     end;
1314     end;
1315     end;
1316     else
1317     IBError(ibxeOutputParsingError, [getItemType]);
1318     end;
1319     Result := Length(FLimboTransactionInfo);
1320     end;
1321    
1322     procedure TIBXLimboTransactionResolutionService.Execute(OutputLog: TStrings);
1323     begin
1324     if Length(FLimboTransactionInfo) > 0 then
1325     begin
1326     ServiceStart; {Fix is implicit in non-zero list of Limbo transactions}
1327     while not Eof do
1328     OutputLog.Add(GetNextLine);
1329     while IsServiceRunning do;
1330     Clear;
1331     end;
1332     end;
1333    
1334     { TIBXSecurityService }
1335    
1336     constructor TIBXSecurityService.Create(AOwner: TComponent);
1337     begin
1338     inherited Create(AOwner);
1339     FModifyParams := [];
1340     end;
1341    
1342     destructor TIBXSecurityService.Destroy;
1343     var
1344     i : Integer;
1345     begin
1346     for i := 0 to High(FUserInfo) do
1347     FUserInfo[i].Free;
1348     FUserInfo := nil;
1349     inherited Destroy;
1350     end;
1351    
1352     procedure TIBXSecurityService.Execute(OutputLog: TStrings);
1353     begin
1354     //Do nothing
1355     end;
1356    
1357     procedure TIBXSecurityService.FetchUserInfo;
1358     var
1359     i, j, k: Integer;
1360     begin
1361     SRB.Add(isc_info_svc_get_users);
1362     InternalServiceQuery;
1363    
1364     for i := 0 to High(FUserInfo) do
1365     FUserInfo[i].Free;
1366     for i := 0 to FServiceQueryResults.Count - 1 do
1367     with FServiceQueryResults[i] do
1368     begin
1369     case getItemType of
1370     isc_info_svc_get_users:
1371     begin
1372     SetLength(FUserInfo,1);
1373     k := 0;
1374     FUserInfo[0] := TUserInfo.Create;
1375     FUserInfo[0].UserName := '';
1376     for j := 0 to FServiceQueryResults[i].Count - 1 do
1377     begin
1378     with FServiceQueryResults[i][j] do
1379     case getItemType of
1380     isc_spb_sec_username:
1381     begin
1382     if FUserInfo[k].UserName <> '' then
1383     begin
1384     Inc(k);
1385     SetLength(FUserInfo,k+1);
1386     if FUserInfo[k] = nil then
1387     FUserInfo[k] := TUserInfo.Create;
1388     end;
1389     FUserInfo[k].UserName := AsString;
1390     end;
1391    
1392     isc_spb_sec_firstname:
1393     FUserInfo[k].FirstName := AsString;
1394    
1395     isc_spb_sec_middlename:
1396     FUserInfo[k].MiddleName := AsString;
1397    
1398     isc_spb_sec_lastname:
1399     FUserInfo[k].LastName := AsString;
1400    
1401     isc_spb_sec_userId:
1402     FUserInfo[k].UserId := AsInteger;
1403    
1404     isc_spb_sec_groupid:
1405     FUserInfo[k].GroupID := AsInteger;
1406    
1407     isc_spb_sec_admin:
1408     FUserInfo[k].AdminRole := AsInteger <> 0;
1409    
1410     else
1411     IBError(ibxeOutputParsingError, [getItemType]);
1412     end;
1413     end;
1414     end;
1415     else
1416     IBError(ibxeOutputParsingError, [getItemType]);
1417     end;
1418     end;
1419     end;
1420    
1421     function TIBXSecurityService.GetUserInfo(Index: Integer): TUserInfo;
1422     begin
1423     if Index <= High(FUSerInfo) then
1424     result := FUserInfo[Index]
1425     else
1426     result := nil;
1427     end;
1428    
1429     function TIBXSecurityService.GetUserInfoCount: Integer;
1430     begin
1431     Result := Length(FUserInfo);
1432     end;
1433    
1434     procedure TIBXSecurityService.AddUser;
1435     begin
1436     SecurityAction := ActionAddUser;
1437     ServiceStart;
1438     while IsServiceRunning do;
1439     end;
1440    
1441     procedure TIBXSecurityService.DeleteUser;
1442     begin
1443     SecurityAction := ActionDeleteUser;
1444     ServiceStart;
1445     while IsServiceRunning do;
1446     end;
1447    
1448     procedure TIBXSecurityService.DisplayUsers;
1449     begin
1450     SecurityAction := ActionDisplayUser;
1451     ClearParams;
1452     FUserName := '';
1453     ServiceStart;
1454     FetchUserInfo;
1455     end;
1456    
1457     procedure TIBXSecurityService.DisplayUser(aUserName: string);
1458     begin
1459     SecurityAction := ActionDisplayUser;
1460     ClearParams;
1461     FUserName := aUserName;
1462     ServiceStart;
1463     FetchUserInfo;
1464     end;
1465    
1466     procedure TIBXSecurityService.ModifyUser;
1467     begin
1468     SecurityAction := ActionModifyUser;
1469     ServiceStart;
1470     while IsServiceRunning do;
1471     end;
1472    
1473     function TIBXSecurityService.HasAdminRole: boolean;
1474     begin
1475     CheckActive;
1476     with ServicesConnection do
1477     Result := (ServerVersionNo[1] > 2) or
1478     ((ServerVersionNo[1] = 2) and (ServerVersionNo[2] = 5));
1479     end;
1480    
1481     procedure TIBXSecurityService.SetAutoAdmin(Value: Boolean);
1482     begin
1483     CheckActive;
1484     {only available for Firebird 2.5 and later}
1485     with ServicesConnection do
1486     if (ServerVersionNo[1] < 2) or
1487     ((ServerVersionNo[1] = 2) and (ServerVersionNo[2] < 5)) then Exit;
1488     if Value then
1489     SRB.Add(isc_action_svc_set_mapping)
1490     else
1491     SRB.Add(isc_action_svc_drop_mapping);
1492     InternalServiceStart;
1493     while IsServiceRunning do;
1494     end;
1495    
1496     procedure TIBXSecurityService.SetSecurityAction (Value: TSecurityAction);
1497     begin
1498     FSecurityAction := Value;
1499     if Value = ActionDeleteUser then
1500     ClearParams;
1501     end;
1502    
1503     procedure TIBXSecurityService.ClearParams;
1504     begin
1505     FModifyParams := [];
1506     FFirstName := '';
1507     FMiddleName := '';
1508     FLastName := '';
1509     FGroupID := 0;
1510     FUserID := 0;
1511     FPassword := '';
1512     end;
1513    
1514     procedure TIBXSecurityService.SetAdminRole(AValue: boolean);
1515     begin
1516     FAdminRole := AValue;
1517     Include (FModifyParams, ModifyAdminRole);
1518     end;
1519    
1520     procedure TIBXSecurityService.SetFirstName (Value: String);
1521     begin
1522     FFirstName := Value;
1523     Include (FModifyParams, ModifyFirstName);
1524     end;
1525    
1526     procedure TIBXSecurityService.SetMiddleName (Value: String);
1527     begin
1528     FMiddleName := Value;
1529     Include (FModifyParams, ModifyMiddleName);
1530     end;
1531    
1532     procedure TIBXSecurityService.SetLastName (Value: String);
1533     begin
1534     FLastName := Value;
1535     Include (FModifyParams, ModifyLastName);
1536     end;
1537    
1538     procedure TIBXSecurityService.SetPassword (Value: String);
1539     begin
1540     FPassword := Value;
1541     Include (FModifyParams, ModifyPassword);
1542     end;
1543    
1544     procedure TIBXSecurityService.SetUserId (Value: Integer);
1545     begin
1546     FUserId := Value;
1547     Include (FModifyParams, ModifyUserId);
1548     end;
1549    
1550     procedure TIBXSecurityService.SetGroupId (Value: Integer);
1551     begin
1552     FGroupId := Value;
1553     Include (FModifyParams, ModifyGroupId);
1554     end;
1555    
1556     procedure TIBXSecurityService.Loaded;
1557     begin
1558     inherited Loaded;
1559     ClearParams;
1560     end;
1561    
1562     procedure TIBXSecurityService.SetServiceStartOptions;
1563     var
1564     Len: UShort;
1565    
1566     begin
1567     case FSecurityAction of
1568     ActionDisplayUser:
1569     begin
1570     if HasAdminRole then
1571     SRB.Add(isc_action_svc_display_user_adm) {Firebird 2.5 and later only}
1572     else
1573     SRB.Add(isc_action_svc_display_user);
1574     if UserName <> '' then
1575     SRB.Add(isc_spb_sec_username).AsString := UserName;
1576     end;
1577    
1578     ActionAddUser:
1579     begin
1580     if ( Pos(' ', FUserName) > 0 ) then
1581     IBError(ibxeStartParamsError, [nil]);
1582     Len := Length(FUserName);
1583     if (Len = 0) then
1584     IBError(ibxeStartParamsError, [nil]);
1585     SRB.Add(isc_action_svc_add_user);
1586     SRB.Add(isc_spb_sec_username).AsString := FUserName;
1587     if FSQLRole <> '' then
1588     SRB.Add(isc_spb_sql_role_name).AsString := FSQLRole;
1589     SRB.Add(isc_spb_sec_userid).AsInteger := FUserID;
1590     SRB.Add(isc_spb_sec_groupid).AsInteger := FGroupID;
1591     SRB.Add(isc_spb_sec_password).AsString := FPassword;
1592     SRB.Add(isc_spb_sec_firstname).AsString := FFirstName;
1593     SRB.Add(isc_spb_sec_middlename).AsString := FMiddleName;
1594     SRB.Add(isc_spb_sec_lastname).AsString := FLastName;
1595     if HasAdminRole then
1596     SRB.Add(isc_spb_sec_admin).AsInteger := ord(FAdminRole);
1597     end;
1598    
1599     ActionDeleteUser:
1600     begin
1601     Len := Length(FUserName);
1602     if (Len = 0) then
1603     IBError(ibxeStartParamsError, [nil]);
1604     SRB.Add(isc_action_svc_delete_user);
1605     SRB.Add(isc_spb_sec_username).AsString := FUserName;
1606     if FSQLRole <> '' then
1607     SRB.Add(isc_spb_sql_role_name).AsString := FSQLRole;
1608     end;
1609    
1610     ActionModifyUser:
1611     begin
1612     Len := Length(FUserName);
1613     if (Len = 0) then
1614     IBError(ibxeStartParamsError, [nil]);
1615     SRB.Add(isc_action_svc_modify_user);
1616     SRB.Add(isc_spb_sec_username).AsString := FUserName;
1617     if FSQLRole <> '' then
1618     SRB.Add(isc_spb_sql_role_name).AsString := FSQLRole;
1619     if (ModifyUserId in FModifyParams) then
1620     SRB.Add(isc_spb_sec_userid).AsInteger := FUserID;
1621     if (ModifyGroupId in FModifyParams) then
1622     SRB.Add(isc_spb_sec_groupid).AsInteger := FGroupID;
1623     if (ModifyPassword in FModifyParams) then
1624     SRB.Add(isc_spb_sec_password).AsString := FPassword;
1625     if (ModifyFirstName in FModifyParams) then
1626     SRB.Add(isc_spb_sec_firstname).AsString := FFirstName;
1627     if (ModifyMiddleName in FModifyParams) then
1628     SRB.Add(isc_spb_sec_middlename).AsString := FMiddleName;
1629     if (ModifyLastName in FModifyParams) then
1630     SRB.Add(isc_spb_sec_lastname).AsString := FLastName;
1631     if (ModifyAdminRole in FModifyParams) and HasAdminRole then
1632     begin
1633     if FAdminRole then
1634     SRB.Add(isc_spb_sec_admin).AsInteger := 1
1635     else
1636     SRB.Add(isc_spb_sec_admin).AsInteger := 0;
1637     end;
1638     end;
1639     end;
1640     ClearParams;
1641     end;
1642    
1643    
1644     { TIBXValidationService }
1645    
1646     procedure TIBXValidationService.SetServiceStartOptions;
1647     var
1648     param: Integer;
1649     begin
1650     SRB.Add(isc_action_svc_repair);
1651     AddDBNAmeToSRB;
1652    
1653     param := 0;
1654     if (SweepDB in Options) then
1655     param := param or isc_spb_rpr_sweep_db;
1656     if (ValidateDB in Options) then
1657     param := param or isc_spb_rpr_validate_db;
1658    
1659     if (CheckDB in Options) then
1660     param := param or isc_spb_rpr_check_db;
1661     if (IgnoreChecksum in Options) then
1662     param := param or isc_spb_rpr_ignore_checksum;
1663     if (KillShadows in Options) then
1664     param := param or isc_spb_rpr_kill_shadows;
1665     if (MendDB in Options) then
1666     param := param or isc_spb_rpr_mend_db;
1667     if (ValidateFull in Options) then
1668     begin
1669     param := param or isc_spb_rpr_full;
1670     if not (MendDB in Options) then
1671     param := param or isc_spb_rpr_validate_db;
1672     end;
1673     if param > 0 then
1674     SRB.Add(isc_spb_options).AsInteger := param;
1675     end;
1676    
1677     { TIBXOnlineValidationService }
1678    
1679     procedure TIBXOnlineValidationService.SetServiceStartOptions;
1680     begin
1681     SRB.Add(isc_action_svc_validate);
1682     AddDBNameToSRB;
1683     if IncludeTables <> '' then
1684     SRB.Add(isc_spb_val_tab_incl).AsString := IncludeTables;
1685     if ExcludeTables <> '' then
1686     SRB.Add(isc_spb_val_tab_excl).AsString := ExcludeTables;
1687     if IncludeIndexes <> '' then
1688     SRB.Add(isc_spb_val_idx_incl).AsString := IncludeIndexes;
1689     if ExcludeIndexes <> '' then
1690     SRB.Add(isc_spb_val_idx_excl).AsString := ExcludeIndexes;
1691     if LockTimeout <> 0 then
1692     SRB.Add(isc_spb_val_lock_timeout).AsInteger := LockTimeout;
1693     end;
1694    
1695     constructor TIBXOnlineValidationService.Create(AOwner: TComponent);
1696     begin
1697     inherited Create(AOwner);
1698     FLockTimeout := 10;
1699     end;
1700    
1701     procedure TIBXOnlineValidationService.ServiceStart;
1702     begin
1703     CheckActive;
1704     {Firebird 2.5 and later}
1705     with ServicesConnection do
1706     if (ServerVersionNo[1] < 2) or
1707     ((ServerVersionNo[1] = 2) and (ServerVersionNo[2] < 5)) then
1708     IBError(ibxeServiceUnavailable,[]);
1709     inherited ServiceStart;
1710     end;
1711    
1712     { TIBXServerSideRestoreService }
1713    
1714     procedure TIBXServerSideRestoreService.SetBackupFiles(const Value: TStrings);
1715     begin
1716     FBackupFiles.Assign(Value);
1717     end;
1718    
1719     procedure TIBXServerSideRestoreService.SetArchiveSource;
1720     var i: integer;
1721     begin
1722     for i := 0 to FBackupFiles.Count - 1 do
1723     begin
1724     if (Trim(FBackupFiles[i]) = '') then continue;
1725     if (Pos('=', FBackupFiles[i]) <> 0) then {mbcs ok}
1726     begin
1727     SRB.Add(isc_spb_bkp_file).AsString := FBackupFiles.Names[i];
1728     SRB.Add(isc_spb_bkp_length).AsInteger := StrToInt(FBackupFiles.ValueFromIndex[i]);
1729     end
1730     else
1731     SRB.Add(isc_spb_bkp_file).AsString := FBackupFiles[i];
1732     end
1733     end;
1734    
1735     constructor TIBXServerSideRestoreService.Create(AOwner: TComponent);
1736     begin
1737     inherited Create(AOwner);
1738     FBackupFiles := TStringList.Create;
1739     end;
1740    
1741     destructor TIBXServerSideRestoreService.Destroy;
1742     begin
1743     if assigned(FBackupFiles) then FBackupFiles.Free;
1744     inherited Destroy;
1745     end;
1746    
1747     { TIBXRestoreService }
1748    
1749     procedure TIBXRestoreService.SetDatabaseFiles(const Value: TStrings);
1750     begin
1751     FDatabaseFiles.Assign(Value);
1752     end;
1753    
1754     procedure TIBXRestoreService.DatabaseNameChanged;
1755     begin
1756     inherited DatabaseNameChanged;
1757     DatabaseFiles.Clear;
1758     DatabaseFiles.Add(DatabaseName);
1759     end;
1760    
1761     procedure TIBXRestoreService.SetServiceStartOptions;
1762     var
1763     param: Integer;
1764     i: integer;
1765     begin
1766     SRB.Add(isc_action_svc_restore);
1767     inherited SetServiceStartOptions;
1768    
1769     param := 0;
1770     if (DeactivateIndexes in Options) then
1771     param := param or isc_spb_res_deactivate_idx;
1772     if (NoShadow in Options) then
1773     param := param or isc_spb_res_no_shadow;
1774     if (NoValidityCheck in Options) then
1775     param := param or isc_spb_res_no_validity;
1776     if (OneRelationAtATime in Options) then
1777     param := param or isc_spb_res_one_at_a_time;
1778     if (Replace in Options) then
1779     param := param or isc_spb_res_replace;
1780     if (CreateNewDB in Options) then
1781     param := param or isc_spb_res_create;
1782     if (UseAllSpace in Options) then
1783     param := param or isc_spb_res_use_all_space;
1784     if (RestoreMetaDataOnly in Options) then
1785     param := param or isc_spb_res_metadata_only;
1786     SRB.Add(isc_spb_options).AsInteger := param;
1787    
1788     if FPageSize > 0 then
1789     SRB.Add(isc_spb_res_page_size).AsInteger := FPageSize;
1790     if FPageBuffers > 0 then
1791     SRB.Add(isc_spb_res_buffers).AsInteger := FPageBuffers;
1792    
1793     SetArchiveSource;
1794    
1795     if FDatabaseFiles.Count > 0 then
1796     FDatabaseName := FDatabaseFiles[0]; {needed if an isc_sec_context error}
1797     for i := 0 to FDatabaseFiles.Count - 1 do
1798     begin
1799     if (Trim(FDatabaseFiles[i]) = '') then continue;
1800     if (Pos('=', FDatabaseFiles[i]) <> 0) then {mbcs ok}
1801     begin
1802     SRB.Add(isc_spb_dbname).AsString := FDatabaseFiles.Names[i];
1803     SRB.Add(isc_spb_res_length).AsInteger := StrToInt(FDatabaseFiles.ValueFromIndex[i]);
1804     end
1805     else
1806     SRB.Add(isc_spb_dbname).AsString := FDatabaseFiles[i];
1807     end;
1808     end;
1809    
1810     constructor TIBXRestoreService.Create(AOwner: TComponent);
1811     begin
1812     inherited Create(AOwner);
1813     FDatabaseFiles := TStringList.Create;
1814     Include (FOptions, CreateNewDB);
1815     end;
1816    
1817     destructor TIBXRestoreService.Destroy;
1818     begin
1819     if FDatabaseFiles <> nil then FDatabaseFiles.Free;
1820     inherited Destroy;
1821     end;
1822    
1823     { TIBXServerSideBackupService }
1824    
1825     procedure TIBXServerSideBackupService.SetBackupFile(const Value: TStrings);
1826     begin
1827     FBackupFiles.Assign(Value);
1828     end;
1829    
1830     procedure TIBXServerSideBackupService.SetBackupTarget;
1831     var i: integer;
1832     begin
1833     for i := 0 to FBackupFiles.Count - 1 do
1834     begin
1835     if (Trim(FBackupFiles[i]) = '') then
1836     continue;
1837     if (Pos('=', FBackupFiles[i]) <> 0) then
1838     begin {mbcs ok}
1839     SRB.Add(isc_spb_bkp_file).AsString := FBackupFiles.Names[i];
1840     SRB.Add(isc_spb_bkp_length).AsInteger := StrToInt(FBackupFiles.ValueFromIndex[i]);
1841     end
1842     else
1843     SRB.Add(isc_spb_bkp_file).AsString := FBackupFiles[i];
1844     end;
1845     end;
1846    
1847     constructor TIBXServerSideBackupService.Create(AOwner: TComponent);
1848     begin
1849     inherited Create(AOwner);
1850     FBackupFiles := TStringList.Create;
1851     end;
1852    
1853     destructor TIBXServerSideBackupService.Destroy;
1854     begin
1855     if assigned(FBackupFiles) then FBackupFiles.Free;
1856     inherited Destroy;
1857     end;
1858    
1859     { TIBXBackupService }
1860    
1861     procedure TIBXBackupService.SetServiceStartOptions;
1862     var
1863     param: Integer;
1864     begin
1865     SRB.Add(isc_action_svc_backup);
1866     AddDBNameToSRB;
1867     inherited SetServiceStartOptions;
1868    
1869     param := 0;
1870     if (IgnoreChecksums in Options) then
1871     param := param or isc_spb_bkp_ignore_checksums;
1872     if (IgnoreLimbo in Options) then
1873     param := param or isc_spb_bkp_ignore_limbo;
1874     if (MetadataOnly in Options) then
1875     param := param or isc_spb_bkp_metadata_only;
1876     if (NoGarbageCollection in Options) then
1877     param := param or isc_spb_bkp_no_garbage_collect;
1878     if (OldMetadataDesc in Options) then
1879     param := param or isc_spb_bkp_old_descriptions;
1880     if (NonTransportable in Options) then
1881     param := param or isc_spb_bkp_non_transportable;
1882     if (ConvertExtTables in Options) then
1883     param := param or isc_spb_bkp_convert;
1884     {Firebird 2.5 and later}
1885     with ServicesConnection do
1886     if (ServerVersionNo[1] > 2) or
1887     ((ServerVersionNo[1] = 2) and (ServerVersionNo[2] = 5)) then
1888     begin
1889     if (NoDBTriggers in Options) then
1890     param := param or isc_spb_bkp_no_triggers;
1891     end;
1892     SRB.Add(isc_spb_options).AsInteger := param;
1893    
1894     if FBlockingFactor > 0 then
1895     SRB.Add(isc_spb_bkp_factor).AsInteger := FBlockingFactor;
1896     SetBackupTarget;
1897     end;
1898    
1899     { TIBXBackupRestoreService }
1900    
1901     procedure TIBXBackupRestoreService.SetServiceStartOptions;
1902     var options: string;
1903     begin
1904     if Verbose then
1905     SRB.Add(isc_spb_verbose);
1906    
1907     with ServicesConnection do
1908     {Firebird 2.5.5 and later}
1909     if (ServerVersionNo[1] < 2) or
1910     ((ServerVersionNo[1] = 2) and ((ServerVersionNo[2] < 5) or
1911     ((ServerVersionNo[2] = 5) and (ServerVersionNo[3] < 5)))) then Exit;
1912    
1913     if StatisticsRequested <> [] then
1914     begin
1915     options := '';
1916     if bsTotalTime in StatisticsRequested then
1917     options += 'T';
1918     if bsTimeDelta in StatisticsRequested then
1919     options += 'D';
1920     if bsPageReads in StatisticsRequested then
1921     options += 'R';
1922     if bsPageWrites in StatisticsRequested then
1923     options += 'W';
1924     SRB.Add(isc_spb_bkp_stat).AsString := options;
1925     end;
1926     end;
1927    
1928    
1929     { TIBXStatisticalService }
1930    
1931     procedure TIBXStatisticalService.SetServiceStartOptions;
1932     var param: integer;
1933     begin
1934     SRB.Add(isc_action_svc_db_stats);
1935     AddDBNameToSRB;
1936    
1937     param := 0;
1938     if (DataPages in Options) then
1939     param := param or isc_spb_sts_data_pages;
1940     if (HeaderPages in Options) then
1941     param := param or isc_spb_sts_hdr_pages;
1942     if (IndexPages in Options) then
1943     param := param or isc_spb_sts_idx_pages;
1944     if (SystemRelations in Options) then
1945     param := param or isc_spb_sts_sys_relations;
1946     SRB.Add(isc_spb_options).AsInteger := param;
1947     end;
1948    
1949     { TIBXConfigService }
1950    
1951     procedure TIBXConfigService.ShutdownDatabase(Options: TDBShutdownMode;
1952     Wait: Integer);
1953     begin
1954     SRB.Add(isc_action_svc_properties);
1955     AddDBNameToSRB;
1956     if (Options = Forced) then
1957     SRB.Add(isc_spb_prp_shutdown_db).AsInteger := Wait
1958     else if (Options = DenyTransaction) then
1959     SRB.Add(isc_spb_prp_deny_new_transactions).AsInteger := Wait
1960     else
1961     SRB.Add(isc_spb_prp_deny_new_attachments).AsInteger := Wait;
1962     InternalServiceStart;
1963     while IsServiceRunning do;
1964     end;
1965    
1966     procedure TIBXConfigService.SetSweepInterval(Value: Integer);
1967     begin
1968     CheckActive;
1969     SRB.Add(isc_action_svc_properties);
1970     AddDBNameToSRB;
1971     SRB.Add(isc_spb_prp_sweep_interval).AsInteger := Value;
1972     InternalServiceStart;
1973     while IsServiceRunning do;
1974     end;
1975    
1976     procedure TIBXConfigService.SetDBSqlDialect(Value: Integer);
1977     begin
1978     SRB.Add(isc_action_svc_properties);
1979     AddDBNameToSRB;
1980     SRB.Add(isc_spb_prp_set_sql_dialect).AsInteger := Value;
1981     InternalServiceStart;
1982     while IsServiceRunning do;
1983     end;
1984    
1985     procedure TIBXConfigService.SetPageBuffers(Value: Integer);
1986     begin
1987     SRB.Add(isc_action_svc_properties);
1988     AddDBNameToSRB;
1989     SRB.Add(isc_spb_prp_page_buffers).AsInteger := Value;
1990     InternalServiceStart;
1991     while IsServiceRunning do;
1992     end;
1993    
1994     procedure TIBXConfigService.ActivateShadow;
1995     begin
1996     SRB.Add(isc_action_svc_properties);
1997     AddDBNameToSRB;
1998     SRB.Add(isc_spb_options).AsInteger := isc_spb_prp_activate;
1999     InternalServiceStart;
2000     while IsServiceRunning do;
2001     end;
2002    
2003     procedure TIBXConfigService.BringDatabaseOnline;
2004     begin
2005     SRB.Add(isc_action_svc_properties);
2006     AddDBNameToSRB;
2007     SRB.Add(isc_spb_options).AsInteger := isc_spb_prp_db_online;
2008     InternalServiceStart;
2009     while IsServiceRunning do;
2010     end;
2011    
2012     procedure TIBXConfigService.SetReserveSpace(Value: Boolean);
2013     begin
2014     SRB.Add(isc_action_svc_properties);
2015     AddDBNameToSRB;
2016     with SRB.Add(isc_spb_prp_reserve_space) do
2017     if Value then
2018     AsByte := isc_spb_prp_res
2019     else
2020     AsByte := isc_spb_prp_res_use_full;
2021     InternalServiceStart;
2022     while IsServiceRunning do;
2023     end;
2024    
2025     procedure TIBXConfigService.SetAsyncMode(Value: Boolean);
2026     begin
2027     SRB.Add(isc_action_svc_properties);
2028     AddDBNameToSRB;
2029     with SRB.Add(isc_spb_prp_write_mode) do
2030     if Value then
2031     AsByte := isc_spb_prp_wm_async
2032     else
2033     AsByte := isc_spb_prp_wm_sync;
2034     InternalServiceStart;
2035     while IsServiceRunning do;
2036     end;
2037    
2038     procedure TIBXConfigService.SetReadOnly(Value: Boolean);
2039     begin
2040     SRB.Add(isc_action_svc_properties);
2041     AddDBNameToSRB;
2042     with SRB.Add(isc_spb_prp_access_mode) do
2043     if Value then
2044     AsByte := isc_spb_prp_am_readonly
2045     else
2046     AsByte := isc_spb_prp_am_readwrite;
2047     InternalServiceStart;
2048     while IsServiceRunning do;
2049     end;
2050    
2051     procedure TIBXConfigService.SetNoLinger;
2052     begin
2053     SRB.Add(isc_action_svc_properties);
2054     AddDBNameToSRB;
2055     SRB.Add(isc_spb_options).AsInteger := isc_spb_prp_nolinger;
2056     InternalServiceStart;
2057     while IsServiceRunning do;
2058     end;
2059    
2060     { TIBXLogService }
2061    
2062     procedure TIBXLogService.SetServiceStartOptions;
2063     begin
2064     SRB.Add(isc_action_svc_get_ib_log);
2065     end;
2066    
2067     { TIBXControlAndQueryService }
2068    
2069     function TIBXControlAndQueryService.GetNextLine: String;
2070     var
2071     i: Integer;
2072     begin
2073     Result := '';
2074     if (FEof = True) then
2075     Exit;
2076     if not FServiceStarted then
2077     IBError(ibxeServiceNotStarted,[nil]);
2078    
2079     SRB.Add(isc_info_svc_line);
2080     InternalServiceQuery;
2081    
2082     for i := 0 to FServiceQueryResults.Count - 1 do
2083     with FServiceQueryResults[i] do
2084     begin
2085     case getItemType of
2086     isc_info_svc_line:
2087     Result := AsString;
2088     else
2089     IBError(ibxeOutputParsingError, [getItemType]);
2090     end;
2091     end;
2092     FEof := Result = '';
2093     Result := Trim(Result);
2094     DoOnGetNextLine(Result);
2095     if FEof then
2096     FServiceStarted := false;
2097     end;
2098    
2099     function TIBXControlAndQueryService.GetNextChunk: String;
2100     var
2101     i: Integer;
2102     begin
2103     if (FEof = True) then
2104     begin
2105     Result := '';
2106     exit;
2107     end;
2108     if not FServiceStarted then
2109     IBError(ibxeServiceNotStarted,[nil]);
2110    
2111     SRB.Add(isc_info_svc_to_eof);
2112     InternalServiceQuery;
2113    
2114     FEof := True;
2115     for i := 0 to FServiceQueryResults.Count - 1 do
2116     with FServiceQueryResults[i] do
2117     begin
2118     case getItemType of
2119     isc_info_svc_to_eof:
2120     Result := AsString;
2121    
2122     isc_info_truncated:
2123     FEof := False;
2124     else
2125     IBError(ibxeOutputParsingError, [getItemType]);
2126     end;
2127     end;
2128     if FEof then
2129     FServiceStarted := false;
2130     end;
2131    
2132     procedure TIBXControlAndQueryService.ServiceStart;
2133     begin
2134     FEof := false;
2135     FSendBytes := 0;
2136     inherited ServiceStart;
2137     FServiceStarted := true;
2138     end;
2139    
2140     function TIBXControlAndQueryService.ReceiveNextChunk(stream: TStream): integer;
2141     var
2142     i: Integer;
2143     TimeOut: boolean;
2144     begin
2145     Result := 0;
2146     TimeOut := false;
2147     if (FEof = True) then
2148     Exit;
2149     if not FServiceStarted then
2150     IBError(ibxeServiceNotStarted,[nil]);
2151    
2152     SQPB.Add(isc_info_svc_timeout).AsInteger := 1;
2153     SRB.Add(isc_info_svc_to_eof);
2154     InternalServiceQuery;
2155    
2156     FEof := True;
2157     for i := 0 to FServiceQueryResults.Count - 1 do
2158     with FServiceQueryResults[i] do
2159     begin
2160     case getItemType of
2161     isc_info_svc_to_eof:
2162     begin
2163     Result := CopyTo(stream,0);
2164     FEof := (Result = 0) and not TimeOut;
2165     end;
2166    
2167     isc_info_truncated:
2168     FEof := False;
2169    
2170     isc_info_svc_timeout:
2171     begin
2172     FEof := False;
2173     TimeOut := true;
2174     end
2175    
2176     else
2177     IBError(ibxeOutputParsingError, [getItemType]);
2178     end;
2179     end;
2180     if FEof then
2181     FServiceStarted := false;
2182     end;
2183    
2184     function TIBXControlAndQueryService.SendNextChunk(stream: TStream;
2185     var line: String): integer;
2186     var
2187     i: Integer;
2188     begin
2189     Result := 0;
2190     line := '';
2191     if (FEof = True) then
2192     Exit;
2193    
2194     if not FServiceStarted then
2195     IBError(ibxeServiceNotStarted,[nil]);
2196    
2197     SRB.Add(isc_info_svc_line);
2198     SRB.Add(isc_info_svc_stdin);
2199    
2200     SQPB.Add(isc_info_svc_timeout).AsInteger := 1;
2201     if FSendBytes > 0 then
2202     Result := SQPB.Add(isc_info_svc_line).CopyFrom(stream,FSendBytes);
2203     try
2204     InternalServiceQuery;
2205     except
2206     FSendBytes := 0;
2207     raise;
2208     end;
2209    
2210     FSendBytes := 0;
2211     for i := 0 to FServiceQueryResults.Count - 1 do
2212     with FServiceQueryResults[i] do
2213     begin
2214     case getItemType of
2215     isc_info_svc_line:
2216     line := AsString;
2217    
2218     isc_info_svc_stdin:
2219     FSendBytes := AsInteger;
2220    
2221     isc_info_svc_timeout,
2222     isc_info_data_not_ready:
2223     {ignore};
2224     else
2225     IBError(ibxeOutputParsingError, [getItemType]);
2226     end;
2227     end;
2228     FEOF := (FSendBytes = 0) and (line = '');
2229     if FEof then
2230     FServiceStarted := false;
2231     end;
2232    
2233     procedure TIBXControlAndQueryService.DoOnGetNextLine(Line: string);
2234     begin
2235     if assigned(FOnGetNextLine) then
2236     OnGetNextLine(self,Line);
2237     end;
2238    
2239     procedure TIBXControlAndQueryService.OnBeforeDisconnect(
2240     Sender: TIBXServicesConnection);
2241     var i: integer;
2242     begin
2243     inherited OnBeforeDisconnect(Sender);
2244     for i := 0 to FDataSets.Count - 1 do
2245     TDataSet(FDataSets[i]).Active := false;
2246     end;
2247    
2248     procedure TIBXControlAndQueryService.Notification(AComponent: TComponent;
2249     Operation: TOperation);
2250     begin
2251     inherited Notification(AComponent, Operation);
2252     if (Operation = opRemove) and (AComponent is TDataSet) then
2253     FDataSets.Remove(AComponent);
2254     end;
2255    
2256     procedure TIBXControlAndQueryService.RegisterDataSet(aDataSet: TDataSet);
2257     begin
2258     if FDataSets.IndexOf(aDataset) = -1 then
2259     begin
2260     FDataSets.Add(aDataSet);
2261     FreeNotification(ADataSet);
2262     end;
2263     end;
2264    
2265     procedure TIBXControlAndQueryService.UnRegisterDataSet(aDataSet: TDataSet);
2266     begin
2267     FDataSets.Remove(aDataSet);
2268     RemoveFreeNotification(aDataset);
2269     end;
2270    
2271     constructor TIBXControlAndQueryService.Create(aOwner: TComponent);
2272     begin
2273     inherited Create(aOwner);
2274     FDataSets := TList.Create;
2275     end;
2276    
2277     destructor TIBXControlAndQueryService.Destroy;
2278     begin
2279     inherited Destroy;
2280     if assigned(FDataSets) then FDataSets.Free;
2281     end;
2282    
2283     procedure TIBXControlAndQueryService.Execute(OutputLog: TStrings);
2284     begin
2285     ServiceStart;
2286     try
2287     while not Eof do
2288     if OutputLog <> nil then
2289     OutputLog.Add(GetNextLine)
2290     else
2291     GetNextLine;
2292     finally
2293     while IsServiceRunning do; {flush}
2294     end;
2295     end;
2296    
2297     { TIBXControlService }
2298    
2299     function TIBXControlService.GetIsServiceRunning: Boolean;
2300     begin
2301     Result := (ServicesConnection <> nil) and (ServicesConnection.Connected);
2302     if Result then
2303     begin
2304     SRB.Add(isc_info_svc_running);
2305     InternalServiceQuery(false);
2306     Result := (FServiceQueryResults <> nil) and (FServiceQueryResults.Count > 0) and
2307     (FServiceQueryResults[0].getItemType = isc_info_svc_running) and
2308     (FServiceQueryResults[0].AsInteger = 1);
2309     end;
2310     end;
2311    
2312     procedure TIBXControlService.HandleSecContextErr;
2313     begin
2314     FAction := scRaiseError;
2315     if MainThreadID = TThread.CurrentThread.ThreadID then
2316     CallSecContextException
2317     else
2318     TThread.Synchronize(TThread.CurrentThread,@CallSecContextException);
2319     end;
2320    
2321     procedure TIBXControlService.CallSecContextException;
2322     begin
2323     ServicesConnection.HandleSecContextException(self,FAction)
2324     end;
2325    
2326     procedure TIBXControlService.SetDatabaseName(AValue: string);
2327     begin
2328     if FDatabaseName = AValue then Exit;
2329     CheckServiceNotRunning;
2330     FDatabaseName := AValue;
2331     DatabaseNameChanged;
2332     end;
2333    
2334     procedure TIBXControlService.DatabaseNameChanged;
2335     begin
2336     //Do nothing
2337     end;
2338    
2339     procedure TIBXControlService.OnAfterConnect(Sender: TIBXServicesConnection;
2340     aDatabaseName: string);
2341     begin
2342     inherited OnAfterConnect(Sender,aDatabaseName);
2343     if aDatabaseName <> '' then
2344     DatabaseName := aDatabaseName;
2345     end;
2346    
2347     procedure TIBXControlService.AddDBNameToSRB;
2348     begin
2349     if FDatabaseName = '' then
2350     IBError(ibxeStartParamsError, [nil]);
2351     SRB.Add(isc_spb_dbname).AsString := FDatabaseName;
2352     end;
2353    
2354     procedure TIBXControlService.CheckServiceNotRunning;
2355     begin
2356     if IsServiceRunning then
2357     IBError(ibxeServiceRunning,[nil]);
2358     end;
2359    
2360     procedure TIBXControlService.InternalServiceStart;
2361     var done: boolean;
2362     theError: EIBInterBaseError;
2363     begin
2364     if SRB = nil then
2365     IBError(ibxeStartParamsError, [nil]);
2366    
2367     FLastStartSRB := SRB;
2368     done := false;
2369     theError := nil;
2370     try
2371     repeat
2372     CheckActive;
2373     done := ServicesConnection.ServiceIntf.Start(SRB,false);
2374     if not done then
2375     begin
2376 tony 263 theError := EIBInterBaseError.Create(ServicesConnection.GetFirebirdAPI.GetStatus);
2377 tony 209 if theError.IBErrorCode = isc_sec_context then
2378     begin
2379     HandleSecContextErr;
2380     if FAction = scRaiseError then
2381     raise theError
2382     else
2383     begin
2384     theError.Free;
2385     FSRB := FLastStartSRB;
2386     end;
2387     end
2388     else
2389     raise theError;
2390     end;
2391     until done;
2392     finally
2393     FSRB := nil;
2394     end;
2395     if tfService in ServicesConnection.TraceFlags then
2396     MonitorHook.ServiceStart(Self);
2397     end;
2398    
2399     procedure TIBXControlService.DoServiceQuery;
2400     var done: boolean;
2401     LastSRB: ISRB;
2402     LastSQPB: ISQPB;
2403     theError: EIBInterBaseError;
2404     begin
2405     done := false;
2406     theError := nil;
2407     repeat
2408     LastSRB := SRB;
2409     LastSQPB := SQPB;
2410     inherited DoServiceQuery;
2411     done := FServiceQueryResults <> nil;
2412     if not done then
2413     begin
2414 tony 263 if ServicesConnection.GetFirebirdAPI.GetStatus.GetIBErrorCode = isc_sec_context then
2415 tony 209 begin
2416 tony 263 theError := EIBInterBaseError.Create(ServicesConnection.GetFirebirdAPI.GetStatus); {save exception}
2417 tony 209 HandleSecContextErr;
2418     if FAction = scReconnect then
2419     begin
2420     {Restart service}
2421     theError.Free;
2422     FSRB := FLastStartSRB;
2423     InternalServiceStart;
2424     FSRB := LastSRB;
2425     FSQPB := LastSQPB;
2426     end
2427     else
2428     raise theError;
2429     end
2430     else
2431     break; {Let the caller handle the error}
2432     end;
2433     until done;
2434     end;
2435    
2436     procedure TIBXControlService.SetServiceStartOptions;
2437     begin
2438     //Do nothing
2439     end;
2440    
2441     procedure TIBXControlService.ServiceStart;
2442     begin
2443     CheckActive;
2444     CheckServiceNotRunning;
2445     SetServiceStartOptions;
2446     InternalServiceStart;
2447     end;
2448    
2449     procedure TIBXControlService.Assign(Source: TPersistent);
2450     begin
2451     inherited Assign(Source);
2452     if Source is TIBXControlService then
2453     DatabaseName := TIBXControlService(Source).DatabaseName;
2454     end;
2455    
2456     { TConfigParams }
2457    
2458     constructor TConfigParams.Create;
2459     begin
2460     ConfigFileData := TConfigFileData.Create;
2461     ConfigFileParams := nil;
2462     end;
2463    
2464     destructor TConfigParams.Destroy;
2465     begin
2466     ConfigFileData.Free;
2467     ConfigFileParams := nil;
2468     inherited Destroy;
2469     end;
2470    
2471     { TConfigFileData }
2472    
2473     constructor TConfigFileData.Create;
2474     begin
2475     ConfigFileValue := nil;
2476     ConfigFileKey := nil;
2477     end;
2478    
2479     destructor TConfigFileData.Destroy;
2480     begin
2481     ConfigFileValue := nil;
2482     ConfigFileKey := nil;
2483     inherited Destroy;
2484     end;
2485    
2486     { TDatabaseInfo }
2487    
2488     constructor TDatabaseInfo.Create;
2489     begin
2490     DbName := nil;
2491     end;
2492    
2493     destructor TDatabaseInfo.Destroy;
2494     begin
2495     DbName := nil;
2496     inherited Destroy;
2497     end;
2498    
2499     { TIBXServerProperties }
2500    
2501     function TIBXServerProperties.GetConfigParams: TConfigParams;
2502     var i, j: Integer;
2503     begin
2504     CheckActive;
2505     if FConfigParams = nil then
2506     begin
2507     SRB.Add(isc_info_svc_get_config);
2508     SRB.Add(isc_info_svc_get_env);
2509     SRB.Add(isc_info_svc_get_env_lock);
2510     SRB.Add(isc_info_svc_get_env_msg);
2511     SRB.Add(isc_info_svc_user_dbpath);
2512    
2513     InternalServiceQuery;
2514    
2515     FConfigParams := TConfigParams.Create;
2516     for i := 0 to FServiceQueryResults.Count - 1 do
2517     with FServiceQueryResults[i] do
2518     begin
2519     case getItemType of
2520     isc_info_svc_get_config:
2521     begin
2522     SetLength (FConfigParams.ConfigFileData.ConfigFileValue, Count);
2523     SetLength (FConfigParams.ConfigFileData.ConfigFileKey, Count);
2524    
2525     for j := 0 to Count - 1 do
2526     begin
2527     FConfigParams.ConfigFileData.ConfigFileKey[j] := Items[j].getItemType;
2528     FConfigParams.ConfigFileData.ConfigFileValue[j] := Items[j].AsInteger;
2529     end;
2530     end;
2531    
2532     isc_info_svc_get_env:
2533     FConfigParams.BaseLocation := AsString;
2534    
2535     isc_info_svc_get_env_lock:
2536     FConfigParams.LockFileLocation := AsString;
2537    
2538     isc_info_svc_get_env_msg:
2539     FConfigParams.MessageFileLocation := AsString;
2540    
2541     isc_info_svc_user_dbpath:
2542     FConfigParams.SecurityDatabaseLocation := AsString;
2543    
2544     else
2545     IBError(ibxeOutputParsingError, [getItemType]);
2546     end;
2547     end;
2548     end;
2549     Result := FConfigParams;
2550     end;
2551    
2552     function TIBXServerProperties.GetDatabaseInfo: TDatabaseInfo;
2553     var i,j: Integer;
2554     begin
2555     if FDatabaseInfo = nil then
2556     begin
2557     SRB.Add(isc_info_svc_svr_db_info);
2558     InternalServiceQuery;
2559    
2560     FDatabaseInfo := TDatabaseInfo.Create;
2561     SetLength(FDatabaseInfo.DbName,0);
2562     for i := 0 to FServiceQueryResults.Count - 1 do
2563     with FServiceQueryResults[i] do
2564     begin
2565     case getItemType of
2566     isc_info_svc_svr_db_info:
2567     for j := 0 to FServiceQueryResults[i].Count - 1 do
2568     with FServiceQueryResults[i][j] do
2569     case getItemType of
2570     isc_spb_num_att:
2571     FDatabaseInfo.NoOfAttachments := AsInteger;
2572    
2573     isc_spb_num_db:
2574     FDatabaseInfo.NoOfDatabases := AsInteger;
2575    
2576     isc_spb_dbname:
2577     begin
2578     SetLength(FDatabaseInfo.DbName,length(FDatabaseInfo.DbName)+1);
2579     FDatabaseInfo.DbName[length(FDatabaseInfo.DbName)-1] := AsString;
2580     end;
2581     else
2582     IBError(ibxeOutputParsingError, [getItemType]);
2583     end;
2584     else
2585     IBError(ibxeOutputParsingError, [getItemType]);
2586     end;
2587     end;
2588     end;
2589     Result := FDatabaseInfo;
2590     end;
2591    
2592     function TIBXServerProperties.GetVersionInfo: TVersionInfo;
2593     var i : Integer;
2594     begin
2595     if FVersionInfo = nil then
2596     begin
2597     SRB.Add(isc_info_svc_version);
2598     SRB.Add(isc_info_svc_server_version);
2599     SRB.Add(isc_info_svc_implementation);
2600     InternalServiceQuery;
2601    
2602     FVersionInfo := TVersionInfo.Create;
2603     for i := 0 to FServiceQueryResults.Count - 1 do
2604     with FServiceQueryResults[i] do
2605     begin
2606     case getItemType of
2607     isc_info_svc_version:
2608     FVersionInfo.ServiceVersion := AsInteger;
2609     isc_info_svc_server_version:
2610     FVersionInfo.ServerVersion := AsString;
2611     isc_info_svc_implementation:
2612     FVersionInfo.ServerImplementation := AsString;
2613     else
2614     IBError(ibxeOutputParsingError, [getItemType]);
2615     end;
2616     end;
2617     end;
2618     Result := FVersionInfo;
2619     end;
2620    
2621     procedure TIBXServerProperties.Clear;
2622     begin
2623     inherited;
2624     if assigned(FDatabaseInfo) then FreeAndNil(FDatabaseInfo);
2625     if assigned(FVersionInfo) then FreeAndNil(FVersionInfo);
2626     if assigned(FConfigParams) then FreeAndNil(FConfigParams);
2627     end;
2628    
2629     { TIBXCustomService }
2630    
2631     procedure TIBXCustomService.CheckActive;
2632     begin
2633     if ServicesConnection = nil then
2634     IBError(ibxeServiceActive,[nil]);
2635     ServicesConnection.CheckActive;
2636     end;
2637    
2638     function TIBXCustomService.GetSQPB: ISQPB;
2639     begin
2640     CheckActive;
2641     if FSQPB = nil then
2642     FSQPB := ServicesConnection.ServiceIntf.AllocateSQPB;
2643     Result := FSQPB;
2644     end;
2645    
2646     function TIBXCustomService.GetSRB: ISRB;
2647     begin
2648     CheckActive;
2649     if FSRB = nil then
2650     FSRB := ServicesConnection.ServiceIntf.AllocateSRB;
2651     Result := FSRB;
2652     end;
2653    
2654     procedure TIBXCustomService.SetServicesConnection(AValue: TIBXServicesConnection
2655     );
2656     begin
2657     if FServicesConnection = AValue then Exit;
2658     if FServicesConnection <> nil then
2659     begin
2660     FServicesConnection.UnRegisterIntf(self);
2661     RemoveFreeNotification(FServicesConnection);
2662     end;
2663     Clear;
2664     FServicesConnection := AValue;
2665     if FServicesConnection <> nil then
2666     begin
2667     FServicesConnection.RegisterIntf(self);
2668     FreeNotification(FServicesConnection);
2669     end;
2670     end;
2671    
2672     procedure TIBXCustomService.OnBeforeDisconnect(Sender: TIBXServicesConnection);
2673     begin
2674     Clear;
2675     end;
2676    
2677     procedure TIBXCustomService.InternalServiceQuery(RaiseExceptionOnError: boolean
2678     );
2679     begin
2680     CheckActive;
2681     try
2682     FServiceQueryResults := nil;
2683     DoServiceQuery;
2684     if (FServiceQueryResults = nil) and RaiseExceptionOnError then
2685 tony 263 raise EIBInterBaseError.Create(ServicesConnection.GetFirebirdAPI.GetStatus);
2686 tony 209 finally
2687     FSQPB := nil;
2688     FSRB := nil;
2689     end;
2690     if tfService in ServicesConnection.TraceFlags then
2691     MonitorHook.ServiceQuery(Self);
2692     end;
2693    
2694     procedure TIBXCustomService.DoServiceQuery;
2695     begin
2696     FServiceQueryResults := ServicesConnection.ServiceIntf.Query(FSQPB,FSRB,false);
2697     end;
2698    
2699     procedure TIBXCustomService.Notification(AComponent: TComponent;
2700     Operation: TOperation);
2701     begin
2702     inherited Notification(AComponent, Operation);
2703     if (Operation = opRemove) and (AComponent = ServicesConnection) then
2704     ServicesConnection := nil;
2705     end;
2706    
2707     constructor TIBXCustomService.Create(AOwner: TComponent);
2708     begin
2709     inherited Create(AOwner);
2710     FSRB := nil;
2711     FServiceQueryResults := nil;
2712     FSQPB := nil;
2713     end;
2714    
2715     destructor TIBXCustomService.Destroy;
2716     begin
2717     if ServicesConnection <> nil then
2718     begin
2719     OnBeforeDisconnect(ServicesConnection);
2720     ServicesConnection := nil;
2721     end;
2722     inherited Destroy;
2723     end;
2724    
2725     procedure TIBXCustomService.Assign(Source: TPersistent);
2726     begin
2727     if Source is TIBXCustomService then
2728     ServicesConnection := TIBXCustomService(Source).ServicesConnection;
2729     end;
2730    
2731     procedure TIBXCustomService.Clear;
2732     begin
2733     FSRB := nil;
2734     FServiceQueryResults := nil;
2735     FSQPB := nil;
2736     end;
2737    
2738     procedure TIBXCustomService.OnAfterConnect(Sender: TIBXServicesConnection;
2739     aDatabaseName: string);
2740     begin
2741     //Do nothing
2742     end;
2743    
2744     { TIBXServicesConnection }
2745    
2746     procedure TIBXServicesConnection.SetParams(AValue: TStrings);
2747     begin
2748     FParams.Assign(AValue);
2749     end;
2750    
2751     procedure TIBXServicesConnection.SetPortNo(AValue: string);
2752     begin
2753     if FPortNo = AValue then Exit;
2754     Connected := false;
2755     FPortNo := AValue;
2756     FConnectString := MakeConnectString(FServerName,'service_mgr',FProtocol,FPortNo);
2757     end;
2758    
2759     procedure TIBXServicesConnection.CheckActive;
2760     begin
2761     if StreamedConnected and (not Connected) then
2762     Loaded;
2763     if FService = nil then
2764     IBError(ibxeServiceActive, [nil]);
2765     end;
2766    
2767     procedure TIBXServicesConnection.CheckInactive;
2768     begin
2769     if FService <> nil then
2770     IBError(ibxeServiceInActive, [nil]);
2771     end;
2772    
2773     procedure TIBXServicesConnection.CheckServerName;
2774     begin
2775     if (FServerName = '') and (FProtocol <> Local) then
2776     IBError(ibxeServerNameMissing, [nil]);
2777     end;
2778    
2779     {
2780     * GenerateSPB -
2781     * Given a string containing a textual representation
2782     * of the Service parameters, generate a service
2783     * parameter buffer, and return it .
2784     }
2785     function TIBXServicesConnection.GenerateSPB(sl: TStrings): ISPB;
2786     var
2787 tony 267 i, j: integer;
2788     SPBServerVal: UShort;
2789 tony 209 param_name, param_value: String;
2790     begin
2791     { The SPB is initially empty, with the exception that
2792     the SPB version must be the first byte of the string.
2793     }
2794     Result := FirebirdAPI.AllocateSPB;
2795    
2796     { Iterate through the textual service parameters, constructing
2797     a SPB on-the-fly }
2798     for i := 0 to sl.Count - 1 do
2799     begin
2800     { Get the parameter's name and value from the list,
2801     and make sure that the name is all lowercase with
2802     no leading 'isc_spb_' prefix }
2803     if (Trim(sl.Names[i]) = '') then continue;
2804     param_name := LowerCase(sl.Names[i]); {mbcs ok}
2805     param_value := sl.ValueFromIndex[i];
2806     if (Pos(SPBPrefix, param_name) = 1) then {mbcs ok}
2807     Delete(param_name, 1, Length(SPBPrefix));
2808     { We want to translate the parameter name to some integer
2809     value. We do this by scanning through a list of known
2810     service parameter names (SPBConstantNames, defined above). }
2811     SPBServerVal := 0;
2812     { Find the parameter }
2813     for j := 1 to isc_spb_last_spb_constant do
2814     if (param_name = SPBConstantNames[j]) then
2815     begin
2816     SPBServerVal := SPBConstantValues[j];
2817     break;
2818     end;
2819     case SPBServerVal of
2820     isc_spb_user_name,
2821     isc_spb_password,
2822     isc_spb_sql_role_name,
2823     isc_spb_expected_db:
2824     Result.Add(SPBServerVal).AsString := param_value;
2825     else
2826     begin
2827     if GetSPBConstName(SPBServerVal) <> '' then
2828     IBError(ibxeSPBConstantNotSupported,
2829     [GetSPBConstName(SPBServerVal)])
2830     else
2831     IBError(ibxeSPBConstantUnknown, [SPBServerVal]);
2832     end;
2833     end;
2834     end;
2835 tony 267 if FConfigOverrides.Count > 0 then
2836     Result.Add(isc_spb_config).SetAsString(FConfigOverrides.Text);
2837 tony 209 end;
2838    
2839 tony 263 function TIBXServicesConnection.GetFirebirdAPI: IFirebirdAPI;
2840     var fblib: IFirebirdLibrary;
2841     begin
2842     if FFirebirdAPI = nil then
2843     begin
2844     if (csDesigning in ComponentState) or (Trim(FFirebirdLibraryPathName) = '') then
2845     FFirebirdAPI := IB.FirebirdAPI
2846     else
2847     begin
2848     fblib := IB.LoadFBLibrary(FFirebirdLibraryPathName);
2849     if assigned(fblib) then
2850     FFirebirdAPI := fblib.GetFirebirdAPI;
2851     end;
2852     end;
2853     Result := FFirebirdAPI;
2854     end;
2855    
2856 tony 209 function TIBXServicesConnection.GetServerVersionNo(index: integer): integer;
2857     begin
2858     CheckActive;
2859     if (index >= Low(FServerVersionNo)) and (index <= High(FServerVersionNo)) then
2860     Result := FServerVersionNo[index]
2861     else
2862     IBError(ibxeInfoBufferIndexError,[index]);
2863     end;
2864    
2865     function TIBXServicesConnection.GetSPBConstName(action: byte): string;
2866     var i: integer;
2867     begin
2868     Result := '';
2869     for i := Low(SPBConstantValues) to High(SPBConstantValues) do
2870     if SPBConstantValues[i] = action then
2871     begin
2872     Result := SPBConstantNames[i];
2873     break;
2874     end;
2875     end;
2876    
2877 tony 267 function TIBXServicesConnection.GetWireCompression: boolean;
2878     begin
2879     Result := CompareText(FConfigOverrides.Values['WireCompression'],'true') = 0;
2880     end;
2881    
2882 tony 209 procedure TIBXServicesConnection.HandleException(Sender: TObject);
2883     var aParent: TComponent;
2884     begin
2885     aParent := Owner;
2886     while aParent <> nil do
2887     begin
2888     if aParent is TCustomApplication then
2889     begin
2890     TCustomApplication(aParent).HandleException(Sender);
2891     Exit;
2892     end;
2893     aParent := aParent.Owner;
2894     end;
2895     SysUtils.ShowException(ExceptObject,ExceptAddr);
2896     end;
2897    
2898     procedure TIBXServicesConnection.HandleSecContextException(
2899     Sender: TIBXControlService; var action: TSecContextAction);
2900     var OldServiceIntf: IServiceManager;
2901     begin
2902     action := scRaiseError;
2903     if assigned(FOnSecurityContextException) then
2904     OnSecurityContextException(self,action);
2905    
2906     if action = scReconnect then
2907     begin
2908     FExpectedDB := Sender.DatabaseName;
2909     try
2910     OldServiceIntf := FService;
2911     Connected := false;
2912     while not Connected do
2913     begin
2914     try
2915     Connected := true;
2916     except
2917     on E:EIBClientError do
2918     begin
2919     action := scRaiseError;
2920     FService := OldServiceIntf;
2921     break;
2922     end;
2923     else
2924     HandleException(self);
2925     end;
2926     end;
2927     finally
2928     FExpectedDB := '';
2929     end;
2930     end;
2931     end;
2932    
2933     function TIBXServicesConnection.Login(var aServerName: string;
2934     LoginParams: TStrings): Boolean;
2935     var
2936     IndexOfUser, IndexOfPassword: Integer;
2937     Username, Password: String;
2938     ExtLoginParams: TStrings;
2939     begin
2940     if Assigned(FOnLogin) then
2941     begin
2942     Result := True;
2943     ExtLoginParams := TStringList.Create;
2944     try
2945     ExtLoginParams.Assign(Params);
2946     FOnLogin(Self, aServerName, ExtLoginParams);
2947     LoginParams.Assign (ExtLoginParams);
2948     finally
2949     ExtLoginParams.Free;
2950     end;
2951     end
2952     else
2953     if assigned(IBGUIInterface) then
2954     begin
2955     IndexOfUser := LoginParams.IndexOfName(GetSPBConstName(isc_spb_user_name));
2956     if IndexOfUser <> -1 then
2957     Username := LoginParams.ValueFromIndex[IndexOfUser]
2958     else
2959     UserName := '';
2960     IndexOfPassword :=LoginParams.IndexOfName(GetSPBConstName(isc_spb_password));
2961     if IndexOfPassword <> -1 then
2962     Password := LoginParams.ValueFromIndex[IndexOfPassword]
2963     else
2964     Password := '';
2965    
2966     result := IBGUIInterface.ServerLoginDialog(aServerName, Username, Password);
2967     if result then
2968     begin
2969     LoginParams.Values[GetSPBConstName(isc_spb_user_name)] := UserName;
2970     LoginParams.Values[GetSPBConstName(isc_spb_password)] := Password;
2971     end
2972     end
2973     else
2974     IBError(ibxeNoLoginDialog,[]);
2975     end;
2976    
2977     procedure TIBXServicesConnection.ParamsChanging(Sender: TObject);
2978     begin
2979     CheckInactive;
2980     end;
2981    
2982 tony 267 procedure TIBXServicesConnection.SetConfigOverrides(AValue: TStrings);
2983     begin
2984     if FConfigOverrides = AValue then Exit;
2985     FConfigOverrides.Assign(AValue);
2986     end;
2987    
2988 tony 209 procedure TIBXServicesConnection.SetConnectString(AValue: string);
2989     var aServiceName: AnsiString;
2990     aProtocol: TProtocolAll;
2991     begin
2992     if FConnectString = AValue then Exit;
2993     Connected := false;
2994     if not ParseConnectString(AValue,FServerName,aServiceName,aProtocol,FPortNo)
2995     or (aServiceName <> 'service_mgr') or (aProtocol = unknownProtocol) then
2996     IBError(ibxeBadConnectString, [nil]);
2997     FConnectString := AValue;
2998     FProtocol := TProtocol(aProtocol);
2999     end;
3000    
3001 tony 263 procedure TIBXServicesConnection.SetFirebirdLibraryPathName(AValue: TIBFileName
3002     );
3003     begin
3004     if FFirebirdLibraryPathName = AValue then Exit;
3005     FFirebirdLibraryPathName := AValue;
3006     Connected := false;
3007     FFirebirdAPI := nil;
3008     end;
3009    
3010 tony 209 procedure TIBXServicesConnection.SetProtocol(AValue: TProtocol);
3011     begin
3012     if FProtocol = AValue then Exit;
3013     Connected := false;
3014     FProtocol := AValue;
3015     FConnectString := MakeConnectString(FServerName,'service_mgr',FProtocol,FPortNo);
3016     end;
3017    
3018     procedure TIBXServicesConnection.SetServerName(AValue: string);
3019     begin
3020     if FServerName = AValue then Exit;
3021     Connected := false;
3022     FServerName := AValue;
3023     FConnectString := MakeConnectString(FServerName,'service_mgr',FProtocol,FPortNo);
3024     end;
3025    
3026 tony 267 procedure TIBXServicesConnection.SetWireCompression(AValue: boolean);
3027     var Index: integer;
3028     begin
3029     if AValue then
3030     FConfigOverrides.Values['WireCompression'] := 'true'
3031     else
3032     begin
3033     Index := FConfigOverrides.IndexOfName('WireCompression');
3034     if Index <> -1 then
3035     FConfigOverrides.Delete(Index);
3036     end;
3037     end;
3038    
3039 tony 209 procedure TIBXServicesConnection.DoConnect;
3040    
3041     procedure ParseServerVersionNo;
3042     var Req: ISRB;
3043     Results: IServiceQueryResults;
3044     RegexObj: TRegExpr;
3045     s: string;
3046     begin
3047     Req := FService.AllocateSRB;
3048     Req.Add(isc_info_svc_server_version);
3049     Results := FService.Query(nil,Req);
3050     if (Results.Count = 1) and (Results[0].getItemType = isc_info_svc_server_version) then
3051     RegexObj := TRegExpr.Create;
3052     try
3053     {extact database file spec}
3054     RegexObj.ModifierG := false; {turn off greedy matches}
3055     RegexObj.Expression := '[A-Z][A-Z]-V([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+) .*';
3056     s := Results[0].AsString;
3057     if RegexObj.Exec(s) then
3058     begin
3059     FServerVersionNo[1] := StrToInt(RegexObj.Match[1]);
3060     FServerVersionNo[2] := StrToInt(RegexObj.Match[2]);
3061     FServerVersionNo[3] := StrToInt(RegexObj.Match[3]);
3062     FServerVersionNo[4] := StrToInt(RegexObj.Match[4]);
3063     end;
3064     finally
3065     RegexObj.Free;
3066     end;
3067     end;
3068    
3069     var aServerName: string;
3070     aProtocol: TProtocolAll;
3071     aPortNo: string;
3072     aDBName: string;
3073     TempSvcParams: TStrings;
3074     SPB: ISPB;
3075     PW: ISPBItem;
3076     i: integer;
3077     begin
3078     CheckInactive;
3079     CheckServerName;
3080    
3081     aServerName := FServerName;
3082     aProtocol := FProtocol;
3083     aPortNo := PortNo;
3084     aDBName := '';
3085    
3086     if FDatabase <> nil then
3087     {Get Connect String from Database Connect String}
3088     begin
3089 tony 263 FFirebirdAPI := FDatabase.FirebirdAPI;
3090 tony 267 FConfigOverrides.Assign(FDatabase.ConfigOverrides);
3091 tony 209 if ParseConnectString(FDatabase.Attachment.GetConnectString,aServerName,aDBName,aProtocol,aPortNo) and
3092     (aProtocol = Local) and
3093     (FDatabase.Attachment.GetRemoteProtocol <> '') then
3094     begin
3095     {Use loopback if database does not use embedded server}
3096     aServerName := 'Localhost';
3097     aProtocol := TCP;
3098     end;
3099     end;
3100    
3101     TempSvcParams := TStringList.Create;
3102     try
3103     TempSvcParams.Assign(FParams);
3104     if LoginPrompt and not Login(aServerName,TempSvcParams) then
3105     IBError(ibxeOperationCancelled, [nil]);
3106    
3107     {Use of non-default security database}
3108     if FExpectedDB <> '' then {set when handling an isc_sec_context exception}
3109     TempSvcParams.Values['expected_db'] := FExpectedDB
3110     else
3111     if (FDatabase <> nil) and (FDatabase.Attachment.GetSecurityDatabase <> 'Default')
3112     and (aDBName <> '') then
3113     {Connect using database using non-default security database}
3114     TempSvcParams.Values['expected_db'] := aDBName;
3115     SPB := GenerateSPB(TempSvcParams);
3116     finally
3117     TempSvcParams.Free;
3118     end;
3119    
3120     FService := FirebirdAPI.GetServiceManager(aServerName,aPortNo,aProtocol,SPB);
3121 tony 231 FServername := aServerName;
3122     FProtocol := aProtocol;
3123     FPortNo := aPortNo;
3124     FConnectString := MakeConnectString(FServerName,'service_mgr',FProtocol,FPortNo);
3125 tony 209 PW := FService.getSPB.Find(isc_spb_password);
3126     if PW <> nil then PW.AsString := 'xxxxxxxx'; {Hide password}
3127    
3128     ParseServerVersionNo;
3129    
3130     for i := low(FIBXServices) to high(FIBXServices) do
3131     FIBXServices[i].OnAfterConnect(self,aDBName);
3132    
3133     if tfService in TraceFlags then
3134     MonitorHook.ServiceAttach(Self);
3135     end;
3136    
3137     procedure TIBXServicesConnection.DoDisconnect;
3138     var i: integer;
3139     begin
3140     CheckActive;
3141     for i := 0 to Length(FIBXServices) - 1 do
3142     FIBXServices[i].OnBeforeDisconnect(self);
3143     FService := nil;
3144     if tfService in TraceFlags then
3145     MonitorHook.ServiceDetach(Self);
3146     end;
3147    
3148     function TIBXServicesConnection.GetConnected: Boolean;
3149     begin
3150     Result := FService <> nil;
3151     end;
3152    
3153     function TIBXServicesConnection.GetDataset(Index: longint): TDataset;
3154     begin
3155     Result := inherited GetDataset(Index);
3156     end;
3157    
3158     function TIBXServicesConnection.GetDataSetCount: Longint;
3159     begin
3160     Result := inherited GetDataSetCount;
3161     end;
3162    
3163     procedure TIBXServicesConnection.ReadState(Reader: TReader);
3164     begin
3165     FParams.Clear;
3166     inherited ReadState(Reader);
3167     end;
3168    
3169     procedure TIBXServicesConnection.RegisterIntf(intf: IIBXServicesClient);
3170     begin
3171     Setlength(FIBXServices,Length(FIBXServices) + 1);
3172     FIBXServices[Length(FIBXServices)-1] := intf;
3173     end;
3174    
3175     procedure TIBXServicesConnection.UnRegisterIntf(intf: IIBXServicesClient);
3176     var i, j: integer;
3177     begin
3178     for i := length(FIBXServices) - 1 downto 0 do
3179     if FIBXServices[i] = intf then
3180     begin
3181     for j := i + 1 to length(FIBXServices) - 1 do
3182     FIBXServices[j-1] := FIBXServices[j];
3183     SetLength(FIBXServices,Length(FIBXServices)-1);
3184     break;
3185     end;
3186     end;
3187    
3188     constructor TIBXServicesConnection.Create(AOwner: TComponent);
3189     begin
3190     inherited Create(AOwner);
3191     FServerName := '';
3192     FParams := TStringList.Create;
3193 tony 267 FConfigOverrides := TStringList.Create;
3194 tony 209 Setlength(FIBXServices,0);
3195     TStringList(FParams).OnChanging := @ParamsChanging;
3196     FService := nil;
3197     FProtocol := Local;
3198     LoginPrompt := true;
3199     if (AOwner <> nil) and
3200     (AOwner is TCustomApplication) and
3201     TCustomApplication(AOwner).ConsoleApplication then
3202     LoginPrompt := false;
3203     end;
3204    
3205     destructor TIBXServicesConnection.Destroy;
3206     begin
3207     inherited Destroy;
3208     Setlength(FIBXServices,0);
3209     if assigned(FParams) then FParams.Free;
3210 tony 267 if assigned (FConfigOverrides) then FConfigOverrides.Free;
3211 tony 263 FFirebirdAPI := nil;
3212 tony 209 end;
3213    
3214     procedure TIBXServicesConnection.ConnectUsing(aDatabase: TIBDatabase);
3215     begin
3216     if not aDatabase.Connected then
3217     IBError(ibxeDatabaseNotConnected,[nil]);
3218     Connected := false;
3219     FDatabase := aDatabase;
3220     try
3221     Connected := true;
3222     finally
3223     FDatabase := nil;
3224     end;
3225     end;
3226    
3227     procedure TIBXServicesConnection.SetDBParams(DBParams: TStrings);
3228     var i: integer;
3229     j: integer;
3230     k: integer;
3231     ParamName: string;
3232     begin
3233     Params.Clear;
3234     for i := 0 to DBParams.Count - 1 do
3235     begin
3236     ParamName := DBParams[i];
3237     k := Pos('=',ParamName);
3238     if k > 0 then system.Delete(ParamName,k,Length(ParamName)-k+1);
3239     for j := 1 to isc_spb_last_spb_constant do
3240 tony 221 if CompareText(ParamName,SPBConstantNames[j]) = 0 then
3241 tony 209 begin
3242     Params.Add(DBParams[i]);
3243     break;
3244     end;
3245     end;
3246     end;
3247    
3248     end.
3249