'use strict'; // TODO: rename to OK packet // https://dev.mysql.com/doc/internals/en/packet-OK_Packet.html const Packet = require('./packet.js'); const ClientConstants = require('../constants/client.js'); const ServerSatusFlags = require('../constants/server_status.js'); const EncodingToCharset = require('../constants/encoding_charset.js'); const sessionInfoTypes = require('../constants/session_track.js'); class ResultSetHeader { constructor(packet, connection) { const bigNumberStrings = connection.config.bigNumberStrings; const encoding = connection.serverEncoding; const flags = connection._handshakePacket.capabilityFlags; const isSet = function(flag) { return flags & ClientConstants[flag]; }; if (packet.buffer[packet.offset] !== 0) { this.fieldCount = packet.readLengthCodedNumber(); if (this.fieldCount === null) { this.infileName = packet.readString(undefined, encoding); } return; } this.fieldCount = packet.readInt8(); // skip OK byte this.affectedRows = packet.readLengthCodedNumber(bigNumberStrings); this.insertId = packet.readLengthCodedNumberSigned(bigNumberStrings); this.info = ''; if (isSet('PROTOCOL_41')) { this.serverStatus = packet.readInt16(); this.warningStatus = packet.readInt16(); } else if (isSet('TRANSACTIONS')) { this.serverStatus = packet.readInt16(); } let stateChanges = null; if (isSet('SESSION_TRACK') && packet.offset < packet.end) { this.info = packet.readLengthCodedString(encoding); if (this.serverStatus && ServerSatusFlags.SERVER_SESSION_STATE_CHANGED) { // session change info record - see // https://dev.mysql.com/doc/internals/en/packet-OK_Packet.html#cs-sect-packet-ok-sessioninfo let len = packet.offset < packet.end ? packet.readLengthCodedNumber() : 0; const end = packet.offset + len; let type, key, stateEnd; if (len > 0) { stateChanges = { systemVariables: {}, schema: null, trackStateChange: null }; } while (packet.offset < end) { type = packet.readInt8(); len = packet.readLengthCodedNumber(); stateEnd = packet.offset + len; if (type === sessionInfoTypes.SYSTEM_VARIABLES) { key = packet.readLengthCodedString(encoding); const val = packet.readLengthCodedString(encoding); stateChanges.systemVariables[key] = val; if (key === 'character_set_client') { const charsetNumber = EncodingToCharset[val]; connection.config.charsetNumber = charsetNumber; } } else if (type === sessionInfoTypes.SCHEMA) { key = packet.readLengthCodedString(encoding); stateChanges.schema = key; } else if (type === sessionInfoTypes.STATE_CHANGE) { stateChanges.trackStateChange = packet.readLengthCodedString( encoding ); } else { // unsupported session track type. For now just ignore } packet.offset = stateEnd; } } } else { this.info = packet.readString(undefined, encoding); } if (stateChanges) { this.stateChanges = stateChanges; } const m = this.info.match(/\schanged:\s*(\d+)/i); if (m !== null) { this.changedRows = parseInt(m[1], 10); } } // TODO: should be consistent instance member, but it's just easier here to have just function static toPacket(fieldCount, insertId) { let length = 4 + Packet.lengthCodedNumberLength(fieldCount); if (typeof insertId !== 'undefined') { length += Packet.lengthCodedNumberLength(insertId); } const buffer = Buffer.allocUnsafe(length); const packet = new Packet(0, buffer, 0, length); packet.offset = 4; packet.writeLengthCodedNumber(fieldCount); if (typeof insertId !== 'undefined') { packet.writeLengthCodedNumber(insertId); } return packet; } } module.exports = ResultSetHeader;