column_definition.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. 'use strict';
  2. const Packet = require('../packets/packet');
  3. const StringParser = require('../parsers/string');
  4. const CharsetToEncoding = require('../constants/charset_encodings.js');
  5. const fields = ['catalog', 'schema', 'table', 'orgTable', 'name', 'orgName'];
  6. // creating JS string is relatively expensive (compared to
  7. // reading few bytes from buffer) because all string properties
  8. // except for name are unlikely to be used we postpone
  9. // string conversion until property access
  10. //
  11. // TODO: watch for integration benchmarks (one with real network buffer)
  12. // there could be bad side effect as keeping reference to a buffer makes it
  13. // sit in the memory longer (usually until final .query() callback)
  14. // Latest v8 perform much better in regard to bufferer -> string conversion,
  15. // at some point of time this optimisation might become unnecessary
  16. // see https://github.com/sidorares/node-mysql2/pull/137
  17. //
  18. class ColumnDefinition {
  19. constructor(packet, clientEncoding) {
  20. this._buf = packet.buffer;
  21. this._clientEncoding = clientEncoding;
  22. this._catalogLength = packet.readLengthCodedNumber();
  23. this._catalogStart = packet.offset;
  24. packet.offset += this._catalogLength;
  25. this._schemaLength = packet.readLengthCodedNumber();
  26. this._schemaStart = packet.offset;
  27. packet.offset += this._schemaLength;
  28. this._tableLength = packet.readLengthCodedNumber();
  29. this._tableStart = packet.offset;
  30. packet.offset += this._tableLength;
  31. this._orgTableLength = packet.readLengthCodedNumber();
  32. this._orgTableStart = packet.offset;
  33. packet.offset += this._orgTableLength;
  34. // name is always used, don't make it lazy
  35. const _nameLength = packet.readLengthCodedNumber();
  36. const _nameStart = packet.offset;
  37. packet.offset += _nameLength;
  38. this._orgNameLength = packet.readLengthCodedNumber();
  39. this._orgNameStart = packet.offset;
  40. packet.offset += this._orgNameLength;
  41. packet.skip(1); // length of the following fields (always 0x0c)
  42. this.characterSet = packet.readInt16();
  43. this.encoding = CharsetToEncoding[this.characterSet];
  44. this.name = StringParser.decode(
  45. this._buf,
  46. this.encoding === 'binary' ? this._clientEncoding : this.encoding,
  47. _nameStart,
  48. _nameStart + _nameLength
  49. );
  50. this.columnLength = packet.readInt32();
  51. this.columnType = packet.readInt8();
  52. this.type = this.columnType;
  53. this.flags = packet.readInt16();
  54. this.decimals = packet.readInt8();
  55. }
  56. inspect() {
  57. return {
  58. catalog: this.catalog,
  59. schema: this.schema,
  60. name: this.name,
  61. orgName: this.orgName,
  62. table: this.table,
  63. orgTable: this.orgTable,
  64. characterSet: this.characterSet,
  65. columnLength: this.columnLength,
  66. columnType: this.columnType,
  67. type: this.columnType,
  68. flags: this.flags,
  69. decimals: this.decimals
  70. };
  71. }
  72. static toPacket(column, sequenceId) {
  73. let length = 17; // = 4 padding + 1 + 12 for the rest
  74. fields.forEach(field => {
  75. length += Packet.lengthCodedStringLength(
  76. column[field],
  77. CharsetToEncoding[column.characterSet]
  78. );
  79. });
  80. const buffer = Buffer.allocUnsafe(length);
  81. const packet = new Packet(sequenceId, buffer, 0, length);
  82. function writeField(name) {
  83. packet.writeLengthCodedString(
  84. column[name],
  85. CharsetToEncoding[column.characterSet]
  86. );
  87. }
  88. packet.offset = 4;
  89. fields.forEach(writeField);
  90. packet.writeInt8(0x0c);
  91. packet.writeInt16(column.characterSet);
  92. packet.writeInt32(column.columnLength);
  93. packet.writeInt8(column.columnType);
  94. packet.writeInt16(column.flags);
  95. packet.writeInt8(column.decimals);
  96. packet.writeInt16(0); // filler
  97. return packet;
  98. }
  99. // node-mysql compatibility: alias "db" to "schema"
  100. get db() {
  101. return this.schema;
  102. }
  103. }
  104. const addString = function(name) {
  105. Object.defineProperty(ColumnDefinition.prototype, name, {
  106. get: function() {
  107. const start = this[`_${name}Start`];
  108. const end = start + this[`_${name}Length`];
  109. const val = StringParser.decode(
  110. this._buf,
  111. this.encoding === 'binary' ? this._clientEncoding : this.encoding,
  112. start,
  113. end
  114. );
  115. Object.defineProperty(this, name, {
  116. value: val,
  117. writable: false,
  118. configurable: false,
  119. enumerable: false
  120. });
  121. return val;
  122. }
  123. });
  124. };
  125. addString('catalog');
  126. addString('schema');
  127. addString('table');
  128. addString('orgTable');
  129. addString('orgName');
  130. module.exports = ColumnDefinition;