resultset_header.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. 'use strict';
  2. // TODO: rename to OK packet
  3. // https://dev.mysql.com/doc/internals/en/packet-OK_Packet.html
  4. const Packet = require('./packet.js');
  5. const ClientConstants = require('../constants/client.js');
  6. const ServerSatusFlags = require('../constants/server_status.js');
  7. const EncodingToCharset = require('../constants/encoding_charset.js');
  8. const sessionInfoTypes = require('../constants/session_track.js');
  9. class ResultSetHeader {
  10. constructor(packet, connection) {
  11. const bigNumberStrings = connection.config.bigNumberStrings;
  12. const encoding = connection.serverEncoding;
  13. const flags = connection._handshakePacket.capabilityFlags;
  14. const isSet = function(flag) {
  15. return flags & ClientConstants[flag];
  16. };
  17. if (packet.buffer[packet.offset] !== 0) {
  18. this.fieldCount = packet.readLengthCodedNumber();
  19. if (this.fieldCount === null) {
  20. this.infileName = packet.readString(undefined, encoding);
  21. }
  22. return;
  23. }
  24. this.fieldCount = packet.readInt8(); // skip OK byte
  25. this.affectedRows = packet.readLengthCodedNumber(bigNumberStrings);
  26. this.insertId = packet.readLengthCodedNumberSigned(bigNumberStrings);
  27. this.info = '';
  28. if (isSet('PROTOCOL_41')) {
  29. this.serverStatus = packet.readInt16();
  30. this.warningStatus = packet.readInt16();
  31. } else if (isSet('TRANSACTIONS')) {
  32. this.serverStatus = packet.readInt16();
  33. }
  34. let stateChanges = null;
  35. if (isSet('SESSION_TRACK') && packet.offset < packet.end) {
  36. this.info = packet.readLengthCodedString(encoding);
  37. if (this.serverStatus && ServerSatusFlags.SERVER_SESSION_STATE_CHANGED) {
  38. // session change info record - see
  39. // https://dev.mysql.com/doc/internals/en/packet-OK_Packet.html#cs-sect-packet-ok-sessioninfo
  40. let len =
  41. packet.offset < packet.end ? packet.readLengthCodedNumber() : 0;
  42. const end = packet.offset + len;
  43. let type, key, stateEnd;
  44. if (len > 0) {
  45. stateChanges = {
  46. systemVariables: {},
  47. schema: null,
  48. gtids: [],
  49. trackStateChange: null
  50. };
  51. }
  52. while (packet.offset < end) {
  53. type = packet.readInt8();
  54. len = packet.readLengthCodedNumber();
  55. stateEnd = packet.offset + len;
  56. if (type === sessionInfoTypes.SYSTEM_VARIABLES) {
  57. key = packet.readLengthCodedString(encoding);
  58. const val = packet.readLengthCodedString(encoding);
  59. stateChanges.systemVariables[key] = val;
  60. if (key === 'character_set_client') {
  61. const charsetNumber = EncodingToCharset[val];
  62. connection.config.charsetNumber = charsetNumber;
  63. }
  64. } else if (type === sessionInfoTypes.SCHEMA) {
  65. key = packet.readLengthCodedString(encoding);
  66. stateChanges.schema = key;
  67. } else if (type === sessionInfoTypes.STATE_CHANGE) {
  68. stateChanges.trackStateChange = packet.readLengthCodedString(
  69. encoding
  70. );
  71. } else if (type === sessionInfoTypes.STATE_GTIDS) {
  72. // TODO: find if the first length coded string means anything. Usually comes as empty
  73. // eslint-disable-next-line no-unused-vars
  74. const _unknownString = packet.readLengthCodedString(encoding);
  75. const gtid = packet.readLengthCodedString(encoding);
  76. stateChanges.gtids = gtid.split(',');
  77. } else {
  78. // unsupported session track type. For now just ignore
  79. }
  80. packet.offset = stateEnd;
  81. }
  82. }
  83. } else {
  84. this.info = packet.readString(undefined, encoding);
  85. }
  86. if (stateChanges) {
  87. this.stateChanges = stateChanges;
  88. }
  89. const m = this.info.match(/\schanged:\s*(\d+)/i);
  90. if (m !== null) {
  91. this.changedRows = parseInt(m[1], 10);
  92. } else {
  93. this.changedRows = 0;
  94. }
  95. }
  96. // TODO: should be consistent instance member, but it's just easier here to have just function
  97. static toPacket(fieldCount, insertId) {
  98. let length = 4 + Packet.lengthCodedNumberLength(fieldCount);
  99. if (typeof insertId !== 'undefined') {
  100. length += Packet.lengthCodedNumberLength(insertId);
  101. }
  102. const buffer = Buffer.allocUnsafe(length);
  103. const packet = new Packet(0, buffer, 0, length);
  104. packet.offset = 4;
  105. packet.writeLengthCodedNumber(fieldCount);
  106. if (typeof insertId !== 'undefined') {
  107. packet.writeLengthCodedNumber(insertId);
  108. }
  109. return packet;
  110. }
  111. }
  112. module.exports = ResultSetHeader;