@msshop/node-firebird
Version:
Forked node-firebird
1,047 lines (942 loc) • 41.7 kB
JavaScript
const Events = require('events');
const stream = require('stream');
const Const = require('./const');
const {BlrReader} = require('./serialize');
const {doError} = require('../callback');
/***************************************
*
* Service Manager
*
***************************************/
const ServiceManager = function(connection) {
this.connection = connection;
connection.svc = this;
}
ServiceManager.prototype.__proto__ = Object.create(Events.EventEmitter.prototype, {
constructor: {
value: ServiceManager,
enumberable: false
}
});
ServiceManager.prototype._createOutputStream = function (optread, buffersize, callback) {
var self = this;
optread = optread || 'byline';
var t = new stream.Readable({ objectMode: optread === 'byline' }); // chunk by line
t.__proto__._read = function () {
var selfread = this;
var fct = optread === 'byline' ? self.readline : self.readeof;
fct.call(self, { buffersize: buffersize }, function (err, data) {
if (err) {
selfread.push(err.message, Const.DEFAULT_ENCODING);
return;
}
if (data.line && data.line.length)
selfread.push(data.line, Const.DEFAULT_ENCODING);
else
selfread.push(null);
});
}
callback(null, t);
}
ServiceManager.prototype._infosmapping = {
"50"/*isc_info_svc_svr_db_info*/ : "dbinfo",
"51"/*isc_info_svc_get_license*/ : "licenses",
"52"/*isc_info_svc_get_license_mask*/ : "licenseoptions",
"53"/*isc_info_svc_get_config*/ : "fbconfig",
"54"/*isc_info_svc_version*/ : "svcversion",
"55"/*isc_info_svc_server_version*/ : "fbversion",
"56"/*isc_info_svc_implementation*/ : "fbimplementation",
"57"/*isc_info_svc_capabilities*/ : "fbcapatibilities",
"58"/*isc_info_svc_user_dbpath*/ : "pathsecuritydb",
"59"/*isc_info_svc_get_env*/ : "fbenv",
"60"/*isc_info_svc_get_env_lock*/ : "fbenvlock",
"61"/*isc_info_svc_get_env_msg*/ : "fbenvmsg",
"62"/*isc_info_svc_line*/ : "",
"63"/*isc_info_svc_to_eof*/ : "",
"64"/*isc_info_svc_timeout*/ : "",
"65"/*isc_info_svc_get_licensed_users*/ : "",
"66"/*isc_info_svc_limbo_trans*/ : "limbotrans",
"67"/*isc_info_svc_running*/ : "",
"68"/*isc_info_svc_get_users*/ : "fbusers",
"78"/*isc_info_svc_stdin*/ : ""
};
ServiceManager.prototype._processcapabilities = function (blr, res) {
var capArray = [
"WAL_SUPPORT",
"MULTI_CLIENT_SUPPORT",
"REMOTE_HOP_SUPPORT",
"NO_SVR_STATS_SUPPORT",
"NO_DB_STATS_SUPPORT",
"LOCAL_ENGINE_SUPPORT",
"NO_FORCED_WRITE_SUPPORT",
"NO_SHUTDOWN_SUPPORT",
"NO_SERVER_SHUTDOWN_SUPPORT",
"SERVER_CONFIG_SUPPORT",
"QUOTED_FILENAME_SUPPORT"
];
var dbcapa = res[this._infosmapping[57]] = [];
var caps = blr.readInt32();
for (var i = 0; i < capArray.length; ++i)
if (caps & (1 << i))
dbcapa.push(capArray[i]);
}
ServiceManager.prototype._processdbinfo = function (blr, res) {
var tinfo = blr.readByteCode();
var dbinfo = res[this._infosmapping[50]] = {};
dbinfo.database = [];
for (; tinfo != Const.isc_info_flag_end; tinfo = blr.readByteCode()) {
switch (tinfo) {
case Const.isc_spb_dbname:
dbinfo.database.push(blr.readString());
break;
case Const.isc_spb_num_att:
dbinfo.nbattachment = blr.readInt32();
break;
case Const.isc_spb_num_db:
dbinfo.nbdatabase = blr.readInt32();
break;
}
}
}
ServiceManager.prototype._processquery = function (buffer, callback) {
//console.log(buffer);
var br = new BlrReader(buffer);
var tinfo = br.readByteCode();
var res = {};
res.result = 0;
for (; tinfo !== Const.isc_info_end; tinfo = br.readByteCode()) {
switch (tinfo) {
case Const.isc_info_svc_server_version:
case Const.isc_info_svc_implementation:
case Const.isc_info_svc_user_dbpath:
case Const.isc_info_svc_get_env:
case Const.isc_info_svc_get_env_lock:
case Const.isc_info_svc_get_env_msg:
res[this._infosmapping[tinfo]] = br.readString();
break;
case Const.isc_info_svc_version:
res[this._infosmapping[tinfo]] = br.readInt32();
break;
case Const.isc_info_svc_svr_db_info:
this._processdbinfo(br, res);
break;
case Const.isc_info_svc_limbo_trans:
// not implemented
for (; tinfo !== isc_info_flag_end; tinfo = br.readByteCode())
break;
case Const.isc_info_svc_get_users:
br.pos += 2
res[this._infosmapping[tinfo]] = [];
break;
case Const.isc_spb_sec_username:
var tuser = res[this._infosmapping[68]];
tuser.push({});
tuser[tuser.length - 1].username = br.readString();
break;
case Const.isc_spb_sec_firstname:
var tuser = res[this._infosmapping[68]];
var user = tuser[tuser.length-1];
user.firstname = br.readString();
break;
case Const.isc_spb_sec_middlename:
var tuser = res[this._infosmapping[68]];
var user = tuser[tuser.length-1];
user.middlename = br.readString();
break;
case Const.isc_spb_sec_lastname:
var tuser = res[this._infosmapping[68]];
var user = tuser[tuser.length-1];
user.lastname = br.readString();
break;
case Const.isc_spb_sec_groupid:
var tuser = res[this._infosmapping[68]];
var user = tuser[tuser.length-1];
user.groupid = br.readInt32();
break;
case Const.isc_spb_sec_userid:
var tuser = res[this._infosmapping[68]];
var user = tuser[tuser.length-1];
user.userid = br.readInt32();
break;
case Const.isc_spb_sec_admin:
var tuser = res[this._infosmapping[68]];
var user = tuser[tuser.length-1];
user.admin = br.readInt32();
break;
case Const.isc_info_svc_line:
res.line = br.readString();
break;
case Const.isc_info_svc_to_eof:
res.line = br.readString();
break;
case Const.isc_info_truncated:
res.result = 1; // too much data for the result buffer increase size of it (buffersize parameter))
break;
case Const.isc_info_data_not_ready:
res.result = 2;
break;
case Const.isc_info_svc_timeout:
res.result = 3;
break;
case Const.isc_info_svc_stdin:
break;
case Const.isc_info_svc_capabilities:
this._processcapabilities(br, res);
break;
}
}
callback(null, res);
}
ServiceManager.prototype.detach = function(callback, force) {
var self = this;
if (!force && self.connection._pending.length > 0) {
self.connection._detachAuto = true;
self.connection._detachCallback = callback;
return self;
}
self.connection.svcdetach(function (err, obj) {
self.connection.disconnect();
self._socket.emit('detach', false);
if (callback)
callback(err, obj);
}, force);
return self;
}
ServiceManager.prototype.backup = function (options, callback) {
var dbpath = options.database || this.connection.options.filename || this.connection.options.database;
var verbose = options.verbose || false;
// format of bckfile {filename:'name', sizefile:''} sizefile is length of part in bytes
var bckfiles = options.backupfiles || options.files || null;
// for convenience
if (bckfiles) bckfiles = bckfiles.constructor !== Array?[{ filename: bckfiles, sizefile: '0' }]:bckfiles;
var factor = options.factor || 0; //If backing up to a physical tape device, this switch lets you specify the tape's blocking factor
var ignorechecksums = options.ignorechecksums || false;
var ignorelimbo = options.ignorelimbo || false;
var metadataonly = options.metadataonly || false;
var nogarbagecollect = options.nogarbasecollect || false;
var olddescriptions = options.olddescriptions || false;
var nontransportable = options.nontransportable || false;
var convert = options.convert || false;
var expand = options.expand || false;
var notriggers = options.notriggers || false;
if (dbpath == null || dbpath.length === 0) {
doError(new Error('No database specified'), callback);
return;
}
if (bckfiles == null || bckfiles.length === 0) {
doError(new Error('No backup path specified'), callback);
return;
}
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_backup);
blr.addString2(Const.isc_spb_dbname, dbpath, Const.DEFAULT_ENCODING);
for (var i = 0; i < bckfiles.length; i++) {
blr.addString2(Const.isc_spb_bkp_file, bckfiles[i].filename, Const.DEFAULT_ENCODING);
if (i !== bckfiles.length - 1) // not the end, so we need to write the size of this part (gsplit)
blr.addString2(Const.isc_spb_bkp_length, bckfiles[i].sizefile, Const.DEFAULT_ENCODING);
}
if (factor)
blr.addByteInt32(Const.isc_spb_bkp_factor, factor);
var opts = 0;
if (ignorechecksums) opts = opts | Const.isc_spb_bkp_ignore_checksums;
if (ignorelimbo) opts = opts | Const.isc_spb_bkp_ignore_limbo;
if (metadataonly) opts = opts | Const.isc_spb_bkp_metadata_only;
if (nogarbagecollect) opts = opts | Const.isc_spb_bkp_no_garbage_collect;
if (olddescriptions) opts = opts | Const.isc_spb_bkp_old_descriptions;
if (nontransportable) opts = opts | Const.isc_spb_bkp_non_transportable;
if (convert) opts = opts | Const.isc_spb_bkp_convert;
if (expand) opts = opts | Const.isc_spb_bkp_expand;
if (notriggers) opts = opts | Const.isc_spb_bkp_no_triggers;
if (opts)
blr.addByteInt32(Const.isc_spb_options, opts);
if (verbose)
blr.addByte(Const.isc_spb_verbose);
var self = this;
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.nbackup = function (options, callback) {
var dbpath = options.database || this.connection.options.filename || this.connection.options.database;
var bckfile = options.backupfile || options.file || null;
var level = options.level || 0; // nb day for incremental
var notriggers = options.notriggers || false;
var direct = options.direct || 'on'; // on or off direct write I/O
if (dbpath == null || dbpath.length === 0) {
doError(new Error('No database specified'), callback);
return;
}
if (bckfile == null || bckfile.length === 0) {
doError(new Error('No backup path specified'), callback);
return;
}
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_nbak);
blr.addString2(Const.isc_spb_dbname, dbpath, Const.DEFAULT_ENCODING);
blr.addString2(Const.isc_spb_nbk_file, bckfile, Const.DEFAULT_ENCODING);
blr.addByteInt32(Const.isc_spb_nbk_level, level);
blr.addString2(Const.isc_spb_nbk_direct, direct, Const.DEFAULT_ENCODING);
var opts = 0;
if (notriggers) opts = opts | Const.isc_spb_nbk_no_triggers;
blr.addByteInt32(Const.isc_spb_options, opts);
var self = this;
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.restore = function(options, callback) {
var bckfiles = options.backupfiles || options.files || null; // format bckfiles ['file1', 'file2', 'file3']
// for convenience
if (bckfiles) bckfiles = bckfiles.constructor !== Array?[bckfiles]:bckfiles;
var dbfile = options.database || this.connection.options.filename || this.connection.options.database;;
var verbose = options.verbose || false;
var cachebuffers = options.cachebuffers || 2048; // gbak -buffers
var pagesize = options.pagesize || 4096; // gbak -page_size
var readonly = options.readonly || false; // gbak -mode
var deactivateindexes = options.deactivateindexes || false;
var noshadow = options.noshadow || false;
var novalidity = options.novalidity || false;
var individualcommit = options.individualcommit || true; // otherwise no data
var replace = options.replace || false;
var create = options.create || true;
var useallspace = options.useallspace || false;
var metadataonly = options.metadataonly || false;
var fixfssdata = options.fixfssdata || null;
var fixfssmetadata = options.fixfssmetadata || null;
if (bckfiles == null || bckfiles.length === 0) {
doError(new Error('No backup file specified'), callback);
return;
}
if (dbfile == null || dbfile.length === 0) {
doError(new Error('No database path specified'), callback);
return;
}
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_restore);
for (var i = 0; i < bckfiles.length; i++) {
blr.addString2(Const.isc_spb_bkp_file, bckfiles[i], Const.DEFAULT_ENCODING);
}
blr.addString2(Const.isc_spb_dbname, dbfile, Const.DEFAULT_ENCODING);
blr.addByte(Const.isc_spb_res_buffers);
blr.addInt32(cachebuffers);
blr.addByte(Const.isc_spb_res_page_size);
blr.addInt32(pagesize);
blr.addByte(Const.isc_spb_res_access_mode);
if (readonly)
blr.addByte(Const.isc_spb_prp_am_readonly);
else
blr.addByte(Const.isc_spb_prp_am_readwrite);
if (fixfssdata) blr.addString2(Const.isc_spb_res_fix_fss_data, fixfssdata, Const.DEFAULT_ENCODING);
if (fixfssmetadata) blr.addString2(Const.isc_spb_res_fix_fss_metadata, fixfssmetadata, Const.DEFAULT_ENCODING);
var opts = 0;
if (deactivateindexes) opts = opts | Const.isc_spb_res_deactivate_idx;
if (noshadow) opts = opts | Const.isc_spb_res_no_shadow;
if (novalidity) opts = opts | Const.isc_spb_res_no_validity;
if (individualcommit) opts = opts | Const.isc_spb_res_one_at_a_time;
if (replace) opts = opts | Const.isc_spb_res_replace;
if (create) opts = opts | Const.isc_spb_res_create;
if (useallspace) opts = opts | Const.isc_spb_res_use_all_space;
if (metadataonly) opts = opts | Const.isc_spb_res_fix_fss_metadata;
if (opts)
blr.addByteInt32(Const.isc_spb_options, opts);
if (verbose)
blr.addByte(Const.isc_spb_verbose);
var self = this;
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.nrestore = function (options, callback) {
var bckfiles = options.backupfiles || options.files || null; // format bckfiles ['file1', 'file2', 'file3']
// for convenience
if (bckfiles) bckfiles = bckfiles.constructor !== Array?[bckfiles]:bckfiles;
var dbpath = options.database || this.connection.options.filename || this.connection.options.database;
if (bckfiles == null || bckfiles.length === 0) {
doError(new Error('No backup file specified'), callback);
return;
}
if (dbpath == null || bckfiles.length === 0) {
doError(new Error('No database path specified'), callback);
return;
}
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_nrest);
for (var i = 0; i < bckfiles.length; i++) {
blr.addString2(Const.isc_spb_nbk_file, bckfiles[i], Const.DEFAULT_ENCODING);
}
blr.addString2(Const.isc_spb_dbname, dbpath, Const.DEFAULT_ENCODING);
var self = this;
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
// only one at time don't use this function directly
ServiceManager.prototype._fixpropertie = function (options, callback) {
var dbpath = options.database || this.connection.options.filename || this.connection.options.database;
var dialect = options.dialect || null;
var sweep = options.sweepinterval || null;
var pagebuffers = options.nbpagebuffers || null;
var online = options.bringonline || false;
var shutdown = options.shutdown != null ? options.shutdown : null; // 0 Forced, 1 deny transaction, 2 deny attachment
var shutdowndelay = options.shutdowndelay || 0;
var shutdownmode = options.shutdownmode; // 0 normal 1 multi 2 single 3 full
var shadow = options.activateshadow || false;
var forcewrite = options.forcewrite;
var reservespace = options.reservespace;
var accessmode = options.accessmode; // 0 readonly 1 readwrite
if (dbpath == null || dbpath.length === 0) {
doError(new Error('No database specified'), callback);
return;
}
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_properties);
blr.addString2(Const.isc_spb_dbname, dbpath, Const.DEFAULT_ENCODING);
if (dialect) blr.addByteInt32(Const.isc_spb_prp_set_sql_dialect, dialect);
if (sweep) blr.addByteInt32(Const.isc_spb_prp_sweep_interval, sweep);
if (pagebuffers) blr.addByteInt32(Const.isc_spb_prp_page_buffers, pagebuffers);
if (shutdown != null) {
if (shutdownmode != null) {
if (SHUTDOWNEX_KIND[shutdown] === undefined) {
doError(new Error('Invalid shutdown kind'), callback);
return;
}
if (SHUTDOWNEX_MODE[shutdownmode] === undefined) {
doError(new Error('Invalid shutdown mode'), callback);
return;
}
// New shutdown with mode
blr.addBytes([Const.isc_spb_prp_shutdown_mode, SHUTDOWNEX_MODE[shutdownmode]]);
blr.addByteInt32(SHUTDOWNEX_KIND[shutdown], shutdowndelay);
} else {
// Old shutdown
blr.addByteInt32(SHUTDOWN_KIND[shutdown], shutdowndelay);
}
}
if (forcewrite) blr.addBytes([Const.isc_spb_prp_write_mode, Const.isc_spb_prp_wm_sync]);
if (forcewrite === false) blr.addBytes([Const.isc_spb_prp_write_mode, Const.isc_spb_prp_wm_async]);
if (accessmode === 1) blr.addBytes([Const.isc_spb_prp_access_mode, Const.isc_spb_prp_am_readwrite]);
if (accessmode === 0) blr.addBytes([Const.isc_spb_prp_access_mode, Const.isc_spb_prp_am_readonly]);
if (reservespace) blr.addBytes([Const.isc_spb_prp_reserve_space, Const.isc_spb_prp_res]);
if (reservespace != null && !reservespace) blr.addBytes([Const.isc_spb_prp_reserve_space, Const.isc_spb_prp_res_use_full]);
var opts = 0;
if (shadow) opts = opts | Const.isc_spb_prp_activate;
if (online) opts = opts | Const.isc_spb_prp_db_online;
if (opts)
blr.addByteInt32(Const.isc_spb_options, opts);
var self = this;
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.setDialect = function (db, dialect, callback) {
this._fixpropertie({ database: db, dialect: dialect }, callback);
}
ServiceManager.prototype.setSweepinterval = function (db, sweepinterval, callback) {
this._fixpropertie({ database: db, sweepinterval: sweepinterval }, callback);
}
ServiceManager.prototype.setCachebuffer = function (db, nbpages, callback) {
this._fixpropertie({ database: db, nbpagebuffers: nbpages }, callback);
}
ServiceManager.prototype.BringOnline = function (db, callback) {
this._fixpropertie({ database: db, bringonline: true }, callback);
}
const SHUTDOWN_KIND = {
0: Const.isc_spb_prp_shutdown_db,
1: Const.isc_spb_prp_deny_new_transactions,
2: Const.isc_spb_prp_deny_new_attachments
};
const SHUTDOWNEX_KIND = {
0: Const.isc_spb_prp_force_shutdown,
1: Const.isc_spb_prp_transactions_shutdown,
2: Const.isc_spb_prp_attachments_shutdown
};
const SHUTDOWNEX_MODE = {
//0: isc_spb_prp_sm_normal,
1: Const.isc_spb_prp_sm_multi,
2: Const.isc_spb_prp_sm_single,
3: Const.isc_spb_prp_sm_full
};
const ShutdownMode = { NORMAL: 0, MULTI: 1, SINGLE: 2, FULL: 3 };
const ShutdownKind = { FORCED: 0, DENY_TRANSACTION: 1, DENY_ATTACHMENT: 2 };
exports.ShutdownMode = ShutdownMode;
exports.ShutdownKind = ShutdownKind;
ServiceManager.prototype.Shutdown = function (db, kind, delay, mode, callback) {
// mode parameter is for server version >= 2.0
if (mode instanceof Function) {
callback = mode;
mode = undefined;
}
this._fixpropertie({ database: db, shutdown: kind, shutdowndelay: delay, shutdownmode: mode }, callback);
}
ServiceManager.prototype.setShadow = function (db, val, callback) {
this._fixpropertie({ database: db, activateshadow : val }, callback);
}
ServiceManager.prototype.setForcewrite = function (db, val, callback) {
this._fixpropertie({ database: db, forcewrite : val }, callback);
}
ServiceManager.prototype.setReservespace = function (db, val, callback) {
this._fixpropertie({ database: db, reservespace : val }, callback);
}
ServiceManager.prototype.setReadonlyMode = function (db, callback) {
this._fixpropertie({ database: db, accessmode : 0 }, callback);
}
ServiceManager.prototype.setReadwriteMode = function (db, callback) {
this._fixpropertie({ database: db, accessmode : 1 }, callback);
}
ServiceManager.prototype.validate = function (options, callback) {
var dbpath = options.database || this.connection.options.filename || this.connection.options.database;
var checkdb = options.checkdb || false;
var ignorechecksums = options.ignorechecksums || false;
var killshadows = options.killshadows || false;
var mend = options.mend || false;
var validate = options.validate || false;
var full = options.full || false;
var sweep = options.sweep || false;
var listlimbo = options.listlimbo || false;
var icu = options.icu || false;
if (dbpath == null || dbpath.length === 0) {
doError(new Error('No database specified'), callback);
return;
}
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_repair);
blr.addString2(Const.isc_spb_dbname, dbpath, Const.DEFAULT_ENCODING);
var opts = 0;
if (checkdb) opts = opts | Const.isc_spb_rpr_check_db;
if (ignorechecksums) opts = opts | Const.isc_spb_rpr_ignore_checksum;
if (killshadows) opts = opts | Const.isc_spb_rpr_kill_shadows;
if (mend) opts = opts | Const.isc_spb_rpr_mend_db;
if (validate) opts = opts | Const.isc_spb_rpr_validate_db;
if (full) opts = opts | Const.isc_spb_rpr_full;
if (sweep) opts = opts | Const.isc_spb_rpr_sweep_db;
if (listlimbo) opts = opts | Const.isc_spb_rpr_list_limbo_trans;
if (icu) opts = opts | Const.isc_spb_rpr_icu;
blr.addByteInt32(Const.isc_spb_options, opts);
var self = this;
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.commit = function(db, transactid, callback) {
var dbpath = db || this.connection.options.filename || this.connection.options.database;
if (dbpath == null || dbpath.length === 0) {
doError(new Error('No database specified'), callback);
return;
}
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_repair);
blr.addString2(Const.isc_spb_dbname, dbpath, Const.DEFAULT_ENCODING);
blr.addByteInt32(Const.isc_spb_rpr_commit_trans, transactid);
var self = this;
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(null, null, callback);
});
}
ServiceManager.prototype.rollback = function (db, transactid, callback) {
var dbpath = db || this.connection.options.filename || this.connection.options.database;
if (dbpath == null || dbpath.length === 0) {
doError(new Error('No database specified'), callback);
return;
}
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_repair);
blr.addString2(Const.isc_spb_dbname, dbpath, Const.DEFAULT_ENCODING);
blr.addByteInt32(Const.isc_spb_rpr_rollback_trans, transactid);
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(null, null, callback);
});
}
ServiceManager.prototype.recover = function (db, transactid, callback) {
var dbpath = db || this.connection.options.filename || this.connection.options.database;
if (dbpath == null || dbpath.length === 0) {
doError(new Error('No database specified'), callback);
return;
}
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_repair);
blr.addString2(Const.isc_spb_dbname, dbpath, Const.DEFAULT_ENCODING);
blr.addByteInt32(Const.isc_spb_rpr_recover_two_phase, transactid);
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(null, null, callback);
});
}
ServiceManager.prototype.getStats = function (options, callback) {
var dbpath = options.database || this.connection.options.filename || this.connection.options.database;
var record = options.record || false;
var nocreation = options.nocreation || false;
var tables = options.tables || false;
var pages = options.pages || false;
var header = options.header || false;
var indexes = options.indexes || false;
var tablesystem = options.tablesystem || false;
var encryption = options.encryption || false;
var objects = options.objects || null; // space-separated list of object index,table,systemtable
if (dbpath == null || dbpath.length === 0) {
doError(new Error('No database specified'), callback);
return;
}
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_db_stats);
blr.addString2(Const.isc_spb_dbname, dbpath, Const.DEFAULT_ENCODING);
var opts = 0;
if (record) opts = opts | Const.isc_spb_sts_record_versions;
if (nocreation) opts = opts | Const.isc_spb_sts_nocreation;
if (tables) opts = opts | Const.isc_spb_sts_table;
if (pages) opts = opts | Const.isc_spb_sts_data_pages;
if (header) opts = opts | Const.isc_spb_sts_hdr_pages;
if (indexes) opts = opts | Const.isc_spb_sts_idx_pages;
if (tablesystem) opts = opts | Const.isc_spb_sts_sys_relations;
if (encryption) opts = opts | Const.isc_spb_sts_encryption;
if (opts)
blr.addByteInt32(Const.isc_spb_options, opts);
if (objects) blr.addString2(Const.isc_spb_command_line, objects, Const.DEFAULT_ENCODING);
var self = this;
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.getLog = function (options, callback) {
var self = this;
var blr = this.connection._blr;
var optread = options.optread || 'byline';
blr.pos = 0;
blr.addByte(Const.isc_action_svc_get_fb_log);
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(optread, options.buffersize, callback);
});
}
ServiceManager.prototype.getUsers = function (username, callback) {
var self = this;
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_display_user);
if (username) blr.addString2(Const.isc_spb_sec_username, username, Const.DEFAULT_ENCODING);
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self.readusers({}, callback);
});
}
ServiceManager.prototype.addUser = function (username, password, options, callback) {
var rolename = options.rolename || null;
var groupname = options.groupname || null;
var firsname = options.firstname || null;
var middlename = options.middlename || null;
var lastname = options.lastname || null;
var userid = options.userid || null;
var groupid = options.groupid || null;
var admin = options.admin || null;
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_add_user);
blr.addString2(Const.isc_spb_sec_username, username, Const.DEFAULT_ENCODING);
blr.addString2(Const.isc_spb_sec_password, password, Const.DEFAULT_ENCODING);
if (rolename) blr.addString2(Const.isc_dpb_sql_role_name, rolename, Const.DEFAULT_ENCODING);
if (groupname) blr.addString2(Const.isc_spb_sec_groupname, groupname, Const.DEFAULT_ENCODING);
if (firsname) blr.addString2(Const.isc_spb_sec_firstname, firsname, Const.DEFAULT_ENCODING);
if (middlename) blr.addString2(Const.isc_spb_sec_middlename, middlename, Const.DEFAULT_ENCODING);
if (lastname) blr.addString2(Const.isc_spb_sec_lastname, lastname, Const.DEFAULT_ENCODING);
if (userid != null) blr.addByteInt32(Const.isc_spb_sec_userid, userid);
if (groupid != null) blr.addByteInt32(Const.isc_spb_sec_groupid, groupid);
if (admin != null) blr.addByteInt32(Const.isc_spb_sec_admin, admin);
var self = this;
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.editUser = function (username, options, callback) {
var rolename = options.rolename || null;
var groupname = options.groupname || null;
var firsname = options.firstname || null;
var middlename = options.middlename || null;
var lastname = options.lastname || null;
var userid = options.userid || null;
var groupid = options.groupid || null;
var admin = options.admin || null;
var password = options.password || null;
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_modify_user);
blr.addString2(Const.isc_spb_sec_username, username, Const.DEFAULT_ENCODING);
if (password) blr.addString2(Const.isc_spb_sec_password, password, Const.DEFAULT_ENCODING);
if (rolename) blr.addString2(Const.isc_dpb_sql_role_name, rolename, Const.DEFAULT_ENCODING);
if (groupname) blr.addString2(Const.isc_spb_sec_groupname, groupname, Const.DEFAULT_ENCODING);
if (firsname) blr.addString2(Const.isc_spb_sec_firstname, firsname, Const.DEFAULT_ENCODING);
if (middlename) blr.addString2(Const.isc_spb_sec_middlename, middlename, Const.DEFAULT_ENCODING);
if (lastname) blr.addString2(Const.isc_spb_sec_lastname, lastname, Const.DEFAULT_ENCODING);
if (userid != null) blr.addByteInt32(Const.isc_spb_sec_userid, userid);
if (groupid != null) blr.addByteInt32(Const.isc_spb_sec_groupid, groupid);
if (admin != null) blr.addByteInt32(Const.isc_spb_sec_admin, admin);
var self = this;
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.removeUser = function (username, rolename, callback) {
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_delete_user);
blr.addString2(Const.isc_spb_sec_username, username, Const.DEFAULT_ENCODING);
if (rolename) blr.addString2(Const.isc_dpb_sql_role_name, rolename, Const.DEFAULT_ENCODING);
var self = this, options = {};
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.getFbserverInfos = function (infos, options, callback) {
var buffersize = options.buffersize || 2048;
var timeout = options.timeout || 1;
var opts = {
"dbinfo" : Const.isc_info_svc_svr_db_info,
"fbconfig" : Const.isc_info_svc_get_config,
"svcversion" : Const.isc_info_svc_version,
"fbversion" : Const.isc_info_svc_server_version,
"fbimplementation" : Const.isc_info_svc_implementation,
"fbcapatibilities" : Const.isc_info_svc_capabilities,
"pathsecuritydb" : Const.isc_info_svc_user_dbpath,
"fbenv" : Const.isc_info_svc_get_env,
"fbenvlock" : Const.isc_info_svc_get_env_lock,
"fbenvmsg" : Const.isc_info_svc_get_env_msg
};
// if infos is empty all options are asked to the service
var tops = [], empty = isEmpty(infos);
for (let popts in opts)
if (empty || infos[popts])
tops.push(opts[popts]);
var self = this;
this.connection.svcquery(tops, buffersize, timeout, function (err, data) {
if (err || !data.buffer) {
doError(new Error(err||'Bad query return'), callback);
return;
}
self._processquery(data.buffer, callback);
});
}
function isEmpty(obj){
for(var p in obj) return false;
return true;
}
ServiceManager.prototype.startTrace = function (options, callback) {
var self = this;
var blr = this.connection._blr;
var configfile = options.configfile || '';
var tracename = options.tracename || '';
if (configfile.length === 0) {
doError(new Error('No config filename specified'), callback);
return;
}
if (tracename.length === 0) {
doError(new Error('No tracename specified'), callback);
return;
}
blr.pos = 0;
blr.addByte(Const.isc_action_svc_trace_start);
blr.addString2(Const.isc_spb_trc_cfg, configfile, Const.DEFAULT_ENCODING);
blr.addString2(Const.isc_spb_trc_name, tracename, Const.DEFAULT_ENCODING);
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.suspendTrace = function (options, callback) {
var self = this;
var blr = this.connection._blr;
var traceid = options.traceid || null;
if (traceid == null) {
doError(new Error('No traceid specified'), callback);
return;
}
blr.pos = 0;
blr.addByte(Const.isc_action_svc_trace_suspend);
blr.addByteInt32(Const.isc_spb_trc_id, traceid);
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.resumeTrace = function (options, callback) {
var self = this;
var blr = this.connection._blr;
var traceid = options.traceid || null;
if (traceid == null) {
doError(new Error('No traceid specified'), callback);
return;
}
blr.pos = 0;
blr.addByte(Const.isc_action_svc_trace_resume);
blr.addByteInt32(Const.isc_spb_trc_id, traceid);
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.stopTrace = function (options, callback) {
var self = this;
var blr = this.connection._blr;
var traceid = options.traceid || null;
if (traceid == null) {
doError(new Error('No traceid specified'), callback);
return;
}
blr.pos = 0;
blr.addByte(Const.isc_action_svc_trace_stop);
blr.addByteInt32(Const.isc_spb_trc_id, traceid);
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.getTraceList = function (options, callback) {
var self = this;
var blr = this.connection._blr;
blr.pos = 0;
blr.addByte(Const.isc_action_svc_trace_list);
this.connection.svcstart(blr, function (err, data) {
if (err) {
doError(new Error(err), callback);
return;
}
self._createOutputStream(options.optread, options.buffersize, callback);
});
}
ServiceManager.prototype.readline = function (options, callback) {
var buffersize = options.buffersize || 2048;
var timeout = options.timeout || 60;
var self = this;
this.connection.svcquery([Const.isc_info_svc_line], buffersize, timeout, function (err, data) {
if (err || !data.buffer) {
doError(new Error(err||'Bad query return'), callback);
return;
}
self._processquery(data.buffer, callback);
});
}
ServiceManager.prototype.readeof = function (options, callback) {
var buffersize = options.buffersize || (8 * 1024);
var timeout = options.timeout || 60;
var self = this;
this.connection.svcquery([Const.isc_info_svc_to_eof], buffersize, timeout, function (err, data) {
if (err || !data.buffer) {
doError(new Error(err||'Bad query return'), callback);
return;
}
self._processquery(data.buffer, callback);
});
}
ServiceManager.prototype.hasRunningAction = function (options, callback) {
var buffersize = options.buffersize || 2048;
var timeout = options.timeout || 60;
var self = this;
this.connection.svcquery([Const.isc_info_svc_running], buffersize, timeout, function (err, data) {
if (err || !data.buffer) {
doError(new Error(err||'Bad query return'), callback);
return;
}
self._processquery(data.buffer, callback);
});
}
ServiceManager.prototype.readusers = function (options, callback) {
var buffersize = options.buffersize || 2048;
var timeout = options.timeout || 60;
var self = this;
this.connection.svcquery([Const.isc_info_svc_get_users], buffersize, timeout, function (err, data) {
if (err || !data.buffer) {
doError(new Error(err||'Bad query return'), callback);
return;
}
self._processquery(data.buffer, callback);
});
}
ServiceManager.prototype.readlimbo = function (options, callback) {
var buffersize = options.buffersize || 2048;
var timeout = options.timeout || 60;
var self = this;
this.connection.svcquery([Const.isc_info_svc_limbo_trans], buffersize, timeout, function (err, data) {
if (err || !data.buffer) {
doError(new Error(err||'Bad query return'), callback);
return;
}
self._processquery(data.buffer, callback);
});
}
module.exports = ServiceManager;