Skip to content

Commit e41e130

Browse files
author
bimalkjha
committed
fix for issue ibmdb#210
1 parent 6ad8580 commit e41e130

File tree

3 files changed

+74
-84
lines changed

3 files changed

+74
-84
lines changed

lib/odbc.js

+37-38
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,6 @@ Database.prototype.query = function (query, params, cb)
318318
!params ? params = null : '';
319319
}
320320

321-
322321
if (typeof(params) === 'function')
323322
{
324323
cb = params;
@@ -353,10 +352,8 @@ Database.prototype.query = function (query, params, cb)
353352
result.fetchMode = self.fetchMode;
354353
}
355354

356-
exports.debug && console.log(getElapsedTime(), "odbc.js:query() => Calling result.fetchAll from conn.query():cbQuery.");
357-
result.fetchAll(function (err, data, noresult) {
355+
result.fetchAll(function (err, data, rowcount) {
358356
var moreResults = false, moreResultsError = null;
359-
exports.debug && console.log(getElapsedTime(), "odbc.js:query() => result.fetchAll Done.");
360357

361358
// If there is any error, return it now only.
362359
if( err || initialErr )
@@ -374,7 +371,7 @@ Database.prototype.query = function (query, params, cb)
374371
}
375372
if(multipleResultSet) resultset.push(data);
376373
else resultset = data;
377-
deferred ? deferred.reject(initialErr || err) : cb(initialErr || err, resultset, moreResults);
374+
deferred ? deferred.reject(initialErr || err) : cb(initialErr || err, resultset);
378375
result.closeSync();
379376
initialErr = null;
380377
err = null;
@@ -384,7 +381,7 @@ Database.prototype.query = function (query, params, cb)
384381
// Get the result data
385382
try
386383
{
387-
if(!noresult)
384+
if(rowcount) // Check for more result set.
388385
moreResults = result.moreResultsSync();
389386
}
390387
catch (e)
@@ -1330,7 +1327,7 @@ odbc.ODBCStatement.prototype.executeNonQuery = function (params, cb)
13301327
{
13311328
if(!deferred)
13321329
{
1333-
cb(err);
1330+
if(cb) cb(err);
13341331
}
13351332
else
13361333
{
@@ -1342,7 +1339,7 @@ odbc.ODBCStatement.prototype.executeNonQuery = function (params, cb)
13421339
if (err) {
13431340
if(!deferred)
13441341
{
1345-
cb(err)
1342+
if(cb) cb(err)
13461343
}
13471344
else
13481345
{
@@ -1354,7 +1351,7 @@ odbc.ODBCStatement.prototype.executeNonQuery = function (params, cb)
13541351
self._executeNonQuery(function (err, result) {
13551352
if(!deferred)
13561353
{
1357-
cb(err, result);
1354+
if(cb) cb(err, result);
13581355
}
13591356
else
13601357
{
@@ -1376,7 +1373,7 @@ odbc.ODBCStatement.prototype.executeNonQuery = function (params, cb)
13761373
self._executeNonQuery(function (err, result) {
13771374
if(!deferred)
13781375
{
1379-
cb(err, result);
1376+
if(cb) cb(err, result);
13801377
}
13811378
else
13821379
{
@@ -1410,7 +1407,7 @@ odbc.ODBCStatement.prototype.prepare = function (sql, cb) {
14101407

14111408
self.queue.push(function (next) {
14121409
self._prepare(sql, function (err) {
1413-
cb(err);
1410+
if(cb) cb(err);
14141411

14151412
return next();
14161413
});
@@ -1427,10 +1424,10 @@ odbc.ODBCStatement.prototype.bind = function (ary, cb) {
14271424
if(Array.isArray(ary))
14281425
{
14291426
var err = parseParams(ary);
1430-
if(err) cb(err);
1427+
if(err && cb) cb(err);
14311428
}
14321429
self._bind(ary, function (err) {
1433-
cb(err);
1430+
if(cb) cb(err);
14341431

14351432
//NOTE: we do not call next() here because
14361433
//we want to pop the next bind call only
@@ -1490,6 +1487,7 @@ Pool.prototype.open = function (connStr, callback)
14901487
{
14911488
db = self.availablePool[connStr].shift();
14921489
db.lastUsed=null;
1490+
self.usedPool[connStr] = self.usedPool[connStr] || [];
14931491
self.usedPool[connStr].push(db);
14941492
callback(null, db);
14951493
}
@@ -1502,6 +1500,7 @@ Pool.prototype.open = function (connStr, callback)
15021500
{
15031501
db = self.availablePool[connStr].shift();
15041502
db.lastUsed=null;
1503+
self.usedPool[connStr] = self.usedPool[connStr] || [];
15051504
self.usedPool[connStr].push(db);
15061505
clearInterval(interval);
15071506
callback(null, db);
@@ -1521,28 +1520,15 @@ Pool.prototype.open = function (connStr, callback)
15211520
{
15221521
db = new Database({ odbc : self.odbc });
15231522
self.poolSize++;
1524-
db.open(connStr, function (error) {
1525-
exports.debug && console.log("%s odbc.js : pool[%s] : pool.db.open new connection.", getElapsedTime(), self.index);
1526-
if(error)
1527-
{
1528-
self.poolSize--;
1529-
}
1530-
else
1531-
{
1532-
self.usedPool[connStr] = self.usedPool[connStr] || [];
1533-
db.created = Date.now();
1534-
self.usedPool[connStr].push(db);
1535-
}
1536-
callback(error, db);
1537-
}); //db.open
15381523

15391524
db.realClose = db.close;
15401525
db.close = function (cb)
15411526
{
1527+
var db = this;
15421528
db.lastUsed = Date.now();
15431529
//call back early, we can do the rest of this stuff after the client
15441530
//thinks that the connection is closed.
1545-
cb(null);
1531+
if(cb) cb(null);
15461532

15471533
// If this connection has some active transaction, rollback the
15481534
// transaction to free up the held resorces before moving back to
@@ -1555,11 +1541,11 @@ Pool.prototype.open = function (connStr, callback)
15551541
//remove this db from the usedPool
15561542
self.usedPool[connStr].splice(self.usedPool[connStr].indexOf(db), 1);
15571543

1558-
//move this connection back to the connection pool
1544+
//move this connection back to the connection pool at the end.
15591545
if(db.conn)
15601546
{
15611547
self.availablePool[connStr] = self.availablePool[connStr] || [];
1562-
self.availablePool[connStr].unshift(db);
1548+
self.availablePool[connStr].push(db);
15631549

15641550
//start cleanUp if enabled
15651551
if(self.options.autoCleanIdle) self.cleanUp(connStr);
@@ -1570,6 +1556,20 @@ Pool.prototype.open = function (connStr, callback)
15701556
}
15711557
}; // db.close function
15721558

1559+
db.open(connStr, function (error) {
1560+
exports.debug && console.log("%s odbc.js : pool[%s] : pool.db.open new connection.", getElapsedTime(), self.index);
1561+
if(error)
1562+
{
1563+
self.poolSize--;
1564+
}
1565+
else
1566+
{
1567+
self.usedPool[connStr] = self.usedPool[connStr] || [];
1568+
db.created = Date.now();
1569+
self.usedPool[connStr].push(db);
1570+
}
1571+
callback(error, db);
1572+
}); //db.open
15731573
}
15741574
};
15751575

@@ -1604,6 +1604,7 @@ Pool.prototype.init = function(count, connStr)
16041604
exports.debug && console.log("%s odbc.js: %d connection(s) initialized.\n", getElapsedTime(), self.poolSize);
16051605
return ret;
16061606
}
1607+
if(ret !== true) break;
16071608
exports.debug && console.log("%s odbc.js : pool[%s] : pool.init %d", getElapsedTime(), self.index, i);
16081609

16091610
self.availablePool[connStr] = self.availablePool[connStr] || [];
@@ -1612,8 +1613,9 @@ Pool.prototype.init = function(count, connStr)
16121613
db.realClose = db.close;
16131614
db.close = function (cb)
16141615
{
1616+
var db = this;
16151617
db.lastUsed = Date.now();
1616-
cb(null);
1618+
if(cb) cb(null);
16171619
if(db.conn && db.conn.inTransaction)
16181620
{
16191621
db.rollbackTransaction(function(err){});
@@ -1622,13 +1624,9 @@ Pool.prototype.init = function(count, connStr)
16221624
if(db.conn)
16231625
{
16241626
self.availablePool[connStr] = self.availablePool[connStr] || [];
1625-
self.availablePool[connStr].unshift(db);
1627+
self.availablePool[connStr].push(db);
16261628
if(self.options.autoCleanIdle) self.cleanUp(connStr);
16271629
}
1628-
if(exports.debug) {
1629-
process.stdout.write(getElapsedTime());
1630-
console.dir(self);
1631-
}
16321630
}; // db.close function
16331631
self.availablePool[connStr].push(db);
16341632
}
@@ -1712,7 +1710,8 @@ Pool.prototype.close = function (callback)
17121710

17131711
if (Object.keys(pools).length === 0)
17141712
{
1715-
return callback();
1713+
if (callback) return callback();
1714+
else return null;
17161715
}
17171716

17181717
for (key in pools)
@@ -1747,7 +1746,7 @@ Pool.prototype.close = function (callback)
17471746

17481747
if (received === required)
17491748
{
1750-
callback();
1749+
if(callback) callback();
17511750

17521751
//prevent mem leaks
17531752
self = null;

src/odbc_result.cpp

+29-41
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,6 @@ void ODBCResult::UV_AfterFetchAll(uv_work_t* work_req, int status) {
477477
ODBCResult* self = data->objResult->self();
478478

479479
bool doMoreWork = true;
480-
bool nodata = false;
481480

482481
if (self->colCount == 0) {
483482
self->columns = ODBC::GetColumns(self->m_hSTMT, &self->colCount);
@@ -490,12 +489,10 @@ void ODBCResult::UV_AfterFetchAll(uv_work_t* work_req, int status) {
490489
//this most likely means that the query was something like
491490
//'insert into ....'
492491
doMoreWork = false;
493-
nodata = true;
494492
}
495493
//check to see if we are at the end of the recordset
496494
else if (data->result == SQL_NO_DATA) {
497495
doMoreWork = false;
498-
nodata = true;
499496
}
500497
//check to see if there was an error
501498
else if (data->result == SQL_ERROR) {
@@ -506,10 +503,9 @@ void ODBCResult::UV_AfterFetchAll(uv_work_t* work_req, int status) {
506503
(char *) "[node-odbc] Error in ODBCResult::UV_AfterFetchAll"
507504
));
508505
doMoreWork = false;
509-
nodata = true;
510506
}
511507

512-
while (doMoreWork) {
508+
else {
513509
Local<Array> rows = Nan::New(data->rows);
514510
if (data->fetchMode == FETCH_ARRAY) {
515511
rows->Set(
@@ -534,53 +530,45 @@ void ODBCResult::UV_AfterFetchAll(uv_work_t* work_req, int status) {
534530
);
535531
}
536532
data->count++;
537-
data->result = SQLFetch(data->objResult->m_hSTMT);
538-
if (data->result == SQL_NO_DATA) {
539-
doMoreWork = false;
540-
}
541-
//check to see if there was an error
542-
else if (data->result == SQL_ERROR) {
543-
data->errorCount++;
544-
data->objError.Reset(ODBC::GetSQLError(
545-
SQL_HANDLE_STMT,
546-
self->m_hSTMT,
547-
(char *) "[node-odbc] Error in ODBCResult::UV_AfterFetchAll"
548-
));
549-
doMoreWork = false;
550-
}
551533
}
552-
553-
if (self->colCount) {
554-
ODBC::FreeColumns(self->columns, &self->colCount);
534+
if (doMoreWork) {
535+
//Go back to the thread pool and fetch more data!
536+
uv_queue_work( uv_default_loop(),
537+
work_req,
538+
UV_FetchAll,
539+
(uv_after_work_cb)UV_AfterFetchAll);
555540
}
556-
DEBUG_PRINTF("ODBCResult::UV_AfterFetchAll Done for stmt %X\n", data->objResult->m_hSTMT);
541+
else {
542+
ODBC::FreeColumns(self->columns, &self->colCount);
543+
DEBUG_PRINTF("ODBCResult::UV_AfterFetchAll Done for stmt %X\n", data->objResult->m_hSTMT);
557544

558-
Local<Value> info[3];
545+
Local<Value> info[3];
559546

560-
if (data->errorCount > 0) {
547+
if (data->errorCount > 0) {
561548
info[0] = Nan::New(data->objError);
562-
}
563-
else {
549+
}
550+
else {
564551
info[0] = Nan::Null();
565-
}
552+
}
566553

567-
info[1] = Nan::New(data->rows);
568-
info[2] = Nan::New(nodata);
569-
Nan::TryCatch try_catch;
554+
info[1] = Nan::New(data->rows);
555+
info[2] = Nan::New(data->count);
556+
Nan::TryCatch try_catch;
570557

571-
data->cb->Call(3, info);
572-
delete data->cb;
573-
data->rows.Reset();
574-
data->objError.Reset();
558+
data->cb->Call(3, info);
559+
delete data->cb;
560+
data->rows.Reset();
561+
data->objError.Reset();
575562

576-
if (try_catch.HasCaught()) {
563+
if (try_catch.HasCaught()) {
577564
FatalException(try_catch);
578-
}
565+
}
579566

580-
//TODO: Do we need to free self->rows somehow?
581-
free(data);
582-
free(work_req);
583-
self->Unref();
567+
//TODO: Do we need to free self->rows somehow?
568+
free(data);
569+
free(work_req);
570+
self->Unref();
571+
}
584572
}
585573

586574
/*

test/test-blocking-issue210.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pool.open(connectionString, function( err, conn) {
1919
conn.querySync("create table mtab2(c1 int, c2 varchar(20))");
2020
conn.querySync("Insert into mtab1 values (1, 'bimal'),(2,'kumar'),(3, 'jha'), (4, 'kamal'), (5, 'ibm')");
2121
conn.querySync("Insert into mtab1 values (1, 'bimal'),(2,'kumar'),(3, 'jha'), (4, 'kamal'), (5, 'ibm')");
22-
for(var i = 0; i < 10 ; i++) {
22+
for(var i = 0; i < 8 ; i++) {
2323
conn.querySync("insert into mtab2 (select * from mtab1)");
2424
conn.querySync("insert into mtab1 (select * from mtab2)");
2525
}
@@ -29,20 +29,22 @@ pool.open(connectionString, function( err, conn) {
2929
});
3030

3131
ibmdb.debug(true);
32+
var q1time, q2time;
3233
console.log(elapsedTime(), "Opening connection #1");
3334
pool.open(connectionString, function (err, connection) {
3435
console.log(elapsedTime(), "Connection 1 opened. Start execution of Query1");
3536
startTime1 = new Date();
3637
connection.query("select * from mtab1", function(err, data) {
3738
if(err) console.log(err);
3839
totalTime = (new Date() - startTime1)/1000;
39-
console.log(elapsedTime(), "Total execution time for Query1 = ",
40-
parseInt(totalTime/60), "min", parseInt(totalTime%60), "sec.");
40+
q1time = parseInt(totalTime%60);
41+
console.log(elapsedTime(), "Total execution time for Query1 = ", q1time, "sec.");
4142
dropTable++;
4243
if(dropTable == 2) {
4344
connection.querySync("drop table mtab1");
4445
ibmdb.debug(false);
4546
pool.close();
47+
assert.equal(q1time > 5, false);
4648
}
4749
});
4850
});
@@ -52,13 +54,14 @@ pool.open(connectionString, function (err, connection) {
5254
connection.query("select c1, c2 from mtab1", function(err, data) {
5355
if(err) console.log(err);
5456
totalTime = (new Date() - startTime1)/1000;
55-
console.log(elapsedTime(), "Total execution time for Query2 = ",
56-
parseInt(totalTime/60), "min", parseInt(totalTime%60), "sec.");
57+
q2time = parseInt(totalTime%60);
58+
console.log(elapsedTime(), "Total execution time for Query2 = ", q2time, "sec.");
5759
dropTable++;
5860
if(dropTable == 2) {
5961
connection.querySync("drop table mtab1");
6062
ibmdb.debug(false);
6163
pool.close();
64+
assert.equal(q2time > 5, false);
6265
}
6366
});
6467
});

0 commit comments

Comments
 (0)