execute.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. var CursorType = require('../constants/cursor');
  2. var CommandCodes = require('../constants/commands');
  3. var Types = require('../constants/types');
  4. var Packet = require('../packets/packet');
  5. function Execute(id, parameters)
  6. {
  7. this.id = id;
  8. this.parameters = parameters;
  9. }
  10. Execute.prototype.toPacket = function()
  11. {
  12. // TODO: don't try to calculate packet length in advance, allocate some big buffer in advance (header + 256 bytes?)
  13. // and copy + reallocate if not enough
  14. var i;
  15. // 0 + 4 - length, seqId
  16. // 4 + 1 - COM_EXECUTE
  17. // 5 + 4 - stmtId
  18. // 9 + 1 - flags
  19. // 10 + 4 - iteration-count (always 1)
  20. var length = 14;
  21. if (this.parameters && this.parameters.length > 0)
  22. {
  23. length += Math.floor((this.parameters.length + 7) / 8);
  24. length += 1; // new-params-bound-flag
  25. length += 2*this.parameters.length; // type byte for each parameter if new-params-bound-flag is set
  26. for (i=0; i < this.parameters.length; i++)
  27. {
  28. if (this.parameters[i] !== null) {
  29. if (Object.prototype.toString.call(this.parameters[i]) == '[object Date]') {
  30. var d = this.parameters[i];
  31. // TODO: move to asMysqlDateTime()
  32. this.parameters[i] = [d.getFullYear(), d.getMonth() + 1, d.getDate()].join('-') +
  33. ' ' + [d.getHours(), d.getMinutes(), d.getSeconds()].join(':');
  34. }
  35. if (Buffer.isBuffer(this.parameters[i])) {
  36. length += Packet.lengthCodedNumberLength(this.parameters[i].length);
  37. length += this.parameters[i].length;
  38. }
  39. else {
  40. var str = this.parameters[i].toString();
  41. var byteLen = Buffer.byteLength(str, 'utf8');
  42. length += Packet.lengthCodedNumberLength(byteLen);
  43. length += byteLen;
  44. }
  45. }
  46. }
  47. }
  48. var buffer = new Buffer(length);
  49. var packet = new Packet(0, buffer, 0, length);
  50. packet.offset = 4;
  51. packet.writeInt8(CommandCodes.STMT_EXECUTE);
  52. packet.writeInt32(this.id);
  53. packet.writeInt8(CursorType.NO_CURSOR); // flags
  54. packet.writeInt32(1); // iteration-count, always 1
  55. if (this.parameters && this.parameters.length > 0) {
  56. var bitmap = 0;
  57. var bitValue = 1;
  58. for (i=0; i < this.parameters.length; i++)
  59. {
  60. if (this.parameters[i] === null)
  61. bitmap += bitValue;
  62. bitValue *= 2;
  63. if (bitValue == 256) {
  64. packet.writeInt8(bitmap);
  65. bitmap = 0;
  66. bitValue = 1;
  67. }
  68. }
  69. if (bitValue != 1)
  70. packet.writeInt8(bitmap);
  71. // TODO: explain meaning of the flag
  72. // afaik, if set n*2 bytes with type of parameter are sent before parameters
  73. // if not, previous execution types are used (TODO prooflink)
  74. packet.writeInt8(1); // new-params-bound-flag
  75. // TODO: don't typecast always to sting, use parameters type
  76. for (i=0; i < this.parameters.length; i++)
  77. {
  78. if (this.parameters[i] !== null)
  79. packet.writeInt16(Types.VAR_STRING);
  80. else
  81. packet.writeInt16(Types.NULL);
  82. }
  83. for (i=0; i < this.parameters.length; i++)
  84. {
  85. if (this.parameters[i] !== null)
  86. if (Buffer.isBuffer(this.parameters[i]))
  87. packet.writeLengthCodedBuffer(this.parameters[i]);
  88. else
  89. packet.writeLengthCodedString(this.parameters[i].toString());
  90. }
  91. }
  92. return packet;
  93. };
  94. module.exports = Execute;