Skip to content

Commit 9d62b53

Browse files
committed
Give error and prevent releasing the connection when a database call is in progress, thus prevent crashes
1 parent bd5077f commit 9d62b53

13 files changed

+342
-126
lines changed

src/njs/src/njsConnection.cpp

Lines changed: 123 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,12 @@ Connection::~Connection()
104104
*/
105105
void Connection::setConnection(dpi::Conn* dpiconn, Oracledb* oracledb)
106106
{
107-
this->dpiconn_ = dpiconn;
108-
this->isValid_ = true;
109-
this->oracledb_ = oracledb;
107+
this->dpiconn_ = dpiconn;
108+
this->isValid_ = true;
109+
this->oracledb_ = oracledb;
110+
this->lobCount_ = 0;
111+
this->rsCount_ = 0;
112+
this->dbCount_ = 0;
110113
}
111114

112115
/*****************************************************************************/
@@ -438,11 +441,10 @@ NAN_METHOD(Connection::Execute)
438441
Connection *connection;
439442
NJS_GET_CALLBACK ( callback, info );
440443

441-
eBaton *executeBaton = new eBaton;
442-
executeBaton->cb.Reset( callback );
443-
NJS_CHECK_NUMBER_OF_ARGS ( executeBaton->error, info, 2, 4, exitExecute );
444444
connection = Nan::ObjectWrap::Unwrap<Connection>(info.This());
445+
eBaton *executeBaton = new eBaton ( connection->DBCount (), callback );
445446

447+
NJS_CHECK_NUMBER_OF_ARGS ( executeBaton->error, info, 2, 4, exitExecute );
446448
NJS_CHECK_OBJECT_VALID3( connection, executeBaton->error, exitExecute );
447449

448450
if(!connection->isValid_)
@@ -479,8 +481,16 @@ NAN_METHOD(Connection::Execute)
479481

480482
exitExecute:
481483
executeBaton->req.data = (void*) executeBaton;
482-
uv_queue_work(uv_default_loop(), &executeBaton->req,
484+
int status = uv_queue_work(uv_default_loop(), &executeBaton->req,
483485
Async_Execute, (uv_after_work_cb)Async_AfterExecute);
486+
// delete the Baton if uv_queue_work fails
487+
if ( status )
488+
{
489+
delete executeBaton;
490+
string error = NJSMessages::getErrorMsg ( errInternalError,
491+
"uv_queue_work", "Execute" );
492+
NJS_SET_EXCEPTION(error.c_str(), error.length());
493+
}
484494

485495
info.GetReturnValue().SetUndefined();
486496
}
@@ -2053,9 +2063,8 @@ void Connection::Async_AfterExecute(uv_work_t *req)
20532063
}
20542064
argv[1] = result;
20552065
}
2056-
exitAsyncAfterExecute:
2066+
exitAsyncAfterExecute:
20572067
Local<Function> callback = Nan::New<Function>(executeBaton->cb);
2058-
executeBaton->cb.Reset ();
20592068
delete executeBaton;
20602069
Nan::MakeCallback( Nan::GetCurrentContext()->Global(), callback, 2, argv );
20612070
if(tc.HasCaught())
@@ -2546,6 +2555,33 @@ v8::Local<v8::Value> Connection::GetOutBindObject ( eBaton *executeBaton )
25462555
return scope.Escape(objectBinds);
25472556
}
25482557

