mysql2
Version:
fast mysql driver. Implements core protocol, prepared statements, ssl and compression in native JS
201 lines (161 loc) • 4.91 kB
JavaScript
var mysql = require('../index.js');
var EventEmitter = require('events').EventEmitter;
var Util = require('util');
var PoolConnection = require('./pool_connection.js');
var Queue = require('double-ended-queue');
var Connection = require('./connection.js');
module.exports = Pool;
Util.inherits(Pool, EventEmitter);
function Pool (options) {
EventEmitter.call(this);
this.config = options.config;
this.config.connectionConfig.pool = this;
this._allConnections = new Queue();
this._freeConnections = new Queue();
this._connectionQueue = new Queue();
this._closed = false;
}
Pool.prototype.getConnection = function (cb) {
if (this._closed) {
return process.nextTick(function () {
return cb(new Error('Pool is closed.'));
});
}
var connection;
if (this._freeConnections.length > 0) {
connection = this._freeConnections.shift();
return process.nextTick(function () {
return cb(null, connection);
});
}
if (this.config.connectionLimit === 0 || this._allConnections.length < this.config.connectionLimit) {
connection = new PoolConnection(this, {config: this.config.connectionConfig});
this._allConnections.push(connection);
return connection.connect(function (err) {
if (this._closed) {
return cb(new Error('Pool is closed.'));
}
if (err) {
return cb(err);
}
this.emit('connection', connection);
return cb(null, connection);
}.bind(this));
}
if (!this.config.waitForConnections) {
return process.nextTick(function () {
return cb(new Error('No connections available.'));
});
}
if (this.config.queueLimit && this._connectionQueue.length >= this.config.queueLimit) {
return cb(new Error('Queue limit reached.'));
}
this.emit('enqueue');
return this._connectionQueue.push(cb);
};
Pool.prototype.releaseConnection = function (connection) {
var cb;
if (!connection._pool) {
// The connection has been removed from the pool and is no longer good.
if (this._connectionQueue.length) {
cb = this._connectionQueue.shift();
process.nextTick(this.getConnection.bind(this, cb));
}
} else if (this._connectionQueue.length) {
cb = this._connectionQueue.shift();
process.nextTick(cb.bind(null, null, connection));
} else {
this._freeConnections.push(connection);
}
};
Pool.prototype.end = function (cb) {
this._closed = true;
if (typeof cb != 'function') {
cb = function (err) {
if (err) {
throw err;
}
};
}
var calledBack = false;
var closedConnections = 0;
var connection;
var endCB = function (err) {
if (calledBack) {
return;
}
if (err || ++closedConnections >= this._allConnections.length) {
calledBack = true;
cb(err);
return;
}
}.bind(this);
if (this._allConnections.length === 0) {
endCB();
return;
}
for (var i = 0; i < this._allConnections.length; i++) {
connection = this._allConnections.get(i);
connection._realEnd(endCB);
}
};
Pool.prototype.query = function (sql, values, cb) {
var cmdQuery = Connection.createQuery(sql, values, cb, this.config.connectionConfig);
cmdQuery.namedPlaceholders = this.config.connectionConfig.namedPlaceholders;
this.getConnection(function (err, conn) {
if (err) {
if (typeof cmdQuery.onResult === 'function') {
cmdQuery.onResult(err);
} else {
cmdQuery.emit('error', err);
}
return;
}
conn.query(cmdQuery).once('end', function () {
conn.release();
});
});
return cmdQuery;
};
Pool.prototype.execute = function (sql, values, cb) {
var useNamedPlaceholders = this.config.connectionConfig.namedPlaceholders;
this.getConnection(function (err, conn) {
if (err) {
return cb(err);
}
conn.config.namedPlaceholders = useNamedPlaceholders;
return conn.execute(sql, values, function () {
conn.release();
cb.apply(this, arguments);
});
});
};
Pool.prototype._removeConnection = function (connection) {
// Remove connection from all connections
spliceConnection(this._allConnections, connection);
// Remove connection from free connections
spliceConnection(this._freeConnections, connection);
this.releaseConnection(connection);
};
Pool.prototype.escape = function (value) {
return mysql.escape(value, this.config.connectionConfig.stringifyObjects, this.config.connectionConfig.timezone);
};
Pool.prototype.escapeId = function escapeId (value) {
return mysql.escapeId(value, false);
};
function spliceConnection (queue, connection) {
var len = queue.length;
if (len) {
if (queue.get(len - 1) === connection) {
queue.pop();
} else {
for (; --len;) {
if (queue.get(0) === connection) {
queue.shift();
break;
}
queue.push(queue.shift());
}
}
}
}