UNPKG

mssql2

Version:

Microsoft SQL Server client for Node.js (fork)

830 lines (779 loc) 29.9 kB
// 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);