Initial Result Set code

This commit is contained in:
Christopher Jones 2015-07-20 14:54:05 +10:00
parent e4a84b520d
commit 1e8d7c558c
14 changed files with 816 additions and 34 deletions

View File

@ -6,6 +6,7 @@
"src/njs/src/njsOracle.cpp",
"src/njs/src/njsPool.cpp",
"src/njs/src/njsConnection.cpp",
"src/njs/src/njsResultSet.cpp",
"src/njs/src/njsMessages.cpp",
"src/dpi/src/dpiEnv.cpp",
"src/dpi/src/dpiEnvImpl.cpp",

View File

@ -146,6 +146,8 @@ public:
// properties
virtual DpiStmtType stmtType() const = 0;
virtual void prefetchRows ( int prefetchRows ) = 0;
virtual bool isDML() const = 0 ;
virtual bool isReturning() = 0 ;

View File

@ -196,15 +196,34 @@ unsigned int StmtImpl::numCols ()
}
/*****************************************************************************/
/*
DESCRIPTION
Prefetch Rows set on statement handle
PARAMETERS
prefetchRows count
RETURNS
NONE
*/
void StmtImpl::prefetchRows (int prefetchRows)
{
ociCall(OCIAttrSet(stmth_, OCI_HTYPE_STMT, &prefetchRows, 0,
OCI_ATTR_PREFETCH_ROWS, errh_), errh_);
}
/*****************************************************************************/
/*
DESCRIPTION
bind the variable(s) by pdpition
bind the variable(s) by position
PARAMETERS
pos - pdpition of the variable 1 based
pos - position of the variable 1 based
type - Data type
buf (IN/OUT) - data buffer for the variable's value
bufSize - size of the buffer

View File

@ -66,6 +66,7 @@ public:
virtual DpiStmtType stmtType () const;
virtual DPI_SZ_TYPE rowsAffected () const;
virtual unsigned int numCols() ;
virtual void prefetchRows( int prefetchRows ) ;
virtual unsigned int rowsFetched () const ;
// Methods

View File

@ -49,6 +49,7 @@
*****************************************************************************/
#include "njsConnection.h"
#include "njsResultSet.h"
#include <stdlib.h>
#include <iostream>
using namespace std;
@ -340,10 +341,12 @@ NAN_METHOD(Connection::Execute)
NJSString (executeBaton->sql, sql);
executeBaton->maxRows = connection->oracledb_->getMaxRows();
executeBaton->prefetchRows = connection->oracledb_->getPrefetchRows();
executeBaton->outFormat = connection->oracledb_->getOutFormat();
executeBaton->autoCommit = connection->oracledb_->getAutoCommit();
executeBaton->dpienv = connection->oracledb_->getDpiEnv();
executeBaton->dpiconn = connection->dpiconn_;
executeBaton->njsconn = connection;
if(args.Length() > 2)
{
@ -411,8 +414,12 @@ void Connection::ProcessOptions (_NAN_METHOD_ARGS, unsigned int index,
options = args[index]->ToObject();
NJS_GET_UINT_FROM_JSON ( executeBaton->maxRows, executeBaton->error,
options, "maxRows", 2, exitProcessOptions );
NJS_GET_UINT_FROM_JSON ( executeBaton->prefetchRows, executeBaton->error,
options, "prefetchRows", 2, exitProcessOptions );
NJS_GET_UINT_FROM_JSON ( executeBaton->outFormat, executeBaton->error,
options, "outFormat", 2, exitProcessOptions );
NJS_GET_BOOL_FROM_JSON ( executeBaton->getRS, executeBaton->error,
options, "resultSet", 2, exitProcessOptions );
NJS_GET_BOOL_FROM_JSON ( executeBaton->autoCommit, executeBaton->error,
options, "autoCommit", 2, exitProcessOptions );
}
@ -731,10 +738,22 @@ void Connection::Async_Execute (uv_work_t *req)
if (executeBaton->st == DpiStmtSelect)
{
executeBaton->dpistmt->execute(0, executeBaton->autoCommit);
Connection::GetDefines(executeBaton);
const dpi::MetaData* meta = executeBaton->dpistmt->getMetaData();
executeBaton->numCols = executeBaton->dpistmt->numCols();
executeBaton->columnNames = new std::string[executeBaton->numCols];
Connection::metaData( executeBaton->columnNames, meta,
executeBaton->numCols );
if( executeBaton->getRS ) goto exitAsyncExecute;
Connection::GetDefines(executeBaton, meta, executeBaton->numCols);
}
else
{
if( executeBaton->getRS )
{
executeBaton->error = NJSMessages::getErrorMsg(
errInvalidNonQueryExecution );
goto exitAsyncExecute;
}
executeBaton->dpistmt->execute(1, executeBaton->autoCommit);
executeBaton->rowsAffected = executeBaton->dpistmt->rowsAffected();
@ -826,6 +845,9 @@ void Connection::PrepareAndBind (eBaton* executeBaton)
executeBaton->st = executeBaton->dpistmt->stmtType ();
executeBaton->stmtIsReturning = executeBaton->dpistmt->isReturning ();
if(executeBaton->getRS && executeBaton->prefetchRows > -1)
executeBaton->dpistmt->prefetchRows(executeBaton->prefetchRows);
if(!executeBaton->binds.empty())
{
if(!executeBaton->binds[0]->key.empty())
@ -930,6 +952,24 @@ void Connection::PrepareAndBind (eBaton* executeBaton)
}
}
/*****************************************************************************/
/*
DESCRIPTION
get meta data into baton
PARAMETERS:
string arrat, metaData, numCols
*/
void Connection::metaData ( std::string* names, const dpi::MetaData* meta,
unsigned int numCols )
{
for (unsigned int i = 0; i < numCols; i++)
{
names[i] = std::string( (const char*)meta[i].colName,
meta[i].colNameLen );
}
}
/*****************************************************************************/
/*
DESCRIPTION
@ -939,19 +979,13 @@ void Connection::PrepareAndBind (eBaton* executeBaton)
PARAMETERS:
eBaton struct
*/
void Connection::GetDefines (eBaton* executeBaton)
void Connection::GetDefines ( eBaton* executeBaton, const dpi::MetaData* meta,
unsigned int numCols )
{
unsigned int numCols = executeBaton->dpistmt->numCols();
Define *defines = new Define[numCols];
const dpi::MetaData* meta = executeBaton->dpistmt->getMetaData();
executeBaton->columnNames = new std::string[numCols];
for (unsigned int i = 0; i < numCols; i++)
{
executeBaton->columnNames[i] = std::string((const char*)meta[i].colName,
meta[i].colNameLen );
switch(meta[i].dbType)
{
case dpi::DpiNumber :
@ -993,8 +1027,22 @@ void Connection::GetDefines (eBaton* executeBaton)
executeBaton->defines = defines;
executeBaton->numCols = numCols;
executeBaton->rowsFetched = executeBaton->dpistmt->rowsFetched();
Connection::descr2Dbl (executeBaton->defines, numCols,
executeBaton->rowsFetched,
executeBaton->getRS);
}
/* Special processing for datetime, as it is obtained as descriptors */
/*****************************************************************************/
/*
DESCRIPTION
Special processing for datetime, as it is obtained as descriptors
PARAMETERS:
Define struct, numCols
*/
void Connection::descr2Dbl( Define* defines, unsigned int numCols,
unsigned int rowsFetched, bool getRS )
{
for (unsigned int col = 0; col < numCols; col ++ )
{
if ( defines[col].dttmarr )
@ -1003,15 +1051,18 @@ void Connection::GetDefines (eBaton* executeBaton)
defines[col].buf =
dblArr = (long double *)malloc ( sizeof ( long double ) *
executeBaton->rowsFetched );
rowsFetched );
for ( int row = 0; row < (int) executeBaton->rowsFetched; row ++ )
for ( int row = 0; row < (int) rowsFetched; row ++ )
{
dblArr[row] = defines[col].dttmarr->getDateTime (row) * NJS_DAY2MS;
}
defines[col].buf = (void *) dblArr;
defines[col].dttmarr->release ();
defines[col].extbuf = NULL;
if ( !getRS )
{
defines[col].dttmarr->release ();
defines[col].extbuf = NULL;
}
}
}
@ -1055,7 +1106,23 @@ void Connection::Async_AfterExecute(uv_work_t *req)
argv[1] = NanUndefined();
goto exitAsyncAfterExecute;
}
result->Set(NanNew<v8::String>("rows"), rowArray);//, v8::ReadOnly);
if( executeBaton->getRS )
{
result->Set(NanNew<v8::String>("rows"), NanUndefined());
Handle<Object> resultSet = NanNew(ResultSet::resultSetTemplate_s)->
GetFunction() ->NewInstance();
(ObjectWrap::Unwrap<ResultSet> (resultSet))->
setResultSet( executeBaton->dpistmt,
executeBaton->dpienv,
executeBaton->njsconn,
executeBaton->outFormat );
result->Set(NanNew<v8::String>("resultSet"), resultSet );
}
else
{
result->Set(NanNew<v8::String>("rows"), rowArray);
result->Set(NanNew<v8::String>("resultSet"), NanUndefined());
}
result->Set(NanNew<v8::String>("outBinds"),NanUndefined());
result->Set(NanNew<v8::String>("rowsAffected"), NanUndefined());
result->Set(NanNew<v8::String>("metaData"), Connection::GetMetaData(

View File

@ -63,6 +63,8 @@ using namespace v8;
using namespace node;
using namespace dpi;
class Connection;
/**
* Structure used for binds
**/
@ -113,8 +115,11 @@ typedef struct eBaton
std::string error;
dpi::Env* dpienv;
dpi::Conn* dpiconn;
Connection *njsconn;
DPI_SZ_TYPE rowsAffected;
unsigned int maxRows;
int prefetchRows;
bool getRS;
bool autoCommit;
unsigned int rowsFetched;
unsigned int outFormat;
@ -128,9 +133,10 @@ typedef struct eBaton
Define *defines;
Persistent<Function> cb;
eBaton() : sql(""), error(""), dpienv(NULL), dpiconn(NULL),
rowsAffected(0), maxRows(0), autoCommit(false),
rowsFetched(0), outFormat(0), numCols(0), dpistmt(NULL),
eBaton() : sql(""), error(""), dpienv(NULL), dpiconn(NULL), njsconn(NULL),
rowsAffected(0), maxRows(0), prefetchRows(0),
getRS(false), autoCommit(false), rowsFetched(0),
outFormat(0), numCols(0), dpistmt(NULL),
st(DpiStmtUnknown), stmtIsReturning (false), numOutBinds(0),
columnNames(NULL), defines(NULL)
{}
@ -171,7 +177,7 @@ typedef struct eBaton
}
if( columnNames )
delete [] columnNames;
if( defines )
if( defines && !getRS )
{
for( unsigned int i=0; i<numCols; i++ )
{
@ -192,6 +198,15 @@ public:
// Define Connection Constructor
static Persistent<FunctionTemplate> connectionTemplate_s;
static void Init (Handle<Object> target);
static Handle<Value> GetRows (eBaton* executeBaton);
static Handle<Value> GetMetaData (std::string* columnNames,
unsigned int numCols);
static void GetDefines ( eBaton* executeBaton, const dpi::MetaData*,
unsigned int numCols );
static void metaData ( std::string*, const dpi::MetaData*, unsigned int );
static void descr2Dbl ( Define* defines, unsigned int numCols,
unsigned int rowsFetched, bool getRS );
bool getIsValid() { return isValid_; }
private:
static NAN_METHOD(New);
@ -241,7 +256,6 @@ private:
static void PrepareAndBind (eBaton* executeBaton);
static void GetDefines (eBaton* executeBaton);
static void ProcessBinds (_NAN_METHOD_ARGS, unsigned int index,
eBaton* executeBaton);
static void ProcessOptions (_NAN_METHOD_ARGS, unsigned int index,
@ -266,9 +280,6 @@ private:
static v8::Handle<v8::Value> GetOutBindObject (std::vector<Bind*> &binds,
bool bDMLReturn = false,
unsigned long rowcount = 1);
static v8::Handle<v8::Value> GetRows (eBaton* executeBaton);
static v8::Handle<v8::Value> GetMetaData (std::string* columnNames,
unsigned int numCols);
static v8::Handle<v8::Value> GetArrayValue (Bind *bind, unsigned long count);
static v8::Handle<v8::Value> GetValue (short ind, unsigned short type, void* val,
DPI_BUFLEN_TYPE len,

View File

@ -50,7 +50,10 @@ static const char *errMsg[] =
"NJS-013: invalid bind direction",
"NJS-014: %s is a read-only property",
"NJS-015: %s is a write-only property",
"NJS-016: Buffer is too small for OUT binds"
"NJS-016: buffer is too small for OUT binds",
"NJS-017: concurrent operations on resultSet are not allowed",
"NJS-018: invalid result set",
"NJS-019: getResultSet set for non-query execution",
};
string NJSMessages::getErrorMsg ( NJSErrorType err, ... )

View File

@ -50,6 +50,9 @@ typedef enum
errReadOnly,
errWriteOnly,
errInsufficientBufferForBinds,
errBusyResultSet,
errInvalidResultSet,
errInvalidNonQueryExecution,
// New ones should be added here

View File

@ -53,6 +53,7 @@
#include "njsOracle.h"
#include "njsConnection.h"
#include "njsPool.h"
#include "njsResultSet.h"
#include "njsMessages.h"
//peristent Oracledb class handle
Persistent<FunctionTemplate> Oracledb::oracledbTemplate_s;
@ -63,6 +64,7 @@ Persistent<FunctionTemplate> Oracledb::oracledbTemplate_s;
#define POOL_MAX 4
#define POOL_INCR 1
#define POOL_TIMEOUT 60
#define PREFETCH_ROWS -1
/*****************************************************************************/
/*
@ -80,6 +82,7 @@ Oracledb::Oracledb()
poolMin_ = POOL_MIN;
poolIncrement_ = POOL_INCR;
poolTimeout_ = POOL_TIMEOUT;
prefetchRows_ = PREFETCH_ROWS;
connClass_ = "";
externalAuth_ = false;
}
@ -356,6 +359,32 @@ NAN_SETTER(Oracledb::SetStmtCacheSize)
NJS_SET_PROP_UINT(oracledb->stmtCacheSize_, value, "stmtCacheSize");
}
/*****************************************************************************/
/*
DESCRIPTION
Get Accessor of prefetchRows property
*/
NAN_PROPERTY_GETTER(Oracledb::GetPrefetchRows)
{
NanScope();
Oracledb* oracledb = ObjectWrap::Unwrap<Oracledb>(args.Holder());
Local<Integer> value = NanNew<v8::Integer>(oracledb->prefetchRows_);
NanReturnValue(value);
}
/*****************************************************************************/
/*
DESCRIPTION
Set Accessor of prefetchRows property
*/
NAN_SETTER(Oracledb::SetPrefetchRows)
{
NanScope();
Oracledb* oracledb = ObjectWrap::Unwrap<Oracledb>(args.Holder());
NJS_SET_PROP_UINT(oracledb->prefetchRows_, value, "prefetchRows");
}
/*****************************************************************************/
/*
DESCRIPTION
@ -769,6 +798,7 @@ extern "C"
Oracledb::Init(target);
Connection::Init(target);
Pool::Init(target);
ResultSet::Init(target);
}
NODE_MODULE(oracledb, init)

View File

@ -94,6 +94,7 @@ class Oracledb: public ObjectWrap
unsigned int getPoolMax () const { return poolMax_; }
unsigned int getPoolIncrement () const { return poolIncrement_; }
unsigned int getPoolTimeout () const { return poolTimeout_; }
unsigned int getPrefetchRows () const { return prefetchRows_; }
const std::string& getConnectionClass () const { return connClass_; }
@ -126,6 +127,7 @@ private:
static NAN_PROPERTY_GETTER(GetVersion);
static NAN_PROPERTY_GETTER(GetConnectionClass);
static NAN_PROPERTY_GETTER(GetExternalAuth);
static NAN_PROPERTY_GETTER(GetPrefetchRows);
// Define Setter Accessors to Properties
static NAN_SETTER(SetPoolMin);
@ -139,6 +141,7 @@ private:
static NAN_SETTER(SetVersion);
static NAN_SETTER(SetConnectionClass);
static NAN_SETTER(SetExternalAuth);
static NAN_SETTER(SetPrefetchRows);
Oracledb();
~Oracledb();
@ -149,6 +152,7 @@ private:
unsigned int maxRows_;
unsigned int stmtCacheSize_;
int prefetchRows_;
unsigned int poolMin_;
unsigned int poolMax_;

View File

@ -158,6 +158,8 @@ NAN_METHOD(Pool::New)
*/
Handle<Value> Pool::getPoolProperty(Pool* njsPool, unsigned int poolProperty)
{
NanScope();
if(!njsPool->isValid_)
{
string msg = NJSMessages::getErrorMsg(errInvalidPool);

View File

@ -0,0 +1,486 @@
/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. */
/******************************************************************************
*
* You may not use the identified files except in compliance with the Apache
* License, Version 2.0 (the "License.")
*
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file uses NAN:
*
* Copyright (c) 2015 NAN contributors
*
* NAN contributors listed at https://github.com/rvagg/nan#contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* NAME
* njsResultSet.cpp
*
* DESCRIPTION
* ResultSet class implementation.
*
*****************************************************************************/
#include "node.h"
#include <string>
#include "njsResultSet.h"
#include "njsConnection.h"
#include <iostream>
using namespace std;
using namespace node;
using namespace v8;
//peristent ResultSet class handle
Persistent<FunctionTemplate> ResultSet::resultSetTemplate_s;
ResultSet::ResultSet(){}
ResultSet::~ResultSet(){}
/*****************************************************************************/
/*
DESCRIPTION
Store the config in pool instance.
*/
void ResultSet::setResultSet ( dpi::Stmt *stmt, dpi::Env *env,
Connection *conn, unsigned int outFormat )
{
this->dpistmt_ = stmt;
this->dpienv_ = env;
this->njsconn_ = conn;
this->meta_ = stmt->getMetaData();
this->numCols_ = stmt->numCols();
this->state_ = INACTIVE;
this->outFormat_ = outFormat;
this->bufferSize_ = 0;
this->rsEmpty_ = false;
this->fetchBuffers_ = NULL;
}
/*****************************************************************************/
/*
DESCRIPTION
Init function of the ResultSet class.
Initiates and maps the functions and properties of ResultSet class.
*/
void ResultSet::Init(Handle<Object> target)
{
NanScope();
Local<FunctionTemplate> temp = NanNew<FunctionTemplate>(New);
temp->InstanceTemplate()->SetInternalFieldCount(1);
temp->SetClassName(NanNew<v8::String>("ResultSet"));
NODE_SET_PROTOTYPE_METHOD(temp, "close", Close);
NODE_SET_PROTOTYPE_METHOD(temp, "getRow", GetRows);
NODE_SET_PROTOTYPE_METHOD(temp, "getRows", GetRows);
temp->InstanceTemplate()->SetAccessor(
NanNew<v8::String>("metaData"),
ResultSet::GetMetaData,
ResultSet::SetMetaData );
NanAssignPersistent( resultSetTemplate_s, temp);
target->Set(NanNew<v8::String>("ResultSet"),temp->GetFunction());
}
/*****************************************************************************/
/*
DESCRIPTION
Invoked when new of connection is called from JS
*/
NAN_METHOD(ResultSet::New)
{
NanScope();
ResultSet *resultSet = new ResultSet();
resultSet->Wrap(args.This());
NanReturnValue(args.This());
}
/*****************************************************************************/
/*
DESCRIPTION
Get Accessor of metaData Property
*/
NAN_PROPERTY_GETTER(ResultSet::GetMetaData)
{
NanScope();
ResultSet* njsResultSet = ObjectWrap::Unwrap<ResultSet>(args.Holder());
std::string *columnNames = new std::string[njsResultSet->numCols_];
Connection::metaData ( columnNames, njsResultSet->meta_,
njsResultSet->numCols_ );
Handle<Value> meta;
meta = Connection::GetMetaData( columnNames,
njsResultSet->numCols_ );
NanReturnValue(meta);
}
/*****************************************************************************/
/*
DESCRIPTION
Set Accessor of metaData Property - throws error
*/
NAN_SETTER(ResultSet::SetMetaData)
{
NanScope();
ResultSet* njsResultSet = ObjectWrap::Unwrap<ResultSet>(args.Holder());
string msg;
if(njsResultSet->state_ == INVALID)
msg = NJSMessages::getErrorMsg(errInvalidResultSet);
else
msg = NJSMessages::getErrorMsg(errReadOnly, "metaData");
NJS_SET_EXCEPTION(msg.c_str(), (int) msg.length());
}
/*****************************************************************************/
/*
DESCRIPTION
Get Connection method on Result Set class.
PARAMETERS:
Arguments - Callback
*/
NAN_METHOD(ResultSet::GetRows)
{
NanScope();
Local<Function> callback;
NJS_GET_CALLBACK ( callback, args );
ResultSet *njsResultSet = ObjectWrap::Unwrap<ResultSet>(args.This());
rsBaton *getRowsBaton = new rsBaton ();
NanAssignPersistent(getRowsBaton->cb, callback );
NJS_CHECK_NUMBER_OF_ARGS ( getRowsBaton->error, args, 1, 2, exitGetRows );
if(args.Length() == 2)
{
NJS_GET_ARG_V8UINT ( getRowsBaton->numRows, getRowsBaton->error,
args, 0, exitGetRows );
}
else
{
getRowsBaton->numRows = 1;
}
getRowsBaton->njsRS = njsResultSet;
getRowsBaton->ebaton = new eBaton;
if(!njsResultSet->njsconn_->getIsValid())
{
getRowsBaton->error = NJSMessages::getErrorMsg ( errInvalidConnection );
goto exitGetRows;
}
if(njsResultSet->state_ == INVALID)
{
getRowsBaton->error = NJSMessages::getErrorMsg ( errInvalidResultSet );
goto exitGetRows;
}
else if(njsResultSet->state_ == ACTIVE)
{
getRowsBaton->error = NJSMessages::getErrorMsg ( errBusyResultSet );
goto exitGetRows;
}
njsResultSet->state_ = ACTIVE;
getRowsBaton->ebaton->columnNames = new std::string[njsResultSet->numCols_];
getRowsBaton->ebaton->maxRows = getRowsBaton->numRows;
getRowsBaton->ebaton->dpistmt = njsResultSet->dpistmt_;
getRowsBaton->ebaton->dpienv = njsResultSet->dpienv_;
getRowsBaton->ebaton->getRS = true;
exitGetRows:
getRowsBaton->req.data = (void *)getRowsBaton;
uv_queue_work(uv_default_loop(), &getRowsBaton->req, Async_GetRows,
(uv_after_work_cb)Async_AfterGetRows);
NanReturnUndefined();
}
/*****************************************************************************/
/*
DESCRIPTION
Worker function of Get Rows method
PARAMETERS:
UV queue work block
NOTES:
DPI call execution.
*/
void ResultSet::Async_GetRows(uv_work_t *req)
{
rsBaton *getRowsBaton = (rsBaton*)req->data;
ResultSet *njsRS = getRowsBaton->njsRS;
eBaton *ebaton = getRowsBaton->ebaton;
if(!(getRowsBaton->error).empty()) goto exitAsyncGetRows;
if(njsRS->rsEmpty_)
{
ebaton->rowsFetched = 0;
goto exitAsyncGetRows;
}
try
{
Connection::metaData( ebaton->columnNames, njsRS->meta_,
njsRS->numCols_ );
if( njsRS->fetchBuffers_ == NULL ||
njsRS->bufferSize_ < getRowsBaton->numRows )
{
if(njsRS->fetchBuffers_ != NULL)
{
ResultSet::nullifyFetchBuffer(njsRS->fetchBuffers_, njsRS->numCols_);
}
Connection::GetDefines(ebaton, njsRS->meta_, njsRS->numCols_);
njsRS->bufferSize_ = getRowsBaton->numRows;
njsRS->fetchBuffers_ = ebaton->defines;
}
else
{
njsRS->dpistmt_->fetch(getRowsBaton->numRows);
ebaton->maxRows = getRowsBaton->numRows;
ebaton->outFormat = njsRS->outFormat_;
ebaton->defines = njsRS->fetchBuffers_;
ebaton->rowsFetched = njsRS->dpistmt_->rowsFetched();
ebaton->numCols = njsRS->numCols_;
Connection::descr2Dbl ( ebaton->defines, ebaton->numCols,
ebaton->rowsFetched, ebaton->getRS );
}
if(ebaton->rowsFetched != getRowsBaton->numRows)
njsRS->rsEmpty_ = true;
}
catch (dpi::Exception &e)
{
getRowsBaton->error = std::string (e.what());
}
exitAsyncGetRows:
;
}
/*****************************************************************************/
/*
DESCRIPTION
Callback function of Get Connection method
PARAMETERS:
UV queue work block
status - expected to be non-zero.
NOTES:
Connection handle is formed and handed over to JS.
*/
void ResultSet::Async_AfterGetRows(uv_work_t *req)
{
NanScope();
rsBaton *getRowsBaton = (rsBaton*)req->data;
v8::TryCatch tc;
Handle<Value> argv[2];
if(!(getRowsBaton->error).empty())
{
argv[0] = v8::Exception::Error(NanNew<v8::String>((getRowsBaton->error).c_str()));
argv[1] = NanUndefined();
}
else
{
getRowsBaton->njsRS->state_ = INACTIVE;
argv[0] = NanUndefined();
eBaton* ebaton = getRowsBaton->ebaton;
ebaton->outFormat = getRowsBaton->njsRS->outFormat_;
Handle<Value> rowsArray = v8::Array::New(0),
rowsArrayValue = NanNull();
if(ebaton->rowsFetched)
{
rowsArray = Connection::GetRows(ebaton);
if(!(ebaton->error).empty())
{
argv[0] = v8::Exception::Error(NanNew<v8::String>((ebaton->error).c_str()));
argv[1] = NanUndefined();
goto exitAsyncAfterGetRows;
}
rowsArrayValue = Handle<Array>::Cast(rowsArray)->Get(0);
}
argv[1] = (getRowsBaton->numRows > 1) ? rowsArray : rowsArrayValue;
}
exitAsyncAfterGetRows:
Local<Function> callback = NanNew(getRowsBaton->cb);
NanMakeCallback(NanGetCurrentContext()->Global(),
callback, 2, argv);
if(tc.HasCaught())
{
node::FatalException(tc);
}
delete getRowsBaton;
}
/*****************************************************************************/
/*
DESCRIPTION
Close method
PARAMETERS:
Arguments - Callback
*/
NAN_METHOD(ResultSet::Close)
{
NanScope();
Local<Function> callback;
NJS_GET_CALLBACK ( callback, args );
ResultSet *njsResultSet = ObjectWrap::Unwrap<ResultSet>(args.This());
rsBaton *closeBaton = new rsBaton ();
NanAssignPersistent( closeBaton->cb, callback );
NJS_CHECK_NUMBER_OF_ARGS ( closeBaton->error, args, 1, 1, exitClose );
if(!njsResultSet->njsconn_->getIsValid())
{
closeBaton->error = NJSMessages::getErrorMsg ( errInvalidConnection );
goto exitClose;
}
else if(njsResultSet->state_ == INVALID)
{
closeBaton->error = NJSMessages::getErrorMsg ( errInvalidResultSet );
goto exitClose;
}
else if(njsResultSet->state_ == ACTIVE)
{
closeBaton->error = NJSMessages::getErrorMsg ( errBusyResultSet );
goto exitClose;
}
closeBaton->njsRS = njsResultSet;
exitClose:
closeBaton->req.data = (void *)closeBaton;
uv_queue_work(uv_default_loop(), &closeBaton->req, Async_Close,
(uv_after_work_cb)Async_AfterClose);
NanReturnUndefined();
}
/*****************************************************************************/
/*
DESCRIPTION
Worker function of close.
PARAMETERS:
UV queue work block
NOTES:
DPI call execution.
*/
void ResultSet::Async_Close(uv_work_t *req)
{
rsBaton *closeBaton = (rsBaton*)req->data;
if(!closeBaton->error.empty()) goto exitAsyncClose;
try
{
closeBaton-> njsRS-> dpistmt_-> release ();
Define* fetchBuffers = closeBaton-> njsRS-> fetchBuffers_;
unsigned int numCols = closeBaton-> njsRS-> numCols_;
ResultSet::nullifyFetchBuffer(fetchBuffers, numCols);
}
catch(dpi::Exception& e)
{
closeBaton->error = std::string(e.what());
}
exitAsyncClose:
;
}
/*****************************************************************************/
/*
DESCRIPTION
Callback function of close
PARAMETERS:
UV queue work block
*/
void ResultSet::Async_AfterClose(uv_work_t *req)
{
NanScope();
rsBaton *closeBaton = (rsBaton*)req->data;
v8::TryCatch tc;
Handle<Value> argv[1];
if(!(closeBaton->error).empty())
{
argv[0] = v8::Exception::Error(NanNew<v8::String>((closeBaton->error).c_str()));
}
else
{
argv[0] = NanUndefined();
// pool is not valid after close succeeds.
closeBaton-> njsRS-> state_ = INVALID;
}
Local<Function> callback = NanNew(closeBaton->cb);
delete closeBaton;
NanMakeCallback( NanGetCurrentContext()->Global(), callback, 1, argv );
if(tc.HasCaught())
{
node::FatalException(tc);
}
}
/*****************************************************************************/
/*
DESCRIPTION
Free FetchBuffers
PARAMETERS:
Fetch Buffer, numCols
*/
void ResultSet::nullifyFetchBuffer( Define* fetchBuffers, unsigned int numCols)
{
for( unsigned int i=0; i<numCols; i++ )
{
if ( fetchBuffers[i].dttmarr )
{
fetchBuffers[i].dttmarr->release ();
fetchBuffers[i].extbuf = NULL;
}
free(fetchBuffers[i].buf);
free(fetchBuffers[i].len);
free(fetchBuffers[i].ind);
}
delete [] fetchBuffers;
fetchBuffers = NULL;
}
/* end of file njsPool.cpp */

136
src/njs/src/njsResultSet.h Normal file
View File

@ -0,0 +1,136 @@
/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. */
/******************************************************************************
*
* You may not use the identified files except in compliance with the Apache
* License, Version 2.0 (the "License.")
*
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file uses NAN:
*
* Copyright (c) 2015 NAN contributors
*
* NAN contributors listed at https://github.com/rvagg/nan#contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* NAME
* njsResultSet.h
*
* DESCRIPTION
* ResultSet class
*
*****************************************************************************/
#ifndef __NJSRESULTSET_H__
#define __NJSRESULTSET_H__
#include "dpi.h"
#include <node.h>
#include "nan.h"
#include <v8.h>
#include <string>
#include "njsUtils.h"
#include "njsConnection.h"
using namespace v8;
using namespace node;
class ResultSet: public ObjectWrap {
public:
static void Init(Handle<Object> target);
void setResultSet ( dpi::Stmt *dpistmt, dpi::Env *env,
Connection* conn, unsigned int outFormat );
// Define ResultSet Constructor
static Persistent<FunctionTemplate> resultSetTemplate_s ;
private:
static NAN_METHOD(New);
// Get Rows Methods
static NAN_METHOD(GetRows);
static void Async_GetRows(uv_work_t *req);
static void Async_AfterGetRows(uv_work_t *req);
// Close Methods
static NAN_METHOD(Close);
static void Async_Close(uv_work_t *req);
static void Async_AfterClose(uv_work_t *req);
// Define Getter Accessors to properties
static NAN_PROPERTY_GETTER(GetMetaData);
// Define Setter Accessors to properties
static NAN_SETTER(SetMetaData);
static void nullifyFetchBuffer( Define* fetchBuffers,
unsigned int numCols );
ResultSet();
~ResultSet();
dpi::Stmt *dpistmt_;
dpi::Env *dpienv_;
Connection *njsconn_;
State state_;
bool rsEmpty_;
Define* fetchBuffers_;
const dpi::MetaData *meta_;
unsigned int numCols_;
unsigned int bufferSize_;
unsigned int outFormat_;
};
typedef struct rsBaton
{
uv_work_t req;
std::string error;
eBaton *ebaton;
unsigned int numRows;
Persistent<Function> cb;
ResultSet* njsRS;
rsBaton() : error(""), ebaton(NULL), numRows(0)
{}
~rsBaton()
{
delete ebaton;
NanDisposePersistent(cb);
}
}rsBaton;
#endif /* __NJSRESULTSET_H__ */

View File

@ -83,15 +83,13 @@ typedef enum
ROWS_OBJECT = 2
}RowsType;
// args
// states
typedef enum
{
ARGS_ZERO = 0,
ARGS_ONE = 1,
ARGS_TWO = 2,
ARGS_THREE = 3,
ARGS_FOUR = 4
}ArgsType;
INVALID = 0,
ACTIVE = 1,
INACTIVE = 2,
}State;
/*
* Get the callback from the last argument.
@ -179,6 +177,25 @@ typedef enum
} \
}
/*
* Get v8 uint from provided argument.
* If it is not a uint, set the error for the given index &
* val is nullified.
*/
#define NJS_GET_ARG_V8UINT( val, err, args, index, exitCode) \
{ \
if( args[index]->IsUint32() ) \
{ \
val = args[index]->ToUint32()->Value(); \
err.clear(); \
} \
else \
{ \
err = NJSMessages::getErrorMsg ( errInvalidParameterType, index+1 ) ; \
goto exitCode ; \
} \
}
/*
* Get the std string value from JSON for the given key.
* index is the argument index in the caller.