From f0a1fb4052995cc55343930c3071643323dd65bc Mon Sep 17 00:00:00 2001 From: Michael Olson Date: Fri, 28 Jun 2013 18:37:24 -0700 Subject: [PATCH] Implement connection.isConnected(), don't segfault when doing work on closed connection We need to be able to detect closed connections so that we can more easily integrate with generic-pool. That module has a validate() hook which pairs nicely with the connection.isConnected() change I'm proposing here. Test scenario for reproing segfault issue: * Open connection * Set timer for closing connection with connection.close() after 10 seconds * Wait for timer to activate and close connection * Try to run connection.execute('SELECT 1 FROM DUAL') * Segfault occurs * After this change, it will throw an error instead of segfaulting --- README.md | 7 +++++++ src/connection.cpp | 18 +++++++++++++++++- src/connection.h | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index de1060f..cd0d939 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,13 @@ oracle.connect(connData, function(err, connection) { }); ``` +To validate whether the connection is still established after some time: + +```javascript +if (! connection.isConnected()) { + // retire this connection from a pool +} +``` ## Out Params diff --git a/src/connection.cpp b/src/connection.cpp index b409ee9..0664149 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -22,6 +22,7 @@ void Connection::Init(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructorTemplate, "execute", Execute); NODE_SET_PROTOTYPE_METHOD(constructorTemplate, "close", Close); + NODE_SET_PROTOTYPE_METHOD(constructorTemplate, "isConnected", IsConnected); NODE_SET_PROTOTYPE_METHOD(constructorTemplate, "setAutoCommit", SetAutoCommit); NODE_SET_PROTOTYPE_METHOD(constructorTemplate, "commit", Commit); NODE_SET_PROTOTYPE_METHOD(constructorTemplate, "rollback", Rollback); @@ -85,6 +86,16 @@ Handle Connection::Close(const Arguments& args) { } } +Handle Connection::IsConnected(const Arguments& args) { + Connection* connection = ObjectWrap::Unwrap(args.This()); + + if(connection && connection->m_connection) { + return Boolean::New(true); + } else { + return Boolean::New(false); + } +} + Handle Connection::Commit(const Arguments& args) { Connection* connection = ObjectWrap::Unwrap(args.This()); @@ -368,6 +379,9 @@ void Connection::EIO_Execute(uv_work_t* req) { oracle::occi::Statement* stmt = NULL; oracle::occi::ResultSet* rs = NULL; try { + if(! baton->connection->m_connection) { + throw NodeOracleException("Connection already closed"); + } stmt = baton->connection->m_connection->createStatement(baton->sql); stmt->setAutoCommit(baton->connection->m_autoCommit); int outputParam = SetValuesOnStatement(stmt, baton->values); @@ -444,7 +458,9 @@ void Connection::EIO_Execute(uv_work_t* req) { rs = NULL; } if(stmt) { - baton->connection->m_connection->terminateStatement(stmt); + if(baton->connection->m_connection) { + baton->connection->m_connection->terminateStatement(stmt); + } stmt = NULL; } } diff --git a/src/connection.h b/src/connection.h index c03c50f..24c1056 100644 --- a/src/connection.h +++ b/src/connection.h @@ -22,6 +22,7 @@ class Connection : ObjectWrap { static Handle New(const Arguments& args); static Handle Execute(const Arguments& args); static Handle Close(const Arguments& args); + static Handle IsConnected(const Arguments& args); static Handle Commit(const Arguments& args); static Handle Rollback(const Arguments& args); static Handle SetAutoCommit(const Arguments& args);