Skip to content

Commit 4f42257

Browse files
authored
Merge pull request #397 from sidorares/cache-text-compiler
Save correctly compiled parser for re-use
2 parents ab51adf + 7f3d84f commit 4f42257

File tree

9 files changed

+62
-26
lines changed

9 files changed

+62
-26
lines changed

lib/commands/execute.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ var Command = require('./command.js');
44
var Query = require('./query.js');
55
var Packets = require('../packets/index.js');
66

7+
var objectAssign = require('object-assign');
8+
79
var compileParser = require('../compile_binary_parser.js');
810

911
function Execute (options, callback)
@@ -22,7 +24,7 @@ function Execute (options, callback)
2224
this._result = [];
2325
this._fieldCount = 0;
2426
this._rowParser = null;
25-
this.options = options;
27+
this._executeOptions = options;
2628
this._resultIndex = 0;
2729
this._localStream = null;
2830
this._streamFactory = options.infileStreamFactory;
@@ -40,6 +42,7 @@ Execute.prototype.buildParserFromFields = function (fields, connection) {
4042
};
4143

4244
Execute.prototype.start = function (packet, connection) {
45+
this.options = objectAssign({}, connection.config, this._executeOptions);
4346
var executePacket = new Packets.Execute(this.statement.id, this.parameters, connection.config.charsetNumber);
4447
connection.writePacket(executePacket.toPacket(1));
4548
return Execute.prototype.resultsetHeader;

lib/commands/query.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ var util = require('util');
33
var Buffer = require('safe-buffer').Buffer;
44

55
var Readable = require('readable-stream');
6+
var objectAssign = require('object-assign');
67

78
var Command = require('./command.js');
89
var Packets = require('../packets/index.js');
910
var compileParser = require('../compile_text_parser.js');
1011
var ServerStatus = require('../constants/server_status.js');
12+
var CharsetToEncoding = require('../constants/charset_encodings.js');
1113

1214
var EmptyPacket = new Packets.Packet(0, Buffer.allocUnsafe(4), 0, 4);
1315

@@ -16,7 +18,7 @@ function Query (options, callback)
1618
Command.call(this);
1719
this.sql = options.sql;
1820
this.values = options.values;
19-
this.options = options;
21+
this._queryOptions = options;
2022
this.onResult = callback;
2123
this._fieldCount = 0;
2224
this._rowParser = null;
@@ -35,6 +37,7 @@ Query.prototype.start = function (packet, connection) {
3537
console.log(' Sending query command: %s', this.sql);
3638
}
3739
this._connection = connection;
40+
this.options = objectAssign({}, connection.config, this._queryOptions);
3841
var cmdPacket = new Packets.Query(this.sql, connection.config.charsetNumber);
3942
connection.writePacket(cmdPacket.toPacket(1));
4043
return Query.prototype.resultsetHeader;
@@ -168,7 +171,7 @@ Query.prototype.readField = function (packet, connection) {
168171
this._rowParser = connection.textProtocolParsers[parserKey];
169172
if (!this._rowParser) {
170173
this._rowParser = compileParser(fields, this.options, connection.config);
171-
connection.textProtocolParsers[parserKey] = this.rowParser;
174+
connection.textProtocolParsers[parserKey] = this._rowParser;
172175
}
173176
return Query.prototype.fieldsEOF;
174177
}
@@ -195,7 +198,7 @@ Query.prototype.row = function (packet)
195198
return this.done();
196199
}
197200

