node-query/node_modules/mysql2/lib/commands/query.js

151 lines
4.6 KiB
JavaScript
Raw Normal View History

var Command = require('./command');
var Packets = require('../packets/index.js');
var util = require('util');
var compileParser = require('../compile_text_parser.js');
var ServerStatus = require('../constants/server_status.js');
function Query(sql, options, callback)
{
Command.call(this);
this.query = sql;
this.options = options;
this.onResult = callback;
this._fieldCount = 0;
this._rowParser = null;
this._fields = [];
this._rows = [];
this._receivedFieldsCount = 0;
this._resultIndex = 0;
}
util.inherits(Query, Command);
Query.prototype.start = function(packet, connection) {
if (connection.config.debug) {
console.log(' Sending query command: %s', this.query);
}
var cmdPacket = new Packets.Query(this.query);
connection.writePacket(cmdPacket.toPacket(1));
return Query.prototype.resultsetHeader;
};
Query.prototype.done = function() {
var self = this;
if (this.onResult) {
var rows, fields;
if (this._resultIndex === 0) {
rows = this._rows[0];
fields = this._fields[0];
} else {
rows = this._rows;
fields = this._fields;
}
if (fields) {
process.nextTick(function() {
self.onResult(null, rows, fields);
});
} else {
process.nextTick(function() {
self.onResult(null, rows);
});
}
}
return null;
};
Query.prototype.resultsetHeader = function(packet, connection) {
var rs = new Packets.ResultSetHeader(packet, connection.config.bigNumberStrings);
this._fieldCount = rs.fieldCount;
if (connection.config.debug) {
console.log(' Resultset header received, expecting ' + rs.fieldCount + ' column definition packets');
}
if (this._fieldCount === 0) {
this._rows.push(rs);
this._fields.push(void(0));
this.emit('result', rs, this._resultIndex);
this.emit('fields', void(0), this._resultIndex);
if (rs.serverStatus & ServerStatus.SERVER_MORE_RESULTS_EXISTS) {
this._resultIndex++;
return Query.prototype.resultsetHeader;
}
return this.done();
}
this._receivedFieldsCount = 0;
this._rows.push([]);
this._fields.push([]);
return Query.prototype.readField;
};
// TODO: move to connection.js ?
function getFieldsKey(fields, options) {
var res = (typeof options.nestTables) + '/' + options.nestTables + '/' + options.rowsAsHash;
for (var i=0; i < fields.length; ++i)
res += '/' + fields[i].name + ':' + fields[i].columnType + ':' + fields[i].flags;
return res;
}
Query.prototype.readField = function(packet, connection) {
this._receivedFieldsCount++;
// Often there is much more data in the column definition than in the row itself
// If you set manually _fields[0] to array of ColumnDefinition's (from previous call)
// you can 'cache' result of parsing. Field packets still received, but ignored in that case
// this is the reason _receivedFieldsCount exist (otherwise we could just use current length of fields array)
if (this._fields[this._resultIndex].length != this._fieldCount) {
var field = new Packets.ColumnDefinition(packet);
this._fields[this._resultIndex].push(field);
if (connection.config.debug) {
console.log(' Column definition:');
console.log(' name: ' + field.name);
console.log(' type: ' + field.columnType);
console.log(' flags: ' + field.flags);
}
}
// last field received
if (this._receivedFieldsCount == this._fieldCount) {
var fields = this._fields[this._resultIndex];
this.emit('fields', fields, this._resultIndex);
var parserKey = getFieldsKey(fields, this.options);
this.rowParser = connection.textProtocolParsers[parserKey];
if (!this.rowParser) {
this.rowParser = compileParser(fields, this.options, connection.config);
connection.textProtocolParsers[parserKey] = this.rowParser;
}
return Query.prototype.fieldsEOF;
}
return Query.prototype.readField;
};
Query.prototype.fieldsEOF = function(packet) {
// check EOF
if (!packet.isEOF())
throw "Expected EOF packet"; // !!!TODO don't crash if there is a protocol error
return Query.prototype.row;
};
Query.prototype.row = function(packet)
{
if (packet.isEOF()) {
var status = packet.eofStatusFlags();
var moreResults = packet.eofStatusFlags() & ServerStatus.SERVER_MORE_RESULTS_EXISTS;
if (moreResults) {
this._resultIndex++;
return Query.prototype.resultsetHeader;
}
return this.done();
}
var row = new this.rowParser(packet);
if (this.onResult)
this._rows[this._resultIndex].push(row);
else
this.emit('result', row, this._resultIndex);
return Query.prototype.row;
};
module.exports = Query;