2558+
2559+
/****************************************************************************/
2560+
/* NAME
2561+
* Connection::getConnectionBusyStatus
2562+
*
2563+
* DESCRIPTION
2564+
* Checks whther connection is busy with database call or not using counters
2565+
*
2566+
* PARAMETERS
2567+
* connection - connection object to check it's counters
2568+
*
2569+
* Note: Currently this function can be used only in Release () method
2570+
*/
2571+
ConnectionBusyStatus Connection::getConnectionBusyStatus ( Connection *conn )
2572+
{
2573+
ConnectionBusyStatus connStatus = CONN_NOT_BUSY;
2574+
2575+
if ( conn->lobCount_ != 0 )
2576+
connStatus = CONN_BUSY_LOB;
2577+
else if ( conn->rsCount_ != 0 )
2578+
connStatus = CONN_BUSY_RS;
2579+
else if ( conn->dbCount_ != 1 ) // 1 for Release operaion itself
2580+
connStatus = CONN_BUSY_DB;
2581+
2582+
return connStatus;
2583+
}
2584+
25492585
/*****************************************************************************/
25502586
/*
25512587
DESCRIPTION
@@ -2560,26 +2596,55 @@ NAN_METHOD(Connection::Release)
25602596
Local<Function> callback;
25612597
Connection *connection;
25622598
NJS_GET_CALLBACK ( callback, info );
2599+
ConnectionBusyStatus connStat;
25632600

2564-
eBaton* releaseBaton = new eBaton;
2565-
releaseBaton->cb.Reset(callback);
2566-
2567-
NJS_CHECK_NUMBER_OF_ARGS ( releaseBaton->error, info, 1, 1, exitRelease );
25682601
connection = Nan::ObjectWrap::Unwrap<Connection>(info.This());
2602+
eBaton *releaseBaton = new eBaton ( connection->DBCount (), callback );
25692603

2604+
NJS_CHECK_NUMBER_OF_ARGS ( releaseBaton->error, info, 1, 1, exitRelease );
25702605
NJS_CHECK_OBJECT_VALID3(connection, releaseBaton->error, exitRelease);
25712606
if(!connection->isValid_)
25722607
{
25732608
releaseBaton->error = NJSMessages::getErrorMsg ( errInvalidConnection );
25742609
goto exitRelease;
25752610
}
2611+
2612+
2613+
// Check to see if database call is in progress
2614+
connStat = getConnectionBusyStatus ( connection );
2615+
switch ( connStat )
2616+
{
2617+
case CONN_NOT_BUSY:
2618+
break; // Nothing to do in this case
2619+
case CONN_BUSY_LOB:
2620+
releaseBaton->error = NJSMessages::getErrorMsg( errBusyConnLOB );
2621+
goto exitRelease;
2622+
case CONN_BUSY_RS:
2623+
releaseBaton->error = NJSMessages::getErrorMsg( errBusyConnRS );
2624+
goto exitRelease;
2625+
case CONN_BUSY_DB:
2626+
releaseBaton->error = NJSMessages::getErrorMsg( errBusyConnDB );
2627+
goto exitRelease;
2628+
2629+
default:
2630+
break;
2631+
}
2632+
25762633
connection->isValid_ = false;
25772634
releaseBaton->dpiconn = connection->dpiconn_;
25782635
exitRelease:
25792636
releaseBaton->req.data = (void*) releaseBaton;
25802637

2581-
uv_queue_work(uv_default_loop(), &releaseBaton->req,
2638+
int status = uv_queue_work(uv_default_loop(), &releaseBaton->req,
25822639
Async_Release, (uv_after_work_cb)Async_AfterRelease);
2640+
// delete the Baton if uv_queue_work fails
2641+
if ( status )
2642+
{
2643+
delete releaseBaton;
2644+
string error = NJSMessages::getErrorMsg ( errInternalError,
2645+
"uv_queue_work", "Release" );
2646+
NJS_SET_EXCEPTION(error.c_str(), error.length());
2647+
}
25832648
info.GetReturnValue().SetUndefined();
25842649
scope.Escape ( Nan::Undefined () );
25852650
}
@@ -2635,7 +2700,6 @@ void Connection::Async_AfterRelease(uv_work_t *req)
26352700
else
26362701
argv[0] = Nan::Undefined();
26372702
Local<Function> callback = Nan::New<Function>(releaseBaton->cb);
2638-
releaseBaton->cb.Reset ();
26392703
delete releaseBaton;
26402704
Nan::MakeCallback( Nan::GetCurrentContext()->Global(),
26412705
callback, 1, argv );
@@ -2660,11 +2724,10 @@ NAN_METHOD(Connection::Commit)
26602724
Connection *connection;
26612725
NJS_GET_CALLBACK ( callback, info );
26622726

2663-
eBaton* commitBaton = new eBaton;
2664-
commitBaton->cb.Reset( callback );
2665-
NJS_CHECK_NUMBER_OF_ARGS ( commitBaton->error, info, 1, 1, exitCommit );
26662727
connection = Nan::ObjectWrap::Unwrap<Connection>(info.This());
2728+
eBaton *commitBaton = new eBaton ( connection->DBCount (), callback );
26672729

2730+
NJS_CHECK_NUMBER_OF_ARGS ( commitBaton->error, info, 1, 1, exitCommit );
26682731
NJS_CHECK_OBJECT_VALID3 ( connection, commitBaton->error, exitCommit );
26692732
if(!connection->isValid_)
26702733
{
@@ -2675,8 +2738,16 @@ NAN_METHOD(Connection::Commit)
26752738
exitCommit:
26762739
commitBaton->req.data = (void*) commitBaton;
26772740

2678-
uv_queue_work(uv_default_loop(), &commitBaton->req,
2741+
int status = uv_queue_work(uv_default_loop(), &commitBaton->req,
26792742
Async_Commit, (uv_after_work_cb)Async_AfterCommit);
2743+
// delete the Baton if uv_queue_work fails
2744+
if ( status )
2745+
{
2746+
delete commitBaton;
2747+
string error = NJSMessages::getErrorMsg ( errInternalError,
2748+
"uv_queue_work", "Commit" );
2749+
NJS_SET_EXCEPTION(error.c_str(), error.length());
2750+
}
26802751

26812752
info.GetReturnValue().SetUndefined();
26822753
}
@@ -2732,14 +2803,15 @@ void Connection::Async_AfterCommit (uv_work_t *req)
27322803
else
27332804
argv[0] = Nan::Undefined();
27342805

2806+
Local<Function> callback = Nan::New<Function>(commitBaton->cb);
2807+
delete commitBaton;
27352808
Nan::MakeCallback( Nan::GetCurrentContext()->Global(),
2736-
Nan::New<Function>(commitBaton->cb), 1, argv );
2809+
callback, 1, argv );
2810+
27372811
if(tc.HasCaught())
27382812
{
27392813
Nan::FatalException(tc);
27402814
}
2741-
commitBaton->cb.Reset ();
2742-
delete commitBaton;
27432815
}
27442816

27452817
/*****************************************************************************/
@@ -2756,10 +2828,9 @@ NAN_METHOD(Connection::Rollback)
27562828
Connection *connection;
27572829
NJS_GET_CALLBACK ( callback, info );
27582830

