binlog_query_statusvars.js 3.43 KB
'use strict';

// http://dev.mysql.com/doc/internals/en/query-event.html

const keys = {
  FLAGS2: 0,
  SQL_MODE: 1,
  CATALOG: 2,
  AUTO_INCREMENT: 3,
  CHARSET: 4,
  TIME_ZONE: 5,
  CATALOG_NZ: 6,
  LC_TIME_NAMES: 7,
  CHARSET_DATABASE: 8,
  TABLE_MAP_FOR_UPDATE: 9,
  MASTER_DATA_WRITTEN: 10,
  INVOKERS: 11,
  UPDATED_DB_NAMES: 12,
  MICROSECONDS: 3
};

module.exports = function parseStatusVars(buffer) {
  const result = {};
  let offset = 0;
  let key, length, prevOffset;
  while (offset < buffer.length) {
    key = buffer[offset++];
    switch (key) {
      case keys.FLAGS2:
        result.flags = buffer.readUInt32LE(offset);
        offset += 4;
        break;
      case keys.SQL_MODE:
        // value is 8 bytes, but all dcumented flags are in first 4 bytes
        result.sqlMode = buffer.readUInt32LE(offset);
        offset += 8;
        break;
      case keys.CATALOG:
        length = buffer[offset++];
        result.catalog = buffer.toString('utf8', offset, offset + length);
        offset += length + 1; // null byte after string
        break;
      case keys.CHARSET:
        result.clientCharset = buffer.readUInt16LE(offset);
        result.connectionCollation = buffer.readUInt16LE(offset + 2);
        result.serverCharset = buffer.readUInt16LE(offset + 4);
        offset += 6;
        break;
      case keys.TIME_ZONE:
        length = buffer[offset++];
        result.timeZone = buffer.toString('utf8', offset, offset + length);
        offset += length; // no null byte
        break;
      case keys.CATALOG_NZ:
        length = buffer[offset++];
        result.catalogNz = buffer.toString('utf8', offset, offset + length);
        offset += length; // no null byte
        break;
      case keys.LC_TIME_NAMES:
        result.lcTimeNames = buffer.readUInt16LE(offset);
        offset += 2;
        break;
      case keys.CHARSET_DATABASE:
        result.schemaCharset = buffer.readUInt16LE(offset);
        offset += 2;
        break;
      case keys.TABLE_MAP_FOR_UPDATE:
        result.mapForUpdate1 = buffer.readUInt32LE(offset);
        result.mapForUpdate2 = buffer.readUInt32LE(offset + 4);
        offset += 8;
        break;
      case keys.MASTER_DATA_WRITTEN:
        result.masterDataWritten = buffer.readUInt32LE(offset);
        offset += 4;
        break;
      case keys.INVOKERS:
        length = buffer[offset++];
        result.invokerUsername = buffer.toString(
          'utf8',
          offset,
          offset + length
        );
        offset += length;
        length = buffer[offset++];
        result.invokerHostname = buffer.toString(
          'utf8',
          offset,
          offset + length
        );
        offset += length;
        break;
      case keys.UPDATED_DB_NAMES:
        length = buffer[offset++];
        // length - number of null-terminated strings
        result.updatedDBs = []; // we'll store them as array here
        for (; length; --length) {
          prevOffset = offset;
          // fast forward to null terminating byte
          while (buffer[offset++] && offset < buffer.length) {
            // empty body, everything inside while condition
          }
          result.updatedDBs.push(
            buffer.toString('utf8', prevOffset, offset - 1)
          );
        }
        break;
      case keys.MICROSECONDS:
        result.microseconds =
          // REVIEW: INVALID UNKNOWN VARIABLE!
          buffer.readInt16LE(offset) + (buffer[offset + 2] << 16);
        offset += 3;
    }
  }
  return result;
};