node-firebird 1.1.8 → 1.1.10
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/.github/workflows/node.js.yml +8 -6
- package/README.md +288 -268
- package/Roadmap.md +80 -0
- package/lib/callback.js +38 -0
- package/lib/index.d.ts +12 -1
- package/lib/index.js +86 -4801
- package/lib/pool.js +107 -0
- package/lib/utils.js +164 -0
- package/lib/wire/connection.js +2052 -0
- package/lib/wire/const.js +772 -0
- package/lib/wire/database.js +198 -0
- package/lib/wire/eventConnection.js +113 -0
- package/lib/wire/fbEventManager.js +98 -0
- package/lib/{serialize.js → wire/serialize.js} +25 -2
- package/lib/wire/service.js +1046 -0
- package/lib/wire/socket.js +100 -0
- package/lib/wire/statement.js +47 -0
- package/lib/wire/transaction.js +160 -0
- package/lib/wire/xsqlvar.js +518 -0
- package/package.json +2 -2
- package/.travis.yml +0 -23
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
const Events = require('events');
|
|
2
|
+
const { doError } = require('../callback');
|
|
3
|
+
const { escape } = require('../utils');
|
|
4
|
+
const EventConnection = require('./eventConnection');
|
|
5
|
+
const FbEventManager = require('./fbEventManager');
|
|
6
|
+
|
|
7
|
+
/***************************************
|
|
8
|
+
*
|
|
9
|
+
* Database
|
|
10
|
+
*
|
|
11
|
+
***************************************/
|
|
12
|
+
|
|
13
|
+
function Database(connection) {
|
|
14
|
+
this.connection = connection;
|
|
15
|
+
connection.db = this;
|
|
16
|
+
this.eventid = 1;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Database.prototype.__proto__ = Object.create(Events.EventEmitter.prototype, {
|
|
20
|
+
constructor: {
|
|
21
|
+
value: Database,
|
|
22
|
+
enumberable: false
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
Database.prototype.escape = function(value) {
|
|
27
|
+
return escape(value, this.connection.accept.protocolVersion);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
Database.prototype.detach = function(callback, force) {
|
|
31
|
+
|
|
32
|
+
var self = this;
|
|
33
|
+
|
|
34
|
+
if (!force && self.connection._pending.length > 0) {
|
|
35
|
+
self.connection._detachAuto = true;
|
|
36
|
+
self.connection._detachCallback = callback;
|
|
37
|
+
return self;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (self.connection._pooled === false) {
|
|
41
|
+
self.connection.detach(function (err, obj) {
|
|
42
|
+
|
|
43
|
+
self.connection.disconnect();
|
|
44
|
+
self.emit('detach', false);
|
|
45
|
+
|
|
46
|
+
if (callback)
|
|
47
|
+
callback(err, obj);
|
|
48
|
+
|
|
49
|
+
}, force);
|
|
50
|
+
} else {
|
|
51
|
+
self.emit('detach', false);
|
|
52
|
+
if (callback)
|
|
53
|
+
callback();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return self;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
Database.prototype.transaction = function(options, callback) {
|
|
60
|
+
return this.startTransaction(options, callback);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
Database.prototype.startTransaction = function(options, callback) {
|
|
64
|
+
this.connection.startTransaction(options, callback);
|
|
65
|
+
return this;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
Database.prototype.newStatement = function (query, callback) {
|
|
69
|
+
|
|
70
|
+
this.startTransaction(function(err, transaction) {
|
|
71
|
+
|
|
72
|
+
if (err) {
|
|
73
|
+
callback(err);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
transaction.newStatement(query, function(err, statement) {
|
|
78
|
+
|
|
79
|
+
if (err) {
|
|
80
|
+
callback(err);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
transaction.commit(function(err) {
|
|
85
|
+
callback(err, statement);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return this;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
Database.prototype.execute = function(query, params, callback, custom) {
|
|
94
|
+
|
|
95
|
+
if (params instanceof Function) {
|
|
96
|
+
custom = callback;
|
|
97
|
+
callback = params;
|
|
98
|
+
params = undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
var self = this;
|
|
102
|
+
|
|
103
|
+
self.connection.startTransaction(function(err, transaction) {
|
|
104
|
+
|
|
105
|
+
if (err) {
|
|
106
|
+
doError(err, callback);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
transaction.execute(query, params, function(err, result, meta, isSelect) {
|
|
111
|
+
|
|
112
|
+
if (err) {
|
|
113
|
+
transaction.rollback(function() {
|
|
114
|
+
doError(err, callback);
|
|
115
|
+
});
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
transaction.commit(function(err) {
|
|
120
|
+
if (callback)
|
|
121
|
+
callback(err, result, meta, isSelect);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
}, custom);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return self;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
Database.prototype.sequentially = function(query, params, on, callback, asArray) {
|
|
131
|
+
|
|
132
|
+
if (params instanceof Function) {
|
|
133
|
+
asArray = callback;
|
|
134
|
+
callback = on;
|
|
135
|
+
on = params;
|
|
136
|
+
params = undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (on === undefined){
|
|
140
|
+
throw new Error('Expected "on" delegate.');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (callback instanceof Boolean) {
|
|
144
|
+
asArray = callback;
|
|
145
|
+
callback = undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
var self = this;
|
|
149
|
+
self.execute(query, params, callback, { asObject: !asArray, asStream: true, on: on });
|
|
150
|
+
return self;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
Database.prototype.query = function(query, params, callback) {
|
|
154
|
+
|
|
155
|
+
if (params instanceof Function) {
|
|
156
|
+
callback = params;
|
|
157
|
+
params = undefined;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
var self = this;
|
|
161
|
+
self.execute(query, params, callback, { asObject: true, asStream: callback === undefined || callback === null });
|
|
162
|
+
return self;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
Database.prototype.drop = function(callback) {
|
|
166
|
+
return this.connection.dropDatabase(callback);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
Database.prototype.attachEvent = function (callback) {
|
|
170
|
+
var self = this;
|
|
171
|
+
this.connection.auxConnection(function (err, socket_info) {
|
|
172
|
+
|
|
173
|
+
if (err) {
|
|
174
|
+
doError(err, callback);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const eventConnection = new EventConnection(self.connection.host, socket_info.port, function (err) {
|
|
179
|
+
if (err) {
|
|
180
|
+
doError(err, callback);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const evt = new FbEventManager(self, eventConnection, self.eventid++, function (err) {
|
|
185
|
+
if (err) {
|
|
186
|
+
doError(err, callback);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
callback(err, evt);
|
|
191
|
+
});
|
|
192
|
+
}, self);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
module.exports = Database;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const net = require('net');
|
|
2
|
+
const { XdrReader } = require('./serialize');
|
|
3
|
+
const DEFAULT_ENCODING = 'utf8';
|
|
4
|
+
const Const = require('./const');
|
|
5
|
+
|
|
6
|
+
var EventConnection = function (host, port, callback, db) {
|
|
7
|
+
var self = this;
|
|
8
|
+
this.db = db;
|
|
9
|
+
this.emgr = null;
|
|
10
|
+
this._isClosed = false;
|
|
11
|
+
this._isOpened = false;
|
|
12
|
+
this._socket = net.createConnection(port, host);
|
|
13
|
+
this._bind_events(host, port, callback);
|
|
14
|
+
this.error;
|
|
15
|
+
this.eventcallback;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
EventConnection.prototype._bind_events = function (host, port, callback) {
|
|
19
|
+
var self = this;
|
|
20
|
+
|
|
21
|
+
self._socket.on('close', function () {
|
|
22
|
+
|
|
23
|
+
self._isClosed = true;
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
self._socket.on('error', function (e) {
|
|
27
|
+
|
|
28
|
+
self.error = e;
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
self._socket.on('connect', function () {
|
|
32
|
+
self._isClosed = false;
|
|
33
|
+
self._isOpened = true;
|
|
34
|
+
if (callback)
|
|
35
|
+
callback();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
self._socket.on('data', function (data) {
|
|
39
|
+
var xdr, buf;
|
|
40
|
+
|
|
41
|
+
if (!self._xdr) {
|
|
42
|
+
xdr = new XdrReader(data);
|
|
43
|
+
} else {
|
|
44
|
+
xdr = self._xdr;
|
|
45
|
+
delete (self._xdr);
|
|
46
|
+
buf = Buffer.from(data.length + xdr.buffer.length);
|
|
47
|
+
xdr.buffer.copy(buf);
|
|
48
|
+
data.copy(buf, xdr.buffer.length);
|
|
49
|
+
xdr.buffer = buf;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
var item, op;
|
|
54
|
+
var op_pos = xdr.pos;
|
|
55
|
+
var tmp_event;
|
|
56
|
+
while (xdr.pos < xdr.buffer.length) {
|
|
57
|
+
do {
|
|
58
|
+
var r = xdr.readInt();
|
|
59
|
+
} while (r === Const.op_dummy);
|
|
60
|
+
|
|
61
|
+
switch (r) {
|
|
62
|
+
case Const.op_event:
|
|
63
|
+
xdr.readInt(); // db handle
|
|
64
|
+
var buf = xdr.readArray();
|
|
65
|
+
// first byte is always set to 1
|
|
66
|
+
tmp_event = {};
|
|
67
|
+
var lst_event = [];
|
|
68
|
+
var eventname = '';
|
|
69
|
+
var eventcount = 0;
|
|
70
|
+
var pos = 1;
|
|
71
|
+
while (pos < buf.length) {
|
|
72
|
+
var len = buf.readInt8(pos++);
|
|
73
|
+
eventname = buf.toString(DEFAULT_ENCODING, pos, pos + len);
|
|
74
|
+
var prevcount = self.emgr.events[eventname] || 0;
|
|
75
|
+
pos += len;
|
|
76
|
+
eventcount = buf.readInt32LE(pos);
|
|
77
|
+
tmp_event[eventname] = eventcount;
|
|
78
|
+
pos += 4;
|
|
79
|
+
if (prevcount !== eventcount)
|
|
80
|
+
lst_event.push({ name: eventname, count: eventcount });
|
|
81
|
+
}
|
|
82
|
+
xdr.readInt64(); // ignore AST INFO
|
|
83
|
+
var event_id = xdr.readInt();
|
|
84
|
+
// set the new count in global event hash
|
|
85
|
+
for (var evt in tmp_event) {
|
|
86
|
+
self.emgr.events[evt] = tmp_event[evt];
|
|
87
|
+
}
|
|
88
|
+
if (self.eventcallback)
|
|
89
|
+
return self.eventcallback(null, { eventid: event_id, events: lst_event });
|
|
90
|
+
|
|
91
|
+
default:
|
|
92
|
+
return cb(new Error('Unexpected:' + r));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} catch (err) {
|
|
96
|
+
if (err instanceof RangeError) { // incomplete packet case
|
|
97
|
+
xdr.buffer = xdr.buffer = xdr.buffer.slice(op_pos);
|
|
98
|
+
xdr.pos = 0;
|
|
99
|
+
self._xdr = xdr;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
EventConnection.prototype.throwClosed = function (callback) {
|
|
106
|
+
var err = new Error('Event Connection is closed.');
|
|
107
|
+
this.db.emit('error', err);
|
|
108
|
+
if (callback)
|
|
109
|
+
callback(err);
|
|
110
|
+
return this;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
module.exports = EventConnection;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const Events = require('events');
|
|
2
|
+
const { doError } = require('../callback');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
function FbEventManager(db, eventconnection, eventid, callback) {
|
|
6
|
+
this.db = db;
|
|
7
|
+
this.eventconnection = eventconnection;
|
|
8
|
+
this.events = {};
|
|
9
|
+
this.eventid = eventid;
|
|
10
|
+
this._createEventLoop(callback);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
FbEventManager.prototype.__proto__ = Object.create(Events.EventEmitter.prototype, {
|
|
14
|
+
constructor: {
|
|
15
|
+
value: FbEventManager,
|
|
16
|
+
enumberable: false
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
FbEventManager.prototype._createEventLoop = function (callback) {
|
|
21
|
+
var self = this;
|
|
22
|
+
var cnx = this.db.connection;
|
|
23
|
+
this.eventconnection.emgr = this;
|
|
24
|
+
// create the loop
|
|
25
|
+
function loop(first) {
|
|
26
|
+
cnx.queEvents(self.events, self.eventid, function (err, ret) {
|
|
27
|
+
if (err) {
|
|
28
|
+
doError(err, callback);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (first)
|
|
32
|
+
callback();
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.eventconnection.eventcallback = function (err, ret) {
|
|
37
|
+
if (err || (self.eventid !== ret.eventid)) {
|
|
38
|
+
doError(err || new Error('Bad eventid'), callback);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
ret.events.forEach(function (event) {
|
|
43
|
+
self.emit('post_event', event.name, event.count)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
loop(false);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
loop(true);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
FbEventManager.prototype._changeEvent = function (callback) {
|
|
53
|
+
var self = this;
|
|
54
|
+
|
|
55
|
+
self.db.connection.closeEvents(this.eventid, function (err) {
|
|
56
|
+
if (err) {
|
|
57
|
+
doError(err, callback);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
self.db.connection.queEvents(self.events, self.eventid, callback);
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
FbEventManager.prototype.registerEvent = function (events, callback) {
|
|
66
|
+
var self = this;
|
|
67
|
+
|
|
68
|
+
if (self.db.connection._isClosed || self.eventconnection._isClosed)
|
|
69
|
+
return self.eventconnection.throwClosed(callback);
|
|
70
|
+
|
|
71
|
+
events.forEach((event) => self.events[event] = self.events[event] || 0);
|
|
72
|
+
self._changeEvent(callback);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
FbEventManager.prototype.unregisterEvent = function (events, callback) {
|
|
76
|
+
var self = this;
|
|
77
|
+
|
|
78
|
+
if (self.db.connection._isClosed || self.eventconnection._isClosed)
|
|
79
|
+
return self.eventconnection.throwClosed(callback);
|
|
80
|
+
|
|
81
|
+
events.forEach(function (event) { delete self.events[event] });
|
|
82
|
+
self._changeEvent(callback);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
FbEventManager.prototype.close = function (callback) {
|
|
86
|
+
var self = this;
|
|
87
|
+
|
|
88
|
+
self.db.connection.closeEvents(this.eventid, function (err) {
|
|
89
|
+
if (err) {
|
|
90
|
+
doError(err, callback);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
self.eventconnection._socket.end();
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = FbEventManager;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
var Long = require('long');
|
|
3
2
|
|
|
4
3
|
function align(n) {
|
|
@@ -103,7 +102,7 @@ BlrWriter.prototype.addString = function (c, s, encoding) {
|
|
|
103
102
|
};
|
|
104
103
|
|
|
105
104
|
BlrWriter.prototype.addBuffer = function (b) {
|
|
106
|
-
this.
|
|
105
|
+
this.addWord(b.length);
|
|
107
106
|
this.ensure(b.length);
|
|
108
107
|
b.copy(this.buffer, this.pos);
|
|
109
108
|
this.pos += b.length;
|
|
@@ -269,6 +268,20 @@ XdrWriter.prototype.addInt64 = function (value) {
|
|
|
269
268
|
this.pos += 4;
|
|
270
269
|
};
|
|
271
270
|
|
|
271
|
+
XdrWriter.prototype.addInt128 = function (value) {
|
|
272
|
+
this.ensure(16);
|
|
273
|
+
|
|
274
|
+
const bigValue = BigInt(value);
|
|
275
|
+
|
|
276
|
+
const high = bigValue >> BigInt(64);
|
|
277
|
+
const low = bigValue & BigInt("0xFFFFFFFFFFFFFFFF");
|
|
278
|
+
|
|
279
|
+
this.buffer.writeBigUInt64BE(high, this.pos);
|
|
280
|
+
this.pos += 8;
|
|
281
|
+
this.buffer.writeBigUInt64BE(low, this.pos);
|
|
282
|
+
this.pos += 8;
|
|
283
|
+
};
|
|
284
|
+
|
|
272
285
|
XdrWriter.prototype.addUInt = function (value) {
|
|
273
286
|
this.ensure(4);
|
|
274
287
|
this.buffer.writeUInt32BE(value, this.pos);
|
|
@@ -366,6 +379,16 @@ XdrReader.prototype.readInt64 = function () {
|
|
|
366
379
|
return new Long(low, high).toNumber();
|
|
367
380
|
};
|
|
368
381
|
|
|
382
|
+
XdrReader.prototype.readInt128 = function () {
|
|
383
|
+
var high = this.buffer.readBigUInt64BE(this.pos)
|
|
384
|
+
this.pos += 8
|
|
385
|
+
|
|
386
|
+
var low = this.buffer.readBigUInt64BE(this.pos)
|
|
387
|
+
this.pos += 8
|
|
388
|
+
|
|
389
|
+
return (BigInt(high) << BigInt(64)) + BigInt(low)
|
|
390
|
+
};
|
|
391
|
+
|
|
369
392
|
XdrReader.prototype.readShort = function () {
|
|
370
393
|
var r = this.buffer.readInt16BE(this.pos);
|
|
371
394
|
this.pos += 2;
|