Fix memory leaks with ResultSets
This commit is contained in:
parent
5f0cc2f142
commit
fa5068f0e9
|
@ -38,6 +38,10 @@
|
|||
# include <dpiConnImpl.h>
|
||||
#endif
|
||||
|
||||
#ifndef DPIEXCEPTIONIMPL_ORACLE
|
||||
# include <dpiExceptionImpl.h>
|
||||
#endif
|
||||
|
||||
#ifndef DPIDATETIMEARRAYIMPL_ORACLE
|
||||
#include <dpiDateTimeArrayImpl.h>
|
||||
#endif
|
||||
|
@ -478,57 +482,63 @@ unsigned int StmtImpl::rowsFetched () const
|
|||
*/
|
||||
const MetaData* StmtImpl::getMetaData ()
|
||||
{
|
||||
numCols();
|
||||
|
||||
if (!numCols_)
|
||||
return NULL;
|
||||
|
||||
ub4 col = 0;
|
||||
void *colDesc = (OCIParam *) 0;
|
||||
|
||||
meta_ = new MetaData[numCols_];
|
||||
void *colName = NULL;
|
||||
|
||||
while (col < numCols_)
|
||||
if ( !meta_ )
|
||||
{
|
||||
ociCall(OCIParamGet((void *)stmth_, OCI_HTYPE_STMT, errh_,
|
||||
&colDesc, (ub4) (col+1)), errh_ );
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM, &colName,
|
||||
(ub4 *) &(meta_[col].colNameLen),
|
||||
(ub4) OCI_ATTR_NAME,errh_ ), errh_ );
|
||||
meta_[col].colName = (unsigned char *) colName;
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM,
|
||||
(void*) &(meta_[col].dbType),(ub4 *) 0,
|
||||
(ub4) OCI_ATTR_DATA_TYPE,
|
||||
errh_ ), errh_ );
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM,
|
||||
(void*) &(meta_[col].dbSize),(ub4 *) 0,
|
||||
(ub4) OCI_ATTR_DATA_SIZE,
|
||||
errh_ ), errh_ );
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM,
|
||||
(void*) &(meta_[col].isNullable),(ub4*) 0,
|
||||
(ub4) OCI_ATTR_IS_NULL,
|
||||
errh_ ), errh_ );
|
||||
if (meta_[col].dbType == DpiNumber || meta_[col].dbType == DpiBinaryFloat
|
||||
||meta_[col].dbType == DpiBinaryDouble )
|
||||
if ( numCols () )
|
||||
{
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM,
|
||||
(void*) &(meta_[col].precision),(ub4* ) 0,
|
||||
(ub4) OCI_ATTR_PRECISION,
|
||||
errh_ ), errh_ );
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM,
|
||||
(void*) &(meta_[col].scale),(ub4*) 0,
|
||||
(ub4) OCI_ATTR_SCALE,
|
||||
errh_ ), errh_ );
|
||||
}
|
||||
else
|
||||
{ // avoid uninitialized variables
|
||||
meta_[col].precision = 0;
|
||||
meta_[col].scale = 0;
|
||||
}
|
||||
ub4 col = 0;
|
||||
void *colDesc = (OCIParam *) 0;
|
||||
void *colName = NULL;
|
||||
|
||||
OCIDescriptorFree( colDesc, OCI_DTYPE_PARAM);
|
||||
col++;
|
||||
meta_ = new MetaData[numCols_];
|
||||
if ( !meta_ )
|
||||
{
|
||||
throw ExceptionImpl ( DpiErrMemAllocFail ) ;
|
||||
}
|
||||
|
||||
while (col < numCols_)
|
||||
{
|
||||
ociCall(OCIParamGet((void *)stmth_, OCI_HTYPE_STMT, errh_,
|
||||
&colDesc, (ub4) (col+1)), errh_ );
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM, &colName,
|
||||
(ub4 *) &(meta_[col].colNameLen),
|
||||
(ub4) OCI_ATTR_NAME,errh_ ), errh_ );
|
||||
meta_[col].colName = (unsigned char *) colName;
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM,
|
||||
(void*) &(meta_[col].dbType),(ub4 *) 0,
|
||||
(ub4) OCI_ATTR_DATA_TYPE,
|
||||
errh_ ), errh_ );
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM,
|
||||
(void*) &(meta_[col].dbSize),(ub4 *) 0,
|
||||
(ub4) OCI_ATTR_DATA_SIZE,
|
||||
errh_ ), errh_ );
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM,
|
||||
(void*) &(meta_[col].isNullable),(ub4*) 0,
|
||||
(ub4) OCI_ATTR_IS_NULL,
|
||||
errh_ ), errh_ );
|
||||
if (meta_[col].dbType == DpiNumber || meta_[col].dbType == DpiBinaryFloat
|
||||
||meta_[col].dbType == DpiBinaryDouble )
|
||||
{
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM,
|
||||
(void*) &(meta_[col].precision),(ub4* ) 0,
|
||||
(ub4) OCI_ATTR_PRECISION,
|
||||
errh_ ), errh_ );
|
||||
ociCall(OCIAttrGet(colDesc, (ub4) OCI_DTYPE_PARAM,
|
||||
(void*) &(meta_[col].scale),(ub4*) 0,
|
||||
(ub4) OCI_ATTR_SCALE,
|
||||
errh_ ), errh_ );
|
||||
}
|
||||
else
|
||||
{ // avoid uninitialized variables
|
||||
meta_[col].precision = 0;
|
||||
meta_[col].scale = 0;
|
||||
}
|
||||
|
||||
OCIDescriptorFree( colDesc, OCI_DTYPE_PARAM);
|
||||
col++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return meta_;
|
||||
|
|
|
@ -1505,15 +1505,18 @@ void Connection::Async_Execute (uv_work_t *req)
|
|||
}
|
||||
|
||||
executeBaton->dpistmt->execute(0, executeBaton->autoCommit);
|
||||
|
||||
if ( executeBaton->getRS )
|
||||
{
|
||||
goto exitAsyncExecute;
|
||||
}
|
||||
|
||||
const dpi::MetaData* meta = executeBaton->dpistmt->getMetaData();
|
||||
executeBaton->numCols = executeBaton->dpistmt->numCols();
|
||||
executeBaton->columnNames = new std::string[executeBaton->numCols];
|
||||
Connection::CopyMetaData( executeBaton->columnNames, meta,
|
||||
executeBaton->numCols );
|
||||
|
||||
if ( executeBaton->getRS )
|
||||
goto exitAsyncExecute;
|
||||
|
||||
Connection::DoDefines(executeBaton, meta, executeBaton->numCols);
|
||||
/* If any errors while creating define structures, bail out */
|
||||
if ( !executeBaton->error.empty() )
|
||||
|
@ -2300,15 +2303,23 @@ void Connection::DoDefines ( eBaton* executeBaton, const dpi::MetaData* meta,
|
|||
*/
|
||||
void Connection::DoFetch (eBaton* executeBaton)
|
||||
{
|
||||
NJSErrorType errNum = errSuccess;
|
||||
executeBaton->dpistmt->fetch ( executeBaton->maxRows );
|
||||
executeBaton->rowsFetched = executeBaton->dpistmt->rowsFetched();
|
||||
Connection::Descr2Double ( executeBaton->defines,
|
||||
executeBaton->numCols,
|
||||
executeBaton->rowsFetched,
|
||||
executeBaton->getRS );
|
||||
Connection::Descr2protoILob ( executeBaton,
|
||||
executeBaton->numCols,
|
||||
executeBaton->rowsFetched );
|
||||
errNum = Connection::Descr2Double ( executeBaton->defines,
|
||||
executeBaton->numCols,
|
||||
executeBaton->rowsFetched,
|
||||
executeBaton->getRS );
|
||||
if ( !errNum )
|
||||
{
|
||||
Connection::Descr2protoILob ( executeBaton,
|
||||
executeBaton->numCols,
|
||||
executeBaton->rowsFetched );
|
||||
}
|
||||
else
|
||||
{
|
||||
executeBaton->error = NJSMessages::getErrorMsg ( errNum );
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -2322,35 +2333,53 @@ void Connection::DoFetch (eBaton* executeBaton)
|
|||
rowsFetched - rows fetched
|
||||
getRS - boolean set for resultset
|
||||
*/
|
||||
void Connection::Descr2Double( Define* defines, unsigned int numCols,
|
||||
NJSErrorType Connection::Descr2Double( Define* defines, unsigned int numCols,
|
||||
unsigned int rowsFetched, bool getRS )
|
||||
{
|
||||
/* Special processing for certain data types */
|
||||
for (unsigned int col = 0; col < numCols; col ++ )
|
||||
NJSErrorType errNum = errSuccess;
|
||||
|
||||
/* Special processing for certain data types */
|
||||
for (unsigned int col = 0; !errNum && ( col < numCols ); col ++ )
|
||||
{
|
||||
|
||||
/* Special processing for datetime, as it is obtained as descriptors */
|
||||
|
||||
if ( defines[col].dttmarr )
|
||||
{
|
||||
long double *dblArr = NULL;
|
||||
|
||||
defines[col].buf =
|
||||
dblArr = (long double *)malloc ( sizeof ( long double ) *
|
||||
rowsFetched );
|
||||
|
||||
for ( int row = 0; row < (int) rowsFetched; row ++ )
|
||||
if ( !defines[col].buf )
|
||||
{
|
||||
dblArr[row] = defines[col].dttmarr->getDateTime (row);
|
||||
// size_t overflow check not required here as rowsFetched(unsigned int)
|
||||
// multiplied by sizeof(long double) never cause size_t overflow
|
||||
defines[col].buf =
|
||||
dblArr =
|
||||
(long double *)malloc ( sizeof ( long double ) * rowsFetched );
|
||||
|
||||
if( !defines[col].buf )
|
||||
{
|
||||
errNum = errInsufficientMemory;
|
||||
}
|
||||
}
|
||||
defines[col].buf = (void *) dblArr;
|
||||
if ( !getRS )
|
||||
else
|
||||
{
|
||||
defines[col].dttmarr->release ();
|
||||
defines[col].extbuf = NULL;
|
||||
dblArr = (long double *) defines[col].buf;
|
||||
}
|
||||
|
||||
if ( !errNum )
|
||||
{
|
||||
for ( int row = 0; row < (int) rowsFetched; row ++ )
|
||||
{
|
||||
dblArr[row] = defines[col].dttmarr->getDateTime (row);
|
||||
}
|
||||
|
||||
if ( !getRS )
|
||||
{
|
||||
defines[col].dttmarr->release ();
|
||||
defines[col].extbuf = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errNum;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -2511,13 +2540,6 @@ void Connection::Async_AfterExecute(uv_work_t *req)
|
|||
switch(executeBaton->st)
|
||||
{
|
||||
case DpiStmtSelect :
|
||||
rowArray = Connection::GetRows(executeBaton);
|
||||
if(!(executeBaton->error).empty())
|
||||
{
|
||||
argv[0] = v8::Exception::Error(Nan::New<v8::String>((executeBaton->error).c_str()).ToLocalChecked());
|
||||
argv[1] = Nan::Undefined();
|
||||
goto exitAsyncAfterExecute;
|
||||
}
|
||||
if( executeBaton->getRS )
|
||||
{
|
||||
Local<Object> resultSet = Nan::New<FunctionTemplate>(
|
||||
|
@ -2542,6 +2564,13 @@ void Connection::Async_AfterExecute(uv_work_t *req)
|
|||
}
|
||||
else
|
||||
{
|
||||
rowArray = Connection::GetRows(executeBaton);
|
||||
if(!(executeBaton->error).empty())
|
||||
{
|
||||
argv[0] = v8::Exception::Error(Nan::New<v8::String>((executeBaton->error).c_str()).ToLocalChecked());
|
||||
argv[1] = Nan::Undefined();
|
||||
goto exitAsyncAfterExecute;
|
||||
}
|
||||
Nan::Set(result, Nan::New<v8::String>("rows").ToLocalChecked(), rowArray);
|
||||
Nan::Set(result, Nan::New<v8::String>("resultSet").ToLocalChecked(), Nan::Undefined());
|
||||
}
|
||||
|
@ -2595,6 +2624,7 @@ void Connection::Async_AfterExecute(uv_work_t *req)
|
|||
}
|
||||
exitAsyncAfterExecute:
|
||||
Local<Function> callback = Nan::New<Function>(executeBaton->cb);
|
||||
executeBaton->getRS = false; // To cleanup in case of parent SQL execution
|
||||
delete executeBaton;
|
||||
Nan::MakeCallback( Nan::GetCurrentContext()->Global(), callback, 2, argv );
|
||||
if(tc.HasCaught())
|
||||
|
|
|
@ -362,8 +362,8 @@ private:
|
|||
|
||||
static void GetOutBindParams (unsigned short dataType, Bind* bind,
|
||||
eBaton* executeBaton);
|
||||
static void Descr2Double ( Define* defines, unsigned int numCols,
|
||||
unsigned int rowsFetched, bool getRS );
|
||||
static NJSErrorType Descr2Double ( Define* defines, unsigned int numCols,
|
||||
unsigned int rowsFetched, bool getRS );
|
||||
static void Descr2protoILob ( eBaton *executeBaton, unsigned int numCols,
|
||||
unsigned int rowsFetched );
|
||||
static v8::Local<v8::Value> GetOutBinds (eBaton* executeBaton);
|
||||
|
|
|
@ -36,6 +36,7 @@ using namespace std;
|
|||
|
||||
static const char *errMsg[] =
|
||||
{
|
||||
"NJS-000: success", // errSuccess
|
||||
"NJS-001: expected callback as last parameter", // errMissingCallback
|
||||
"NJS-002: invalid pool", // errInvalidPool
|
||||
"NJS-003: invalid connection", // errInvalidConnection
|
||||
|
@ -92,7 +93,7 @@ string NJSMessages::getErrorMsg ( NJSErrorType err, ... )
|
|||
{
|
||||
// print all specified arguments
|
||||
va_start (vlist, err);
|
||||
if ( vsnprintf (msg, MAX_ERROR_MSG_LEN, errMsg[err-1], vlist) <= 0)
|
||||
if ( vsnprintf (msg, MAX_ERROR_MSG_LEN, errMsg[err], vlist) <= 0)
|
||||
{
|
||||
msg[0] = 0;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,8 @@ using namespace std;
|
|||
|
||||
typedef enum
|
||||
{
|
||||
errMissingCallback = 1,
|
||||
errSuccess = 0,
|
||||
errMissingCallback,
|
||||
errInvalidPool,
|
||||
errInvalidConnection,
|
||||
errInvalidPropertyValue,
|
||||
|
|
|
@ -73,22 +73,14 @@ void ResultSet::setResultSet ( dpi::Stmt *stmt, eBaton *executeBaton )
|
|||
this->dpistmt_ = stmt;
|
||||
this->dpienv_ = executeBaton->dpienv;
|
||||
this->njsconn_ = executeBaton->njsconn;
|
||||
if ( stmt )
|
||||
{
|
||||
this->meta_ = stmt->getMetaData();
|
||||
this->numCols_ = this->dpistmt_->numCols();
|
||||
this->state_ = NJS_INACTIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* This could happen in REFCURSOR case, when the stored procedure
|
||||
* did not return a valid handle
|
||||
*/
|
||||
this->numCols_ = 0;
|
||||
this->meta_ = NULL;
|
||||
this->state_ = NJS_INVALID;
|
||||
}
|
||||
this->numCols_ = 0; // numCols_ and meta_ are initialized as part
|
||||
this->meta_ = NULL; // of the first call on RS
|
||||
|
||||
/*
|
||||
* stmt can be NULL in REFCURSOR case, when the stored procedure
|
||||
* did not return a valid stmt handle
|
||||
*/
|
||||
this->state_ = ( stmt ) ? NJS_INACTIVE : NJS_INVALID;
|
||||
|
||||
this->outFormat_ = executeBaton->outFormat;
|
||||
this->fetchRowCount_ = 0;
|
||||
|
@ -228,12 +220,30 @@ NAN_GETTER(ResultSet::GetMetaData)
|
|||
info.GetReturnValue().SetUndefined();
|
||||
return;
|
||||
}
|
||||
if ( !njsResultSet->meta_ )
|
||||
{
|
||||
try
|
||||
{
|
||||
njsResultSet->meta_ = njsResultSet->dpistmt_->getMetaData();
|
||||
njsResultSet->numCols_ = njsResultSet->dpistmt_->numCols();
|
||||
}
|
||||
catch(dpi::Exception &e)
|
||||
{
|
||||
NJS_SET_CONN_ERR_STATUS ( e.errnum(), NULL );
|
||||
NJS_SET_EXCEPTION(e.what(), (int) strlen(e.what()));
|
||||
info.GetReturnValue().SetUndefined();
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::string *columnNames = new std::string[njsResultSet->numCols_];
|
||||
Connection::CopyMetaData ( columnNames, njsResultSet->meta_,
|
||||
njsResultSet->numCols_ );
|
||||
Local<Value> meta;
|
||||
meta = Connection::GetMetaData( columnNames,
|
||||
njsResultSet->numCols_ );
|
||||
delete [] columnNames;
|
||||
columnNames = NULL;
|
||||
|
||||
info.GetReturnValue().Set(meta);
|
||||
}
|
||||
|
||||
|
@ -383,7 +393,6 @@ void ResultSet::GetRowsCommon(rsBaton *getRowsBaton)
|
|||
|
||||
ebaton = getRowsBaton->ebaton;
|
||||
njsRS = getRowsBaton->njsRS;
|
||||
ebaton->columnNames = new std::string[njsRS->numCols_];
|
||||
ebaton->maxRows = getRowsBaton->numRows;
|
||||
ebaton->dpistmt = njsRS->dpistmt_;
|
||||
ebaton->getRS = true;
|
||||
|
@ -458,15 +467,24 @@ void ResultSet::Async_GetRows(uv_work_t *req)
|
|||
|
||||
try
|
||||
{
|
||||
if ( !njsRS->meta_ )
|
||||
{
|
||||
njsRS->meta_ = njsRS->dpistmt_->getMetaData();
|
||||
njsRS->numCols_ = njsRS->dpistmt_->numCols();
|
||||
}
|
||||
ebaton->columnNames = new std::string[njsRS->numCols_];
|
||||
Connection::CopyMetaData ( ebaton->columnNames, njsRS->meta_,
|
||||
njsRS->numCols_ );
|
||||
ebaton->numCols = njsRS->numCols_;
|
||||
|
||||
// Allocate if not already done, or need more buffer
|
||||
if( !njsRS->defineBuffers_ ||
|
||||
njsRS->fetchRowCount_ < getRowsBaton->numRows )
|
||||
{
|
||||
if( njsRS->defineBuffers_ )
|
||||
{
|
||||
ResultSet::clearFetchBuffer(njsRS->defineBuffers_, njsRS->numCols_);
|
||||
ResultSet::clearFetchBuffer(njsRS->defineBuffers_, njsRS->numCols_,
|
||||
njsRS->fetchRowCount_);
|
||||
getRowsBaton-> njsRS-> defineBuffers_ = NULL;
|
||||
}
|
||||
Connection::DoDefines(ebaton, njsRS->meta_, njsRS->numCols_);
|
||||
|
@ -480,8 +498,11 @@ void ResultSet::Async_GetRows(uv_work_t *req)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Buffers are reused except for LOB columns
|
||||
for (unsigned int col = 0; col < njsRS->numCols_; col++)
|
||||
{
|
||||
// In case of LOB column, descriptor would have been wrapped by
|
||||
// ProtoILob & njsIntLob and set the element to NULL, so reallocate
|
||||
switch(njsRS->meta_[col].dbType)
|
||||
{
|
||||
case dpi::DpiClob:
|
||||
|
@ -489,15 +510,26 @@ void ResultSet::Async_GetRows(uv_work_t *req)
|
|||
case dpi::DpiBfile:
|
||||
for (unsigned int j = 0; j < ebaton->maxRows; j++)
|
||||
{
|
||||
((Descriptor **)(njsRS->defineBuffers_[col].buf))[j] =
|
||||
ebaton->dpienv->allocDescriptor(LobDescriptorType);
|
||||
if ( !( ((Descriptor **)(njsRS->defineBuffers_[col].buf))[j] ) )
|
||||
{
|
||||
((Descriptor **)(njsRS->defineBuffers_[col].buf))[j] =
|
||||
ebaton->dpienv->allocDescriptor(LobDescriptorType);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ebaton->defines = njsRS->defineBuffers_;
|
||||
Connection::DoFetch(ebaton);
|
||||
if ( !ebaton->error.empty () )
|
||||
{
|
||||
getRowsBaton->error = ebaton->error;
|
||||
goto exitAsyncGetRows;
|
||||
}
|
||||
|
||||
if(ebaton->rowsFetched != getRowsBaton->numRows)
|
||||
njsRS->rsEmpty_ = true;
|
||||
|
@ -661,7 +693,8 @@ void ResultSet::Async_Close(uv_work_t *req)
|
|||
unsigned int numCols = closeBaton-> njsRS-> numCols_;
|
||||
if(defineBuffers)
|
||||
{
|
||||
ResultSet::clearFetchBuffer(defineBuffers, numCols);
|
||||
ResultSet::clearFetchBuffer(defineBuffers, numCols,
|
||||
closeBaton-> njsRS-> fetchRowCount_);
|
||||
closeBaton-> njsRS-> defineBuffers_ = NULL;
|
||||
}
|
||||
|
||||
|
@ -735,7 +768,8 @@ void ResultSet::Async_AfterClose(uv_work_t *req)
|
|||
defineBuffers - Define bufferes from njsResultSet,
|
||||
numCols - # of columns
|
||||
*/
|
||||
void ResultSet::clearFetchBuffer( Define* defineBuffers, unsigned int numCols)
|
||||
void ResultSet::clearFetchBuffer( Define* defineBuffers, unsigned int numCols,
|
||||
unsigned int numRows )
|
||||
{
|
||||
for( unsigned int i=0; i<numCols; i++ )
|
||||
{
|
||||
|
@ -744,6 +778,20 @@ void ResultSet::clearFetchBuffer( Define* defineBuffers, unsigned int numCols)
|
|||
defineBuffers[i].dttmarr->release ();
|
||||
defineBuffers[i].extbuf = NULL;
|
||||
}
|
||||
else if ( ( defineBuffers[i].fetchType == DpiClob ) ||
|
||||
( defineBuffers[i].fetchType == DpiBlob ) ||
|
||||
( defineBuffers[i].fetchType == DpiBfile ) )
|
||||
{
|
||||
for (unsigned int j = 0; j < numRows; j++)
|
||||
{
|
||||
if (((Descriptor **)(defineBuffers[i].buf))[j])
|
||||
{
|
||||
Env::freeDescriptor(((Descriptor **)(defineBuffers[i].buf))[j],
|
||||
LobDescriptorType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(defineBuffers[i].buf);
|
||||
free(defineBuffers[i].len);
|
||||
free(defineBuffers[i].ind);
|
||||
|
|
|
@ -132,7 +132,7 @@ private:
|
|||
static NAN_SETTER(SetMetaData);
|
||||
|
||||
static void clearFetchBuffer( Define* defineBuffers,
|
||||
unsigned int numCols );
|
||||
unsigned int numCols, unsigned int numRows );
|
||||
|
||||
|
||||
dpi::Stmt *dpistmt_;
|
||||
|
|
Loading…
Reference in New Issue