2759-
eBaton* rollbackBaton = new eBaton;
2760-
rollbackBaton->cb.Reset( callback );
2761-
NJS_CHECK_NUMBER_OF_ARGS ( rollbackBaton->error, info, 1, 1, exitRollback );
27622831
connection = Nan::ObjectWrap::Unwrap<Connection>(info.This());
2832+
eBaton *rollbackBaton = new eBaton ( connection->DBCount (), callback );
2833+
NJS_CHECK_NUMBER_OF_ARGS ( rollbackBaton->error, info, 1, 1, exitRollback );
27632834
NJS_CHECK_OBJECT_VALID3 ( connection, rollbackBaton->error, exitRollback );
27642835

27652836
if(!connection->isValid_)
@@ -2770,8 +2841,16 @@ NAN_METHOD(Connection::Rollback)
27702841
rollbackBaton->dpiconn = connection->dpiconn_;
27712842
exitRollback:
27722843
rollbackBaton->req.data = (void*) rollbackBaton;
2773-
uv_queue_work(uv_default_loop(), &rollbackBaton->req,
2774-
Async_Rollback, (uv_after_work_cb)Async_AfterRollback);
2844+
int status = uv_queue_work(uv_default_loop(), &rollbackBaton->req,
2845+
Async_Rollback, (uv_after_work_cb)Async_AfterRollback);
2846+
// delete the Baton if uv_queue_work fails
2847+
if ( status )
2848+
{
2849+
delete rollbackBaton;
2850+
string error = NJSMessages::getErrorMsg ( errInternalError,
2851+
"uv_queue_work", "Rollback" );
2852+
NJS_SET_EXCEPTION(error.c_str(), error.length());
2853+
}
27752854
info.GetReturnValue().SetUndefined();
27762855
}
27772856