198-
var row = new this._rowParser(packet, this._fields[this._resultIndex], this.options);
201+
var row = new this._rowParser(packet, this._fields[this._resultIndex], this.options, CharsetToEncoding);
199202
if (this.onResult) {
200203
this._rows[this._resultIndex].push(row);
201204
} else {

lib/compile_binary_parser.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function compile (fields, options, config) {
1515
var result = [];
1616
var i = 0;
1717
var nullBitmapLength = Math.floor((fields.length + 7 + 2) / 8);
18-
result.push('(function(){ return function BinaryRow(packet) {');
18+
result.push('(function(){ return function BinaryRow(packet, fields, options, CharsetToEncoding) {');
1919

2020
if (options.rowsAsArray) {
2121
result.push(' var result = new Array(' + fields.length + ');');
@@ -73,7 +73,7 @@ function compile (fields, options, config) {
7373
result.push(' if (nullBitmaskByte' + nullByteIndex + ' & ' + currentFieldNullBit + ')');
7474
result.push(' ' + lvalue + ' = null;');
7575
result.push(' else');
76-
result.push(' ' + lvalue + ' = ' + readCodeFor(fields[i], config, options));
76+
result.push(' ' + lvalue + ' = ' + readCodeFor(fields[i], config, options, i));
7777
// }
7878
currentFieldNullBit *= 2;
7979
if (currentFieldNullBit == 0x100) {
@@ -96,7 +96,7 @@ function compile (fields, options, config) {
9696
return vm.runInThisContext(src);
9797
}
9898

99-
function readCodeFor (field, config, options) {
99+
function readCodeFor (field, config, options, fieldNum) {
100100
var supportBigNumbers = options.supportBigNumbers || config.supportBigNumbers;
101101
var bigNumberStrings = options.bigNumberStrings || config.bigNumberStrings;
102102
var unsigned = field.flags & FieldFlags.UNSIGNED;
@@ -135,7 +135,7 @@ function readCodeFor (field, config, options) {
135135
case Types.GEOMETRY:
136136
return 'packet.parseGeometryValue();';
137137
case Types.JSON:
138-
return 'JSON.parse(packet.readLengthCodedString("' + CharsetToEncoding[field.characterSet] + '"));';
138+
return 'JSON.parse(packet.readLengthCodedString(CharsetToEncoding[fields[' + fieldNum + '].characterSet]));';
139139
case Types.LONGLONG:
140140
if (!supportBigNumbers) {
141141
return unsigned ? 'packet.readInt64JSNumber();' : 'packet.readSInt64JSNumber();';
@@ -150,7 +150,7 @@ function readCodeFor (field, config, options) {
150150
if (field.characterSet == Charsets.BINARY) {
151151
return 'packet.readLengthCodedBuffer();';
152152
} else {
153-
return 'packet.readLengthCodedString("' + CharsetToEncoding[field.characterSet] + '")';
153+
return 'packet.readLengthCodedString(CharsetToEncoding[fields[' + fieldNum + '].characterSet])';
154154
}
155155
}
156156
}

lib/compile_text_parser.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ function compile (fields, options, config) {
3131
var i = 0;
3232
var lvalue = '';
3333

34-
result.push('(function() { return function TextRow(packet, fields, options) {');
34+
result.push('(function() { return function TextRow(packet, fields, options, CharsetToEncoding) {');
3535
if (options.rowsAsArray) {
3636
result.push(' var result = new Array(' + fields.length + ')');
3737
}
@@ -74,10 +74,10 @@ function compile (fields, options, config) {
7474
} else {
7575
lvalue = ' this[' + srcEscape(fields[i].name) + ']';
7676
}
77-
var encoding = CharsetToEncoding[fields[i].characterSet];
78-
var readCode = readCodeFor(fields[i].columnType, fields[i].characterSet, encoding, config, options);
77+
var encodingExpr = 'CharsetToEncoding[fields[' + i + '].characterSet]';
78+
var readCode = readCodeFor(fields[i].columnType, fields[i].characterSet, encodingExpr, config, options);
7979
if (typeof options.typeCast === 'function') {
80-
result.push(lvalue + ' = options.typeCast(wrap(fields[' + i + '], ' + srcEscape(typeNames[fields[i].columnType]) + ', packet, "' + encoding + '"), function() { return ' + readCode + ';})');
80+
result.push(lvalue + ' = options.typeCast(wrap(fields[' + i + '], ' + srcEscape(typeNames[fields[i].columnType]) + ', packet, ' + encodingExpr + '), function() { return ' + readCode + ';})');
8181
} else if (options.typeCast === false) {
8282
result.push(lvalue + ' = packet.readLengthCodedBuffer();');
8383
} else {
@@ -100,7 +100,7 @@ function compile (fields, options, config) {
100100
return vm.runInThisContext(src);
101101
}
102102

103-
function readCodeFor (type, charset, encoding, config, options) {
103+
function readCodeFor (type, charset, encodingExpr, config, options) {
104104
var supportBigNumbers = options.supportBigNumbers || config.supportBigNumbers;
105105
var bigNumberStrings = options.bigNumberStrings || config.bigNumberStrings;
106106

@@ -143,12 +143,12 @@ function readCodeFor (type, charset, encoding, config, options) {
143143
case Types.GEOMETRY:
144144
return 'packet.parseGeometryValue()';
145145
case Types.JSON:
146-
return 'JSON.parse(packet.readLengthCodedString("' + encoding + '"))';
146+
return 'JSON.parse(packet.readLengthCodedString(' + encodingExpr + '))';
147147
default:
148148
if (charset == Charsets.BINARY) {
149149
return 'packet.readLengthCodedBuffer()';
150150
} else {
151-
return 'packet.readLengthCodedString("' + encoding + '")';
151+
return 'packet.readLengthCodedString(' + encodingExpr + ')';
152152
}
153153
}
154154
}

lib/connection.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ Connection.prototype.resume = function resume () {
442442

443443
Connection.prototype.keyFromFields = function keyFromFields (fields, options) {
444444
var res = (typeof options.nestTables) + '/' + options.nestTables + '/' + options.rowsAsArray
445-
+ options.supportBigNumbers + '/' + options.bigNumberStrings;
445+
+ options.supportBigNumbers + '/' + options.bigNumberStrings + '/' + typeof options.typeCast;
446446
for (var i = 0; i < fields.length; ++i) {
447447
res += '/' + fields[i].name + ':' + fields[i].columnType + ':' + fields[i].flags;
448448
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"iconv-lite": "^0.4.13",
3434
"long": "^3.2.0",
3535
"named-placeholders": "1.1.1",
36+
"object-assign": "^4.1.0",
3637
"readable-stream": "2.1.5",
3738
"safe-buffer": "^5.0.1",
3839
"seq-queue": "0.0.5",

test/integration/connection/encoding/test-charset-results.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var payload = 'привет, мир';
77

88
function tryEncoding (encoding, cb) {
99
connection.query('set character_set_results = ?', [encoding], function (err) {
10+
assert.ifError(err);
1011
connection.query('SELECT ?', [payload], function (err, rows, fields) {
1112
assert.ifError(err);
1213
var iconvEncoding = encoding;
@@ -21,11 +22,38 @@ function tryEncoding (encoding, cb) {
2122
});
2223
}
2324

25+
function tryEncodingExecute (encoding, cb) {
26+
connection.execute('set character_set_results = ?', [encoding], function (err) {
27+
assert.ifError(err);
28+
connection.execute('SELECT ? as n', [payload], function (err, rows, fields) {
29+
assert.ifError(err);
30+
var iconvEncoding = encoding;
31+
if (encoding == 'utf8mb4') {
32+
iconvEncoding = 'utf8';
33+
}
34+
assert.equal(mysql.CharsetToEncoding[fields[0].characterSet], iconvEncoding);
35+
// TODO: figure out correct metadata encodings setup for binary protocol
36+
// assert.equal(fields[0].name, payload);
37+
assert.equal(rows[0][fields[0].name], payload);
38+
cb();
39+
});
40+
});
41+
}
42+
43+
// christmas tree!!! :)
2444
tryEncoding('cp1251', function () {
2545
tryEncoding('koi8r', function () {
2646
tryEncoding('cp866', function () {
2747
tryEncoding('utf8mb4', function () {
28-
connection.end();
48+
tryEncodingExecute('cp1251', function () {
49+
tryEncodingExecute('koi8r', function () {
50+
tryEncodingExecute('cp866', function () {
51+
tryEncodingExecute('utf8mb4', function () {
52+
connection.end();
53+
});
54+
});
55+
});
56+
});
2957
});
3058
});
3159
});

test/integration/connection/encoding/test-client-encodings.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@ var mysql = require('../../../../index.js');
22
var common = require('../../../common');
33
var assert = require('assert');
44

5-
var connection = common.createConnection({charset: 'UTF8_GENERAL_CI'});
6-
connection.query('create table if not exists __test_client_encodings (name VARCHAR(200))', function(err) {
5+
var connection = common.createConnection({charset: 'UTF8MB4_GENERAL_CI'});
6+
connection.query('drop table if exists __test_client_encodings');
7+
connection.query('create table if not exists __test_client_encodings (name VARCHAR(200)) CHARACTER SET=utf8mb4', function (err) {
78
assert.ifError(err);
8-
connection.query('delete from __test_client_encodings', function(err) {
9+
connection.query('delete from __test_client_encodings', function (err) {
910
assert.ifError(err);
1011
connection.end();
1112

1213
var connection1 = common.createConnection({charset: 'CP1251_GENERAL_CI'});
13-
connection1.query('insert into __test_client_encodings values("привет, мир")', function(err) {
14+
connection1.query('insert into __test_client_encodings values("привет, мир")', function (err) {
1415
assert.ifError(err);
1516
connection1.end();
1617

1718
var connection2 = common.createConnection({charset: 'KOI8R_GENERAL_CI'});
18-
connection2.query('select * from __test_client_encodings', function(err, rows) {
19+
connection2.query('select * from __test_client_encodings', function (err, rows) {
1920
assert.ifError(err);
2021
assert.equal(rows[0].name, 'привет, мир');
2122
connection2.end();

test/integration/connection/test-typecast.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ connection.query({
1010
}
1111
return next();
1212
}
13-
}, function(err, res) {
13+
}, function (err, res) {
1414
assert.ifError(err);
15-
assert.equal(res[0].foo, 'FOO UPPERCASE')
15+
assert.equal(res[0].foo, 'FOO UPPERCASE');
1616
});
1717

1818

1919
connection.query({
2020
sql: 'select "foobar" as foo',
2121
typeCast: false
22-
}, function(err, res) {
22+
}, function (err, res) {
2323
assert.ifError(err);
2424
assert(Buffer.isBuffer(res[0].foo));
2525
assert.equal(res[0].foo.toString('utf8'), 'foobar');

0 commit comments

Comments
 (0)