mysql-live-select
Advanced tools
Comparing version 0.0.10 to 0.0.11
{ | ||
"name": "mysql-live-select", | ||
"version": "0.0.10", | ||
"version": "0.0.11", | ||
"description": "Live updating MySQL SELECT statements", | ||
@@ -5,0 +5,0 @@ "main": "lib/LiveMysql.js", |
@@ -10,2 +10,4 @@ # mysql-live-select | ||
This package has been tested to work in MySQL 5.5.40 and 5.6.19. Expected support is all MySQL server version >= 5.1.15. | ||
## Installation | ||
@@ -12,0 +14,0 @@ |
@@ -192,3 +192,3 @@ /* mysql-live-select, MIT License ben@latenightsketches.com | ||
error_invalid_query: function(test){ | ||
var table = 'error_no_db'; | ||
var table = 'error_invalid_query'; | ||
server.on('ready', function(conn, esc, escId, queries){ | ||
@@ -198,5 +198,3 @@ querySequence(conn.db, [ | ||
'CREATE TABLE ' + escId(table) + ' (col INT UNSIGNED)', | ||
'INSERT INTO ' + escId(table) + ' (col) VALUES (10)', | ||
], function(results){ | ||
conn.select('SELECT notcol FROM ' + escId(table), [ { | ||
@@ -203,0 +201,0 @@ table: table, |
@@ -41,32 +41,50 @@ var mysql = require('mysql'); | ||
var self = this; | ||
var binlogOptions = { | ||
tableMap: self.tableMap, | ||
}; | ||
this._isChecksumEnabled(function(checksumEnabled) { | ||
self.useChecksum = checksumEnabled; | ||
var options = { | ||
tableMap: self.tableMap, | ||
useChecksum: checksumEnabled, | ||
}; | ||
var asyncMethods = [ | ||
{ | ||
name: '_isChecksumEnabled', | ||
callback: function(checksumEnabled) { | ||
self.useChecksum = checksumEnabled; | ||
binlogOptions.useChecksum = checksumEnabled | ||
} | ||
}, | ||
{ | ||
name: '_findBinlogEnd', | ||
callback: function(result){ | ||
if(result && self.options.startAtEnd){ | ||
binlogOptions.filename = result.Log_name; | ||
binlogOptions.position = result.File_size; | ||
} | ||
} | ||
} | ||
]; | ||
var methodIndex = 0; | ||
var nextMethod = function(){ | ||
var method = asyncMethods[methodIndex]; | ||
self[method.name](function(/* args */){ | ||
method.callback.apply(this, arguments); | ||
methodIndex++; | ||
if(methodIndex < asyncMethods.length){ | ||
nextMethod(); | ||
}else{ | ||
ready(); | ||
} | ||
}); | ||
}; | ||
nextMethod(); | ||
var ready = function(){ | ||
// Run asynchronously from _init(), as serverId option set in start() | ||
if(self.options.serverId !== undefined){ | ||
options.serverId = self.options.serverId; | ||
binlogOptions.serverId = self.options.serverId; | ||
} | ||
var ready = function(){ | ||
self.binlog = generateBinlog.call(self, options); | ||
self.ready = true; | ||
self._executeCtrlCallbacks(); | ||
} | ||
if(self.options.startAtEnd){ | ||
self._findBinlogEnd(function(result){ | ||
if(result){ | ||
options.filename = result.Log_name; | ||
options.position = result.File_size; | ||
} | ||
ready(); | ||
}); | ||
}else{ | ||
ready(); | ||
} | ||
}); | ||
self.binlog = generateBinlog.call(self, binlogOptions); | ||
self.ready = true; | ||
self._executeCtrlCallbacks(); | ||
}; | ||
}; | ||
@@ -73,0 +91,0 @@ |
@@ -19,2 +19,6 @@ var MysqlTypes = { | ||
'BIT': 16, | ||
// Fractional temporal types in MySQL >=5.6.4 | ||
'TIMESTAMP2': 17, | ||
'DATETIME2': 18, | ||
'TIME2': 19, | ||
'NEWDECIMAL': 246, | ||
@@ -85,2 +89,10 @@ 'ENUM': 247, | ||
// @param {string} type - ex. 'time(4)' | ||
// @return {int} - ex. 4 | ||
var parseTypeDefIntArg = function(type){ | ||
var start = type.indexOf('(') + 1; | ||
if(start === 0) return undefined; | ||
return parseInt(type.substr(start, type.length - start - 1), 10); | ||
}; | ||
var zeroPad = function(num, size) { | ||
@@ -333,2 +345,32 @@ // Max 32 digits | ||
var readTemporalFraction = function(parser, columnSchema) { | ||
var fractionPrecision = parseTypeDefIntArg(columnSchema.COLUMN_TYPE); | ||
if(fractionPrecision === undefined || fractionPrecision === 0) return false; | ||
var fractionSize = Math.ceil(fractionPrecision / 2); | ||
var fraction = readIntBE(parser._buffer, parser._offset, fractionSize); | ||
parser._offset += fractionSize; | ||
if(fractionPrecision % 2 !== 0) fraction /= 10; // Not using full space | ||
if(fraction < 0) fraction *= -1; // Negative time, fraction not negative | ||
var fractionStr = zeroPad(fraction, fractionPrecision); | ||
var milliseconds; | ||
if(fractionStr.length > 3){ | ||
milliseconds = fractionStr.substr(0, 3); | ||
}else if(fractionStr.length === 2){ | ||
milliseconds = fractionStr + '0'; | ||
}else if(fractionStr.length === 1){ | ||
milliseconds = fractionStr + '00'; | ||
}else{ | ||
milliseconds = fractionStr; | ||
} | ||
return { | ||
value: fraction, | ||
precision: fractionPrecision, | ||
string: fractionStr, | ||
milliseconds: parseInt(milliseconds, 10) | ||
}; | ||
}; | ||
exports.readMysqlValue = function(parser, column, columnSchema) { | ||
@@ -437,3 +479,24 @@ var result; | ||
if(isNegative) second += 1; | ||
result = (isNegative ? '-' : '') + | ||
zeroPad(hour, hour > 99 ? 3 : 2) + ':' + | ||
zeroPad(minute, 2) + ':' + | ||
zeroPad(second, 2); | ||
break; | ||
case MysqlTypes.TIME2: | ||
var raw = readIntBE(parser._buffer, parser._offset, 3); | ||
parser._offset += 3; | ||
var fraction = readTemporalFraction(parser, columnSchema); | ||
var isNegative = (raw & (1 << 23)) === 0; | ||
if(isNegative) raw = raw ^ ((1 << 24) - 1); // flip all bits | ||
var hour = sliceBits(raw, 12, 22); | ||
var minute = sliceBits(raw, 6, 12); | ||
var second = sliceBits(raw, 0, 6); | ||
if(isNegative && (fraction === false || fraction.value === 0)){ | ||
second++; | ||
} | ||
result = (isNegative ? '-' : '') + | ||
@@ -443,2 +506,6 @@ zeroPad(hour, hour > 99 ? 3 : 2) + ':' + | ||
zeroPad(second, 2); | ||
if(fraction !== false){ | ||
result += '.' + fraction.string; | ||
} | ||
break; | ||
@@ -458,2 +525,24 @@ case MysqlTypes.DATETIME: | ||
break; | ||
case MysqlTypes.DATETIME2: | ||
// Overlapping high-low to get all data in 32-bit numbers | ||
var rawHigh = readIntBE(parser._buffer, parser._offset, 4); | ||
var rawLow = readIntBE(parser._buffer, parser._offset + 1, 4); | ||
parser._offset += 5; | ||
var fraction = readTemporalFraction(parser, columnSchema); | ||
var yearMonth = sliceBits(rawHigh, 14, 31); | ||
result = new Date( | ||
Math.floor(yearMonth / 13), // year | ||
(yearMonth % 13) - 1, // month | ||
sliceBits(rawLow, 17, 22), // day | ||
sliceBits(rawLow, 12, 17), // hour | ||
sliceBits(rawLow, 6, 12), // minutes | ||
sliceBits(rawLow, 0, 6) // seconds | ||
); | ||
if(fraction !== false){ | ||
// Javascript Date only supports milliseconds | ||
result.setMilliseconds(fraction.milliseconds); | ||
} | ||
break; | ||
case MysqlTypes.TIMESTAMP: | ||
@@ -463,2 +552,9 @@ var raw = parser.parseUnsignedNumber(4); | ||
break; | ||
case MysqlTypes.TIMESTAMP2: | ||
var raw = readIntBE(parser._buffer, parser._offset, 4); | ||
parser._offset += 4; | ||
var fraction = readTemporalFraction(parser, columnSchema); | ||
var milliseconds = fraction !== false ? fraction.milliseconds : 0; | ||
result = new Date((raw * 1000) + milliseconds); | ||
break; | ||
case MysqlTypes.YEAR: | ||
@@ -465,0 +561,0 @@ var raw = parser.parseUnsignedNumber(1); |
@@ -11,2 +11,4 @@ var util = require('util'); | ||
var CHECKSUM_SIZE = 4; | ||
/** | ||
@@ -17,2 +19,3 @@ * Generic RowsEvent class | ||
* binlogName: Name of next binlog file | ||
* zongji: ZongJi instance | ||
**/ | ||
@@ -24,2 +27,3 @@ | ||
this.flags = parser.parseUnsignedNumber(2); | ||
this.useChecksum = zongji.useChecksum; | ||
@@ -55,2 +59,7 @@ // Version 2 Events | ||
if(this.useChecksum){ | ||
// Ignore the checksum at the end of this packet | ||
parser._packetEnd -= CHECKSUM_SIZE; | ||
} | ||
this.rows = []; | ||
@@ -60,2 +69,8 @@ while (!parser.reachedPacketEnd()) { | ||
} | ||
if(this.useChecksum){ | ||
// Skip past the checksum at the end of the packet | ||
parser._packetEnd += CHECKSUM_SIZE; | ||
parser._offset += CHECKSUM_SIZE; | ||
} | ||
} | ||
@@ -62,0 +77,0 @@ } |
@@ -8,2 +8,4 @@ # ZongJi | ||
This package has been tested with MySQL server 5.5.40 and 5.6.19. All MySQL server versions >= 5.1.15 are supported. | ||
## Quick Start | ||
@@ -110,2 +112,3 @@ | ||
* :point_right: `TRUNCATE` statement does not cause corresponding `DeleteRows` event. Use unqualified `DELETE FROM` for same effect. | ||
* When using fractional seconds with `DATETIME` and `TIMESTAMP` data types in MySQL > 5.6.4, only millisecond precision is available due to the limit of Javascript's `Date` object. | ||
@@ -129,4 +132,5 @@ ## Run Tests | ||
* https://github.com/jeremycole/mysql_binlog (Ruby implemenation of MySQL binlog parser) | ||
* http://dev.mysql.com/doc/internals/en/date-and-time-data-type-representation.html | ||
## License | ||
MIT |
82353
2009
141