@@ -2826,14 +2905,14 @@ void Connection::Async_AfterRollback(uv_work_t *req)
28262905
else
28272906
argv[0] = Nan::Undefined();
28282907

2908+
Local<Function> callback = Nan::New<Function>(rollbackBaton->cb);
2909+
delete rollbackBaton;
28292910
Nan::MakeCallback( Nan::GetCurrentContext()->Global(),
2830-
Nan::New<Function>(rollbackBaton->cb), 1, argv );
2911+
callback, 1, argv );
28312912
if(tc.HasCaught())
28322913
{
28332914
Nan::FatalException(tc);
28342915
}
2835-
rollbackBaton->cb.Reset ();
2836-
delete rollbackBaton;
28372916
}
28382917

28392918
/*****************************************************************************/
@@ -2850,11 +2929,10 @@ NAN_METHOD(Connection::Break)
28502929
Connection *connection;
28512930
NJS_GET_CALLBACK ( callback, info );
28522931

2853-
eBaton* breakBaton = new eBaton;
2854-
breakBaton->cb.Reset( callback );
2855-
NJS_CHECK_NUMBER_OF_ARGS ( breakBaton->error, info, 1, 1, exitBreak );
28562932
connection = Nan::ObjectWrap::Unwrap<Connection>(info.This());
2933+
eBaton *breakBaton = new eBaton ( connection->DBCount (), callback );
28572934

2935+
NJS_CHECK_NUMBER_OF_ARGS ( breakBaton->error, info, 1, 1, exitBreak );
28582936
NJS_CHECK_OBJECT_VALID3 ( connection, breakBaton->error, exitBreak );
28592937

28602938
if(!connection->isValid_)
@@ -2866,8 +2944,16 @@ NAN_METHOD(Connection::Break)
28662944
exitBreak:
28672945
breakBaton->req.data = (void*) breakBaton;
28682946

2869-
uv_queue_work(uv_default_loop(), &breakBaton->req,
2947+
int status = uv_queue_work(uv_default_loop(), &breakBaton->req,
28702948
Async_Break, (uv_after_work_cb)Async_AfterBreak);
2949+
// delete the Baton if uv_queue_work fails
2950+
if ( status )
2951+
{
2952+
delete breakBaton;
2953+
string error = NJSMessages::getErrorMsg ( errInternalError,
2954+
"uv_queue_work", "Break" );
2955+
NJS_SET_EXCEPTION(error.c_str(), error.length());
2956+
}
28712957

28722958
info.GetReturnValue().SetUndefined();
28732959
}
@@ -2923,14 +3009,14 @@ void Connection::Async_AfterBreak (uv_work_t *req)
29233009
argv[0] = v8::Exception::Error(Nan::New<v8::String>((breakBaton->error).c_str()).ToLocalChecked());
29243010
else
29253011
argv[0] = Nan::Undefined();
3012+
Local<Function> callback = Nan::New<Function>(breakBaton->cb);
3013+
delete breakBaton;
29263014
Nan::MakeCallback( Nan::GetCurrentContext()->Global(),
2927-
Nan::New<Function>(breakBaton->cb), 1, argv );
3015+
callback, 1, argv );
29283016
if(tc.HasCaught())
29293017
{
29303018
Nan::FatalException(tc);
29313019
}
2932-
breakBaton->cb.Reset ();
2933-
delete breakBaton;
29343020
}
29353021

