Comparing version 0.2.2 to 0.2.3
@@ -11,3 +11,4 @@ var common = require('../test/common'); | ||
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', | ||
'`title` varchar(255),', | ||
'`id1` tinyint NOT NULL,', | ||
// '`title` varchar(255),', | ||
'PRIMARY KEY (`id`)', | ||
@@ -18,3 +19,4 @@ ') ENGINE=InnoDB DEFAULT CHARSET=utf8' | ||
function benchmarkInsert(numLeft, callback) { | ||
connection.execute('INSERT INTO ' + table + ' SET title="' + text + '"', [], function(err, result) { | ||
//connection.execute('INSERT INTO ' + table + ' SET title="' + text + '"', [], function(err, result) { | ||
connection.execute('INSERT INTO ' + table + ' SET id1=123', [], function(err, result) { | ||
if (err) throw err; | ||
@@ -29,3 +31,3 @@ if (numLeft > 1) | ||
function benchmarkInserts(n, cb) { | ||
var numInsert = 10000; | ||
var numInsert = 500000; | ||
var start = process.hrtime(); | ||
@@ -70,5 +72,5 @@ benchmarkInsert(numInsert, function() { | ||
benchmarkInserts(1, function() { | ||
benchmarkSelects(5, 100, function() { | ||
benchmarkSelects(10, 1000, function() { | ||
benchmarkSelects(2, 50000, function() { | ||
benchmarkSelects(50, 100, function() { | ||
benchmarkSelects(100, 1000, function() { | ||
benchmarkSelects(20, 500000, function() { | ||
var testEnd = process.hrtime(); | ||
@@ -75,0 +77,0 @@ console.log('total time: ', common.hrdiff(testStart, testEnd)/1e9 ); |
@@ -10,3 +10,3 @@ var common = require('../test/common'); | ||
'`id` int(11) unsigned NOT NULL AUTO_INCREMENT,', | ||
'`title` varchar(255),', | ||
'`ttt` int(11) unsigned NOT NULL,', | ||
'PRIMARY KEY (`id`)', | ||
@@ -17,3 +17,3 @@ ') ENGINE=InnoDB DEFAULT CHARSET=utf8' | ||
function benchmarkInsert(numLeft, callback) { | ||
connection.query('INSERT INTO ' + table + ' SET title="' + text + '"', function(err, result) { | ||
connection.query('INSERT INTO ' + table + ' SET ttt=123', function(err, result) { | ||
if (err) throw err; | ||
@@ -20,0 +20,0 @@ if (numLeft > 1) |
@@ -5,1 +5,3 @@ var Connection = require('./lib/connection'); | ||
}; | ||
module.exports.Connection = Connection; |
var Command = require('./command'); | ||
var Packets = require('../packets/index.js'); | ||
var util = require('util'); | ||
var compileParser = require('../compile_binary_parser'); | ||
@@ -22,2 +23,3 @@ function Execute(sql, parameters, callback) | ||
this.id = 0; | ||
this.rowParser = null; | ||
} | ||
@@ -62,6 +64,30 @@ util.inherits(Execute, Command); | ||
Execute.prototype.readField = function(packet) { | ||
// TODO: move to connection.js? | ||
function getFieldsKey(fields) { | ||
var res = ''; | ||
for (var i=0; i < fields.length; ++i) | ||
res += '/' + fields[i].name + ':' + fields[i].columnType + ':' + fields[i].flags; | ||
return res; | ||
} | ||
Execute.prototype.readField = function(packet, connection) { | ||
var def = new Packets.ColumnDefinition(packet); | ||
this.fields.push(def); | ||
// TODO: api to allow to flag "I'm not going to chnge schema for this statement" | ||
// this way we can ignore column definitions in binary response and use | ||
// definition from prepare phase. Note that it's what happens currently | ||
// e.i if you do execute("select * from foo") and later add/remove/rename rows to foo | ||
// (without reconnecting) you are in trouble | ||
if (this.fields.length == this.fieldCount) { | ||
// compile row parser | ||
var parserKey = getFieldsKey(this.fields); | ||
// try cached first | ||
this.rowParser = connection.textProtocolParsers[parserKey]; | ||
if (!this.rowParser) { | ||
this.rowParser = compileParser(this.fields); | ||
console.log(this.rowParser.toString()); | ||
connection.textProtocolParsers[parserKey] = this.rowParser; | ||
} | ||
return Execute.prototype.fieldsEOF; | ||
@@ -109,4 +135,9 @@ } | ||
Execute.prototype.readResultField = function(packet) { | ||
var def = new Packets.ColumnDefinition(packet); | ||
this.resultFields.push(def); | ||
var def; | ||
if (this.rowParser) // ignore result fields definition, we are reusing fields from prepare response | ||
this.resultFields.push(null); | ||
else { | ||
def = new Packets.ColumnDefinition(packet); | ||
this.resultFields.push(def); | ||
} | ||
if (this.resultFields.length == this.resultFieldCount) { | ||
@@ -133,5 +164,16 @@ return Execute.prototype.resultFieldsEOF; | ||
} | ||
if (this.rowParser) | ||
{ | ||
var r = new this.rowParser(packet); | ||
if (this.onResult) | ||
this.rows.push(r); | ||
else | ||
this.emit('result', r); | ||
return Execute.prototype.row; | ||
} | ||
var row = Packets.BinaryRow.fromPacket(this.fields, packet); | ||
// TODO: here we'll have dynamically pre-compiled and cached row parser | ||
if (true) // TODO: think of API to store raw copulns array (most probably connection options flags) | ||
if (true) // TODO: think of API to store raw columns array (most probably connection options flags) | ||
{ | ||
@@ -138,0 +180,0 @@ var r = {}; |
@@ -37,6 +37,7 @@ var Command = require('./command'); | ||
// TODO: move to connection.js ? | ||
function getFieldsKey(fields) { | ||
var res = ''; | ||
for (var i=0; i < fields.length; ++i) | ||
res += '/' + fields[i].name + ':' + fields[i].columnType; | ||
res += '/' + fields[i].name + ':' + fields[i].columnType + ':' + fields[i].flags; | ||
return res; | ||
@@ -43,0 +44,0 @@ } |
@@ -0,1 +1,2 @@ | ||
var constants = require('./constants'); | ||
var vm = require('vm'); | ||
@@ -17,15 +18,13 @@ | ||
switch(type) { | ||
case 1: | ||
case 2: | ||
case 3: | ||
case 9: | ||
case 13: | ||
case constants.MYSQL_TYPE_TINY: | ||
case constants.MYSQL_TYPE_SHORT: | ||
case constants.MYSQL_TYPE_LONG: | ||
case constants.MYSQL_TYPE_INT24: | ||
case constants.MYSQL_TYPE_YEAR: | ||
return "packet.parseLengthCodedInt();"; | ||
// TODO: implement parseFloat | ||
//case 4: | ||
//case 5: | ||
// return "packet.parseFloat();"; | ||
case 6: | ||
return "null;"; | ||
case constants.MYSQL_TYPE_FLOAT: | ||
case constants.MYSQL_TYPE_DOUBLE: | ||
return "packet.parseLengthCodedFloat();"; | ||
case constants.MYSQL_TYPE_NULL: | ||
return "null; packet.skip(1);"; | ||
default: | ||
@@ -32,0 +31,0 @@ return "packet.readLengthCodedString(); //" + type; |
@@ -24,3 +24,4 @@ var _ = require('underscore'); | ||
} | ||
// fill defaults | ||
// TODO: fill defaults | ||
// if no params, connect to /var/lib/mysql/mysql.sock ( /tmp/mysql.sock on OSX ) | ||
@@ -40,2 +41,3 @@ // if host is given, connect to host:3306 | ||
this.statements = {}; | ||
// TODO: make it lru cache | ||
@@ -46,5 +48,9 @@ // https://github.com/mercadolibre/node-simple-lru-cache | ||
// | ||
// key is field.name + ':' + field.columnType + '/' | ||
// key is field.name + ':' + field.columnType + ':' field.flags + '/' | ||
this.textProtocolParsers = {}; | ||
// TODO: not sure if cache should be separate (same key as with textProtocolParsers) | ||
// or part of prepared statements cache (key is sql query) | ||
this.binaryProtocolParsers = {}; | ||
var connection = this; | ||
@@ -70,3 +76,3 @@ this.packetParser = new PacketParser(this.handlePacket.bind(this)); | ||
if (commands.length !== 0) | ||
this.handlePacket(); // TODO: process.nextTick ? | ||
this.handlePacket(); // TODO: process.nextTick to avoid recursion? | ||
} | ||
@@ -73,0 +79,0 @@ }; |
@@ -1,2 +0,2 @@ | ||
//var constants = require('../constants'); | ||
var constants = require('../constants'); | ||
var Packet = require('../packets/packet'); | ||
@@ -9,19 +9,22 @@ | ||
var binaryReader = new Array(256); | ||
binaryReader[0] = Packet.prototype.readLengthCodedString; // MYSQL_TYPE_DECIMAL | ||
binaryReader[1] = Packet.prototype.readInt8; // tiny | ||
binaryReader[2] = Packet.prototype.readInt16; // short | ||
binaryReader[3] = Packet.prototype.readInt32; // long | ||
binaryReader[4] = Packet.prototype.readFloat; // float | ||
binaryReader[5] = Packet.prototype.readDouble; // double | ||
binaryReader[6] = Packet.prototype.assertInvalid; // null, should be skipped vie null bitmap | ||
binaryReader[7] = Packet.prototype.readTimestamp; // timestamp, http://dev.mysql.com/doc/internals/en/prepared-statements.html#packet-ProtocolBinary::MYSQL_TYPE_TIMESTAMP | ||
binaryReader[8] = Packet.prototype.readInt64; // long long | ||
binaryReader[9] = Packet.prototype.readInt32; // int24 | ||
binaryReader[10] = Packet.prototype.readTimestamp; // date | ||
binaryReader[11] = Packet.prototype.readTime; // time, http://dev.mysql.com/doc/internals/en/prepared-statements.html#packet-ProtocolBinary::MYSQL_TYPE_TIME | ||
binaryReader[12] = Packet.prototype.readDateTime; // datetime, http://dev.mysql.com/doc/internals/en/prepared-statements.html#packet-ProtocolBinary::MYSQL_TYPE_DATETIME | ||
binaryReader[13] = Packet.prototype.readInt16; // year | ||
// TODO: complete list of types... | ||
var binaryReader = new Array(256); | ||
// TODO: replace with constants.MYSQL_TYPE_* | ||
binaryReader[0] = Packet.prototype.readLengthCodedString; // MYSQL_TYPE_DECIMAL | ||
binaryReader[1] = Packet.prototype.readInt8; // tiny | ||
binaryReader[2] = Packet.prototype.readInt16; // short | ||
binaryReader[3] = Packet.prototype.readInt32; // long | ||
binaryReader[4] = Packet.prototype.readFloat; // float | ||
binaryReader[5] = Packet.prototype.readDouble; // double | ||
binaryReader[6] = Packet.prototype.assertInvalid; // null, should be skipped vie null bitmap | ||
binaryReader[7] = Packet.prototype.readTimestamp; // timestamp, http://dev.mysql.com/doc/internals/en/prepared-statements.html#packet-ProtocolBinary::MYSQL_TYPE_TIMESTAMP | ||
binaryReader[8] = Packet.prototype.readInt64; // long long | ||
binaryReader[9] = Packet.prototype.readInt32; // int24 | ||
binaryReader[10] = Packet.prototype.readTimestamp; // date | ||
binaryReader[11] = Packet.prototype.readTime; // time, http://dev.mysql.com/doc/internals/en/prepared-statements.html#packet-ProtocolBinary::MYSQL_TYPE_TIME | ||
binaryReader[12] = Packet.prototype.readDateTime; // datetime, http://dev.mysql.com/doc/internals/en/prepared-statements.html#packet-ProtocolBinary::MYSQL_TYPE_DATETIME | ||
binaryReader[13] = Packet.prototype.readInt16; // year | ||
binaryReader[constants.MYSQL_TYPE_VAR_STRING] = Packet.prototype.readLengthCodedString; // var string | ||
// TODO: complete list of types... | ||
BinaryRow.fromPacket = function(fields, packet) { | ||
@@ -34,3 +37,3 @@ var columns = new Array(fields.length); | ||
for (var i = 0; i < columns.length; ++i) | ||
columns[i] = binaryReader[fields[i].type].apply(packet); | ||
columns[i] = binaryReader[fields[i].columnType].apply(packet); | ||
return new BinaryRow(columns); | ||
@@ -37,0 +40,0 @@ }; |
@@ -78,2 +78,14 @@ //var BigNumber = require("bignumber.js"); | ||
Packet.prototype.readFloat = function() { | ||
var res = this.buffer.readFloatLE(this.offset); | ||
this.offset += 4; | ||
return res; | ||
}; | ||
Packet.prototype.readDouble = function() { | ||
var res = this.buffer.readDoubleLE(this.offset); | ||
this.offset += 8; | ||
return res; | ||
}; | ||
Packet.prototype.readBuffer = function(len) { | ||
@@ -84,2 +96,50 @@ this.offset += len; | ||
// DATE, DATETIME and TIMESTAMP | ||
Packet.prototype.readDateTime = function(convertTtoMs) { | ||
var length = this.readInt8(); | ||
var y = 0; | ||
var m = 0; | ||
var d = 0; | ||
var H = 0; | ||
var M = 0; | ||
var S = 0; | ||
var ms = 0; | ||
if (length > 3) { | ||
y = this.readInt16(); | ||
m = this.readInt8(); | ||
d = this.readInt8(); | ||
} | ||
if (length > 6) { | ||
H = this.readInt8(); | ||
M = this.readInt8(); | ||
} | ||
if (length > 11) | ||
ms = this.readInt32(); | ||
return new Date(y, m, d, H, M, S, ms); | ||
}; | ||
// TIME - value in microseconds. Can be negative | ||
Packet.prototype.readTime = function(convertTtoMs) { | ||
var length = this.readInt8(); | ||
if (length === 0) | ||
return 0; | ||
var result = 0; | ||
var sign = this.readInt8() ? -1 : 1; // 'isNegative' flag byte | ||
var d = 0; | ||
var H = 0; | ||
var M = 0; | ||
var S = 0; | ||
var ms = 0; | ||
if (length > 7) { | ||
d = this.readInt32(); | ||
H = this.readInt8(); | ||
M = this.readInt8(); | ||
S = this.readInt8(); | ||
} | ||
if (length > 11) | ||
ms = this.readInt32(); | ||
return d*86400000 + H*3600000 + M*60000 + S*1000 + ms; | ||
}; | ||
Packet.prototype.readLengthCodedString = function() { | ||
@@ -109,2 +169,4 @@ var len = this.readLengthCodedNumber(); | ||
var minus = '-'.charCodeAt(0); | ||
var plus = '+'.charCodeAt(0); | ||
// TODO: base? sign? parseFloat? | ||
@@ -114,2 +176,12 @@ Packet.prototype.parseInt = function(len) { | ||
var end = this.offset + len; | ||
var sign = 1; | ||
if (len === 0) | ||
return 0; // TODO: assert? exception? | ||
if (this.buffer[this.offset] == minus) { | ||
this.offset++; | ||
sign = -1; | ||
} | ||
if (this.buffer[this.offset] == plus) { | ||
this.offset++; // just ignore | ||
} | ||
while(this.offset < end) { | ||
@@ -120,5 +192,47 @@ result *= 10; | ||
} | ||
return result; | ||
return result*sign; | ||
}; | ||
// TODO: handle E notation | ||
var dot = '.'.charCodeAt(0); | ||
var exponent = 'e'.charCodeAt(0); | ||
var exponentCapital = 'E'.charCodeAt(0); | ||
Packet.prototype.parseFloat = function(len) { | ||
var result = 0; | ||
var end = this.offset + len; | ||
var factor = 1; | ||
var pastDot = false; | ||
var charCode = 0; | ||
if (len === 0) | ||
return 0; // TODO: assert? exception? | ||
if (this.buffer[this.offset] == minus) { | ||
this.offset++; | ||
factor = -1; | ||
} | ||
if (this.buffer[this.offset] == plus) { | ||
this.offset++; // just ignore | ||
} | ||
while(this.offset < end) { | ||
charCode = this.buffer[this.offset]; | ||
if (charCode == dot) | ||
{ | ||
pastDot = true; | ||
this.offset++; | ||
} else if (charCode == exponent || charCode == exponentCapital) { | ||
this.offset++; | ||
var exponentValue = this.parseInt(end - this.offset); | ||
return (result/factor)*Math.pow(10, exponentValue); | ||
} else { | ||
result *= 10; | ||
result += this.buffer[this.offset] - 48; | ||
this.offset++; | ||
if (pastDot) | ||
factor = factor*10; | ||
} | ||
} | ||
return result/factor; | ||
}; | ||
Packet.prototype.parseLengthCodedInt = function() { | ||
@@ -128,2 +242,6 @@ return this.parseInt(this.readLengthCodedNumber()); | ||
Packet.prototype.parseLengthCodedFloat = function() { | ||
return this.parseFloat(this.readLengthCodedNumber()); | ||
}; | ||
Packet.prototype.isError = function() { | ||
@@ -134,3 +252,5 @@ return this.buffer[this.offset] == 0xff; | ||
Packet.prototype.asError = function() { | ||
this.offset = 1; | ||
this.reset(); | ||
this.skip(1); | ||
var code = this.readInt8(); | ||
@@ -137,0 +257,0 @@ var sqlState = this.readBuffer(7); |
{ | ||
"name": "mysql2", | ||
"version": "0.2.2", | ||
"version": "0.2.3", | ||
"description": "fast mysql driver", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
Sorry, the diff of this file is not supported yet
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
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
74706
47
1685
15