UNPKG

mysql2

Version:

fast mysql driver. Implements core protocol, prepared statements, ssl and compression in native JS

178 lines (155 loc) 5.15 kB
'use strict'; const CursorType = require('../constants/cursor'); const CommandCodes = require('../constants/commands'); const ClientConstants = require('../constants/client'); const Types = require('../constants/types'); const Packet = require('../packets/packet'); const CharsetToEncoding = require('../constants/charset_encodings.js'); const { toParameter } = require('./encode_parameter.js'); class Execute { constructor( id, parameters, charsetNumber, timezone, attributes, clientFlags ) { this.id = id; this.parameters = parameters; this.encoding = CharsetToEncoding[charsetNumber]; this.timezone = timezone; this.attributes = attributes; this.clientFlags = clientFlags || 0; } static fromPacket(packet, encoding) { const stmtId = packet.readInt32(); const flags = packet.readInt8(); const iterationCount = packet.readInt32(); let i = packet.offset; while (i < packet.end - 1) { if ( (packet.buffer[i + 1] === Types.VAR_STRING || packet.buffer[i + 1] === Types.NULL || packet.buffer[i + 1] === Types.DOUBLE || packet.buffer[i + 1] === Types.TINY || packet.buffer[i + 1] === Types.DATETIME || packet.buffer[i + 1] === Types.JSON) && packet.buffer[i] === 1 && packet.buffer[i + 2] === 0 ) { break; } else { packet.readInt8(); } i++; } const types = []; for (let i = packet.offset + 1; i < packet.end - 1; i++) { if ( (packet.buffer[i] === Types.VAR_STRING || packet.buffer[i] === Types.NULL || packet.buffer[i] === Types.DOUBLE || packet.buffer[i] === Types.TINY || packet.buffer[i] === Types.DATETIME || packet.buffer[i] === Types.JSON) && packet.buffer[i + 1] === 0 ) { types.push(packet.buffer[i]); packet.skip(2); } } packet.skip(1); const values = []; for (let i = 0; i < types.length; i++) { if (types[i] === Types.VAR_STRING) { values.push(packet.readLengthCodedString(encoding)); } else if (types[i] === Types.DOUBLE) { values.push(packet.readDouble()); } else if (types[i] === Types.TINY) { values.push(packet.readInt8()); } else if (types[i] === Types.DATETIME) { values.push(packet.readDateTime()); } else if (types[i] === Types.JSON) { values.push(JSON.parse(packet.readLengthCodedString(encoding))); } if (types[i] === Types.NULL) { values.push(null); } } return { stmtId, flags, iterationCount, values }; } _serializeToBuffer(buffer) { const useQueryAttributes = this.clientFlags & ClientConstants.CLIENT_QUERY_ATTRIBUTES; const attrNames = useQueryAttributes && this.attributes ? Object.keys(this.attributes) : []; const numParams = this.parameters ? this.parameters.length : 0; const numAttrs = attrNames.length; const totalParams = numParams + numAttrs; const packet = new Packet(0, buffer, 0, buffer.length); packet.offset = 4; packet.writeInt8(CommandCodes.STMT_EXECUTE); packet.writeInt32(this.id); let cursorFlags = CursorType.NO_CURSOR; if (useQueryAttributes) { cursorFlags |= CursorType.PARAMETER_COUNT_AVAILABLE; } packet.writeInt8(cursorFlags); packet.writeInt32(1); // iteration-count, always 1 if (useQueryAttributes) { packet.writeLengthCodedNumber(totalParams); } if (totalParams > 0) { const bindParams = numParams > 0 ? this.parameters.map((v) => toParameter(v, this.encoding, this.timezone) ) : []; const attrParams = attrNames.map((name) => toParameter(this.attributes[name], this.encoding, this.timezone) ); const allParams = bindParams.concat(attrParams); // null bitmap let bitmap = 0; let bitValue = 1; allParams.forEach((parameter) => { if (parameter.type === Types.NULL) { bitmap += bitValue; } bitValue *= 2; if (bitValue === 256) { packet.writeInt8(bitmap); bitmap = 0; bitValue = 1; } }); if (bitValue !== 1) { packet.writeInt8(bitmap); } packet.writeInt8(1); // new-params-bound-flag // types (and names for attributes) for (let i = 0; i < allParams.length; i++) { packet.writeInt8(allParams[i].type); packet.writeInt8(0); // unsigned flag if (useQueryAttributes) { const name = i < numParams ? '' : attrNames[i - numParams]; packet.writeLengthCodedString(name, this.encoding); } } // values allParams.forEach((parameter) => { if (parameter.type !== Types.NULL) { parameter.writer.call(packet, parameter.value); } }); } return packet; } toPacket() { const p = this._serializeToBuffer(Packet.MockBuffer()); return this._serializeToBuffer(Buffer.allocUnsafe(p.offset)); } } module.exports = Execute;