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