29363022
/****************************************************************************/

src/njs/src/njsConnection.h

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
#include "njsUtils.h"
5959
#include "njsOracle.h"
6060

61-
6261
using namespace v8;
6362
using namespace node;
6463
using namespace dpi;
@@ -159,19 +158,24 @@ typedef struct eBaton
159158
unsigned int fetchInfoCount; // Conversion requested count
160159
FetchInfo *fetchInfo; // Conversion meta data
161160
Nan::Persistent<Function> cb;
161+
RefCounter counter;
162162

163-
eBaton() : sql(""), error(""), dpienv(NULL), dpiconn(NULL), njsconn(NULL),
163+
eBaton( unsigned int& count, Local<Function> callback ) :
164+
sql(""), error(""), dpienv(NULL), dpiconn(NULL), njsconn(NULL),
164165
rowsAffected(0), maxRows(0), prefetchRows(0),
165166
getRS(false), autoCommit(false), rowsFetched(0),
166167
outFormat(0), numCols(0), dpistmt(NULL),
167168
st(DpiStmtUnknown), stmtIsReturning (false), numOutBinds(0),
168169
columnNames(NULL), defines(NULL), fetchAsStringTypesCount (0),
169-
fetchAsStringTypes(NULL), fetchInfoCount(0), fetchInfo(NULL)
170-
{}
170+
fetchAsStringTypes(NULL), fetchInfoCount(0), fetchInfo(NULL),
171+
counter ( count )
172+
{
173+
cb.Reset( callback );
174+
}
171175

172176
~eBaton ()
173177
{
174-
//NanDisposePersistent(cb);
178+
cb.Reset ();
175179
if( !binds.empty() )
176180
{
177181
for( unsigned int index = 0 ;index < binds.size(); index++ )
@@ -258,6 +262,16 @@ class Connection: public Nan::ObjectWrap
258262
static void CopyMetaData ( std::string*, const dpi::MetaData*, unsigned int );
259263
bool isValid() { return isValid_; }
260264
dpi::Conn* getDpiConn() { return dpiconn_; }
265+
266+
/*
267+
* Counters to see whether connection is busy or not with LOB, ResultSet or
268+
* DB operations. This counters incremented and decremented for each
269+
* operation and used to prevent releasing busy connection.
270+
*/
271+
inline unsigned int& LOBCount () { return lobCount_; }
272+
inline unsigned int& RSCount () { return rsCount_; }
273+
inline unsigned int& DBCount () { return dbCount_; }
274+
261275
Oracledb* oracledb_;
262276

263277
private:
@@ -367,6 +381,7 @@ class Connection: public Nan::ObjectWrap
367381
//static void UpdateDateValue ( eBaton *executeBaton );
368382
static void UpdateDateValue ( eBaton *executeBaton, unsigned int index );
369383
static void v8Date2OraDate ( v8::Local<v8::Value>, Bind *bind);
384+
static ConnectionBusyStatus getConnectionBusyStatus ( Connection *conn );
370385

371386
// Callback/Utility function used to allocate buffer(s) for Bind Structs
372387
static void cbDynBufferAllocate ( void *ctx, bool dmlReturning,
@@ -396,6 +411,13 @@ class Connection: public Nan::ObjectWrap
396411
dpi::Conn* dpiconn_;
397412
bool isValid_;
398413
unsigned int oracleServerVersion_;
414+
/*
415+
* Counters to see whether connection is busy or not with LOB, ResultSet or
416+
* DB operations. This counters used to prevent releasing busy connection.
417+
*/
418+
unsigned int lobCount_; // LOB operations counter
419+
unsigned int rsCount_; // ResultSet operations counter
420+
unsigned int dbCount_; // Connection or DB operations counter
399421

400422
};
401423

0 commit comments

Comments
 (0)