diff options
Diffstat (limited to 'node_modules/mysql2/lib/parsers/text_parser.js')
-rw-r--r-- | node_modules/mysql2/lib/parsers/text_parser.js | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/node_modules/mysql2/lib/parsers/text_parser.js b/node_modules/mysql2/lib/parsers/text_parser.js new file mode 100644 index 0000000..0af4a7a --- /dev/null +++ b/node_modules/mysql2/lib/parsers/text_parser.js @@ -0,0 +1,202 @@ +'use strict'; + +const Types = require('../constants/types.js'); +const Charsets = require('../constants/charsets.js'); +const helpers = require('../helpers'); +const genFunc = require('generate-function'); +const parserCache = require('./parser_cache.js'); + +const typeNames = []; +for (const t in Types) { + typeNames[Types[t]] = t; +} + +function readCodeFor(type, charset, encodingExpr, config, options) { + const supportBigNumbers = + options.supportBigNumbers || config.supportBigNumbers; + const bigNumberStrings = options.bigNumberStrings || config.bigNumberStrings; + const timezone = options.timezone || config.timezone; + const dateStrings = options.dateStrings || config.dateStrings; + + switch (type) { + case Types.TINY: + case Types.SHORT: + case Types.LONG: + case Types.INT24: + case Types.YEAR: + return 'packet.parseLengthCodedIntNoBigCheck()'; + case Types.LONGLONG: + if (supportBigNumbers && bigNumberStrings) { + return 'packet.parseLengthCodedIntString()'; + } + return `packet.parseLengthCodedInt(${supportBigNumbers})`; + case Types.FLOAT: + case Types.DOUBLE: + return 'packet.parseLengthCodedFloat()'; + case Types.NULL: + return 'packet.readLengthCodedNumber()'; + case Types.DECIMAL: + case Types.NEWDECIMAL: + if (config.decimalNumbers) { + return 'packet.parseLengthCodedFloat()'; + } + return 'packet.readLengthCodedString("ascii")'; + case Types.DATE: + if (helpers.typeMatch(type, dateStrings, Types)) { + return 'packet.readLengthCodedString("ascii")'; + } + return `packet.parseDate('${timezone}')`; + case Types.DATETIME: + case Types.TIMESTAMP: + if (helpers.typeMatch(type, dateStrings, Types)) { + return 'packet.readLengthCodedString("ascii")'; + } + return `packet.parseDateTime('${timezone}')`; + case Types.TIME: + return 'packet.readLengthCodedString("ascii")'; + case Types.GEOMETRY: + return 'packet.parseGeometryValue()'; + case Types.JSON: + // Since for JSON columns mysql always returns charset 63 (BINARY), + // we have to handle it according to JSON specs and use "utf8", + // see https://github.com/sidorares/node-mysql2/issues/409 + return 'JSON.parse(packet.readLengthCodedString("utf8"))'; + default: + if (charset === Charsets.BINARY) { + return 'packet.readLengthCodedBuffer()'; + } + return `packet.readLengthCodedString(${encodingExpr})`; + } +} + +function compile(fields, options, config) { + // use global typeCast if current query doesn't specify one + if ( + typeof config.typeCast === 'function' && + typeof options.typeCast !== 'function' + ) { + options.typeCast = config.typeCast; + } + + function wrap(field, _this) { + return { + type: typeNames[field.columnType], + length: field.columnLength, + db: field.schema, + table: field.table, + name: field.name, + string: function() { + return _this.packet.readLengthCodedString(field.encoding); + }, + buffer: function() { + return _this.packet.readLengthCodedBuffer(); + }, + geometry: function() { + return _this.packet.parseGeometryValue(); + } + }; + } + + const parserFn = genFunc(); + + /* eslint-disable no-trailing-spaces */ + /* eslint-disable no-spaced-func */ + /* eslint-disable no-unexpected-multiline */ + parserFn('(function () {')( + 'return class TextRow {' + ); + + // constructor method + parserFn('constructor(fields) {'); + // 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;'); + parserFn('for(let i=0; i<fields.length; ++i) {'); + parserFn('this[`wrap${i}`] = wrap(fields[i], _this);'); + parserFn('}'); + } + parserFn('}'); + + // next method + parserFn('next(packet, fields, options) {'); + parserFn("this.packet = packet;"); + if (options.rowsAsArray) { + parserFn(`const result = new Array(${fields.length});`); + } else { + parserFn("const result = {};"); + } + + const resultTables = {}; + let resultTablesArray = []; + + if (options.nestTables === true) { + for (let i=0; i < fields.length; i++) { + resultTables[fields[i].table] = 1; + } + resultTablesArray = Object.keys(resultTables); + for (let i=0; i < resultTablesArray.length; i++) { + parserFn(`result[${helpers.srcEscape(resultTablesArray[i])}] = {};`); + } + } + + let lvalue = ''; + let fieldName = ''; + for (let i = 0; i < fields.length; i++) { + fieldName = helpers.srcEscape(fields[i].name); + parserFn(`// ${fieldName}: ${typeNames[fields[i].columnType]}`); + if (typeof options.nestTables === 'string') { + lvalue = `result[${helpers.srcEscape( + fields[i].table + options.nestTables + fields[i].name + )}]`; + } else if (options.nestTables === true) { + lvalue = `result[${helpers.srcEscape(fields[i].table)}][${fieldName}]`; + } else if (options.rowsAsArray) { + lvalue = `result[${i.toString(10)}]`; + } else { + lvalue = `result[${fieldName}]`; + } + if (options.typeCast === false) { + parserFn(`${lvalue} = packet.readLengthCodedBuffer();`); + } else { + const encodingExpr = `fields[${i}].encoding`; + const readCode = readCodeFor( + fields[i].columnType, + fields[i].characterSet, + encodingExpr, + config, + options + ); + if (typeof options.typeCast === 'function') { + parserFn(`${lvalue} = options.typeCast(this.wrap${i}, function() { return ${readCode} });`); + } else { + parserFn(`${lvalue} = ${readCode};`); + } + } + } + + parserFn('return result;'); + parserFn('}'); + parserFn('};')('})()'); + + /* eslint-enable no-trailing-spaces */ + /* eslint-enable no-spaced-func */ + /* eslint-enable no-unexpected-multiline */ + + if (config.debug) { + helpers.printDebugWithCode( + 'Compiled text protocol row parser', + parserFn.toString() + ); + } + if (typeof options.typeCast === 'function') { + return parserFn.toFunction({wrap}); + } + return parserFn.toFunction(); +} + +function getTextParser(fields, options, config) { + return parserCache.getParser('text', fields, options, config, compile); +} + +module.exports = getTextParser; |