@@ -48,16 +48,20 @@ uni::CallbackType Reader::NextRows(const uni::FunctionCallbackInfo& args) {
4848 Local<String> message = String::New (baton->error ->c_str ());
4949 UNI_THROW (Exception::Error (message));
5050 }
51+ if (baton->busy ) {
52+ UNI_THROW (Exception::Error (String::New (" invalid state: reader is busy with another nextRows call" )));
53+ }
54+ baton->busy = true ;
5155
5256 if (args.Length () > 1 ) {
5357 REQ_INT_ARG (0 , count);
5458 REQ_FUN_ARG (1 , callback);
5559 baton->count = count;
56- uni::Reset (baton->nextRowsCallback , callback);
60+ uni::Reset (baton->callback , callback);
5761 } else {
5862 REQ_FUN_ARG (0 , callback);
5963 baton->count = baton->connection ->getPrefetchRowCount ();
60- uni::Reset (baton->nextRowsCallback , callback);
64+ uni::Reset (baton->callback , callback);
6165 }
6266 if (baton->count <= 0 ) baton->count = 1 ;
6367
@@ -72,77 +76,64 @@ uni::CallbackType Reader::NextRows(const uni::FunctionCallbackInfo& args) {
7276void Reader::EIO_NextRows (uv_work_t * req) {
7377 ReaderBaton* baton = static_cast <ReaderBaton*>(req->data );
7478
75- baton->rows = NULL ;
76- baton->error = NULL ;
79+ baton->rows = new vector< row_t *>() ;
80+ if ( baton->done ) return ;
7781
78- try {
79- if (! baton->connection -> getConnection ()) {
80- baton-> error = new std::string ( " Connection already closed " ) ;
81- return ;
82- }
83- if (!baton-> rs ) {
82+ if (!baton-> connection -> getConnection ()) {
83+ baton->error = new std::string ( " Connection already closed " );
84+ return ;
85+ }
86+ if (!baton-> rs ) {
87+ try {
8488 baton->stmt = baton->connection ->getConnection ()->createStatement (baton->sql );
8589 baton->stmt ->setAutoCommit (baton->connection ->getAutoCommit ());
8690 baton->stmt ->setPrefetchRowCount (baton->count );
8791 Connection::SetValuesOnStatement (baton->stmt , baton);
88- if (baton->error ) goto cleanup ;
92+ if (baton->error ) return ;
8993
9094 int status = baton->stmt ->execute ();
91- if (status != oracle::occi::Statement::RESULT_SET_AVAILABLE) {
95+ if (status != oracle::occi::Statement::RESULT_SET_AVAILABLE) {
9296 baton->error = new std::string (" Connection already closed" );
9397 return ;
9498 }
9599 baton->rs = baton->stmt ->getResultSet ();
96- Connection::CreateColumnsFromResultSet (baton->rs , baton, baton->columns );
97- if (baton->error ) goto cleanup;
98- }
99- baton->rows = new vector<row_t *>();
100-
101- for (int i = 0 ; i < baton->count && baton->rs ->next (); i++) {
102- row_t * row = Connection::CreateRowFromCurrentResultSetRow (baton->rs , baton, baton->columns );
103- if (baton->error ) goto cleanup;
104- baton->rows ->push_back (row);
100+ } catch (oracle::occi::SQLException &ex) {
101+ baton->error = new string (ex.getMessage ());
102+ return ;
105103 }
106- } catch (oracle::occi::SQLException &ex) {
107- baton->error = new string (ex.getMessage ());
108- } catch (const exception& ex) {
109- baton->error = new string (ex.what ());
110- } catch (...) {
111- baton->error = new string (" Unknown Error" );
104+ Connection::CreateColumnsFromResultSet (baton->rs , baton, baton->columns );
105+ if (baton->error ) return ;
112106 }
113- cleanup:
114- // nothing for now, cleanup happens in destructor
115- ;
116- }
117-
118- #if NODE_MODULE_VERSION >= 0x000D
119- void ReaderWeakReferenceCallback (Isolate* isolate, v8::Persistent<v8::Function>* callback, void * dummy)
120- {
121- callback->Dispose ();
122- }
123- #else
124- void ReaderWeakReferenceCallback (v8::Persistent<v8::Value> callback, void * dummy)
125- {
126- (Persistent<Function>(Function::Cast (*callback))).Dispose ();
107+ for (int i = 0 ; i < baton->count && baton->rs ->next (); i++) {
108+ row_t * row = Connection::CreateRowFromCurrentResultSetRow (baton->rs , baton, baton->columns );
109+ if (baton->error ) return ;
110+ baton->rows ->push_back (row);
111+ }
112+ if (baton->rows ->size () < (size_t )baton->count ) baton->done = true ;
127113}
128- #endif
129114
130115void Reader::EIO_AfterNextRows (uv_work_t * req, int status) {
131116 UNI_SCOPE (scope);
132117 ReaderBaton* baton = static_cast <ReaderBaton*>(req->data );
133118
119+ baton->busy = false ;
134120 baton->connection ->Unref ();
135-
136- try {
137- Handle<Value> argv[2 ];
138- Connection::handleResult (baton, argv);
139- node::MakeCallback (Context::GetCurrent ()->Global (), uni::Deref (baton->nextRowsCallback ), 2 , argv);
140- } catch (const exception &ex) {
141- Handle<Value> argv[2 ];
142- argv[0 ] = Exception::Error (String::New (ex.what ()));
143- argv[1 ] = Undefined ();
144- node::MakeCallback (Context::GetCurrent ()->Global (), uni::Deref (baton->nextRowsCallback ), 2 , argv);
121+ // transfer callback to local and dispose persistent handle
122+ // must be done before invoking callback because callback may set another callback into baton->callback
123+ Local<Function> cb = uni::HandleToLocal (uni::Deref (baton->callback ));
124+ baton->callback .Dispose ();
125+ baton->callback .Clear ();
126+
127+ Handle<Value> argv[2 ];
128+ Connection::handleResult (baton, argv);
129+ node::MakeCallback (Context::GetCurrent ()->Global (), cb, 2 , argv);
130+
131+ baton->ResetRows ();
132+ if (baton->done || baton->error ) {
133+ // free occi resources so that we don't run out of cursors if gc is not fast enough
134+ // reader destructor will delete the baton and everything else.
135+ baton->ResetStatement ();
145136 }
146- baton-> nextRowsCallback . MakeWeak (( void *) NULL , ReaderWeakReferenceCallback) ;
137+ delete req ;
147138}
148139
0 commit comments