// *************************************************************************** // Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved. // *************************************************************************** #include "nodever_cover.h" #include "sqlany_utils.h" #include "nan.h" #if !v010 using namespace v8; using namespace node; int getError( a_sqlany_connection *conn, char *str, size_t len ) /**************************************************************/ { int sqlcode; sqlcode = api.sqlany_error( conn, str, len ); return sqlcode; } void getErrorMsg( int code, std::string &str ) /********************************************/ { std::ostringstream message; message << "Code: "; message << code; message << " Msg: "; switch( code ) { case JS_ERR_INVALID_OBJECT: message << "Invalid Object"; break; case JS_ERR_INVALID_ARGUMENTS: message << "Invalid Arguments"; break; case JS_ERR_CONNECTION_ALREADY_EXISTS: message << "Already Connected"; break; case JS_ERR_INITIALIZING_DBCAPI: message << "Can't initialize DBCAPI"; break; case JS_ERR_NOT_CONNECTED: message << "No Connection Available"; break; case JS_ERR_BINDING_PARAMETERS: message << "Can not bind parameter(s)"; break; case JS_ERR_GENERAL_ERROR: message << "An error occurred"; break; case JS_ERR_RESULTSET: message << "Error making result set Object"; break; case JS_ERR_NO_WIDE_STATEMENTS: message << "The DBCAPI library must be upgraded to support wide statements"; break; default: message << "Unknown Error"; } str = message.str(); } void getErrorMsg( a_sqlany_connection *conn, std::string &str ) /*************************************************************/ { char buffer[SACAPI_ERROR_SIZE]; int sqlcode; sqlcode = getError( conn, buffer, sizeof(buffer) ); std::ostringstream message; message << "Code: "; message << sqlcode; message << " Msg: "; message << buffer; str = message.str(); } void throwError( a_sqlany_connection *conn ) /******************************************/ { Isolate *isolate = Isolate::GetCurrent(); std::string message; getErrorMsg( conn, message ); isolate->ThrowException( Exception::Error( String::NewFromUtf8( isolate, message.c_str() ) ) ); } void throwError( int code ) /*************************/ { Isolate *isolate = Isolate::GetCurrent(); std::string message; getErrorMsg( code, message ); isolate->ThrowException( Exception::Error( String::NewFromUtf8( isolate, message.c_str() ) ) ); } void callBack( std::string * str, Persistent & callback, Local & Result, bool callback_required ) /*********************************************************/ { Isolate *isolate = Isolate::GetCurrent(); HandleScope scope( isolate ); Local local_callback = Local::New( isolate, callback ); // If string is NULL, then there is no error if( callback_required ) { if( !local_callback->IsFunction() ) { throwError( JS_ERR_INVALID_ARGUMENTS ); return; } Local Err; if( str == NULL ) { Err = Local::New( isolate, Undefined( isolate ) ); } else { Err = Exception::Error( String::NewFromUtf8( isolate, str->c_str() ) ); } int argc = 2; Local argv[2] = { Err, Result }; #if v012 TryCatch try_catch; #else TryCatch try_catch( isolate ); #endif Nan::Callback *cb = new Nan::Callback( local_callback ); Nan::Call( *cb, argc, argv ); if( try_catch.HasCaught()) { node::FatalException( isolate, try_catch ); } } else { if( str != NULL ) { isolate->ThrowException( Exception::Error( String::NewFromUtf8( isolate, str->c_str() ) ) ); } } } void callBack( std::string * str, Persistent & callback, Persistent & Result, bool callback_required ) /*********************************************************/ { Isolate *isolate = Isolate::GetCurrent(); HandleScope scope( isolate ); Local local_result = Local::New( isolate, Result ); callBack( str, callback, local_result, callback_required ); } void callBack( std::string * str, const Local & arg, Local & Result, bool callback_required ) /*********************************************************/ { Isolate *isolate = Isolate::GetCurrent(); HandleScope scope( isolate ); // If string is NULL, then there is no error if( callback_required ) { if( !arg->IsFunction() ) { throwError( JS_ERR_INVALID_ARGUMENTS ); return; } Local callback = Local::Cast(arg); Local Err; if( str == NULL ) { Err = Local::New( isolate, Undefined( isolate ) ); } else { Err = Exception::Error( String::NewFromUtf8( isolate, str->c_str() ) ); } int argc = 2; Local argv[2] = { Err, Result }; #if v012 TryCatch try_catch; #else TryCatch try_catch( isolate ); #endif Nan::Callback *cb = new Nan::Callback( callback ); Nan::Call( *cb, argc, argv ); if( try_catch.HasCaught()) { node::FatalException( isolate, try_catch ); } } else { if( str != NULL ) { isolate->ThrowException( Exception::Error( String::NewFromUtf8( isolate, str->c_str() ) ) ); } } } static bool getWideBindParameters( std::vector &execData, Isolate * isolate, Local arg, std::vector & params, unsigned &num_rows ) /*********************************************************************************/ { Local context = isolate->GetCurrentContext(); Local rows = Local::Cast( arg ); num_rows = rows->Length(); Local row0 = Local::Cast( rows->Get(0) ); unsigned num_cols = row0->Length(); unsigned c; if( num_cols == 0 ) { // if an empty array was passed in, we still need ExecuteData ExecuteData *ex = new ExecuteData; execData.push_back( ex ); return true; } // Make sure that each array in the list has the same number and types // of values for( unsigned int r = 1; r < num_rows; r++ ) { Local row = Local::Cast( rows->Get(r) ); for( c = 0; c < num_cols; c++ ) { Local val0 = row0->Get(c); Local val = row->Get(c); if( ( val0->IsInt32() || val0->IsNumber() ) && ( !val->IsInt32() && !val->IsNumber() && !val->IsNull() ) ) { return false; } if( val0->IsString() && !val->IsString() && !val->IsNull() ) { return false; } if( Buffer::HasInstance( val0 ) && !Buffer::HasInstance( val ) && !val->IsNull() ) { return false; } } } for( c = 0; c < num_cols; c++ ) { a_sqlany_bind_param param; memset( ¶m, 0, sizeof( param ) ); ExecuteData *ex = new ExecuteData; execData.push_back( ex ); double * param_double = new double[num_rows]; ex->addNum( param_double ); char ** char_arr = new char *[num_rows]; size_t * len = new size_t[num_rows]; ex->addStrings( char_arr, len ); sacapi_bool * is_null = new sacapi_bool[num_rows]; ex->addNull( is_null ); param.value.is_null = is_null; param.value.is_address = false; if( row0->Get(c)->IsInt32() || row0->Get(c)->IsNumber() ) { param.value.type = A_DOUBLE; param.value.buffer = (char *)( param_double ); } else if( row0->Get(c)->IsString() ) { param.value.type = A_STRING; param.value.buffer = (char *)char_arr; param.value.length = len; param.value.is_address = true; } else if( Buffer::HasInstance( row0->Get(c) ) ) { param.value.type = A_BINARY; param.value.buffer = (char *)char_arr; param.value.length = len; param.value.is_address = true; } else if( row0->Get(c)->IsNull() ) { } else{ return false; } for( unsigned int r = 0; r < num_rows; r++ ) { Local bind_params = Local::Cast( rows->Get(r) ); is_null[r] = false; if( bind_params->Get(c)->IsInt32() || bind_params->Get(c)->IsNumber() ) { param_double[r] = bind_params->Get(c)->NumberValue(context).FromJust(); } else if( bind_params->Get(c)->IsString() ) { #if NODE_MAJOR_VERSION >= 12 String::Utf8Value paramValue( isolate, (bind_params->Get(c)->ToString(context)).ToLocalChecked() ); #else String::Utf8Value paramValue( (bind_params->Get(c)->ToString(context)).ToLocalChecked() ); #endif const char* param_string = (*paramValue); len[r] = (size_t)paramValue.length(); char *param_char = new char[len[r] + 1]; char_arr[r] = param_char; memcpy( param_char, param_string, len[r] + 1 ); } else if( Buffer::HasInstance( bind_params->Get(c) ) ) { len[r] = Buffer::Length( bind_params->Get(c) ); char *param_char = new char[len[r]]; char_arr[r] = param_char; memcpy( param_char, Buffer::Data( bind_params->Get(c) ), len[r] ); } else if( bind_params->Get(c)->IsNull() ) { is_null[r] = true; } } params.push_back( param ); } return true; } bool getBindParameters( std::vector &execData, Isolate * isolate, Local arg, std::vector & params, unsigned &num_rows ) /*************************************************************************/ { Local context = isolate->GetCurrentContext(); Local bind_params = Local::Cast( arg ); if( bind_params->Length() == 0 ) { // if an empty array was passed in, we still need ExecuteData ExecuteData *ex = new ExecuteData; execData.push_back( ex ); return true; } if( bind_params->Get(0)->IsArray() ) { return getWideBindParameters( execData, isolate, arg, params, num_rows ); } num_rows = 1; ExecuteData *ex = new ExecuteData; execData.push_back( ex ); for( unsigned int i = 0; i < bind_params->Length(); i++ ) { a_sqlany_bind_param param; memset( ¶m, 0, sizeof( param ) ); if( bind_params->Get(i)->IsInt32() ) { int *param_int = new int; *param_int = bind_params->Get(i)->Int32Value(context).FromJust(); ex->addInt( param_int ); param.value.buffer = (char *)( param_int ); param.value.type = A_VAL32; } else if( bind_params->Get(i)->IsNumber() ) { double *param_double = new double; *param_double = bind_params->Get(i)->NumberValue(context).FromJust(); // Remove Round off Error ex->addNum( param_double ); param.value.buffer = (char *)( param_double ); param.value.type = A_DOUBLE; } else if( bind_params->Get(i)->IsString() ) { #if NODE_MAJOR_VERSION >= 12 String::Utf8Value paramValue( isolate, (bind_params->Get(i)->ToString(context)).ToLocalChecked() ); #else String::Utf8Value paramValue( (bind_params->Get(i)->ToString(context)).ToLocalChecked() ); #endif const char* param_string = (*paramValue); size_t *len = new size_t; *len = (size_t)paramValue.length(); char **char_arr = new char *; char *param_char = new char[*len + 1]; *char_arr = param_char; memcpy( param_char, param_string, ( *len ) + 1 ); ex->addStrings( char_arr, len ); param.value.type = A_STRING; param.value.buffer = param_char; param.value.length = len; param.value.buffer_size = *len + 1; } else if( Buffer::HasInstance( bind_params->Get(i) ) ) { size_t *len = new size_t; *len = Buffer::Length( bind_params->Get(i) ); char **char_arr = new char *; char *param_char = new char[*len]; *char_arr = param_char; memcpy( param_char, Buffer::Data( bind_params->Get(i) ), *len ); ex->addStrings( char_arr, len ); param.value.type = A_BINARY; param.value.buffer = param_char; param.value.length = len; param.value.buffer_size = sizeof( param_char ); } else if( bind_params->Get(i)->IsNull() ) { param.value.type = A_STRING; sacapi_bool *is_null = new sacapi_bool; param.value.is_null = is_null; ex->addNull( is_null ); is_null[0] = true; } else{ return false; } params.push_back( param ); } return true; } bool getResultSet( Persistent & Result, int & rows_affected, std::vector & colNames, ExecuteData * execData, std::vector & col_types ) /*****************************************************************/ { Isolate *isolate = Isolate::GetCurrent(); HandleScope scope( isolate ); int num_rows = 0; size_t num_cols = colNames.size(); if( rows_affected >= 0 ) { Result.Reset( isolate, Integer::New( isolate, rows_affected ) ); return true; } if( num_cols > 0 ) { size_t count = 0; size_t count_int = 0, count_num = 0, count_string = 0; Local ResultSet = Array::New( isolate ); while( count_int < execData->intSize() || count_num < execData->numSize() || count_string < execData->stringSize() ) { Local curr_row = Object::New( isolate ); num_rows++; for( size_t i = 0; i < num_cols; i++ ) { switch( col_types[count] ) { case A_INVALID_TYPE: curr_row->Set( String::NewFromUtf8( isolate, colNames[i] ), Null( isolate ) ); break; case A_VAL32: case A_VAL16: case A_UVAL16: case A_VAL8: case A_UVAL8: if( execData->intIsNull( count_int ) ) { curr_row->Set( String::NewFromUtf8( isolate, colNames[i] ), Null( isolate ) ); } else { curr_row->Set( String::NewFromUtf8( isolate, colNames[i] ), Integer::New( isolate, execData->getInt( count_int ) ) ); } count_int++; break; case A_UVAL32: case A_UVAL64: case A_VAL64: case A_DOUBLE: if( execData->numIsNull( count_num ) ) { curr_row->Set( String::NewFromUtf8( isolate, colNames[i] ), Null( isolate ) ); } else { curr_row->Set( String::NewFromUtf8( isolate, colNames[i] ), Number::New( isolate, execData->getNum( count_num ) ) ); } count_num++; break; case A_BINARY: if( execData->stringIsNull( count_string ) ) { curr_row->Set( String::NewFromUtf8( isolate, colNames[i] ), Null( isolate ) ); } else { #if v012 Local buf = node::Buffer::New( isolate, execData->getString( count_string ), execData->getLen( count_string ) ); curr_row->Set( String::NewFromUtf8( isolate, colNames[i] ), buf ); #else MaybeLocal mbuf = node::Buffer::Copy( isolate, execData->getString( count_string ), execData->getLen( count_string ) ); Local buf = mbuf.ToLocalChecked(); #endif curr_row->Set( String::NewFromUtf8( isolate, colNames[i] ), buf ); } count_string++; break; case A_STRING: if( execData->stringIsNull( count_string ) ) { curr_row->Set( String::NewFromUtf8( isolate, colNames[i] ), Null( isolate ) ); } else { curr_row->Set( String::NewFromUtf8( isolate, colNames[i] ), #if v012 String::NewFromUtf8( isolate, execData->getString( count_string ), String::NewStringType::kNormalString, (int)execData->getLen( count_string ) ) #else String::NewFromUtf8( isolate, execData->getString( count_string ), NewStringType::kNormal, (int)execData->getLen( count_string ) ).ToLocalChecked() #endif ); } count_string++; break; default: return false; } count++; } ResultSet->Set( num_rows - 1, curr_row ); } Result.Reset( isolate, ResultSet ); } else { Result.Reset( isolate, Local::New( isolate, Undefined( isolate ) ) ); } return true; } bool fetchResultSet( a_sqlany_stmt * sqlany_stmt, int & rows_affected, std::vector & colNames, ExecuteData * execData, std::vector & col_types ) /*****************************************************************/ { a_sqlany_data_value value; int num_cols = 0; rows_affected = api.sqlany_affected_rows( sqlany_stmt ); num_cols = api.sqlany_num_cols( sqlany_stmt ); if( rows_affected > 0 && num_cols < 1 ) { return true; } rows_affected = -1; if( num_cols > 0 ) { for( int i = 0; i < num_cols; i++ ) { a_sqlany_column_info info; api.sqlany_get_column_info( sqlany_stmt, i, &info ); size_t size = strlen( info.name ) + 1; char *name = new char[ size ]; memcpy( name, info.name, size ); colNames.push_back( name ); } int count_string = 0, count_num = 0, count_int = 0; while( true ) { if( !api.sqlany_fetch_next( sqlany_stmt ) ) { return false; } for( int i = 0; i < num_cols; i++ ) { if( !api.sqlany_get_column( sqlany_stmt, i, &value ) ) { return false; } if( *(value.is_null) ) { col_types.push_back( A_INVALID_TYPE ); continue; } switch( value.type ) { case A_BINARY: { size_t *size = new size_t; *size = *(value.length); char *val = new char[ *size ]; memcpy( val, value.buffer, *size ); execData->addString( val, size ); count_string++; break; } case A_STRING: { size_t *size = new size_t; *size = (size_t)( (int)*(value.length) ); char *val = new char[ *size ]; memcpy( val, (char *)value.buffer, *size ); execData->addString( val, size ); count_string++; break; } case A_VAL64: { double *val = new double; *val = (double)*(long long *)value.buffer; execData->addNum( val ); count_num++; break; } case A_UVAL64: { double *val = new double; *val = (double)*(unsigned long long *)value.buffer; execData->addNum( val ); count_num++; break; } case A_VAL32: { int *val = new int; *val = *(int*)value.buffer; execData->addInt( val ); count_int++; break; } case A_UVAL32: { double *val = new double; *val = (double)*(unsigned int*)value.buffer; execData->addNum( val ); count_num++; break; } case A_VAL16: { int *val = new int; *val = (int)*(short*)value.buffer; execData->addInt( val ); count_int++; break; } case A_UVAL16: { int *val = new int; *val = (int)*(unsigned short*)value.buffer; execData->addInt( val ); count_int++; break; } case A_VAL8: { int *val = new int; *val = (int)*(char *)value.buffer; execData->addInt( val ); count_int++; break; } case A_UVAL8: { int *val = new int; *val = (int)*(unsigned char *)value.buffer; execData->addInt( val ); count_int++; break; } case A_DOUBLE: { double *val = new double; *val = (double)*(double *)value.buffer; execData->addNum( val ); count_num++; break; } default: return false; } col_types.push_back( value.type ); } } } return true; } bool cleanAPI() /*************/ { if( openConnections == 0 ) { if( api.initialized ) { api.sqlany_fini(); sqlany_finalize_interface( &api ); return true; } } return false; } // Generic Baton and Callback (After) Function // Use this if the function does not have any return values and // Does not take any parameters. // Create custom Baton and Callback (After) functions otherwise void Connection::noParamAfter( uv_work_t *req ) /*********************************************/ { Isolate *isolate = Isolate::GetCurrent(); HandleScope scope(isolate); noParamBaton *baton = static_cast(req->data); Local undef = Local::New( isolate, Undefined( isolate ) ); if( baton->err ) { callBack( &( baton->error_msg ), baton->callback, undef, baton->callback_required ); return; } callBack( NULL, baton->callback, undef, baton->callback_required ); delete baton; delete req; } // Stmt Object Functions StmtObject::StmtObject() /**********************/ { connection = NULL; sqlany_stmt = NULL; } StmtObject::~StmtObject() /***********************/ { uv_mutex_t *mutex = NULL; if( connection != NULL ) { mutex = &connection->conn_mutex; uv_mutex_lock( mutex ); } cleanup(); removeConnection(); if( mutex != NULL ) { uv_mutex_unlock( mutex ); } } Persistent StmtObject::constructor; void StmtObject::Init( Isolate *isolate ) /***************************************/ { HandleScope scope(isolate); // Prepare constructor template Local tpl = FunctionTemplate::New( isolate, New ); tpl->SetClassName( String::NewFromUtf8( isolate, "StmtObject" ) ); tpl->InstanceTemplate()->SetInternalFieldCount( 1 ); // Prototype NODE_SET_PROTOTYPE_METHOD( tpl, "exec", exec ); NODE_SET_PROTOTYPE_METHOD( tpl, "drop", drop ); NODE_SET_PROTOTYPE_METHOD( tpl, "getMoreResults", getMoreResults ); Local context = isolate->GetCurrentContext(); constructor.Reset( isolate, tpl->GetFunction( context ).ToLocalChecked() ); } void StmtObject::New( const FunctionCallbackInfo &args ) /*************************************************************/ { StmtObject* obj = new StmtObject(); obj->Wrap( args.This() ); args.GetReturnValue().Set( args.This() ); } void StmtObject::NewInstance( const FunctionCallbackInfo &args ) /*********************************************************************/ { Persistent obj; CreateNewInstance( args, obj ); args.GetReturnValue().Set( obj ); } void StmtObject::CreateNewInstance( const FunctionCallbackInfo & args, Persistent & obj ) /***************************************************************************/ { Isolate *isolate = args.GetIsolate(); HandleScope scope(isolate); const unsigned argc = 1; Local argv[argc] = { args[0] }; Localcons = Local::New( isolate, constructor ); #if NODE_MAJOR_VERSION >= 10 Local env = isolate->GetCurrentContext(); MaybeLocal mlObj = cons->NewInstance( env, argc, argv ); Local instance = mlObj.ToLocalChecked(); obj.Reset( isolate, instance ); #else obj.Reset( isolate, cons->NewInstance( argc, argv ) ); #endif } void StmtObject::cleanup( void ) /******************************/ { if( sqlany_stmt != NULL ) { api.sqlany_free_stmt( sqlany_stmt ); sqlany_stmt = NULL; } } void StmtObject::removeConnection( void ) /***************************************/ { if( connection != NULL ) { connection->removeStmt( this ); connection = NULL; } } // Connection Functions void HashToString( Isolate *isolate, Local obj, Persistent &ret ) /*************************************************************/ { Local context = isolate->GetCurrentContext(); HandleScope scope(isolate); Local props = (obj->GetOwnPropertyNames(context)).ToLocalChecked(); int length = props->Length(); std::string params = ""; bool first = true; for( int i = 0; i < length; i++ ) { Local key = props->Get(i).As(); Local val = obj->Get(key).As(); #if NODE_MAJOR_VERSION >= 12 String::Utf8Value key_utf8( isolate, key ); String::Utf8Value val_utf8( isolate, val ); #else String::Utf8Value key_utf8( key ); String::Utf8Value val_utf8( val ); #endif if( !first ) { params += ";"; } first = false; params += std::string(*key_utf8); params += "="; params += std::string(*val_utf8); } ret.Reset( isolate, String::NewFromUtf8( isolate, params.c_str() ) ); } #if 0 // Handy function for determining what type an object is. static void CheckArgType( Local &obj ) /*******************************************/ { static const char *type = NULL; if( obj->IsArray() ) { type = "Array"; } else if( obj->IsBoolean() ) { type = "Boolean"; } else if( obj->IsBooleanObject() ) { type = "BooleanObject"; } else if( obj->IsDate() ) { type = "Date"; } else if( obj->IsExternal() ) { type = "External"; } else if( obj->IsFunction() ) { type = "Function"; } else if( obj->IsInt32() ) { type = "Int32"; } else if( obj->IsNativeError() ) { type = "NativeError"; } else if( obj->IsNull() ) { type = "Null"; } else if( obj->IsNumber() ) { type = "Number"; } else if( obj->IsNumberObject() ) { type = "NumberObject"; } else if( obj->IsObject() ) { type = "Object"; } else if( obj->IsRegExp() ) { type = "RegExp"; } else if( obj->IsString() ) { type = "String"; } else if( obj->IsStringObject() ) { type = "StringObject"; } else if( obj->IsUint32() ) { type = "Uint32"; } else if( obj->IsUndefined() ) { type = "Undefined"; } else { type = "Unknown"; } } #endif Connection::Connection( const FunctionCallbackInfo &args ) /***************************************************************/ { Isolate *isolate = args.GetIsolate(); HandleScope scope( isolate ); uv_mutex_init(&conn_mutex); conn = NULL; if( args.Length() > 1 ) { throwError( JS_ERR_INVALID_ARGUMENTS ); return; } if( args.Length() == 1 ) { //CheckArgType( args[0] ); if( args[0]->IsString() ) { Local str = args[0]->ToString(isolate); #if NODE_MAJOR_VERSION >= 12 int string_len = str->Utf8Length(isolate); char *buf = new char[string_len + 1]; str->WriteUtf8(isolate, buf); #else int string_len = str->Utf8Length(); char *buf = new char[string_len+1]; str->WriteUtf8( buf ); #endif _arg.Reset( isolate, String::NewFromUtf8( isolate, buf ) ); delete [] buf; } else if( args[0]->IsObject() ) { HashToString( isolate, args[0]->ToObject(isolate), _arg ); } else if( !args[0]->IsUndefined() && !args[0]->IsNull() ) { throwError( JS_ERR_INVALID_ARGUMENTS ); } else { _arg.Reset( isolate, String::NewFromUtf8( isolate, "" ) ); } } else { _arg.Reset( isolate, String::NewFromUtf8( isolate, "" ) ); } } Connection::~Connection() /***********************/ { scoped_lock api_lock( api_mutex ); scoped_lock lock( conn_mutex ); _arg.Reset(); cleanupStmts(); if( conn != NULL ) { api.sqlany_disconnect( conn ); api.sqlany_free_connection( conn ); conn = NULL; openConnections--; } cleanAPI(); }; void Connection::cleanupStmts( void ) /***********************************/ { std::vector::iterator findit; for( findit = statements.begin(); findit != statements.end(); findit++ ) { StmtObject *s = reinterpret_cast(*findit); s->cleanup(); } } void Connection::removeStmt( class StmtObject *stmt ) /***************************************************/ { // caller must get mutex std::vector::iterator findit; for( findit = statements.begin(); findit != statements.end(); findit++ ) { if( *findit == reinterpret_cast(stmt) ) { statements.erase( findit ); return; } } } Persistent Connection::constructor; void Connection::Init( Isolate *isolate ) /***************************************/ { HandleScope scope( isolate ); // Prepare constructor template Local tpl = FunctionTemplate::New( isolate, New ); tpl->SetClassName( String::NewFromUtf8( isolate, "Connection" ) ); tpl->InstanceTemplate()->SetInternalFieldCount( 1 ); // Prototype NODE_SET_PROTOTYPE_METHOD( tpl, "exec", exec ); NODE_SET_PROTOTYPE_METHOD( tpl, "prepare", prepare ); NODE_SET_PROTOTYPE_METHOD( tpl, "connect", connect ); NODE_SET_PROTOTYPE_METHOD( tpl, "disconnect", disconnect ); NODE_SET_PROTOTYPE_METHOD( tpl, "close", disconnect ); NODE_SET_PROTOTYPE_METHOD( tpl, "commit", commit ); NODE_SET_PROTOTYPE_METHOD( tpl, "rollback", rollback ); NODE_SET_PROTOTYPE_METHOD( tpl, "connected", connected ); Local context = isolate->GetCurrentContext(); constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked()); } void Connection::New( const FunctionCallbackInfo &args ) /*************************************************************/ { Isolate *isolate = args.GetIsolate(); HandleScope scope( isolate ); if( args.IsConstructCall() ) { Connection *obj = new Connection( args ); obj->Wrap( args.This() ); args.GetReturnValue().Set( args.This() ); } else { const int argc = 1; Local argv[argc] = { args[0] }; Local cons = Local::New( isolate, constructor ); #if NODE_MAJOR_VERSION >= 10 Local env = isolate->GetCurrentContext(); MaybeLocal mlObj = cons->NewInstance( env, argc, argv ); const Local obj = mlObj.ToLocalChecked(); args.GetReturnValue().Set( obj ); #else args.GetReturnValue().Set( cons->NewInstance( argc, argv ) ); #endif } } void Connection::NewInstance( const FunctionCallbackInfo &args ) /*********************************************************************/ { Isolate *isolate = args.GetIsolate(); HandleScope scope( isolate ); const unsigned argc = 1; Local argv[argc] = { args[0] }; Local cons = Local::New( isolate, constructor ); #if NODE_MAJOR_VERSION >= 10 Local env = isolate->GetCurrentContext(); MaybeLocal mlObj = cons->NewInstance( env, argc, argv ); Local instance = mlObj.ToLocalChecked(); #else Local instance = cons->NewInstance( argc, argv ); #endif args.GetReturnValue().Set( instance ); } #endif // !v010