query.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. 'use strict';
  2. const Packet = require('../packets/packet.js');
  3. const CommandCode = require('../constants/commands.js');
  4. const StringParser = require('../parsers/string.js');
  5. const CharsetToEncoding = require('../constants/charset_encodings.js');
  6. const ClientConstants = require('../constants/client.js');
  7. const Types = require('../constants/types.js');
  8. const { toParameter } = require('./encode_parameter.js');
  9. class Query {
  10. constructor(sql, charsetNumber, attributes, clientFlags) {
  11. this.query = sql;
  12. this.charsetNumber = charsetNumber;
  13. this.encoding = CharsetToEncoding[charsetNumber];
  14. this.attributes = attributes;
  15. this.clientFlags = clientFlags || 0;
  16. }
  17. serializeToBuffer(buffer) {
  18. const useQueryAttributes =
  19. this.clientFlags & ClientConstants.CLIENT_QUERY_ATTRIBUTES;
  20. const sqlBuf = StringParser.encode(this.query, this.encoding);
  21. const packet = new Packet(0, buffer, 0, buffer.length);
  22. packet.offset = 4;
  23. packet.writeInt8(CommandCode.QUERY);
  24. if (useQueryAttributes) {
  25. const attrs = this.attributes;
  26. const names = attrs ? Object.keys(attrs) : [];
  27. const paramCount = names.length;
  28. packet.writeLengthCodedNumber(paramCount);
  29. packet.writeLengthCodedNumber(1); // parameter_set_count, always 1
  30. if (paramCount > 0) {
  31. const parameters = names.map((name) =>
  32. toParameter(attrs[name], this.encoding, 'local')
  33. );
  34. // null bitmap
  35. let bitmap = 0;
  36. let bitValue = 1;
  37. parameters.forEach((parameter) => {
  38. if (parameter.type === Types.NULL) {
  39. bitmap += bitValue;
  40. }
  41. bitValue *= 2;
  42. if (bitValue === 256) {
  43. packet.writeInt8(bitmap);
  44. bitmap = 0;
  45. bitValue = 1;
  46. }
  47. });
  48. if (bitValue !== 1) {
  49. packet.writeInt8(bitmap);
  50. }
  51. packet.writeInt8(1); // new_params_bind_flag
  52. // types and names
  53. for (let i = 0; i < paramCount; i++) {
  54. packet.writeInt8(parameters[i].type);
  55. packet.writeInt8(0); // unsigned flag
  56. packet.writeLengthCodedString(names[i], this.encoding);
  57. }
  58. // values
  59. parameters.forEach((parameter) => {
  60. if (parameter.type !== Types.NULL) {
  61. parameter.writer.call(packet, parameter.value);
  62. }
  63. });
  64. }
  65. }
  66. packet.writeBuffer(sqlBuf);
  67. return packet;
  68. }
  69. toPacket() {
  70. const useQueryAttributes =
  71. this.clientFlags & ClientConstants.CLIENT_QUERY_ATTRIBUTES;
  72. if (!useQueryAttributes) {
  73. const buf = StringParser.encode(this.query, this.encoding);
  74. const length = 5 + buf.length;
  75. const buffer = Buffer.allocUnsafe(length);
  76. const packet = new Packet(0, buffer, 0, length);
  77. packet.offset = 4;
  78. packet.writeInt8(CommandCode.QUERY);
  79. packet.writeBuffer(buf);
  80. return packet;
  81. }
  82. // dry run to calculate required buffer length
  83. const p = this.serializeToBuffer(Packet.MockBuffer());
  84. return this.serializeToBuffer(Buffer.allocUnsafe(p.offset));
  85. }
  86. }
  87. module.exports = Query;