Comparing version 2.3.2 to 2.4.0
@@ -7,2 +7,18 @@ # Changes | ||
## v2.4.0 (2014-07-13) | ||
* Add code `POOL_NOEXIST` in PoolCluster error #846 | ||
* Add `acquireTimeout` pool option to specify a timeout for acquiring a connection #821 #854 | ||
* Add `connection.escapeId` | ||
* Add `pool.escapeId` | ||
* Add `timeout` option to all sequences #855 #863 | ||
* Default `connectTimeout` to 10 seconds | ||
* Fix domain binding with `conn.connect` | ||
* Fix `packet.default` to actually be a string | ||
* Fix `PARSER_*` errors to be catchable | ||
* Fix `PROTOCOL_PACKETS_OUT_OF_ORDER` error to be catchable #844 | ||
* Include packets that failed parsing under `debug` | ||
* Return `Query` object from `pool.query` like `conn.query` #830 | ||
* Use `EventEmitter.listenerCount` when possible for faster counting | ||
## v2.3.2 (2014-05-29) | ||
@@ -9,0 +25,0 @@ |
@@ -25,8 +25,10 @@ var Crypto = require('crypto'); | ||
function bindToCurrentDomain(cb) { | ||
function bindToCurrentDomain(callback) { | ||
if (!callback) return; | ||
var domain = process.domain; | ||
if (!domain || !cb) | ||
return cb; | ||
else | ||
return domain.bind(cb); | ||
return domain | ||
? domain.bind(callback) | ||
: callback; | ||
} | ||
@@ -62,3 +64,8 @@ | ||
Connection.prototype.connect = function(cb) { | ||
Connection.prototype.connect = function connect(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
if (!this._connectCalled) { | ||
@@ -103,15 +110,13 @@ this._connectCalled = true; | ||
this._protocol.handshake(cb); | ||
this._protocol.handshake(options, bindToCurrentDomain(callback)); | ||
}; | ||
Connection.prototype.changeUser = function(options, cb){ | ||
cb = cb || function() {}; | ||
Connection.prototype.changeUser = function changeUser(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
this._implyConnect(); | ||
if (typeof options === 'function') { | ||
cb = options; | ||
options = {}; | ||
} | ||
var charsetNumber = (options.charset) | ||
@@ -125,32 +130,45 @@ ? ConnectionConfig.getCharsetNumber(options.charset) | ||
database : options.database || this.config.database, | ||
timeout : options.timeout, | ||
charsetNumber : charsetNumber, | ||
currentConfig : this.config | ||
}, bindToCurrentDomain(cb)); | ||
}, bindToCurrentDomain(callback)); | ||
}; | ||
Connection.prototype.beginTransaction = function(cb) { | ||
this._implyConnect(); | ||
Connection.prototype.beginTransaction = function beginTransaction(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
options = options || {}; | ||
options.sql = 'START TRANSACTION'; | ||
options.values = null; | ||
var query = Connection.createQuery('START TRANSACTION', cb); | ||
query._connection = this; | ||
return this._protocol._enqueue(query); | ||
return this.query(options, callback); | ||
}; | ||
Connection.prototype.commit = function(cb) { | ||
this._implyConnect(); | ||
Connection.prototype.commit = function commit(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
options = options || {}; | ||
options.sql = 'COMMIT'; | ||
options.values = null; | ||
var query = Connection.createQuery('COMMIT', cb); | ||
query._connection = this; | ||
return this._protocol._enqueue(query); | ||
return this.query(options, callback); | ||
}; | ||
Connection.prototype.rollback = function(cb) { | ||
this._implyConnect(); | ||
Connection.prototype.rollback = function rollback(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
options = options || {}; | ||
options.sql = 'ROLLBACK'; | ||
options.values = null; | ||
var query = Connection.createQuery('ROLLBACK', cb); | ||
query._connection = this; | ||
return this._protocol._enqueue(query); | ||
return this.query(options, callback); | ||
}; | ||
@@ -173,15 +191,30 @@ | ||
Connection.prototype.ping = function(cb) { | ||
Connection.prototype.ping = function ping(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
this._implyConnect(); | ||
this._protocol.ping(bindToCurrentDomain(cb)); | ||
this._protocol.ping(options, bindToCurrentDomain(callback)); | ||
}; | ||
Connection.prototype.statistics = function(cb) { | ||
Connection.prototype.statistics = function statistics(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
this._implyConnect(); | ||
this._protocol.stats(bindToCurrentDomain(cb)); | ||
this._protocol.stats(options, bindToCurrentDomain(callback)); | ||
}; | ||
Connection.prototype.end = function(cb) { | ||
Connection.prototype.end = function end(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
this._implyConnect(); | ||
this._protocol.quit(bindToCurrentDomain(cb)); | ||
this._protocol.quit(options, bindToCurrentDomain(callback)); | ||
}; | ||
@@ -210,2 +243,6 @@ | ||
Connection.prototype.escapeId = function escapeId(value) { | ||
return SqlString.escapeId(value, false); | ||
}; | ||
Connection.prototype.format = function(sql, values) { | ||
@@ -212,0 +249,0 @@ if (typeof this.config.queryFormat == "function") { |
@@ -20,3 +20,3 @@ var urlParse = require('url').parse; | ||
this.connectTimeout = (options.connectTimeout === undefined) | ||
? (2 * 60 * 1000) | ||
? (10 * 1000) | ||
: options.connectTimeout; | ||
@@ -23,0 +23,0 @@ this.insecureAuth = options.insecureAuth || false; |
@@ -42,3 +42,3 @@ var mysql = require('../'); | ||
return connection.connect(function(err) { | ||
return connection.connect({timeout: this.config.acquireTimeout}, function (err) { | ||
if (this._closed) { | ||
@@ -79,3 +79,3 @@ return cb(new Error('Pool is closed.')); | ||
connection._pool = null; | ||
connection.ping(function(err){ | ||
connection.ping({timeout: this.config.acquireTimeout}, function(err) { | ||
if (!err) { | ||
@@ -166,18 +166,4 @@ connection._pool = pool; | ||
Pool.prototype.query = function (sql, values, cb) { | ||
if (typeof values === 'function') { | ||
cb = values; | ||
values = null; | ||
} | ||
var query = Connection.createQuery(sql, values, cb); | ||
if (!cb) { | ||
// Ignore results and errors if no cb supplied; matches connection.query | ||
cb = function () {}; | ||
} | ||
var connection; | ||
var query = Connection.createQuery(sql, values, function (err, rows, fields) { | ||
connection.release(); | ||
cb.apply(this, arguments); | ||
}); | ||
if (this.config.connectionConfig.trace) { | ||
@@ -189,7 +175,13 @@ // Long stack trace support | ||
this.getConnection(function (err, conn) { | ||
if (err) return cb(err); | ||
if (err) return cb && cb(err); | ||
connection = conn; | ||
// Release connection based off event | ||
query.once('end', function() { | ||
conn.release(); | ||
}); | ||
conn.query(query); | ||
}); | ||
return query; | ||
}; | ||
@@ -230,1 +222,5 @@ | ||
}; | ||
Pool.prototype.escapeId = function escapeId(value) { | ||
return mysql.escapeId(value, false); | ||
}; |
@@ -185,3 +185,5 @@ var Pool = require('./Pool'); | ||
if (clusterNode === null) { | ||
return cb(new Error('Pool does not exist.')); | ||
var err = new Error('Pool does not exist.') | ||
err.code = 'POOL_NOEXIST'; | ||
return cb(err); | ||
} | ||
@@ -188,0 +190,0 @@ |
@@ -10,2 +10,5 @@ | ||
this.acquireTimeout = (options.acquireTimeout === undefined) | ||
? 10 * 1000 | ||
: Number(options.acquireTimeout); | ||
this.connectionConfig = new ConnectionConfig(options); | ||
@@ -12,0 +15,0 @@ this.waitForConnections = (options.waitForConnections === undefined) |
@@ -11,3 +11,2 @@ module.exports = FieldPacket; | ||
this.orgName = options.orgName; | ||
this.filler1 = undefined; | ||
this.charsetNr = options.charsetNr; | ||
@@ -18,3 +17,2 @@ this.length = options.length; | ||
this.decimals = options.decimals; | ||
this.filler2 = undefined; | ||
this.default = options.default; | ||
@@ -33,3 +31,9 @@ this.zeroFill = options.zeroFill; | ||
this.orgName = parser.parseLengthCodedString(); | ||
this.filler1 = parser.parseFiller(1); | ||
if (parser.parseLengthCodedNumber() !== 0x0c) { | ||
var err = new TypeError('Received invalid field length'); | ||
err.code = 'PARSER_INVALID_FIELD_LENGTH'; | ||
throw err; | ||
} | ||
this.charsetNr = parser.parseUnsignedNumber(2); | ||
@@ -40,4 +44,10 @@ this.length = parser.parseUnsignedNumber(4); | ||
this.decimals = parser.parseUnsignedNumber(1); | ||
this.filler2 = parser.parseFiller(2); | ||
var filler = parser.parseBuffer(2); | ||
if (filler[0] !== 0x0 || filler[1] !== 0x0) { | ||
var err = new TypeError('Received invalid filler'); | ||
err.code = 'PARSER_INVALID_FILLER'; | ||
throw err; | ||
} | ||
// parsed flags | ||
@@ -50,3 +60,3 @@ this.zeroFill = (this.flags & 0x0040 ? true : false); | ||
this.default = parser.parseLengthCodedNumber(); | ||
this.default = parser.parseLengthCodedString(); | ||
} else { | ||
@@ -68,3 +78,4 @@ this.table = parser.parseLengthCodedString(); | ||
writer.writeLengthCodedString(this.orgName); | ||
writer.writeFiller(1); | ||
writer.writeLengthCodedNumber(0x0c); | ||
writer.writeUnsignedNumber(2, this.charsetNr || 0); | ||
@@ -71,0 +82,0 @@ writer.writeUnsignedNumber(4, this.length || 0); |
@@ -16,2 +16,4 @@ var MAX_PACKET_LENGTH = Math.pow(2, 24) - 1; | ||
this._packetHeader = null; | ||
this._packetOffset = null; | ||
this._onError = options.onError || function(err) { throw err; }; | ||
this._onPacket = options.onPacket || function() {}; | ||
@@ -41,3 +43,15 @@ this._nextPacketNumber = 0; | ||
this._trackAndVerifyPacketNumber(this._packetHeader.number); | ||
if (this._packetHeader.number !== this._nextPacketNumber) { | ||
var err = new Error( | ||
'Packets out of order. Got: ' + this._packetHeader.number + ' ' + | ||
'Expected: ' + this._nextPacketNumber | ||
); | ||
err.code = 'PROTOCOL_PACKETS_OUT_OF_ORDER'; | ||
err.fatal = true; | ||
this._onError(err); | ||
} | ||
this.incrementPacketNumber(); | ||
} | ||
@@ -49,6 +63,7 @@ | ||
this._packetEnd = this._offset + this._packetHeader.length; | ||
this._packetEnd = this._offset + this._packetHeader.length; | ||
this._packetOffset = this._offset; | ||
if (this._packetHeader.length === MAX_PACKET_LENGTH) { | ||
this._longPacketBuffers.push(this._buffer.slice(this._offset, this._packetEnd)); | ||
this._longPacketBuffers.push(this._buffer.slice(this._packetOffset, this._packetEnd)); | ||
@@ -67,2 +82,11 @@ this._advanceToNextPacket(); | ||
hadException = false; | ||
} catch (err) { | ||
if (typeof err.code !== 'string' || err.code.substr(0, 7) !== 'PARSER_') { | ||
// Rethrow unknown errors | ||
throw err; | ||
} | ||
// Pass down parser errors | ||
this._onError(err); | ||
hadException = false; | ||
} finally { | ||
@@ -128,3 +152,6 @@ this._advanceToNextPacket(); | ||
if (bytes > 4) { | ||
throw new Error('parseUnsignedNumber: Supports only up to 4 bytes'); | ||
var err = new Error('parseUnsignedNumber: Supports only up to 4 bytes'); | ||
err.offset = (this._offset - this._packetOffset - 1); | ||
err.code = 'PARSER_UNSIGNED_TOO_LONG'; | ||
throw err; | ||
} | ||
@@ -162,3 +189,10 @@ | ||
Parser.prototype.parseLengthCodedNumber = function() { | ||
Parser.prototype.parseLengthCodedNumber = function parseLengthCodedNumber() { | ||
if (this._offset >= this._buffer.length) { | ||
var err = new Error('Parser: read past end'); | ||
err.offset = (this._offset - this._packetOffset); | ||
err.code = 'PARSER_READ_PAST_END'; | ||
throw err; | ||
} | ||
var bits = this._buffer[this._offset++]; | ||
@@ -180,3 +214,6 @@ | ||
default: | ||
throw new Error('parseLengthCodedNumber: Unexpected first byte: 0x' + bits.toString(16)); | ||
var err = new Error('Unexpected first byte' + (bits ? ': 0x' + bits.toString(16) : '')); | ||
err.offset = (this._offset - this._packetOffset - 1); | ||
err.code = 'PARSER_BAD_LENGTH_BYTE'; | ||
throw err; | ||
} | ||
@@ -195,6 +232,9 @@ | ||
throw new Error( | ||
var err = new Error( | ||
'parseLengthCodedNumber: JS precision range exceeded, ' + | ||
'number is >= 53 bit: "' + value + '"' | ||
); | ||
err.offset = (this._offset - this._packetOffset - 8); | ||
err.code = 'PARSER_JS_PRECISION_RANGE_EXCEEDED'; | ||
throw err; | ||
} | ||
@@ -234,3 +274,6 @@ | ||
if (offset >= this._buffer.length) { | ||
throw new Error('Offset of null terminated string not found.'); | ||
var err = new Error('Offset of null terminated string not found.'); | ||
err.offset = (this._offset - this._packetOffset); | ||
err.code = 'PARSER_MISSING_NULL_BYTE'; | ||
throw err; | ||
} | ||
@@ -329,17 +372,2 @@ } | ||
Parser.prototype._trackAndVerifyPacketNumber = function(number) { | ||
if (number !== this._nextPacketNumber) { | ||
var err = new Error( | ||
'Packets out of order. Got: ' + number + ' ' + | ||
'Expected: ' + this._nextPacketNumber | ||
); | ||
err.code = 'PROTOCOL_PACKETS_OUT_OF_ORDER'; | ||
throw err; | ||
} | ||
this.incrementPacketNumber(); | ||
}; | ||
Parser.prototype.incrementPacketNumber = function() { | ||
@@ -386,2 +414,3 @@ var currentPacketNumber = this._nextPacketNumber; | ||
this._packetEnd = this._buffer.length - trailingPacketBytes; | ||
this._packetOffset = 0; | ||
}; | ||
@@ -393,2 +422,3 @@ | ||
this._packetEnd = null; | ||
this._packetOffset = null; | ||
}; |
var Parser = require('./Parser'); | ||
var Sequences = require('./sequences'); | ||
var Packets = require('./packets'); | ||
var Timers = require('timers'); | ||
var Stream = require('stream').Stream; | ||
@@ -31,2 +32,3 @@ var Util = require('util'); | ||
this._parser = new Parser({ | ||
onError : this.handleParserError.bind(this), | ||
onPacket : this._parsePacket.bind(this), | ||
@@ -42,24 +44,47 @@ config : this._config | ||
Protocol.prototype.handshake = function(cb) { | ||
return this._handshakeSequence = this._enqueue(new Sequences.Handshake(this._config, cb)); | ||
Protocol.prototype.handshake = function handshake(options, callback) { | ||
if (typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
options = options || {}; | ||
options.config = this._config; | ||
return this._handshakeSequence = this._enqueue(new Sequences.Handshake(options, callback)); | ||
}; | ||
Protocol.prototype.query = function(options, cb) { | ||
return this._enqueue(new Sequences.Query(options, cb)); | ||
Protocol.prototype.query = function query(options, callback) { | ||
return this._enqueue(new Sequences.Query(options, callback)); | ||
}; | ||
Protocol.prototype.changeUser = function(options, cb) { | ||
return this._enqueue(new Sequences.ChangeUser(options, cb)); | ||
Protocol.prototype.changeUser = function changeUser(options, callback) { | ||
return this._enqueue(new Sequences.ChangeUser(options, callback)); | ||
}; | ||
Protocol.prototype.ping = function(cb) { | ||
return this._enqueue(new Sequences.Ping(cb)); | ||
Protocol.prototype.ping = function ping(options, callback) { | ||
if (typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
return this._enqueue(new Sequences.Ping(options, callback)); | ||
}; | ||
Protocol.prototype.stats = function(cb) { | ||
return this._enqueue(new Sequences.Statistics(cb)); | ||
Protocol.prototype.stats = function stats(options, callback) { | ||
if (typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
return this._enqueue(new Sequences.Statistics(options, callback)); | ||
}; | ||
Protocol.prototype.quit = function(cb) { | ||
return this._quitSequence = this._enqueue(new Sequences.Quit(cb)); | ||
Protocol.prototype.quit = function quit(options, callback) { | ||
if (typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
return this._quitSequence = this._enqueue(new Sequences.Quit(options, callback)); | ||
}; | ||
@@ -123,8 +148,19 @@ | ||
.on('packet', function(packet) { | ||
Timers.active(sequence); | ||
self._emitPacket(packet); | ||
}) | ||
.on('end', function() { | ||
self._dequeue(); | ||
self._dequeue(sequence); | ||
}) | ||
.on('timeout', function() { | ||
var err = new Error(sequence.constructor.name + ' inactivity timeout'); | ||
err.code = 'PROTOCOL_SEQUENCE_TIMEOUT'; | ||
err.fatal = true; | ||
err.timeout = sequence._timeout; | ||
self._delegateError(err, sequence); | ||
}) | ||
.on('start-tls', function() { | ||
Timers.active(sequence); | ||
self._connection._startTLS(function(err) { | ||
@@ -139,2 +175,3 @@ if (err) { | ||
Timers.active(sequence); | ||
sequence._tlsUpgradeCompleteHandler(); | ||
@@ -207,6 +244,6 @@ }) | ||
packet.parse(this._parser); | ||
if (this._config.debug) { | ||
this._debugPacket(true, packet); | ||
this._parsePacketDebug(packet); | ||
} else { | ||
packet.parse(this._parser); | ||
} | ||
@@ -218,5 +255,14 @@ | ||
Timers.active(sequence); | ||
sequence[Packet.name](packet); | ||
}; | ||
Protocol.prototype._parsePacketDebug = function _parsePacketDebug(packet) { | ||
try { | ||
packet.parse(this._parser); | ||
} finally { | ||
this._debugPacket(true, packet); | ||
} | ||
}; | ||
Protocol.prototype._emitPacket = function(packet) { | ||
@@ -256,3 +302,5 @@ var packetWriter = new PacketWriter(); | ||
Protocol.prototype._dequeue = function() { | ||
Protocol.prototype._dequeue = function(sequence) { | ||
Timers.unenroll(sequence); | ||
// No point in advancing the queue, we are dead | ||
@@ -277,2 +325,7 @@ if (this._fatalError) { | ||
Protocol.prototype._startSequence = function(sequence) { | ||
if (sequence._timeout > 0 && isFinite(sequence._timeout)) { | ||
Timers.enroll(sequence, sequence._timeout); | ||
Timers.active(sequence); | ||
} | ||
if (sequence.constructor === Sequences.ChangeUser) { | ||
@@ -296,2 +349,11 @@ sequence.start(this._handshakeInitializationPacket); | ||
Protocol.prototype.handleParserError = function handleParserError(err) { | ||
var sequence = this._queue[0]; | ||
if (sequence) { | ||
sequence.end(err); | ||
} else { | ||
this._delegateError(err); | ||
} | ||
}; | ||
Protocol.prototype._delegateError = function(err, sequence) { | ||
@@ -298,0 +360,0 @@ // Stop delegating errors after the first fatal error |
@@ -9,3 +9,3 @@ var Sequence = require('./Sequence'); | ||
function ChangeUser(options, callback) { | ||
Sequence.call(this, callback); | ||
Sequence.call(this, options, callback); | ||
@@ -12,0 +12,0 @@ this._user = options.user; |
@@ -9,6 +9,8 @@ var Sequence = require('./Sequence'); | ||
Util.inherits(Handshake, Sequence); | ||
function Handshake(config, callback) { | ||
Sequence.call(this, callback); | ||
function Handshake(options, callback) { | ||
Sequence.call(this, options, callback); | ||
this._config = config; | ||
options = options || {}; | ||
this._config = options.config; | ||
this._handshakeInitializationPacket = null; | ||
@@ -15,0 +17,0 @@ } |
@@ -8,4 +8,9 @@ var Sequence = require('./Sequence'); | ||
function Ping(callback) { | ||
Sequence.call(this, callback); | ||
function Ping(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
Sequence.call(this, options, callback); | ||
} | ||
@@ -12,0 +17,0 @@ |
@@ -12,3 +12,3 @@ var Sequence = require('./Sequence'); | ||
function Query(options, callback) { | ||
Sequence.call(this, callback); | ||
Sequence.call(this, options, callback); | ||
@@ -15,0 +15,0 @@ this.sql = options.sql; |
@@ -7,4 +7,9 @@ var Sequence = require('./Sequence'); | ||
Util.inherits(Quit, Sequence); | ||
function Quit(callback) { | ||
Sequence.call(this, callback); | ||
function Quit(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
Sequence.call(this, options, callback); | ||
} | ||
@@ -11,0 +16,0 @@ |
@@ -6,10 +6,28 @@ var Util = require('util'); | ||
var listenerCount = EventEmitter.listenerCount | ||
|| function(emitter, type){ return emitter.listeners(type).length; }; | ||
module.exports = Sequence; | ||
Util.inherits(Sequence, EventEmitter); | ||
function Sequence(callback) { | ||
function Sequence(options, callback) { | ||
if (typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
EventEmitter.call(this); | ||
this._callback = callback; | ||
this._callSite = null; | ||
this._ended = false; | ||
options = options || {}; | ||
this._callback = callback; | ||
this._callSite = null; | ||
this._ended = false; | ||
this._timeout = options.timeout; | ||
// For Timers | ||
this._idleNext = null; | ||
this._idlePrev = null; | ||
this._idleStart = null; | ||
this._idleTimeout = undefined; | ||
this._repeat = null; | ||
} | ||
@@ -26,3 +44,3 @@ | ||
Sequence.prototype.hasErrorHandler = function() { | ||
return this._callback || this.listeners('error').length > 1; | ||
return Boolean(this._callback) || listenerCount(this, 'error') > 1; | ||
}; | ||
@@ -98,1 +116,5 @@ | ||
Sequence.prototype.start = function() {}; | ||
Sequence.prototype._onTimeout = function _onTimeout() { | ||
this.emit('timeout'); | ||
}; |
@@ -7,4 +7,9 @@ var Sequence = require('./Sequence'); | ||
Util.inherits(Statistics, Sequence); | ||
function Statistics(callback) { | ||
Sequence.call(this, callback); | ||
function Statistics(options, callback) { | ||
if (!callback && typeof options === 'function') { | ||
callback = options; | ||
options = {}; | ||
} | ||
Sequence.call(this, options, callback); | ||
} | ||
@@ -11,0 +16,0 @@ |
@@ -105,15 +105,4 @@ var SqlString = exports; | ||
SqlString.bufferToString = function(buffer) { | ||
var hex = ''; | ||
try { | ||
hex = buffer.toString('hex'); | ||
} catch (err) { | ||
// node v0.4.x does not support hex / throws unknown encoding error | ||
for (var i = 0; i < buffer.length; i++) { | ||
var byte = buffer[i]; | ||
hex += zeroPad(byte.toString(16)); | ||
} | ||
} | ||
return "X'" + hex+ "'"; | ||
SqlString.bufferToString = function bufferToString(buffer) { | ||
return "X'" + buffer.toString('hex') + "'"; | ||
}; | ||
@@ -120,0 +109,0 @@ |
{ | ||
"name": "mysql", | ||
"description": "A node.js driver for mysql. It is written in JavaScript, does not require compiling, and is 100% MIT licensed.", | ||
"version": "2.3.2", | ||
"version": "2.4.0", | ||
"license": "MIT", | ||
"author": "Felix Geisendörfer <felix@debuggable.com> (http://debuggable.com/)", | ||
"contributors": [ | ||
{ | ||
"name": "Andrey Sidorov", | ||
"email": "sidorares@yandex.ru" | ||
}, | ||
{ | ||
"name": "Douglas Christopher Wilson", | ||
"email": "doug@somethingdoug.com" | ||
}, | ||
{ | ||
"name": "Diogo Resende", | ||
"email": "dresende@thinkdigital.pt" | ||
} | ||
"Andrey Sidorov <sidorares@yandex.ru>", | ||
"Douglas Christopher Wilson <doug@somethingdoug.com>", | ||
"Diogo Resende <dresende@thinkdigital.pt>" | ||
], | ||
"homepage": "https://github.com/felixge/node-mysql", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/felixge/node-mysql" | ||
}, | ||
"main": "./index", | ||
"scripts": { | ||
"test": "node test/run.js" | ||
}, | ||
"repository": "felixge/node-mysql", | ||
"dependencies": { | ||
@@ -42,3 +26,6 @@ "bignumber.js": "1.4.0", | ||
"node": ">= 0.8" | ||
}, | ||
"scripts": { | ||
"test": "node test/run.js" | ||
} | ||
} |
@@ -149,3 +149,3 @@ # mysql [![Build Status](https://travis-ci.org/felixge/node-mysql.svg?branch=master)](https://travis-ci.org/felixge/node-mysql) [![NPM version](https://badge.fury.io/js/mysql.svg)](http://badge.fury.io/js/mysql) | ||
* `connectTimeout`: The milliseconds before a timeout occurs during the initial connection | ||
to the MySQL server. (Default: 2 minutes) | ||
to the MySQL server. (Default: 10 seconds) | ||
* `stringifyObjects`: Stringify objects instead of converting to values. See | ||
@@ -332,2 +332,5 @@ issue [#501](https://github.com/felixge/node-mysql/issues/501). (Default: `'false'`) | ||
* `acquireTimeout`: The milliseconds before a timeout occurs during the connection | ||
acquisition. This is slightly different from `connectTimeout`, because acquiring | ||
a pool connection does not always involve making a connection. (Default: 10 seconds) | ||
* `waitForConnections`: Determines the pool's action when no connections are | ||
@@ -507,9 +510,11 @@ available and the limit has been reached. If `true`, the pool will queue the | ||
If you can't trust an SQL identifier (database / table / column name) because it is | ||
provided by a user, you should escape it with `mysql.escapeId(identifier)` like this: | ||
provided by a user, you should escape it with `mysql.escapeId(identifier)`, | ||
`connection.escapeId(identifier)` or `pool.escapeId(identifier)` like this: | ||
```js | ||
var sorter = 'date'; | ||
var query = 'SELECT * FROM posts ORDER BY ' + mysql.escapeId(sorter); | ||
console.log(query); // SELECT * FROM posts ORDER BY `date` | ||
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter); | ||
connection.query(sql, function(err, results) { | ||
// ... | ||
}); | ||
``` | ||
@@ -521,5 +526,6 @@ | ||
var sorter = 'date'; | ||
var query = 'SELECT * FROM posts ORDER BY ' + mysql.escapeId('posts.' + sorter); | ||
console.log(query); // SELECT * FROM posts ORDER BY `posts`.`date` | ||
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId('posts.' + sorter); | ||
connection.query(sql, function(err, results) { | ||
// ... | ||
}); | ||
``` | ||
@@ -615,3 +621,3 @@ | ||
```js | ||
connection.query('UPDATE posts SET ...', function (err, response) { | ||
connection.query('UPDATE posts SET ...', function (err, result) { | ||
if (err) throw err; | ||
@@ -837,2 +843,25 @@ | ||
## Timeouts | ||
Every operation takes an optional inactivity timeout option. This allows you to | ||
specify appropriate timeouts for operations. It is important to note that these | ||
timeouts are not part of the MySQL protocol, and rather timeout operations through | ||
the client. This means that when a timeout is reached, the connection it occurred | ||
on will be destroyed and no further operations can be performed. | ||
```js | ||
// Kill query after 60s | ||
connection.query({sql: 'SELECT COUNT(*) AS count FROM big_table', timeout: 60000}, function (err, rows) { | ||
if (err && err.code === 'PROTOCOL_SEQUENCE_TIMEOUT') { | ||
throw new Error('too long to count table rows!'); | ||
} | ||
if (err) { | ||
throw err; | ||
} | ||
console.log(rows[0].count + ' rows'); | ||
}); | ||
``` | ||
## Error handling | ||
@@ -1086,11 +1115,25 @@ | ||
## Running unit tests | ||
## Running tests | ||
Set the environment variables `MYSQL_DATABASE`, `MYSQL_HOST`, `MYSQL_PORT`, `MYSQL_USER` and `MYSQL_PASSWORD`. Then run `npm test`. | ||
The test suite is split into two parts: unit tests and integration tests. | ||
The unit tests run on any machine while the integration tests require a | ||
MySQL server instance to be setup. | ||
For example, if you have an installation of mysql running on localhost:3306 and no password set for the `root` user, run: | ||
### Running unit tests | ||
```sh | ||
$ FILTER=unit npm test | ||
``` | ||
mysql -u root -e "CREATE DATABASE IF NOT EXISTS node_mysql_test" | ||
MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_DATABASE=node_mysql_test MYSQL_USER=root MYSQL_PASSWORD= npm test | ||
### Running integration tests | ||
Set the environment variables `MYSQL_DATABASE`, `MYSQL_HOST`, `MYSQL_PORT`, | ||
`MYSQL_USER` and `MYSQL_PASSWORD`. Then run `npm test`. | ||
For example, if you have an installation of mysql running on localhost:3306 | ||
and no password set for the `root` user, run: | ||
```sh | ||
$ mysql -u root -e "CREATE DATABASE IF NOT EXISTS node_mysql_test" | ||
$ MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_DATABASE=node_mysql_test MYSQL_USER=root MYSQL_PASSWORD= FILTER=integration npm test | ||
``` | ||
@@ -1101,3 +1144,2 @@ | ||
* Prepared statements | ||
* setTimeout() for Query | ||
* Support for encodings other than UTF-8 / ASCII |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
298809
5370
1138
2