Skip to content

Commit 9fc091d

Browse files
committed
Sync /lib with master
1 parent 03b3bb7 commit 9fc091d

File tree

7 files changed

+308
-74
lines changed

7 files changed

+308
-74
lines changed

lib/connection.js

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ var QueryStream = require('./querystream.js');
2424
var nodbUtil = require('./util.js');
2525
var executePromisified;
2626
var commitPromisified;
27+
var createLobPromisified;
2728
var rollbackPromisified;
2829
var releasePromisified;
2930
var breakPromisified;
@@ -146,6 +147,18 @@ function commit(commitCb) {
146147

147148
commitPromisified = nodbUtil.promisify(commit);
148149

150+
// This createLob function is just a place holder to allow for easier extension later.
151+
function createLob(type, createLobCb) {
152+
var self = this;
153+
154+
nodbUtil.assert(arguments.length === 2, 'NJS-009');
155+
nodbUtil.assert(typeof createLobCb === 'function', 'NJS-006', 2);
156+
157+
self._createLob.apply(self, arguments);
158+
}
159+
160+
createLobPromisified = nodbUtil.promisify(createLob);
161+
149162
// This rollback function is just a place holder to allow for easier extension later.
150163
function rollback(rollbackCb) {
151164
var self = this;
@@ -159,23 +172,19 @@ function rollback(rollbackCb) {
159172
rollbackPromisified = nodbUtil.promisify(rollback);
160173

161174
// This release function is used to override the release method of the Connection
162-
// class, which is defined in the C layer. Currently the main difference is that
163-
// connections obtained from a pool need to invoke the pool's _onConnectionRelease
164-
// method so the pool can dequeue the next connection request.
175+
// class, which is defined in the C layer.
165176
function release(releaseCb) {
166177
var self = this;
167178

168179
nodbUtil.assert(arguments.length === 1, 'NJS-009');
169180
nodbUtil.assert(typeof releaseCb === 'function', 'NJS-006', 1);
170181

171182
self._release(function(err) {
172-
releaseCb(err);
173-
174-
// pool will only exist for connections obtained from a pool.
175-
if (self._pool && self._pool.queueRequests !== false) {
176-
self._pool._onConnectionRelease();
183+
if (!err) {
184+
self.emit('_after_close');
177185
}
178186

187+
releaseCb(err);
179188
});
180189
}
181190

@@ -198,6 +207,8 @@ breakPromisified = nodbUtil.promisify(module.break);
198207
// custom properties and method overrides. References to the original methods are
199208
// maintained so they can be invoked by the overriding method at the right time.
200209
function extend(conn, oracledb, pool) {
210+
nodbUtil.makeEventEmitter(conn);
211+
201212
// Using Object.defineProperties to add properties to the Connection instance with
202213
// special properties, such as enumerable but not writable.
203214
Object.defineProperties(
@@ -206,7 +217,7 @@ function extend(conn, oracledb, pool) {
206217
_oracledb: { // storing a reference to the base instance to avoid circular references with require
207218
value: oracledb
208219
},
209-
_pool: {
220+
_pool: { // storing a reference to the pool, if any, from which the connection was obtained
210221
value: pool
211222
},
212223
_execute: {
@@ -230,6 +241,14 @@ function extend(conn, oracledb, pool) {
230241
enumerable: true,
231242
writable: true
232243
},
244+
_createLob: {
245+
value: conn.createLob
246+
},
247+
createLob: {
248+
value: createLobPromisified,
249+
enumerable: true,
250+
writable: true
251+
},
233252
_rollback: {
234253
value: conn.rollback
235254
},

lib/lob.js

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,27 @@
2121

2222
var Duplex = require('stream').Duplex;
2323
var util = require('util');
24+
var nodbUtil = require('./util.js');
25+
var closePromisified;
2426

2527
util.inherits(Lob, Duplex);
2628

2729
// The Lob class is used to support the streaming of LOB data to/from the database.
28-
function Lob(iLob, opt) {
30+
function Lob(iLob, opt, oracledb) {
2931
Duplex.call(this, opt);
3032

3133
this.iLob = iLob;
32-
this.once('finish', this.close);
3334

3435
Object.defineProperties(
3536
this,
3637
{
38+
_oracledb: { // _oracledb property used by promisify () in util.js
39+
value: oracledb
40+
},
41+
_autoCloseLob: { // Tells whether to close at the end of stream or not
42+
value: iLob.autoCloseLob,
43+
writable: false
44+
},
3745
chunkSize: {
3846
value: iLob.chunkSize,
3947
writable: false
@@ -55,8 +63,17 @@ function Lob(iLob, opt) {
5563
get: function() {
5664
return iLob.type;
5765
}
66+
},
67+
close: {
68+
value: closePromisified,
69+
enumerable: true,
70+
writable: true
5871
}
5972
});
73+
74+
if (this._autoCloseLob) {
75+
this.once('finish', this._closeSync);
76+
}
6077
}
6178

6279
Lob.prototype._read = function() {
@@ -65,24 +82,29 @@ Lob.prototype._read = function() {
6582
self.iLob.read(
6683
function(err, str) {
6784
if (err) {
68-
self.close(); // Ignore if any error occurs during close
85+
if (self._autoCloseLob) {
86+
// Ignore if any error occurs during close
87+
// Emits 'close' event after closing LOB
88+
self._closeSync();
89+
}
90+
6991
self.emit('error', err);
70-
self.emit('close');
7192
return;
7293
}
7394

7495
self.push(str);
7596

76-
if (!str) {
77-
process.nextTick(function() {
78-
err = self.close();
79-
80-
if (err) {
81-
self.emit('error', err);
82-
}
97+
if (self._autoCloseLob) {
98+
if (!str) {
99+
process.nextTick(function() {
100+
err = self._closeSync(); // Emits 'close' event after closing LOB
83101

84-
self.emit('close');
85-
});
102+
if (err) {
103+
self.emit('error', err);
104+
return;
105+
}
106+
});
107+
}
86108
}
87109
}
88110
);
@@ -95,32 +117,57 @@ Lob.prototype._write = function(data, encoding, cb) {
95117
data,
96118
function(err) {
97119
if (err) {
98-
self.close(); // Ignore if any error occurs during close
99-
return cb(err);
120+
self._closeSync(); // Ignore if any error occurs during close
121+
cb(err);
122+
return;
100123
}
101124

102125
cb();
103126
}
104127
);
105128
};
106129

107-
Lob.prototype.close = function(cb) {
130+
// This function will be deprecated in the future
131+
// This internal function used to close the LOB at the end of writable
132+
// stream in synchronus way to avoid race condition between this function and
133+
// application's listener function on 'finish' event.
134+
Lob.prototype._closeSync = function() {
108135
var self = this;
109136

110-
if (cb) {
111-
this.once('close', cb);
112-
}
113-
114-
if (self.iLob != null) {
137+
if (self.iLob !== null) {
115138
try {
116139
self.iLob.release();
117140
} catch(err) {
118-
self.iLob = null;
119-
return err;
141+
self.iLob = null;
142+
return err;
120143
}
121144

122-
self.iLob = null;
145+
self.emit('close');
123146
}
124147
};
125148

149+
Lob.prototype.close = function(closeCb) {
150+
var self = this;
151+
152+
nodbUtil.assert(arguments.length === 1, 'NJS-009');
153+
nodbUtil.assert(typeof closeCb === 'function', 'NJS-006', 1);
154+
155+
// Return if LOB already closed to support multiple close() calls should be
156+
// no-op
157+
if (!self.iLob.valid) {
158+
closeCb(null);
159+
return;
160+
}
161+
162+
self.iLob.close(function(err) {
163+
if (!err) {
164+
self.emit('close');
165+
}
166+
167+
closeCb(err);
168+
});
169+
};
170+
171+
closePromisified = nodbUtil.promisify(Lob.prototype.close);
172+
126173
module.exports.Lob = Lob;

0 commit comments

Comments
 (0)