mssql2
Version:
Microsoft SQL Server client for Node.js (fork)
830 lines (779 loc) • 29.9 kB
JavaScript
// Generated by CoffeeScript 1.10.0
(function() {
var CONNECTION_STRING_NAMED_INSTANCE, CONNECTION_STRING_PORT, DECLARATIONS, EMPTY_BUFFER, ISOLATION_LEVEL, JSON_COLUMN_ID, Pool, TYPES, UDT, XML_COLUMN_ID, castParameter, createColumns, declare, isolationLevelDeclaration, msnodesql, ref, util, valueCorrection,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
Pool = require('generic-pool').Pool;
msnodesql = require('msnodesqlv8');
util = require('util');
ref = require('./datatypes'), TYPES = ref.TYPES, declare = ref.declare;
UDT = require('./udt').PARSERS;
ISOLATION_LEVEL = require('./isolationlevel');
DECLARATIONS = require('./datatypes').DECLARATIONS;
EMPTY_BUFFER = new Buffer(0);
JSON_COLUMN_ID = 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B';
XML_COLUMN_ID = 'XML_F52E2B61-18A1-11d1-B105-00805F49916B';
CONNECTION_STRING_PORT = 'Driver={SQL Server Native Client 11.0};Server={#{server},#{port}};Database={#{database}};Uid={#{user}};Pwd={#{password}};Trusted_Connection={#{trusted}};';
CONNECTION_STRING_NAMED_INSTANCE = 'Driver={SQL Server Native Client 11.0};Server={#{server}\\#{instance}};Database={#{database}};Uid={#{user}};Pwd={#{password}};Trusted_Connection={#{trusted}};';
/*
@ignore
*/
castParameter = function(value, type) {
if (value == null) {
if (type === TYPES.Binary || type === TYPES.VarBinary || type === TYPES.Image) {
return EMPTY_BUFFER;
}
return null;
}
switch (type) {
case TYPES.VarChar:
case TYPES.NVarChar:
case TYPES.Char:
case TYPES.NChar:
case TYPES.Xml:
case TYPES.Text:
case TYPES.NText:
if (typeof value !== 'string' && !(value instanceof String)) {
value = value.toString();
}
break;
case TYPES.Int:
case TYPES.TinyInt:
case TYPES.BigInt:
case TYPES.SmallInt:
if (typeof value !== 'number' && !(value instanceof Number)) {
value = parseInt(value);
if (isNaN(value)) {
value = null;
}
}
break;
case TYPES.Float:
case TYPES.Real:
case TYPES.Decimal:
case TYPES.Numeric:
case TYPES.SmallMoney:
case TYPES.Money:
if (typeof value !== 'number' && !(value instanceof Number)) {
value = parseFloat(value);
if (isNaN(value)) {
value = null;
}
}
break;
case TYPES.Bit:
if (typeof value !== 'boolean' && !(value instanceof Boolean)) {
value = Boolean(value);
}
break;
case TYPES.DateTime:
case TYPES.SmallDateTime:
case TYPES.DateTimeOffset:
case TYPES.Date:
if (!(value instanceof Date)) {
value = new Date(value);
}
break;
case TYPES.Binary:
case TYPES.VarBinary:
case TYPES.Image:
if (!(value instanceof Buffer)) {
value = new Buffer(value.toString());
}
}
return value;
};
/*
@ignore
*/
createColumns = function(metadata) {
var column, i, index, len, out;
out = {};
for (index = i = 0, len = metadata.length; i < len; index = ++i) {
column = metadata[index];
out[column.name] = {
index: index,
name: column.name,
length: column.size,
type: DECLARATIONS[column.sqlType]
};
if (column.udtType != null) {
out[column.name].udt = {
name: column.udtType
};
if (DECLARATIONS[column.udtType]) {
out[column.name].type = DECLARATIONS[column.udtType];
}
}
}
return out;
};
/*
@ignore
*/
isolationLevelDeclaration = function(type) {
switch (type) {
case ISOLATION_LEVEL.READ_UNCOMMITTED:
return "READ UNCOMMITTED";
case ISOLATION_LEVEL.READ_COMMITTED:
return "READ COMMITTED";
case ISOLATION_LEVEL.REPEATABLE_READ:
return "REPEATABLE READ";
case ISOLATION_LEVEL.SERIALIZABLE:
return "SERIALIZABLE";
case ISOLATION_LEVEL.SNAPSHOT:
return "SNAPSHOT";
default:
throw new TransactionError("Invalid isolation level.");
}
};
/*
@ignore
*/
valueCorrection = function(value, metadata) {
if (metadata.sqlType === 'time' && (value != null)) {
value.setFullYear(1970);
return value;
} else if (metadata.sqlType === 'udt' && (value != null)) {
if (UDT[metadata.udtType]) {
return UDT[metadata.udtType](value);
} else {
return value;
}
} else {
return value;
}
};
/*
@ignore
*/
module.exports = function(Connection, Transaction, Request, ConnectionError, TransactionError, RequestError) {
var MsnodesqlConnection, MsnodesqlRequest, MsnodesqlTransaction;
MsnodesqlConnection = (function(superClass) {
extend(MsnodesqlConnection, superClass);
function MsnodesqlConnection() {
return MsnodesqlConnection.__super__.constructor.apply(this, arguments);
}
MsnodesqlConnection.prototype.pool = null;
MsnodesqlConnection.prototype.connect = function(config, callback) {
var cfg, cfg_pool, defaultConnectionString, key, ref1, ref2, ref3, ref4, value;
defaultConnectionString = CONNECTION_STRING_PORT;
if (config.options.instanceName != null) {
defaultConnectionString = CONNECTION_STRING_NAMED_INSTANCE;
}
cfg = {
conn_str: (ref1 = config.connectionString) != null ? ref1 : defaultConnectionString,
conn_timeout: ((ref2 = (ref3 = config.connectionTimeout) != null ? ref3 : config.timeout) != null ? ref2 : 15000) / 1000
};
cfg.conn_str = cfg.conn_str.replace(new RegExp('#{([^}]*)}', 'g'), function(p) {
var key, ref4;
key = p.substr(2, p.length - 3);
if (key === 'instance') {
return config.options.instanceName;
} else if (key === 'trusted') {
if (config.options.trustedConnection) {
return 'Yes';
} else {
return 'No';
}
} else {
return (ref4 = config[key]) != null ? ref4 : '';
}
});
cfg_pool = {
name: 'mssql',
max: 10,
min: 0,
idleTimeoutMillis: 30000,
create: (function(_this) {
return function(callback) {
return msnodesql.open(cfg, function(err, c) {
if (err) {
err = ConnectionError(err);
}
if (err) {
return callback(err, null);
}
return callback(null, c);
});
};
})(this),
validate: function(c) {
return (c != null) && !c.hasError;
},
destroy: function(c) {
return c != null ? c.close() : void 0;
}
};
if (config.pool) {
ref4 = config.pool;
for (key in ref4) {
value = ref4[key];
cfg_pool[key] = value;
}
}
this.pool = Pool(cfg_pool, cfg);
return this.pool.acquire((function(_this) {
return function(err, connection) {
if (err && !(err instanceof Error)) {
err = new Error(err);
}
if (err) {
_this.pool.drain(function() {
var ref5;
if ((ref5 = _this.pool) != null) {
ref5.destroyAllNow();
}
return _this.pool = null;
});
} else {
_this.pool.release(connection);
}
return callback(err);
};
})(this));
};
MsnodesqlConnection.prototype.close = function(callback) {
if (!this.pool) {
return callback(null);
}
return this.pool.drain((function(_this) {
return function() {
var ref1;
if ((ref1 = _this.pool) != null) {
ref1.destroyAllNow();
}
_this.pool = null;
return callback(null);
};
})(this));
};
return MsnodesqlConnection;
})(Connection);
MsnodesqlTransaction = (function(superClass) {
extend(MsnodesqlTransaction, superClass);
function MsnodesqlTransaction() {
return MsnodesqlTransaction.__super__.constructor.apply(this, arguments);
}
MsnodesqlTransaction.prototype.begin = function(callback) {
return this.connection.pool.acquire((function(_this) {
return function(err, connection) {
if (err) {
return callback(err);
}
_this._pooledConnection = connection;
return _this.request()._dedicated(_this._pooledConnection).query("set transaction isolation level " + (isolationLevelDeclaration(_this.isolationLevel)) + ";begin tran;", callback);
};
})(this));
};
MsnodesqlTransaction.prototype.commit = function(callback) {
return this.request()._dedicated(this._pooledConnection).query('commit tran', (function(_this) {
return function(err) {
_this.connection.pool.release(_this._pooledConnection);
_this._pooledConnection = null;
return callback(err);
};
})(this));
};
MsnodesqlTransaction.prototype.rollback = function(callback) {
return this.request()._dedicated(this._pooledConnection).query('rollback tran', (function(_this) {
return function(err) {
_this.connection.pool.release(_this._pooledConnection);
_this._pooledConnection = null;
return callback(err);
};
})(this));
};
return MsnodesqlTransaction;
})(Transaction);
MsnodesqlRequest = (function(superClass) {
extend(MsnodesqlRequest, superClass);
function MsnodesqlRequest() {
return MsnodesqlRequest.__super__.constructor.apply(this, arguments);
}
MsnodesqlRequest.prototype.batch = function(batch, callback) {
return MsnodesqlRequest.prototype.query.call(this, batch, callback);
};
MsnodesqlRequest.prototype.bulk = function(table, callback) {
var started;
table._makeBulk();
if (!table.name) {
process.nextTick(function() {
return callback(RequestError("Table name must be specified for bulk insert.", "ENAME"));
});
}
if (table.name.charAt(0) === '@') {
process.nextTick(function() {
return callback(RequestError("You can't use table variables for bulk insert.", "ENAME"));
});
}
started = Date.now();
return this._acquire((function(_this) {
return function(err, connection) {
var done, elapsed, go, objectid, req;
if (!err) {
if (_this.verbose) {
_this._log("-------- sql bulk load --------\n table: " + table.name);
}
done = function(err, rowCount) {
var e, elapsed;
if (err) {
if ('string' === typeof err.sqlstate && err.sqlstate.toLowerCase() === '08s01') {
connection.hasError = true;
}
e = RequestError(err);
if (/^\[Microsoft\]\[SQL Server Native Client 11\.0\](?:\[SQL Server\])?([\s\S]*)$/.exec(err.message)) {
e.message = RegExp.$1;
}
e.code = 'EREQUEST';
if (_this.verbose && !_this.nested) {
_this._log(" error: " + e);
}
}
if (_this.verbose) {
elapsed = Date.now() - started;
_this._log(" duration: " + elapsed + "ms");
_this._log("---------- completed ----------");
}
_this._release(connection);
if (e) {
return typeof callback === "function" ? callback(e) : void 0;
} else {
return typeof callback === "function" ? callback(null, table.rows.length) : void 0;
}
};
go = function() {
var tm;
tm = connection.tableMgr();
return tm.bind(table.path.replace(/\[|\]/g, ''), function(mgr) {
var col, i, index, item, j, len, len1, ref1, ref2, row, rows;
if (mgr.columns.length === 0) {
return done(new RequestError("Table was not found on the server.", "ENAME"));
}
rows = [];
ref1 = table.rows;
for (i = 0, len = ref1.length; i < len; i++) {
row = ref1[i];
item = {};
ref2 = table.columns;
for (index = j = 0, len1 = ref2.length; j < len1; index = ++j) {
col = ref2[index];
item[col.name] = row[index];
}
rows.push(item);
}
return mgr.insertRows(rows, done);
});
};
if (table.create) {
if (table.temporary) {
objectid = "tempdb..[" + table.name + "]";
} else {
objectid = table.path;
}
if (_this.verbose) {
elapsed = Date.now() - started;
_this._log(" message: attempting to create table " + table.path + " if not exists");
}
return req = connection.queryRaw("if object_id('" + (objectid.replace(/'/g, '\'\'')) + "') is null " + (table.declare()), function(err) {
if (err) {
return done(err);
}
return go();
});
} else {
return go();
}
}
};
})(this));
};
MsnodesqlRequest.prototype.query = function(command, callback) {
var chunksBuffer, columns, handleOutput, input, isChunkedRecordset, name, output, param, recordset, recordsets, row, sets, started;
if (command.length === 0) {
return process.nextTick(function() {
var elapsed;
if (this.verbose && !this.nested) {
this._log("---------- response -----------");
elapsed = Date.now() - started;
this._log(" duration: " + elapsed + "ms");
this._log("---------- completed ----------");
}
return typeof callback === "function" ? callback(null, this.multiple || this.nested ? [] : null) : void 0;
});
}
row = null;
columns = null;
recordset = null;
recordsets = [];
started = Date.now();
handleOutput = false;
isChunkedRecordset = false;
chunksBuffer = null;
if (!this.nested) {
input = (function() {
var ref1, results;
ref1 = this.parameters;
results = [];
for (name in ref1) {
param = ref1[name];
results.push("@" + param.name + " " + (declare(param.type, param)));
}
return results;
}).call(this);
sets = (function() {
var ref1, results;
ref1 = this.parameters;
results = [];
for (name in ref1) {
param = ref1[name];
if (param.io === 1) {
results.push("set @" + param.name + "=?");
}
}
return results;
}).call(this);
output = (function() {
var ref1, results;
ref1 = this.parameters;
results = [];
for (name in ref1) {
param = ref1[name];
if (param.io === 2) {
results.push("@" + param.name + " as '" + param.name + "'");
}
}
return results;
}).call(this);
if (input.length) {
command = "declare " + (input.join(',')) + ";" + (sets.join(';')) + ";" + command + ";";
}
if (output.length) {
command += "select " + (output.join(',')) + ";";
handleOutput = true;
}
}
return this._acquire((function(_this) {
return function(err, connection) {
var req;
if (!err) {
if (_this.verbose && !_this.nested) {
_this._log("---------- sql query ----------\n query: " + command);
}
req = connection.queryRaw(command, (function() {
var ref1, results;
ref1 = this.parameters;
results = [];
for (name in ref1) {
param = ref1[name];
if (param.io === 1) {
results.push(castParameter(param.value, param.type));
}
}
return results;
}).call(_this));
if (_this.verbose && !_this.nested) {
_this._log("---------- response -----------");
}
req.on('meta', function(metadata) {
var error, ex, ref1;
if (row) {
if (isChunkedRecordset) {
if (columns[0].name === JSON_COLUMN_ID && _this.connection.config.parseJSON === true) {
try {
row = JSON.parse(chunksBuffer.join(''));
if (!_this.stream) {
recordsets[recordsets.length - 1][0] = row;
}
} catch (error) {
ex = error;
row = null;
ex = RequestError(new Error("Failed to parse incoming JSON. " + ex.message), 'EJSON');
if (_this.stream) {
_this.emit('error', ex);
} else {
console.error(ex);
}
}
} else {
row[columns[0].name] = chunksBuffer.join('');
}
chunksBuffer = null;
}
if (_this.verbose) {
_this._log(util.inspect(row));
_this._log("---------- --------------------");
}
if (row["___return___"] == null) {
if (_this.stream) {
_this.emit('row', row);
}
}
}
row = null;
columns = metadata;
recordset = [];
Object.defineProperty(recordset, 'columns', {
enumerable: false,
value: createColumns(metadata)
});
isChunkedRecordset = false;
if (metadata.length === 1 && ((ref1 = metadata[0].name) === JSON_COLUMN_ID || ref1 === XML_COLUMN_ID)) {
isChunkedRecordset = true;
chunksBuffer = [];
}
if (_this.stream) {
if (recordset.columns["___return___"] == null) {
return _this.emit('recordset', recordset.columns);
}
} else {
return recordsets.push(recordset);
}
});
req.on('row', function(rownumber) {
if (row) {
if (isChunkedRecordset) {
return;
}
if (_this.verbose) {
_this._log(util.inspect(row));
_this._log("---------- --------------------");
}
if (row["___return___"] == null) {
if (_this.stream) {
_this.emit('row', row);
}
}
}
row = {};
if (!_this.stream) {
return recordset.push(row);
}
});
req.on('column', function(idx, data, more) {
var exi;
if (isChunkedRecordset) {
return chunksBuffer.push(data);
} else {
data = valueCorrection(data, columns[idx]);
exi = row[columns[idx].name];
if (exi != null) {
if (exi instanceof Array) {
return exi.push(data);
} else {
return row[columns[idx].name] = [exi, data];
}
} else {
return row[columns[idx].name] = data;
}
}
});
req.on('rowcount', function(count) {
if (count > 0) {
return _this.rowsAffected += count;
}
});
req.once('error', function(err) {
var e, elapsed;
if ('string' === typeof err.sqlstate && err.sqlstate.toLowerCase() === '08s01') {
connection.hasError = true;
}
e = RequestError(err);
if (/^\[Microsoft\]\[SQL Server Native Client 11\.0\](?:\[SQL Server\])?([\s\S]*)$/.exec(err.message)) {
e.message = RegExp.$1;
}
e.code = 'EREQUEST';
if (_this.verbose && !_this.nested) {
elapsed = Date.now() - started;
_this._log(" error: " + err);
_this._log(" duration: " + elapsed + "ms");
_this._log("---------- completed ----------");
}
_this._release(connection);
return typeof callback === "function" ? callback(e) : void 0;
});
return req.once('done', function() {
var elapsed, error, ex, last, ref1, ref2;
if (!_this.nested) {
if (row) {
if (isChunkedRecordset) {
if (columns[0].name === JSON_COLUMN_ID && _this.connection.config.parseJSON === true) {
try {
row = JSON.parse(chunksBuffer.join(''));
if (!_this.stream) {
recordsets[recordsets.length - 1][0] = row;
}
} catch (error) {
ex = error;
row = null;
ex = RequestError(new Error("Failed to parse incoming JSON. " + ex.message), 'EJSON');
if (_this.stream) {
_this.emit('error', ex);
} else {
console.error(ex);
}
}
} else {
row[columns[0].name] = chunksBuffer.join('');
}
chunksBuffer = null;
}
if (_this.verbose) {
_this._log(util.inspect(row));
_this._log("---------- --------------------");
}
if (row["___return___"] == null) {
if (_this.stream) {
_this.emit('row', row);
}
}
}
if (handleOutput) {
last = (ref1 = recordsets.pop()) != null ? ref1[0] : void 0;
ref2 = _this.parameters;
for (name in ref2) {
param = ref2[name];
if (!(param.io === 2)) {
continue;
}
param.value = last[param.name];
if (_this.verbose) {
_this._log(" output: @" + param.name + ", " + param.type.declaration + ", " + param.value);
}
}
}
if (_this.verbose) {
elapsed = Date.now() - started;
_this._log(" duration: " + elapsed + "ms");
_this._log("---------- completed ----------");
}
}
_this._release(connection);
if (_this.stream) {
return callback(null, _this.nested ? row : null);
} else {
return typeof callback === "function" ? callback(null, _this.multiple || _this.nested ? recordsets : recordsets[0]) : void 0;
}
});
} else {
if (connection) {
_this._release(connection);
}
return typeof callback === "function" ? callback(err) : void 0;
}
};
})(this));
};
MsnodesqlRequest.prototype.execute = function(procedure, callback) {
var cmd, name, param, ref1, spp, started;
if (this.verbose) {
this._log("---------- sql execute --------\n proc: " + procedure);
}
started = Date.now();
cmd = "declare " + (['@___return___ int'].concat((function() {
var ref1, results;
ref1 = this.parameters;
results = [];
for (name in ref1) {
param = ref1[name];
if (param.io === 2) {
results.push("@" + param.name + " " + (declare(param.type, param)));
}
}
return results;
}).call(this)).join(', ')) + ";";
cmd += "exec @___return___ = " + procedure + " ";
spp = [];
ref1 = this.parameters;
for (name in ref1) {
param = ref1[name];
if (this.verbose) {
this._log(" " + (param.io === 1 ? " input" : "output") + ": @" + param.name + ", " + param.type.declaration + ", " + param.value);
}
if (param.io === 2) {
spp.push("@" + param.name + "=@" + param.name + " output");
} else {
spp.push("@" + param.name + "=?");
}
}
cmd += (spp.join(', ')) + ";";
cmd += "select " + (['@___return___ as \'___return___\''].concat((function() {
var ref2, results;
ref2 = this.parameters;
results = [];
for (name in ref2) {
param = ref2[name];
if (param.io === 2) {
results.push("@" + param.name + " as '" + param.name + "'");
}
}
return results;
}).call(this)).join(', ')) + ";";
if (this.verbose) {
this._log("---------- response -----------");
}
this.nested = true;
return MsnodesqlRequest.prototype.query.call(this, cmd, (function(_this) {
return function(err, recordsets) {
var elapsed, last, ref2, ref3, returnValue;
_this.nested = false;
if (err) {
if (_this.verbose) {
elapsed = Date.now() - started;
_this._log(" error: " + err);
_this._log(" duration: " + elapsed + "ms");
_this._log("---------- completed ----------");
}
return typeof callback === "function" ? callback(err) : void 0;
} else {
if (_this.stream) {
last = recordsets;
} else {
last = (ref2 = recordsets.pop()) != null ? ref2[0] : void 0;
}
if (last && (last.___return___ != null)) {
returnValue = last.___return___;
ref3 = _this.parameters;
for (name in ref3) {
param = ref3[name];
if (!(param.io === 2)) {
continue;
}
param.value = last[param.name];
if (_this.verbose) {
_this._log(" output: @" + param.name + ", " + param.type.declaration + ", " + param.value);
}
}
}
if (_this.verbose) {
elapsed = Date.now() - started;
_this._log(" return: " + returnValue);
_this._log(" duration: " + elapsed + "ms");
_this._log("---------- completed ----------");
}
if (_this.stream) {
return callback(null, null, returnValue);
} else {
recordsets.returnValue = returnValue;
return typeof callback === "function" ? callback(null, recordsets, returnValue) : void 0;
}
}
};
})(this));
};
/*
Cancel currently executed request.
*/
MsnodesqlRequest.prototype.cancel = function() {
return false;
};
return MsnodesqlRequest;
})(Request);
return {
Connection: MsnodesqlConnection,
Transaction: MsnodesqlTransaction,
Request: MsnodesqlRequest,
fix: function() {}
};
};
}).call(this);