@vlasky/zongji 0.5.9 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +60 -0
- package/README.md +48 -20
- package/docker-compose.yml +14 -13
- package/docker-test.sh +7 -7
- package/eslint.config.js +35 -0
- package/example.js +1 -1
- package/index.d.ts +314 -0
- package/index.js +444 -272
- package/jsconfig.json +15 -0
- package/lib/binlog_event.js +296 -217
- package/lib/code_map.js +7 -4
- package/lib/common.js +35 -22
- package/lib/datetime_decode.js +147 -34
- package/lib/json_decode.js +12 -6
- package/lib/packet/binlog.js +3 -3
- package/lib/packet/combinlog.js +22 -20
- package/lib/packet/index.js +50 -50
- package/lib/reader.js +215 -109
- package/lib/rows_event.js +98 -102
- package/lib/sequence/binlog.js +142 -39
- package/package.json +16 -11
- package/scripts/start-mysql.sh +28 -0
- package/.eslintrc +0 -19
package/lib/common.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import iconv from 'iconv-lite';
|
|
2
|
+
import decodeJson from './json_decode.js';
|
|
3
|
+
import * as dtDecode from './datetime_decode.js';
|
|
4
|
+
import bigInt from 'big-integer';
|
|
5
5
|
|
|
6
|
-
const MysqlTypes =
|
|
6
|
+
export const MysqlTypes = {
|
|
7
7
|
DECIMAL: 0,
|
|
8
8
|
TINY: 1,
|
|
9
9
|
SHORT: 2,
|
|
@@ -42,9 +42,9 @@ const MysqlTypes = exports.MysqlTypes = {
|
|
|
42
42
|
const TWO_TO_POWER_THIRTY_TWO = Math.pow(2, 32);
|
|
43
43
|
const TWO_TO_POWER_SIXTY_THREE = '9223372036854775808'; // Math.pow(2, 63) or 1 << 63
|
|
44
44
|
// This function will return a Number
|
|
45
|
-
// if the
|
|
45
|
+
// if the result < Math.MAX_SAFE_INTEGER or result > Math.MIN_SAFE_INTEGER,
|
|
46
46
|
// otherwise, will return a string.
|
|
47
|
-
const parseUInt64 =
|
|
47
|
+
export const parseUInt64 = function(parser) {
|
|
48
48
|
const low = parser.parseUnsignedNumber(4);
|
|
49
49
|
const high = parser.parseUnsignedNumber(4);
|
|
50
50
|
|
|
@@ -55,19 +55,19 @@ const parseUInt64 = exports.parseUInt64 = function(parser) {
|
|
|
55
55
|
return (high * Math.pow(2,32)) + low;
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
export function parseUInt48(parser) {
|
|
59
59
|
const low = parser.parseUnsignedNumber(4);
|
|
60
60
|
const high = parser.parseUnsignedNumber(2);
|
|
61
61
|
return (high * Math.pow(2, 32)) + low;
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
const parseUInt24 =
|
|
64
|
+
export const parseUInt24 = function(parser) {
|
|
65
65
|
const low = parser.parseUnsignedNumber(2);
|
|
66
66
|
const high = parser.parseUnsignedNumber(1);
|
|
67
67
|
return (high << 16) + low;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
export function parseBytesArray(parser, length) {
|
|
71
71
|
const result = new Array(length);
|
|
72
72
|
for (let i = 0; i < length; i++) {
|
|
73
73
|
result[i] = parser.parseUnsignedNumber(1);
|
|
@@ -88,13 +88,13 @@ const parseSetEnumTypeDef = function(type, prefixLen) {
|
|
|
88
88
|
});
|
|
89
89
|
};
|
|
90
90
|
|
|
91
|
-
const zeroPad =
|
|
91
|
+
export const zeroPad = function(num, size) {
|
|
92
92
|
// Max 32 digits
|
|
93
93
|
const s = '00000000000000000000000000000000' + num;
|
|
94
94
|
return s.substr(s.length-size);
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
-
const sliceBits =
|
|
97
|
+
export const sliceBits = function(input, start, end) {
|
|
98
98
|
// ex: start: 10, end: 15 = "111110000000000"
|
|
99
99
|
const match = (((1 << end) - 1) ^ ((1 << start) - 1));
|
|
100
100
|
return (input & match) >> start;
|
|
@@ -102,7 +102,7 @@ const sliceBits = exports.sliceBits = function(input, start, end) {
|
|
|
102
102
|
|
|
103
103
|
// Use Typed Arrays to convert IEEE 754 numbers
|
|
104
104
|
// Pass only high for 32-bit float, pass high and low for 64-bit double
|
|
105
|
-
const parseIEEE754Float =
|
|
105
|
+
export const parseIEEE754Float = function(high, low) {
|
|
106
106
|
if (low !== undefined) {
|
|
107
107
|
let value = new DataView(new ArrayBuffer(8));
|
|
108
108
|
value.setUint32(0, high);
|
|
@@ -115,7 +115,7 @@ const parseIEEE754Float = exports.parseIEEE754Float = function(high, low) {
|
|
|
115
115
|
}
|
|
116
116
|
};
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
export function getUInt32Value(input) {
|
|
119
119
|
// Last bit is not sign, it is part of value!
|
|
120
120
|
if (input & (1 << 31)) return Math.pow(2, 31) + (input & ((1 << 31) -1));
|
|
121
121
|
else return input;
|
|
@@ -312,6 +312,7 @@ const parseGeometryValue = function(buffer) {
|
|
|
312
312
|
|
|
313
313
|
// Returns false, or an object describing the fraction of a second part of a
|
|
314
314
|
// TIME, DATETIME, or TIMESTAMP.
|
|
315
|
+
/** @returns {false | { value: number, precision: number, milliseconds: number }} */
|
|
315
316
|
const readTemporalFraction = function(parser, fractionPrecision) {
|
|
316
317
|
if (!fractionPrecision) return false;
|
|
317
318
|
let fractionSize = Math.ceil(fractionPrecision / 2);
|
|
@@ -340,7 +341,7 @@ const readTemporalFraction = function(parser, fractionPrecision) {
|
|
|
340
341
|
// The parser object contains the raw value, and functions useful for value
|
|
341
342
|
// interpretation, but not the underlying column type or how the value ought to
|
|
342
343
|
// be interpreted based on that column type.
|
|
343
|
-
|
|
344
|
+
export function readMysqlValue(
|
|
344
345
|
parser, // node-mysql parser instance, from mysql/lib/protocol/Parser
|
|
345
346
|
column, // tableMap.columns[columnNumber]
|
|
346
347
|
columnSchema, // tableMap.columnSchemas[columnNumber]
|
|
@@ -471,7 +472,8 @@ exports.readMysqlValue = function(
|
|
|
471
472
|
zongji.connection.config.dateStrings, // node-mysql dateStrings option
|
|
472
473
|
sliceBits(raw, 9, 24), // year
|
|
473
474
|
sliceBits(raw, 5, 9), // month
|
|
474
|
-
sliceBits(raw, 0, 5)
|
|
475
|
+
sliceBits(raw, 0, 5), // day
|
|
476
|
+
zongji.connection.config.timezone
|
|
475
477
|
);
|
|
476
478
|
break;
|
|
477
479
|
case MysqlTypes.TIME:
|
|
@@ -526,7 +528,9 @@ exports.readMysqlValue = function(
|
|
|
526
528
|
date % 100, // day
|
|
527
529
|
Math.floor(time / 10000), // hour
|
|
528
530
|
Math.floor((time % 10000) / 100), // minutes
|
|
529
|
-
time % 100
|
|
531
|
+
time % 100, // seconds
|
|
532
|
+
undefined, // fraction
|
|
533
|
+
zongji.connection.config.timezone
|
|
530
534
|
);
|
|
531
535
|
break;
|
|
532
536
|
case MysqlTypes.DATETIME2: {
|
|
@@ -545,21 +549,30 @@ exports.readMysqlValue = function(
|
|
|
545
549
|
sliceBits(rawLow, 12, 17), // hour
|
|
546
550
|
sliceBits(rawLow, 6, 12), // minutes
|
|
547
551
|
sliceBits(rawLow, 0, 6), // seconds
|
|
548
|
-
fraction
|
|
552
|
+
fraction, // fraction of a second object
|
|
553
|
+
zongji.connection.config.timezone
|
|
549
554
|
);
|
|
550
555
|
break;
|
|
551
556
|
}
|
|
552
557
|
case MysqlTypes.TIMESTAMP:
|
|
553
558
|
raw = parser.parseUnsignedNumber(4);
|
|
554
|
-
result = dtDecode.getTimeStamp(
|
|
559
|
+
result = dtDecode.getTimeStamp(
|
|
560
|
+
zongji.connection.config.dateStrings,
|
|
561
|
+
raw,
|
|
562
|
+
undefined,
|
|
563
|
+
zongji.connection.config.timezone
|
|
564
|
+
);
|
|
555
565
|
break;
|
|
556
566
|
case MysqlTypes.TIMESTAMP2:
|
|
557
567
|
raw = readIntBE(parser._buffer, parser._offset, 4);
|
|
558
568
|
parser._offset += 4;
|
|
559
569
|
fraction = readTemporalFraction(parser, column.metadata.decimals);
|
|
560
|
-
result = dtDecode.getTimeStamp(
|
|
561
|
-
|
|
562
|
-
|
|
570
|
+
result = dtDecode.getTimeStamp(
|
|
571
|
+
zongji.connection.config.dateStrings,
|
|
572
|
+
raw, // seconds from epoch
|
|
573
|
+
fraction, // fraction of a second object
|
|
574
|
+
zongji.connection.config.timezone
|
|
575
|
+
);
|
|
563
576
|
break;
|
|
564
577
|
case MysqlTypes.YEAR:
|
|
565
578
|
raw = parser.parseUnsignedNumber(1);
|
package/lib/datetime_decode.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// dateStrings option. The dateStrings option should be read from
|
|
4
4
|
// zongji.connection.config, where zongji is the current instance of the ZongJi
|
|
5
5
|
// object. The dateStrings option is interpreted the same as in node-mysql.
|
|
6
|
-
|
|
6
|
+
import { zeroPad } from './common.js';
|
|
7
7
|
|
|
8
8
|
// dateStrings are used only if the dateStrings option is true, or is an array
|
|
9
9
|
// containing the sql type name string, 'DATE', 'DATETIME', or 'TIMESTAMP'.
|
|
@@ -16,19 +16,19 @@ const useDateStringsForType = function(dateStrings, sqlTypeString) {
|
|
|
16
16
|
|
|
17
17
|
// fraction is the fractional second object from readTemporalFraction().
|
|
18
18
|
// returns '' or a '.' followed by fraction.precision digits, like '.123'
|
|
19
|
-
const getFractionString =
|
|
19
|
+
export const getFractionString = function(fraction) {
|
|
20
20
|
return fraction ?
|
|
21
|
-
'.' +
|
|
21
|
+
'.' + zeroPad(fraction.value, fraction.precision) :
|
|
22
22
|
'';
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
// 1950-00-00 and the like are perfectly valid Mysql dateStrings. A 0 portion
|
|
26
26
|
// of a date is essentially a null part of the date, so we should keep it.
|
|
27
27
|
// year, month, and date must be integers >= 0. January is month === 1.
|
|
28
|
-
const getDateString =
|
|
29
|
-
return
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
export const getDateString = function(year, month, date) {
|
|
29
|
+
return zeroPad(year, 4) + '-' +
|
|
30
|
+
zeroPad(month, 2) + '-' +
|
|
31
|
+
zeroPad(date, 2);
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
// Date object months are 1 less than Mysql months, and we need to filter 0.
|
|
@@ -44,16 +44,65 @@ const jsMonthFromMysqlMonth = function(month) {
|
|
|
44
44
|
// option. With the dateStrings option, it can output valid Mysql DATE strings
|
|
45
45
|
// representing values that cannot be represented by a Date object, such as
|
|
46
46
|
// values with a null part like '1950-00-04', or a zero date '0000-00-00'.
|
|
47
|
-
|
|
47
|
+
const createDateFromParts = function(year,
|
|
48
|
+
month,
|
|
49
|
+
date,
|
|
50
|
+
hour,
|
|
51
|
+
minute,
|
|
52
|
+
second,
|
|
53
|
+
millisecond,
|
|
54
|
+
timezone) {
|
|
55
|
+
const jsMonth = jsMonthFromMysqlMonth(month);
|
|
56
|
+
if (!timezone || timezone === 'local') {
|
|
57
|
+
return new Date(year,
|
|
58
|
+
jsMonth,
|
|
59
|
+
date,
|
|
60
|
+
hour,
|
|
61
|
+
minute,
|
|
62
|
+
second,
|
|
63
|
+
millisecond);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const utcTime = Date.UTC(year,
|
|
67
|
+
jsMonth,
|
|
68
|
+
date,
|
|
69
|
+
hour,
|
|
70
|
+
minute,
|
|
71
|
+
second,
|
|
72
|
+
millisecond);
|
|
73
|
+
if (timezone === 'Z') {
|
|
74
|
+
return new Date(utcTime);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const offsetMinutes = getTimezoneOffsetMinutes(timezone);
|
|
78
|
+
if (offsetMinutes === null) {
|
|
79
|
+
return new Date(year,
|
|
80
|
+
jsMonth,
|
|
81
|
+
date,
|
|
82
|
+
hour,
|
|
83
|
+
minute,
|
|
84
|
+
second,
|
|
85
|
+
millisecond);
|
|
86
|
+
}
|
|
87
|
+
return new Date(utcTime - offsetMinutes * 60000);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export function getDate(dateStrings, // node-mysql dateStrings option
|
|
48
91
|
year,
|
|
49
92
|
month, // January === 1
|
|
50
|
-
date
|
|
93
|
+
date,
|
|
94
|
+
timezone
|
|
51
95
|
)
|
|
52
96
|
{
|
|
53
97
|
if (!useDateStringsForType(dateStrings, 'DATE')) {
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
98
|
+
return createDateFromParts(year,
|
|
99
|
+
month,
|
|
100
|
+
date,
|
|
101
|
+
0,
|
|
102
|
+
0,
|
|
103
|
+
0,
|
|
104
|
+
0,
|
|
105
|
+
timezone);
|
|
57
106
|
}
|
|
58
107
|
return getDateString(year, month, date);
|
|
59
108
|
};
|
|
@@ -62,40 +111,103 @@ exports.getDate = function(dateStrings, // node-mysql dateStrings option
|
|
|
62
111
|
// option. Fraction is an optional parameter that comes from
|
|
63
112
|
// readTemporalFraction(). Mysql dateStrings are needed for microsecond
|
|
64
113
|
// precision, or to represent '0000-00-00 00:00:00'.
|
|
65
|
-
|
|
114
|
+
export function getDateTime(dateStrings, // node-mysql dateStrings option
|
|
66
115
|
year,
|
|
67
116
|
month, // January === 1
|
|
68
117
|
date,
|
|
69
118
|
hour,
|
|
70
119
|
minute,
|
|
71
120
|
second,
|
|
72
|
-
fraction
|
|
121
|
+
fraction, // optional fractional second object
|
|
122
|
+
timezone
|
|
73
123
|
)
|
|
74
124
|
{
|
|
75
125
|
if (!useDateStringsForType(dateStrings, 'DATETIME')) {
|
|
76
|
-
return
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
126
|
+
return createDateFromParts(year,
|
|
127
|
+
month,
|
|
128
|
+
date,
|
|
129
|
+
hour,
|
|
130
|
+
minute,
|
|
131
|
+
second,
|
|
132
|
+
fraction ? fraction.milliseconds : 0,
|
|
133
|
+
timezone);
|
|
83
134
|
}
|
|
84
135
|
return getDateString(year, month, date) + ' ' +
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
136
|
+
zeroPad(hour, 2) + ':' +
|
|
137
|
+
zeroPad(minute, 2) + ':' +
|
|
138
|
+
zeroPad(second, 2) +
|
|
88
139
|
getFractionString(fraction);
|
|
89
|
-
}
|
|
140
|
+
}
|
|
90
141
|
|
|
91
142
|
// Returns a new Date object or Mysql dateString, following the dateStrings
|
|
92
143
|
// option. Fraction is an optional parameter that comes from
|
|
93
144
|
// readTemporalFraction(). With the dateStrings option from node-mysql,
|
|
94
145
|
// this returns a mysql TIMESTAMP string, like '1975-03-01 23:03:20.38945' or
|
|
95
146
|
// '1975-03-01 00:03:20'. Mysql strings are needed for precision beyond ms.
|
|
96
|
-
|
|
147
|
+
const getTimezoneOffsetMinutes = function(timezone) {
|
|
148
|
+
if (!timezone || timezone === 'local' || timezone === 'Z') {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
const match = timezone.match(/^([+-])(\d\d):(\d\d)$/);
|
|
152
|
+
if (!match) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const sign = match[1] === '-' ? -1 : 1;
|
|
156
|
+
const hours = parseInt(match[2], 10);
|
|
157
|
+
const minutes = parseInt(match[3], 10);
|
|
158
|
+
return sign * (hours * 60 + minutes);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const getTimeComponents = function(dateObject, timezone) {
|
|
162
|
+
if (!timezone || timezone === 'local') {
|
|
163
|
+
return {
|
|
164
|
+
year: dateObject.getFullYear(),
|
|
165
|
+
month: dateObject.getMonth() + 1,
|
|
166
|
+
day: dateObject.getDate(),
|
|
167
|
+
hours: dateObject.getHours(),
|
|
168
|
+
minutes: dateObject.getMinutes(),
|
|
169
|
+
seconds: dateObject.getSeconds(),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (timezone === 'Z') {
|
|
174
|
+
return {
|
|
175
|
+
year: dateObject.getUTCFullYear(),
|
|
176
|
+
month: dateObject.getUTCMonth() + 1,
|
|
177
|
+
day: dateObject.getUTCDate(),
|
|
178
|
+
hours: dateObject.getUTCHours(),
|
|
179
|
+
minutes: dateObject.getUTCMinutes(),
|
|
180
|
+
seconds: dateObject.getUTCSeconds(),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const offsetMinutes = getTimezoneOffsetMinutes(timezone);
|
|
185
|
+
if (offsetMinutes === null) {
|
|
186
|
+
return {
|
|
187
|
+
year: dateObject.getFullYear(),
|
|
188
|
+
month: dateObject.getMonth() + 1,
|
|
189
|
+
day: dateObject.getDate(),
|
|
190
|
+
hours: dateObject.getHours(),
|
|
191
|
+
minutes: dateObject.getMinutes(),
|
|
192
|
+
seconds: dateObject.getSeconds(),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const shifted = new Date(dateObject.getTime() + offsetMinutes * 60000);
|
|
197
|
+
return {
|
|
198
|
+
year: shifted.getUTCFullYear(),
|
|
199
|
+
month: shifted.getUTCMonth() + 1,
|
|
200
|
+
day: shifted.getUTCDate(),
|
|
201
|
+
hours: shifted.getUTCHours(),
|
|
202
|
+
minutes: shifted.getUTCMinutes(),
|
|
203
|
+
seconds: shifted.getUTCSeconds(),
|
|
204
|
+
};
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export function getTimeStamp(dateStrings, // node-mysql dateStrings option
|
|
97
208
|
secondsFromEpoch, // an integer
|
|
98
|
-
fraction // optional fraction of second object
|
|
209
|
+
fraction, // optional fraction of second object
|
|
210
|
+
timezone // mysql2 timezone option
|
|
99
211
|
)
|
|
100
212
|
{
|
|
101
213
|
const milliseconds = fraction ? fraction.milliseconds : 0;
|
|
@@ -106,11 +218,12 @@ exports.getTimeStamp = function(dateStrings, // node-mysql dateStrings option
|
|
|
106
218
|
if (secondsFromEpoch === 0 && (!fraction || fraction.value === 0)) {
|
|
107
219
|
return '0000-00-00 00:00:00' + getFractionString(fraction);
|
|
108
220
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
221
|
+
const parts = getTimeComponents(dateObject, timezone);
|
|
222
|
+
return getDateString(parts.year,
|
|
223
|
+
parts.month,
|
|
224
|
+
parts.day) + ' ' +
|
|
225
|
+
zeroPad(parts.hours, 2) + ':' +
|
|
226
|
+
zeroPad(parts.minutes, 2) + ':' +
|
|
227
|
+
zeroPad(parts.seconds, 2) +
|
|
115
228
|
getFractionString(fraction);
|
|
116
|
-
}
|
|
229
|
+
}
|
package/lib/json_decode.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import * as common from './common.js';
|
|
2
|
+
import { Parser } from './reader.js';
|
|
3
3
|
|
|
4
4
|
const JSONB_TYPE_SMALL_OBJECT = 0;
|
|
5
5
|
const JSONB_TYPE_LARGE_OBJECT = 1;
|
|
@@ -21,12 +21,12 @@ const JSONB_LITERALS = [ null, true, false ];
|
|
|
21
21
|
// node-mysql prefixes binary string values
|
|
22
22
|
const VAR_STRING_PREFIX = 'base64:type253:';
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
export default function decodeJson(input) {
|
|
25
25
|
// Value must be JSON string to match node-mysql results
|
|
26
26
|
// Related to this node-mysql PR:
|
|
27
27
|
// https://github.com/felixge/node-mysql/pull/1299
|
|
28
28
|
return JSON.stringify(parseBinaryBuffer(input));
|
|
29
|
-
}
|
|
29
|
+
}
|
|
30
30
|
|
|
31
31
|
/*
|
|
32
32
|
* @func parseBinaryBuffer
|
|
@@ -69,7 +69,7 @@ function parseBinaryBuffer(input, offset, parentValueOffset, readUInt, isLarge)
|
|
|
69
69
|
}
|
|
70
70
|
// All other types are retrieved from pointer
|
|
71
71
|
case JSONB_TYPE_STRING: {
|
|
72
|
-
let strLen, strLenSize = 0, curStrLenByte;
|
|
72
|
+
let strLen = 0, strLenSize = 0, curStrLenByte;
|
|
73
73
|
// If the high bit is 1, the string length continues to the next byte
|
|
74
74
|
while (strLenSize === 0 || (curStrLenByte & 128) === 128) {
|
|
75
75
|
strLenSize++;
|
|
@@ -135,7 +135,7 @@ function parseBinaryBuffer(input, offset, parentValueOffset, readUInt, isLarge)
|
|
|
135
135
|
}
|
|
136
136
|
case JSONB_TYPE_OPAQUE: {
|
|
137
137
|
const customType = input.readUInt8(valueOffset + 1);
|
|
138
|
-
let dataLen, dataLenSize = 0, curDataLenByte;
|
|
138
|
+
let dataLen = 0, dataLenSize = 0, curDataLenByte;
|
|
139
139
|
// If the high bit is 1, the string length continues to the next byte
|
|
140
140
|
while (dataLenSize === 0 || (curDataLenByte & 128) === 128) {
|
|
141
141
|
dataLenSize++;
|
|
@@ -216,9 +216,15 @@ function parseBinaryBuffer(input, offset, parentValueOffset, readUInt, isLarge)
|
|
|
216
216
|
decimals: parser.parseUnsignedNumber(1),
|
|
217
217
|
};
|
|
218
218
|
break;
|
|
219
|
+
case common.MysqlTypes.VARCHAR:
|
|
220
|
+
result = 'base64:type15:' + parser._buffer.toString('base64');
|
|
221
|
+
break;
|
|
219
222
|
case common.MysqlTypes.VAR_STRING:
|
|
220
223
|
result = VAR_STRING_PREFIX + parser._buffer.toString('base64');
|
|
221
224
|
break;
|
|
225
|
+
case common.MysqlTypes.STRING:
|
|
226
|
+
result = 'base64:type254:' + parser._buffer.toString('base64');
|
|
227
|
+
break;
|
|
222
228
|
default:
|
|
223
229
|
throw new Error('JSON Opaque Type Not Implemented: ' + customType);
|
|
224
230
|
}
|
package/lib/packet/binlog.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { getEventClass } from '../code_map.js';
|
|
2
2
|
|
|
3
3
|
//TODO Don't depend on zongji instance here
|
|
4
|
-
|
|
4
|
+
export default function initBinlogPacketClass(zongji) {
|
|
5
5
|
|
|
6
6
|
class BinlogPacket {
|
|
7
7
|
|
|
@@ -37,7 +37,7 @@ module.exports = function initBinlogPacketClass(zongji) {
|
|
|
37
37
|
try {
|
|
38
38
|
this._event = new EventClass(parser, options, zongji);
|
|
39
39
|
} catch (err) {
|
|
40
|
-
// Record error
|
|
40
|
+
// Record error occurrence but suppress until handled
|
|
41
41
|
this._error = err;
|
|
42
42
|
}
|
|
43
43
|
}
|
package/lib/packet/combinlog.js
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
class ComBinlog {
|
|
2
|
+
constructor({ serverId, nonBlock, filename, position }) {
|
|
3
|
+
this.command = 0x12;
|
|
4
|
+
this.position = position || 4;
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
// will send eof package if there is no more binlog event
|
|
7
|
+
// https://dev.mysql.com/doc/internals/en/com-binlog-dump.html#binlog-dump-non-block
|
|
8
|
+
this.flags = nonBlock ? 1 : 0;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
10
|
+
this.serverId = serverId || 1;
|
|
11
|
+
this.filename = filename || '';
|
|
12
|
+
}
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
14
|
+
write(writer) {
|
|
15
|
+
writer.writeUnsignedNumber(1, this.command);
|
|
16
|
+
writer.writeUnsignedNumber(4, this.position);
|
|
17
|
+
writer.writeUnsignedNumber(2, this.flags);
|
|
18
|
+
writer.writeUnsignedNumber(4, this.serverId);
|
|
19
|
+
writer.writeNullTerminatedString(this.filename);
|
|
20
|
+
}
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
22
|
+
parse() {
|
|
23
|
+
throw new Error('should never be called here');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
export default ComBinlog;
|
package/lib/packet/index.js
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
options = options || {};
|
|
1
|
+
import ComBinlog from './combinlog.js';
|
|
2
|
+
import initBinlogPacketClass from './binlog.js';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
// from npm package mysql
|
|
5
|
+
class EofPacket {
|
|
6
|
+
constructor(options = {}) {
|
|
7
|
+
this.fieldCount = undefined;
|
|
8
|
+
this.warningCount = options.warningCount;
|
|
9
|
+
this.serverStatus = options.serverStatus;
|
|
10
|
+
this.protocol41 = options.protocol41;
|
|
11
|
+
}
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
parse(parser) {
|
|
14
|
+
this.fieldCount = parser.parseUnsignedNumber(1);
|
|
15
|
+
if (this.protocol41) {
|
|
16
|
+
this.warningCount = parser.parseUnsignedNumber(2);
|
|
17
|
+
this.serverStatus = parser.parseUnsignedNumber(2);
|
|
18
|
+
}
|
|
16
19
|
}
|
|
17
|
-
};
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
write(writer) {
|
|
22
|
+
writer.writeUnsignedNumber(1, 0xfe);
|
|
23
|
+
if (this.protocol41) {
|
|
24
|
+
writer.writeUnsignedNumber(2, this.warningCount);
|
|
25
|
+
writer.writeUnsignedNumber(2, this.serverStatus);
|
|
26
|
+
}
|
|
24
27
|
}
|
|
25
|
-
}
|
|
28
|
+
}
|
|
26
29
|
|
|
27
30
|
// from npm package mysql
|
|
28
|
-
|
|
29
|
-
options =
|
|
31
|
+
class ErrorPacket {
|
|
32
|
+
constructor(options = {}) {
|
|
33
|
+
this.fieldCount = options.fieldCount;
|
|
34
|
+
this.errno = options.errno;
|
|
35
|
+
this.sqlStateMarker = options.sqlStateMarker;
|
|
36
|
+
this.sqlState = options.sqlState;
|
|
37
|
+
this.message = options.message;
|
|
38
|
+
}
|
|
30
39
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.sqlState = options.sqlState;
|
|
35
|
-
this.message = options.message;
|
|
36
|
-
}
|
|
40
|
+
parse(parser) {
|
|
41
|
+
this.fieldCount = parser.parseUnsignedNumber(1);
|
|
42
|
+
this.errno = parser.parseUnsignedNumber(2);
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
// sqlStateMarker ('#' = 0x23) indicates error packet format
|
|
45
|
+
if (parser.peak() === 0x23) {
|
|
46
|
+
this.sqlStateMarker = parser.parseString(1);
|
|
47
|
+
this.sqlState = parser.parseString(5);
|
|
48
|
+
}
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
if (parser.peak() === 0x23) {
|
|
44
|
-
this.sqlStateMarker = parser.parseString(1);
|
|
45
|
-
this.sqlState = parser.parseString(5);
|
|
50
|
+
this.message = parser.parsePacketTerminatedString();
|
|
46
51
|
}
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
write(writer) {
|
|
54
|
+
writer.writeUnsignedNumber(1, 0xff);
|
|
55
|
+
writer.writeUnsignedNumber(2, this.errno);
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
if (this.sqlStateMarker) {
|
|
58
|
+
writer.writeString(this.sqlStateMarker);
|
|
59
|
+
writer.writeString(this.sqlState);
|
|
60
|
+
}
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
writer.writeString(this.sqlStateMarker);
|
|
57
|
-
writer.writeString(this.sqlState);
|
|
62
|
+
writer.writeString(this.message);
|
|
58
63
|
}
|
|
64
|
+
}
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
exports.EofPacket = EofPacket;
|
|
64
|
-
exports.ErrorPacket = ErrorPacket;
|
|
65
|
-
exports.ComBinlog = require('./combinlog');
|
|
66
|
-
exports.initBinlogPacketClass = require('./binlog');
|
|
66
|
+
export { EofPacket, ErrorPacket, ComBinlog, initBinlogPacketClass };
|