diff --git a/lib/commands/execute.js b/lib/commands/execute.js index d5c2d8ab79..8ab7304b5b 100644 --- a/lib/commands/execute.js +++ b/lib/commands/execute.js @@ -85,10 +85,10 @@ class Execute extends Command { if (!packet.isEOF()) { return connection.protocolError('Expected EOF packet'); } - this._rowParser = this.buildParserFromFields( + this._rowParser = new (this.buildParserFromFields( this._fields[this._resultIndex], connection - ); + ))(); return Execute.prototype.row; } } diff --git a/lib/commands/query.js b/lib/commands/query.js index f36dd5e4c9..d5c6cdd1ae 100644 --- a/lib/commands/query.js +++ b/lib/commands/query.js @@ -9,7 +9,6 @@ const Command = require('./command.js'); const Packets = require('../packets/index.js'); const getTextParser = require('../parsers/text_parser.js'); const ServerStatus = require('../constants/server_status.js'); -const CharsetToEncoding = require('../constants/charset_encodings.js'); const EmptyPacket = new Packets.Packet(0, Buffer.allocUnsafe(4), 0, 4); @@ -213,7 +212,7 @@ class Query extends Command { if (this._receivedFieldsCount === this._fieldCount) { const fields = this._fields[this._resultIndex]; this.emit('fields', fields); - this._rowParser = getTextParser(fields, this.options, connection.config); + this._rowParser = new (getTextParser(fields, this.options, connection.config))(); return Query.prototype.fieldsEOF; } return Query.prototype.readField; @@ -240,11 +239,10 @@ class Query extends Command { } let row; try { - row = new this._rowParser( + row = this._rowParser.next( packet, this._fields[this._resultIndex], - this.options, - CharsetToEncoding + this.options ); } catch (err) { this._localStreamError = err; diff --git a/lib/parsers/binary_parser.js b/lib/parsers/binary_parser.js index d20c87cb2d..bbd29596ec 100644 --- a/lib/parsers/binary_parser.js +++ b/lib/parsers/binary_parser.js @@ -74,7 +74,7 @@ function readCodeFor(field, config, options, fieldNum) { if (field.characterSet === Charsets.BINARY) { return 'packet.readLengthCodedBuffer();'; } - return `packet.readLengthCodedString(CharsetToEncoding[fields[${fieldNum}].characterSet])`; + return `packet.readLengthCodedString(fields[${fieldNum}].encoding)`; } } @@ -87,12 +87,16 @@ function compile(fields, options, config) { /* eslint-disable no-spaced-func */ /* eslint-disable no-unexpected-multiline */ - parserFn('(function(){')( - 'return function BinaryRow(packet, fields, options, CharsetToEncoding) {' - ); + parserFn('(function(){'); + parserFn('return class BinaryRow {'); + parserFn('constructor() {'); + parserFn('}'); + parserFn('next(packet, fields, options) {'); if (options.rowsAsArray) { parserFn(`const result = new Array(${fields.length});`); + } else { + parserFn("const result = {};"); } const resultTables = {}; @@ -104,7 +108,7 @@ function compile(fields, options, config) { } resultTablesArray = Object.keys(resultTables); for (i = 0; i < resultTablesArray.length; i++) { - parserFn(`this[${helpers.srcEscape(resultTablesArray[i])}] = {};`); + parserFn(`result[${helpers.srcEscape(resultTablesArray[i])}] = {};`); } } @@ -125,16 +129,16 @@ function compile(fields, options, config) { if (typeof options.nestTables === 'string') { tableName = helpers.srcEscape(fields[i].table); - lvalue = `this[${helpers.srcEscape( + lvalue = `result[${helpers.srcEscape( fields[i].table + options.nestTables + fields[i].name )}]`; } else if (options.nestTables === true) { tableName = helpers.srcEscape(fields[i].table); - lvalue = `this[${tableName}][${fieldName}]`; + lvalue = `result[${tableName}][${fieldName}]`; } else if (options.rowsAsArray) { lvalue = `result[${i.toString(10)}]`; } else { - lvalue = `this[${helpers.srcEscape(fields[i].name)}]`; + lvalue = `result[${helpers.srcEscape(fields[i].name)}]`; } // TODO: this used to be an optimisation ( if column marked as NOT_NULL don't include code to check null @@ -158,10 +162,8 @@ function compile(fields, options, config) { } } - if (options.rowsAsArray) { - parserFn('return result;'); - } - + parserFn('return result;'); + parserFn('}'); parserFn('};')('})()'); /* eslint-enable no-trailing-spaces */ diff --git a/lib/parsers/parser_cache.js b/lib/parsers/parser_cache.js index 2fa8cf066a..509b5c6736 100644 --- a/lib/parsers/parser_cache.js +++ b/lib/parsers/parser_cache.js @@ -20,13 +20,7 @@ function keyFromFields(type, fields, options, config) { `/${options.dateStrings}`; for (let i = 0; i < fields.length; ++i) { const field = fields[i]; - res += `/${field.name}:${field.columnType}:${field.flags}:${ - field.characterSet - }`; - - if (options.nestTables) { - res += `:${field.table}` - } + res += `/${field.name}:${field.columnType}:${field.length}:${field.schema}:${field.table}:${field.flags}:${field.characterSet}`; } return res; } diff --git a/lib/parsers/text_parser.js b/lib/parsers/text_parser.js index eb777d8eb7..2036caed6e 100644 --- a/lib/parsers/text_parser.js +++ b/lib/parsers/text_parser.js @@ -70,27 +70,6 @@ function readCodeFor(type, charset, encodingExpr, config, options) { } function compile(fields, options, config) { - // node-mysql typeCast compatibility wrapper - // see https://github.com/mysqljs/mysql/blob/96fdd0566b654436624e2375c7b6604b1f50f825/lib/protocol/packets/Field.js - function wrap(field, type, packet, encoding) { - return { - type: type, - length: field.columnLength, - db: field.schema, - table: field.table, - name: field.name, - string: function() { - return packet.readLengthCodedString(encoding); - }, - buffer: function() { - return packet.readLengthCodedBuffer(); - }, - geometry: function() { - return packet.parseGeometryValue(); - } - }; - } - // use global typeCast if current query doesn't specify one if ( typeof config.typeCast === 'function' && @@ -100,77 +79,110 @@ function compile(fields, options, config) { } const parserFn = genFunc(); - let i = 0; /* eslint-disable no-trailing-spaces */ /* eslint-disable no-spaced-func */ /* eslint-disable no-unexpected-multiline */ parserFn('(function () {')( - 'return function TextRow(packet, fields, options, CharsetToEncoding) {' + 'return class TextRow {' ); - if (options.rowsAsArray) { - parserFn(`const result = new Array(${fields.length})`); + // constructor method + parserFn('constructor() {'); + // node-mysql typeCast compatibility wrapper + // see https://github.com/mysqljs/mysql/blob/96fdd0566b654436624e2375c7b6604b1f50f825/lib/protocol/packets/Field.js + if (typeof options.typeCast === 'function') { + parserFn('const _this = this;'); + for(let i=0; i 0) { if ( - _rows.constructor.name === 'Array' && - _rows[0].constructor.name === 'TextRow' + _rows.constructor.name === 'Array' ) { _numResults = 1; } diff --git a/test/unit/commands/test-query.js b/test/unit/commands/test-query.js index c10cd27b57..0aee201c45 100644 --- a/test/unit/commands/test-query.js +++ b/test/unit/commands/test-query.js @@ -9,11 +9,11 @@ const testQuery = new Query({}, (err, res) => { assert.equal(res, null); }); -testQuery._rowParser = class FailingRowParser { - constructor() { +testQuery._rowParser = new class FailingRowParser { + next() { throw testError; } -}; +}(); testQuery.row({ isEOF: () => false