prepare.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. 'use strict';
  2. const Packets = require('../packets/index.js');
  3. const Command = require('./command.js');
  4. const CloseStatement = require('./close_statement.js');
  5. const Execute = require('./execute.js');
  6. class PreparedStatementInfo {
  7. constructor(query, id, columns, parameters, connection) {
  8. this.query = query;
  9. this.id = id;
  10. this.columns = columns;
  11. this.parameters = parameters;
  12. this.rowParser = null;
  13. this._connection = connection;
  14. }
  15. close() {
  16. return this._connection.addCommand(new CloseStatement(this.id));
  17. }
  18. execute(parameters, callback) {
  19. if (typeof parameters === 'function') {
  20. callback = parameters;
  21. parameters = [];
  22. }
  23. return this._connection.addCommand(
  24. new Execute({ statement: this, values: parameters }, callback)
  25. );
  26. }
  27. }
  28. class Prepare extends Command {
  29. constructor(options, callback) {
  30. super();
  31. this.query = options.sql;
  32. this.onResult = callback;
  33. this.id = 0;
  34. this.fieldCount = 0;
  35. this.parameterCount = 0;
  36. this.fields = [];
  37. this.parameterDefinitions = [];
  38. this.options = options;
  39. }
  40. start(packet, connection) {
  41. const Connection = connection.constructor;
  42. this.key = Connection.statementKey(this.options);
  43. const statement = connection._statements.get(this.key);
  44. if (statement) {
  45. if (this.onResult) {
  46. this.onResult(null, statement);
  47. }
  48. return null;
  49. }
  50. const cmdPacket = new Packets.PrepareStatement(
  51. this.query,
  52. connection.config.charsetNumber,
  53. this.options.values
  54. );
  55. connection.writePacket(cmdPacket.toPacket(1));
  56. return Prepare.prototype.prepareHeader;
  57. }
  58. prepareHeader(packet, connection) {
  59. const header = new Packets.PreparedStatementHeader(packet);
  60. this.id = header.id;
  61. this.fieldCount = header.fieldCount;
  62. this.parameterCount = header.parameterCount;
  63. if (this.parameterCount > 0) {
  64. return Prepare.prototype.readParameter;
  65. } if (this.fieldCount > 0) {
  66. return Prepare.prototype.readField;
  67. }
  68. return this.prepareDone(connection);
  69. }
  70. readParameter(packet, connection) {
  71. // there might be scenarios when mysql server reports more parameters than
  72. // are actually present in the array of parameter definitions.
  73. // if EOF packet is received we switch to "read fields" state if there are
  74. // any fields reported by the server, otherwise we finish the command.
  75. if (packet.isEOF()) {
  76. if (this.fieldCount > 0) {
  77. return Prepare.prototype.readField;
  78. }
  79. return this.prepareDone(connection);
  80. }
  81. const def = new Packets.ColumnDefinition(packet, connection.clientEncoding);
  82. this.parameterDefinitions.push(def);
  83. if (this.parameterDefinitions.length === this.parameterCount) {
  84. return Prepare.prototype.parametersEOF;
  85. }
  86. return this.readParameter;
  87. }
  88. readField(packet, connection) {
  89. if (packet.isEOF()) {
  90. return this.prepareDone(connection);
  91. }
  92. const def = new Packets.ColumnDefinition(packet, connection.clientEncoding);
  93. this.fields.push(def);
  94. if (this.fields.length === this.fieldCount) {
  95. return Prepare.prototype.fieldsEOF;
  96. }
  97. return Prepare.prototype.readField;
  98. }
  99. parametersEOF(packet, connection) {
  100. if (!packet.isEOF()) {
  101. return connection.protocolError('Expected EOF packet after parameters');
  102. }
  103. if (this.fieldCount > 0) {
  104. return Prepare.prototype.readField;
  105. }
  106. return this.prepareDone(connection);
  107. }
  108. fieldsEOF(packet, connection) {
  109. if (!packet.isEOF()) {
  110. return connection.protocolError('Expected EOF packet after fields');
  111. }
  112. return this.prepareDone(connection);
  113. }
  114. prepareDone(connection) {
  115. const statement = new PreparedStatementInfo(
  116. this.query,
  117. this.id,
  118. this.fields,
  119. this.parameterDefinitions,
  120. connection
  121. );
  122. connection._statements.set(this.key, statement);
  123. if (this.onResult) {
  124. this.onResult(null, statement);
  125. }
  126. return null;
  127. }
  128. }
  129. module.exports = Prepare;