execute.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. 'use strict';
  2. const CursorType = require('../constants/cursor');
  3. const CommandCodes = require('../constants/commands');
  4. const ClientConstants = require('../constants/client');
  5. const Types = require('../constants/types');
  6. const Packet = require('../packets/packet');
  7. const CharsetToEncoding = require('../constants/charset_encodings.js');
  8. const { toParameter } = require('./encode_parameter.js');
  9. class Execute {
  10. constructor(
  11. id,
  12. parameters,
  13. charsetNumber,
  14. timezone,
  15. attributes,
  16. clientFlags
  17. ) {
  18. this.id = id;
  19. this.parameters = parameters;
  20. this.encoding = CharsetToEncoding[charsetNumber];
  21. this.timezone = timezone;
  22. this.attributes = attributes;
  23. this.clientFlags = clientFlags || 0;
  24. }
  25. static fromPacket(packet, encoding) {
  26. const stmtId = packet.readInt32();
  27. const flags = packet.readInt8();
  28. const iterationCount = packet.readInt32();
  29. let i = packet.offset;
  30. while (i < packet.end - 1) {
  31. if (
  32. (packet.buffer[i + 1] === Types.VAR_STRING ||
  33. packet.buffer[i + 1] === Types.NULL ||
  34. packet.buffer[i + 1] === Types.DOUBLE ||
  35. packet.buffer[i + 1] === Types.TINY ||
  36. packet.buffer[i + 1] === Types.DATETIME ||
  37. packet.buffer[i + 1] === Types.JSON) &&
  38. packet.buffer[i] === 1 &&
  39. packet.buffer[i + 2] === 0
  40. ) {
  41. break;
  42. } else {
  43. packet.readInt8();
  44. }
  45. i++;
  46. }
  47. const types = [];
  48. for (let i = packet.offset + 1; i < packet.end - 1; i++) {
  49. if (
  50. (packet.buffer[i] === Types.VAR_STRING ||
  51. packet.buffer[i] === Types.NULL ||
  52. packet.buffer[i] === Types.DOUBLE ||
  53. packet.buffer[i] === Types.TINY ||
  54. packet.buffer[i] === Types.DATETIME ||
  55. packet.buffer[i] === Types.JSON) &&
  56. packet.buffer[i + 1] === 0
  57. ) {
  58. types.push(packet.buffer[i]);
  59. packet.skip(2);
  60. }
  61. }
  62. packet.skip(1);
  63. const values = [];
  64. for (let i = 0; i < types.length; i++) {
  65. if (types[i] === Types.VAR_STRING) {
  66. values.push(packet.readLengthCodedString(encoding));
  67. } else if (types[i] === Types.DOUBLE) {
  68. values.push(packet.readDouble());
  69. } else if (types[i] === Types.TINY) {
  70. values.push(packet.readInt8());
  71. } else if (types[i] === Types.DATETIME) {
  72. values.push(packet.readDateTime());
  73. } else if (types[i] === Types.JSON) {
  74. values.push(JSON.parse(packet.readLengthCodedString(encoding)));
  75. }
  76. if (types[i] === Types.NULL) {
  77. values.push(null);
  78. }
  79. }
  80. return { stmtId, flags, iterationCount, values };
  81. }
  82. _serializeToBuffer(buffer) {
  83. const useQueryAttributes =
  84. this.clientFlags & ClientConstants.CLIENT_QUERY_ATTRIBUTES;
  85. const attrNames =
  86. useQueryAttributes && this.attributes ? Object.keys(this.attributes) : [];
  87. const numParams = this.parameters ? this.parameters.length : 0;
  88. const numAttrs = attrNames.length;
  89. const totalParams = numParams + numAttrs;
  90. const packet = new Packet(0, buffer, 0, buffer.length);
  91. packet.offset = 4;
  92. packet.writeInt8(CommandCodes.STMT_EXECUTE);
  93. packet.writeInt32(this.id);
  94. let cursorFlags = CursorType.NO_CURSOR;
  95. if (useQueryAttributes) {
  96. cursorFlags |= CursorType.PARAMETER_COUNT_AVAILABLE;
  97. }
  98. packet.writeInt8(cursorFlags);
  99. packet.writeInt32(1); // iteration-count, always 1
  100. if (useQueryAttributes) {
  101. packet.writeLengthCodedNumber(totalParams);
  102. }
  103. if (totalParams > 0) {
  104. const bindParams =
  105. numParams > 0
  106. ? this.parameters.map((v) =>
  107. toParameter(v, this.encoding, this.timezone)
  108. )
  109. : [];
  110. const attrParams = attrNames.map((name) =>
  111. toParameter(this.attributes[name], this.encoding, this.timezone)
  112. );
  113. const allParams = bindParams.concat(attrParams);
  114. // null bitmap
  115. let bitmap = 0;
  116. let bitValue = 1;
  117. allParams.forEach((parameter) => {
  118. if (parameter.type === Types.NULL) {
  119. bitmap += bitValue;
  120. }
  121. bitValue *= 2;
  122. if (bitValue === 256) {
  123. packet.writeInt8(bitmap);
  124. bitmap = 0;
  125. bitValue = 1;
  126. }
  127. });
  128. if (bitValue !== 1) {
  129. packet.writeInt8(bitmap);
  130. }
  131. packet.writeInt8(1); // new-params-bound-flag
  132. // types (and names for attributes)
  133. for (let i = 0; i < allParams.length; i++) {
  134. packet.writeInt8(allParams[i].type);
  135. packet.writeInt8(0); // unsigned flag
  136. if (useQueryAttributes) {
  137. const name = i < numParams ? '' : attrNames[i - numParams];
  138. packet.writeLengthCodedString(name, this.encoding);
  139. }
  140. }
  141. // values
  142. allParams.forEach((parameter) => {
  143. if (parameter.type !== Types.NULL) {
  144. parameter.writer.call(packet, parameter.value);
  145. }
  146. });
  147. }
  148. return packet;
  149. }
  150. toPacket() {
  151. const p = this._serializeToBuffer(Packet.MockBuffer());
  152. return this._serializeToBuffer(Buffer.allocUnsafe(p.offset));
  153. }
  154. }
  155. module.exports = Execute;