|
| 1 | +#include <string.h> |
| 2 | +#include "connection.h" |
| 3 | +#include "executeBaton.h" |
| 4 | +#include "reader.h" |
| 5 | + |
| 6 | +using namespace std; |
| 7 | + |
| 8 | +Persistent<FunctionTemplate> Reader::constructorTemplate; |
| 9 | + |
| 10 | +void Reader::Init(Handle<Object> target) { |
| 11 | + UNI_SCOPE(scope); |
| 12 | + |
| 13 | + Local<FunctionTemplate> t = FunctionTemplate::New(New); |
| 14 | + uni::Reset(constructorTemplate, t); |
| 15 | + uni::Deref(constructorTemplate)->InstanceTemplate()->SetInternalFieldCount(1); |
| 16 | + uni::Deref(constructorTemplate)->SetClassName(String::NewSymbol("Reader")); |
| 17 | + |
| 18 | + NODE_SET_PROTOTYPE_METHOD(uni::Deref(constructorTemplate), "nextRows", NextRows); |
| 19 | + target->Set(String::NewSymbol("Reader"), uni::Deref(constructorTemplate)->GetFunction()); |
| 20 | +} |
| 21 | + |
| 22 | +Reader::Reader(): ObjectWrap() { |
| 23 | +} |
| 24 | + |
| 25 | +Reader::~Reader() { |
| 26 | + delete m_baton; |
| 27 | + m_baton = NULL; |
| 28 | +} |
| 29 | + |
| 30 | +uni::CallbackType Reader::New(const uni::FunctionCallbackInfo& args) { |
| 31 | + UNI_SCOPE(scope); |
| 32 | + |
| 33 | + Reader* reader = new Reader(); |
| 34 | + reader->Wrap(args.This()); |
| 35 | + |
| 36 | + UNI_RETURN(scope, args, args.This()); |
| 37 | +} |
| 38 | + |
| 39 | +void Reader::setBaton(ReaderBaton* baton) { |
| 40 | + m_baton = baton; |
| 41 | +} |
| 42 | + |
| 43 | +uni::CallbackType Reader::NextRows(const uni::FunctionCallbackInfo& args) { |
| 44 | + UNI_SCOPE(scope); |
| 45 | + Reader* reader = ObjectWrap::Unwrap<Reader>(args.This()); |
| 46 | + ReaderBaton* baton = reader->m_baton; |
| 47 | + if (baton->error) { |
| 48 | + Local<String> message = String::New(baton->error->c_str()); |
| 49 | + UNI_THROW(Exception::Error(message)); |
| 50 | + } |
| 51 | + |
| 52 | + if (args.Length() > 1) { |
| 53 | + REQ_INT_ARG(0, count); |
| 54 | + REQ_FUN_ARG(1, callback); |
| 55 | + baton->count = count; |
| 56 | + uni::Reset(baton->nextRowsCallback, callback); |
| 57 | + } else { |
| 58 | + REQ_FUN_ARG(0, callback); |
| 59 | + baton->count = baton->connection->getPrefetchRowCount(); |
| 60 | + uni::Reset(baton->nextRowsCallback, callback); |
| 61 | + } |
| 62 | + if (baton->count <= 0) baton->count = 1; |
| 63 | + |
| 64 | + uv_work_t* req = new uv_work_t(); |
| 65 | + req->data = baton; |
| 66 | + uv_queue_work(uv_default_loop(), req, EIO_NextRows, (uv_after_work_cb)EIO_AfterNextRows); |
| 67 | + baton->connection->Ref(); |
| 68 | + |
| 69 | + UNI_RETURN(scope, args, Undefined()); |
| 70 | +} |
| 71 | + |
| 72 | +void Reader::EIO_NextRows(uv_work_t* req) { |
| 73 | + ReaderBaton* baton = static_cast<ReaderBaton*>(req->data); |
| 74 | + |
| 75 | + baton->rows = NULL; |
| 76 | + baton->error = NULL; |
| 77 | + |
| 78 | + try { |
| 79 | + if(! baton->connection->getConnection()) { |
| 80 | + baton->error = new std::string("Connection already closed"); |
| 81 | + return; |
| 82 | + } |
| 83 | + if (!baton->rs) { |
| 84 | + baton->stmt = baton->connection->getConnection()->createStatement(baton->sql); |
| 85 | + baton->stmt->setAutoCommit(baton->connection->getAutoCommit()); |
| 86 | + baton->stmt->setPrefetchRowCount(baton->count); |
| 87 | + Connection::SetValuesOnStatement(baton->stmt, baton); |
| 88 | + if (baton->error) goto cleanup; |
| 89 | + |
| 90 | + int status = baton->stmt->execute(); |
| 91 | + if(status != oracle::occi::Statement::RESULT_SET_AVAILABLE) { |
| 92 | + baton->error = new std::string("Connection already closed"); |
| 93 | + return; |
| 94 | + } |
| 95 | + 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); |
| 105 | + } |
| 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"); |
| 112 | + } |
| 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(); |
| 127 | +} |
| 128 | +#endif |
| 129 | + |
| 130 | +void Reader::EIO_AfterNextRows(uv_work_t* req, int status) { |
| 131 | + UNI_SCOPE(scope); |
| 132 | + ReaderBaton* baton = static_cast<ReaderBaton*>(req->data); |
| 133 | + |
| 134 | + 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); |
| 145 | + } |
| 146 | + baton->nextRowsCallback.MakeWeak((void*)NULL, ReaderWeakReferenceCallback); |
| 147 | +} |
| 148 | + |
0 commit comments