void MetadataNode::InjectPrototype(Local<Object>& target, Local<Object>& implementationObject) { auto isolate = Isolate::GetCurrent(); implementationObject->SetAccessor(ConvertToV8String("super"), SuperAccessorGetterCallback, nullptr, implementationObject); implementationObject->SetPrototype(target->GetPrototype()); target->SetPrototype(implementationObject); }
Local<Object> ODBC::GetSQLError (SQLSMALLINT handleType, SQLHANDLE handle, char* message) { HandleScope scope; DEBUG_PRINTF("ODBC::GetSQLError : handleType=%i, handle=%p\n", handleType, handle); Local<Object> objError = Object::New(); SQLINTEGER i = 0; SQLINTEGER native; SQLSMALLINT len; SQLINTEGER numfields; SQLRETURN ret; char errorSQLState[14]; char errorMessage[512]; SQLGetDiagField( handleType, handle, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &len); for (i = 0; i < numfields; i++){ DEBUG_PRINTF("ODBC::GetSQLError : calling SQLGetDiagRec; i=%i, numfields=%i\n", i, numfields); ret = SQLGetDiagRec( handleType, handle, i + 1, (SQLTCHAR *) errorSQLState, &native, (SQLTCHAR *) errorMessage, sizeof(errorMessage), &len); DEBUG_PRINTF("ODBC::GetSQLError : after SQLGetDiagRec; i=%i\n", i); if (SQL_SUCCEEDED(ret)) { DEBUG_PRINTF("ODBC::GetSQLError : errorMessage=%s, errorSQLState=%s\n", errorMessage, errorSQLState); objError->Set(String::New("error"), String::New(message)); #ifdef UNICODE objError->SetPrototype(Exception::Error(String::New((uint16_t *) errorMessage))); objError->Set(String::New("message"), String::New((uint16_t *) errorMessage)); objError->Set(String::New("state"), String::New((uint16_t *) errorSQLState)); #else objError->SetPrototype(Exception::Error(String::New(errorMessage))); objError->Set(String::New("message"), String::New(errorMessage)); objError->Set(String::New("state"), String::New(errorSQLState)); #endif } } return scope.Close(objError); }
void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { SET_PROFILER_FRAME(); auto isolate = info.GetIsolate(); auto thiz = info.This(); auto node = reinterpret_cast<MetadataNode*>(info.Data().As<External>()->Value()); Local<Object> implementationObject; Local<String> v8ExtendName; string extendLocation; bool extendLocationFound = GetExtendLocation(extendLocation); if (info.Length() == 1) { if (!extendLocationFound) { ASSERT_FAIL("Invalid extend() call. No name specified for extend. Location: %s", extendLocation.c_str()); } ASSERT_MESSAGE(info[0]->IsObject(), "Invalid extend() call. No implementation object specified. Location: %s", extendLocation.c_str()); implementationObject = info[0]->ToObject(); } else if (info.Length() == 2) { ASSERT_MESSAGE(info[0]->IsString(), "Invalid extend() call. No name for extend specified. Location: %s", extendLocation.c_str()); ASSERT_MESSAGE(info[1]->IsObject(), "Invalid extend() call. Named extend should be called with second object parameter containing overridden methods. Location: %s", extendLocation.c_str()); DEBUG_WRITE("InterfaceConstructorCallback: getting extend name"); v8ExtendName = info[0]->ToString(); implementationObject = info[1]->ToObject(); } else { ASSERT_FAIL("Invalid extend() call. Location: %s", extendLocation.c_str()); } auto className = node->m_implType; auto extendName = ConvertToString(v8ExtendName); auto extendNameAndLocation = extendLocation + extendName; SetInstanceMetadata(isolate, implementationObject, node); //@@@ Refactor thiz->SetInternalField(static_cast<int>(ObjectManager::MetadataNodeKeys::CallSuper), True(isolate)); string fullClassName = CreateFullClassName(className, extendNameAndLocation); implementationObject->SetPrototype(thiz->GetPrototype()); thiz->SetPrototype(implementationObject); thiz->SetHiddenValue(ConvertToV8String("t::implObj"), implementationObject); ArgsWrapper argWrapper(info, ArgType::Interface, Local<Object>()); auto success = NativeScriptRuntime::RegisterInstance(thiz, fullClassName, argWrapper, implementationObject, true); }
FunctionTemplate::FunctionTemplate() : Template(&gFunctionTemplateClass) { PrivateData* data = cx()->new_<PrivateData>(); JS_SetPrivate(cx(), JSVAL_TO_OBJECT(mVal), data); Handle<ObjectTemplate> protoTemplate = ObjectTemplate::New(); Set("prototype", protoTemplate); // Instance template Local<ObjectTemplate> instanceTemplate = ObjectTemplate::New(); instanceTemplate->SetPrototype(protoTemplate); data->instanceTemplate = instanceTemplate; data->callback = NULL; }
Local<Object> MetadataNode::CreateExtendedJSWrapper(Isolate *isolate, const string& proxyClassName) { Local<Object> extInstance; auto cacheData = GetCachedExtendedClassData(isolate, proxyClassName); if (cacheData.node != nullptr) { extInstance = s_objectManager->GetEmptyObject(isolate); extInstance->SetInternalField(static_cast<int>(ObjectManager::MetadataNodeKeys::CallSuper), True(isolate)); auto extdCtorFunc = Local<Function>::New(isolate, *cacheData.extendedCtorFunction); extInstance->SetPrototype(extdCtorFunc->Get(ConvertToV8String("prototype"))); SetInstanceMetadata(isolate, extInstance, cacheData.node); } return extInstance; }
Local<Object> MetadataNode::CreateJSWrapper(Isolate *isolate) { Local<Object> obj; if (m_isArray) { obj = CreateArrayWrapper(isolate); } else { auto ctorFunc = GetConstructorFunction(isolate); //obj = Object::New(isolate); obj = s_objectManager->GetEmptyObject(isolate); obj->Set(ConvertToV8String("constructor"), ctorFunc); obj->SetPrototype(ctorFunc->Get(ConvertToV8String("prototype"))); SetInstanceMetadata(isolate, obj, this); } return obj; }
void MetadataNode::ExtendCallMethodHandler(const v8::FunctionCallbackInfo<v8::Value>& info) { if (info.IsConstructCall()) { string exMsg("Cannot call 'extend' as constructor"); ExceptionUtil::GetInstance()->ThrowExceptionToJs(exMsg); return; } SET_PROFILER_FRAME(); Local<Object> implementationObject; Local<String> extendName; string extendLocation; auto validArgs = ValidateExtendArguments(info, extendLocation, extendName, implementationObject); if (!validArgs) return; auto node = reinterpret_cast<MetadataNode*>(info.Data().As<External>()->Value()); DEBUG_WRITE("ExtendsCallMethodHandler: called with %s", ConvertToString(extendName).c_str()); string extendNameAndLocation = extendLocation + ConvertToString(extendName); auto fullClassName = TNS_PREFIX + CreateFullClassName(node->m_name, extendNameAndLocation); // //resolve class (pre-generated or generated runtime from dex generator) jclass resolvedClass = NativeScriptRuntime::ResolveClass(fullClassName, implementationObject); //resolve class returns GlobalRef std::string generatedFullClassName = s_objectManager->GetClassName(resolvedClass); // auto fullExtendedName = generatedFullClassName; DEBUG_WRITE("ExtendsCallMethodHandler: extend full name %s", fullClassName.c_str()); auto isolate = info.GetIsolate(); auto cachedData = GetCachedExtendedClassData(isolate, fullExtendedName); if (cachedData.extendedCtorFunction != nullptr) { auto cachedExtendedCtorFunc = Local<Function>::New(isolate, *cachedData.extendedCtorFunction); info.GetReturnValue().Set(cachedExtendedCtorFunc); return; } auto implementationObjectPropertyName = V8StringConstants::GetClassImplementationObject(); //reuse validation - checks that implementationObject is not reused for different classes auto implementationObjectProperty = implementationObject->GetHiddenValue(implementationObjectPropertyName).As<String>(); if (implementationObjectProperty.IsEmpty()) { //mark the implementationObject as such and set a pointer to it's class node inside it for reuse validation later implementationObject->SetHiddenValue(implementationObjectPropertyName, String::NewFromUtf8(isolate, fullExtendedName.c_str())); } else { string usedClassName = ConvertToString(implementationObjectProperty); stringstream s; s << "This object is used to extend another class '" << usedClassName << "'"; ExceptionUtil::GetInstance()->ThrowExceptionToJs(s.str()); return; } auto baseClassCtorFunc = node->GetConstructorFunction(isolate); auto extendData = External::New(isolate, new ExtendedClassData(node, extendNameAndLocation, implementationObject, fullExtendedName)); auto extendFuncTemplate = FunctionTemplate::New(isolate, ExtendedClassConstructorCallback, extendData); extendFuncTemplate->InstanceTemplate()->SetInternalFieldCount(static_cast<int>(ObjectManager::MetadataNodeKeys::END)); auto extendFunc = extendFuncTemplate->GetFunction(); auto prototypeName = ConvertToV8String("prototype"); implementationObject->SetPrototype(baseClassCtorFunc->Get(prototypeName)); implementationObject->SetAccessor(ConvertToV8String("super"), SuperAccessorGetterCallback, nullptr, implementationObject); auto extendFuncPrototype = extendFunc->Get(prototypeName).As<Object>(); auto p = extendFuncPrototype->GetPrototype(); extendFuncPrototype->SetPrototype(implementationObject); extendFunc->SetPrototype(baseClassCtorFunc); SetClassAccessor(extendFunc); SetTypeMetadata(isolate, extendFunc, new TypeMetadata(fullExtendedName)); info.GetReturnValue().Set(extendFunc); s_name2NodeCache.insert(make_pair(fullExtendedName, node)); ExtendedClassCacheData cacheData(extendFunc, fullExtendedName, node); s_extendedCtorFuncCache.insert(make_pair(fullExtendedName, cacheData)); }
Handle<Value> ODBC::GetColumnValue( SQLHSTMT hStmt, Column column, uint16_t* buffer, int bufferLength) { HandleScope scope; SQLLEN len = 0; //reset the buffer buffer[0] = '\0'; //TODO: SQLGetData can supposedly return multiple chunks, need to do this to //retrieve large fields int ret; switch ((int) column.type) { case SQL_INTEGER : case SQL_SMALLINT : case SQL_TINYINT : { long value; ret = SQLGetData( hStmt, column.index, SQL_C_SLONG, &value, sizeof(value), &len); DEBUG_PRINTF("ODBC::GetColumnValue - Integer: index=%i name=%s type=%i len=%i ret=%i\n", column.index, column.name, column.type, len, ret); if (len == SQL_NULL_DATA) { return scope.Close(Null()); //return Null(); } else { return scope.Close(Integer::New(value)); //return Integer::New(value); } } break; case SQL_NUMERIC : case SQL_DECIMAL : case SQL_BIGINT : case SQL_FLOAT : case SQL_REAL : case SQL_DOUBLE : { double value; ret = SQLGetData( hStmt, column.index, SQL_C_DOUBLE, &value, sizeof(value), &len); DEBUG_PRINTF("ODBC::GetColumnValue - Number: index=%i name=%s type=%i len=%i ret=%i val=%f\n", column.index, column.name, column.type, len, ret, value); if(len == SQL_NULL_DATA) { return scope.Close(Null()); //return Null(); } else { return scope.Close(Number::New(value)); //return Number::New(value); } } break; case SQL_DATETIME : case SQL_TIMESTAMP : { //I am not sure if this is locale-safe or cross database safe, but it //works for me on MSSQL #ifdef _WIN32 struct tm timeInfo = {}; ret = SQLGetData( hStmt, column.index, SQL_C_CHAR, (char *) buffer, bufferLength, &len); DEBUG_PRINTF("ODBC::GetColumnValue - W32 Timestamp: index=%i name=%s type=%i len=%i\n", column.index, column.name, column.type, len); if(len == SQL_NULL_DATA) { return scope.Close(Null()); //return Null(); } else { strptime((char *) buffer, "%Y-%m-%d %H:%M:%S", &timeInfo); //a negative value means that mktime() should use timezone information //and system databases to attempt to determine whether DST is in effect //at the specified time. timeInfo.tm_isdst = -1; //return Date::New((double(mktime(&timeInfo)) * 1000)); return scope.Close(Date::New((double(mktime(&timeInfo)) * 1000))); } #else struct tm timeInfo = { tm_sec : 0 , tm_min : 0 , tm_hour : 0 , tm_mday : 0 , tm_mon : 0 , tm_year : 0 , tm_wday : 0 , tm_yday : 0 , tm_isdst : 0 , tm_gmtoff : 0 , tm_zone : 0 }; SQL_TIMESTAMP_STRUCT odbcTime; ret = SQLGetData( hStmt, column.index, SQL_C_TYPE_TIMESTAMP, &odbcTime, bufferLength, &len); DEBUG_PRINTF("ODBC::GetColumnValue - Unix Timestamp: index=%i name=%s type=%i len=%i\n", column.index, column.name, column.type, len); if(len == SQL_NULL_DATA) { return scope.Close(Null()); //return Null(); } else { timeInfo.tm_year = odbcTime.year - 1900; timeInfo.tm_mon = odbcTime.month - 1; timeInfo.tm_mday = odbcTime.day; timeInfo.tm_hour = odbcTime.hour; timeInfo.tm_min = odbcTime.minute; timeInfo.tm_sec = odbcTime.second; //a negative value means that mktime() should use timezone information //and system databases to attempt to determine whether DST is in effect //at the specified time. timeInfo.tm_isdst = -1; return scope.Close(Date::New((double(timegm(&timeInfo)) * 1000) + (odbcTime.fraction / 1000000))); //return Date::New((double(timegm(&timeInfo)) * 1000) // + (odbcTime.fraction / 1000000)); } #endif } break; case SQL_BIT : //again, i'm not sure if this is cross database safe, but it works for //MSSQL ret = SQLGetData( hStmt, column.index, SQL_C_CHAR, (char *) buffer, bufferLength, &len); DEBUG_PRINTF("ODBC::GetColumnValue - Bit: index=%i name=%s type=%i len=%i\n", column.index, column.name, column.type, len); if(len == SQL_NULL_DATA) { return scope.Close(Null()); //return Null(); } else { return scope.Close(Boolean::New(( *buffer == '0') ? false : true )); //return Boolean::New(( *buffer == '0') ? false : true ); } default : Local<String> str; int count = 0; do { ret = SQLGetData( hStmt, column.index, SQL_C_TCHAR, (char *) buffer, bufferLength, &len); DEBUG_PRINTF("ODBC::GetColumnValue - String: index=%i name=%s type=%i len=%i value=%s ret=%i bufferLength=%i\n", column.index, column.name, column.type, len,(char *) buffer, ret, bufferLength); if(len == SQL_NULL_DATA) { return scope.Close(Null()); //return Null(); } if (SQL_NO_DATA == ret) { //we have captured all of the data break; } else if (SQL_SUCCEEDED(ret)) { //we have not captured all of the data yet if (count == 0) { //no concatenation required, this is our first pass #ifdef UNICODE str = String::New((uint16_t*) buffer); #else str = String::New((char *) buffer); #endif } else { //we need to concatenate #ifdef UNICODE str = String::Concat(str, String::New((uint16_t*) buffer)); #else str = String::Concat(str, String::New((char *) buffer)); #endif } count += 1; } else { //an error has occured char *errorMessage = "ODBC::GetColumnValue - String: - ERROR"; DEBUG_PRINTF("%s\n", errorMessage); Local<Object> objError = Object::New(); objError->SetPrototype(Exception::Error(String::New(errorMessage))); objError->Set(String::New("message"), String::New(errorMessage)); objError->Set(String::New("state"), String::New("F****D UP")); return ThrowException(scope.Close(objError)); // ThrowException(ODBC::GetSQLError( // SQL_HANDLE_STMT, // hStmt, // (char *) "[node-odbc] Error in ODBC::GetColumnValue" // )); break; } } while (true); return scope.Close(str); //return str; } }
void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { try { SET_PROFILER_FRAME(); auto isolate = info.GetIsolate(); auto thiz = info.This(); auto node = reinterpret_cast<MetadataNode*>(info.Data().As<External>()->Value()); Local<Object> implementationObject; Local<String> v8ExtendName; string extendLocation; bool extendLocationFound = GetExtendLocation(extendLocation); if (info.Length() == 1) { if (!extendLocationFound) { stringstream ss; ss << "(InternalError): Invalid extend() call. No name specified for extend. Location: " << extendLocation.c_str(); throw NativeScriptException(ss.str()); } if (!info[0]->IsObject()) { throw NativeScriptException(string("First argument must be implementation object")); } implementationObject = info[0]->ToObject(); } else if (info.Length() == 2) { if (!info[0]->IsString()) { throw NativeScriptException(string("First argument must be string")); } if (!info[1]->IsObject()) { throw NativeScriptException(string("Second argument must be implementation object")); } DEBUG_WRITE("InterfaceConstructorCallback: getting extend name"); v8ExtendName = info[0]->ToString(); implementationObject = info[1]->ToObject(); } else { throw NativeScriptException(string("Invalid number of arguments")); } auto className = node->m_implType; auto extendName = ConvertToString(v8ExtendName); auto extendNameAndLocation = extendLocation + extendName; SetInstanceMetadata(isolate, implementationObject, node); //@@@ Refactor thiz->SetInternalField(static_cast<int>(ObjectManager::MetadataNodeKeys::CallSuper), True(isolate)); string fullClassName = CreateFullClassName(className, extendNameAndLocation); implementationObject->SetPrototype(thiz->GetPrototype()); thiz->SetPrototype(implementationObject); thiz->SetHiddenValue(ConvertToV8String("t::implObj"), implementationObject); ArgsWrapper argWrapper(info, ArgType::Interface, Local<Object>()); auto success = NativeScriptRuntime::RegisterInstance(thiz, fullClassName, argWrapper, implementationObject, true); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { stringstream ss; ss << "Error: c++ exception: " << e.what() << endl; NativeScriptException nsEx(ss.str()); nsEx.ReThrowToV8(); } catch (...) { NativeScriptException nsEx(std::string("Error: c++ exception!")); nsEx.ReThrowToV8(); } }
Local<Object> ODBC::GetSQLError (SQLSMALLINT handleType, SQLHANDLE handle, char* message) { Nan::EscapableHandleScope scope; DEBUG_PRINTF("ODBC::GetSQLError : handleType=%i, handle=%p\n", handleType, handle); Local<Object> objError = Nan::New<Object>(); SQLINTEGER i = 0; SQLINTEGER native; SQLSMALLINT len; SQLINTEGER statusRecCount; SQLRETURN ret; char errorSQLState[14]; char errorMessage[ERROR_MESSAGE_BUFFER_BYTES]; ret = SQLGetDiagField( handleType, handle, 0, SQL_DIAG_NUMBER, &statusRecCount, SQL_IS_INTEGER, &len); // Windows seems to define SQLINTEGER as long int, unixodbc as just int... %i should cover both DEBUG_PRINTF("ODBC::GetSQLError : called SQLGetDiagField; ret=%i, statusRecCount=%i\n", ret, statusRecCount); Local<Array> errors = Nan::New<Array>(); objError->Set(Nan::New("errors").ToLocalChecked(), errors); for (i = 0; i < statusRecCount; i++) { DEBUG_PRINTF("ODBC::GetSQLError : calling SQLGetDiagRec; i=%i, statusRecCount=%i\n", i, statusRecCount); ret = SQLGetDiagRec( handleType, handle, (SQLSMALLINT)(i + 1), (SQLTCHAR *) errorSQLState, &native, (SQLTCHAR *) errorMessage, ERROR_MESSAGE_BUFFER_CHARS, &len); DEBUG_PRINTF("ODBC::GetSQLError : after SQLGetDiagRec; i=%i\n", i); if (SQL_SUCCEEDED(ret)) { DEBUG_PRINTF("ODBC::GetSQLError : errorMessage=%s, errorSQLState=%s\n", errorMessage, errorSQLState); if (i == 0) { // First error is assumed the primary error objError->Set(Nan::New("error").ToLocalChecked(), Nan::New(message).ToLocalChecked()); #ifdef UNICODE objError->SetPrototype(Exception::Error(Nan::New((uint16_t *)errorMessage).ToLocalChecked())); objError->Set(Nan::New("message").ToLocalChecked(), Nan::New((uint16_t *)errorMessage).ToLocalChecked()); objError->Set(Nan::New("state").ToLocalChecked(), Nan::New((uint16_t *)errorSQLState).ToLocalChecked()); #else objError->SetPrototype(Exception::Error(Nan::New(errorMessage).ToLocalChecked())); objError->Set(Nan::New("message").ToLocalChecked(), Nan::New(errorMessage).ToLocalChecked()); objError->Set(Nan::New("state").ToLocalChecked(), Nan::New(errorSQLState).ToLocalChecked()); #endif } Local<Object> subError = Nan::New<Object>(); #ifdef UNICODE subError->Set(Nan::New("message").ToLocalChecked(), Nan::New((uint16_t *)errorMessage).ToLocalChecked()); subError->Set(Nan::New("state").ToLocalChecked(), Nan::New((uint16_t *)errorSQLState).ToLocalChecked()); #else subError->Set(Nan::New("message").ToLocalChecked(), Nan::New(errorMessage).ToLocalChecked()); subError->Set(Nan::New("state").ToLocalChecked(), Nan::New(errorSQLState).ToLocalChecked()); #endif errors->Set(Nan::New(i), subError); } else if (ret == SQL_NO_DATA) { break; } } if (statusRecCount == 0) { //Create a default error object if there were no diag records objError->Set(Nan::New("error").ToLocalChecked(), Nan::New(message).ToLocalChecked()); objError->SetPrototype(Exception::Error(Nan::New(message).ToLocalChecked())); objError->Set(Nan::New("message").ToLocalChecked(), Nan::New( (const char *) "[node-odbc] An error occurred but no diagnostic information was available.").ToLocalChecked()); } return scope.Escape(objError); }
Local<Object> ODBC::GetSQLError (SQLSMALLINT handleType, SQLHANDLE handle, char* message) { HandleScope scope; DEBUG_PRINTF("ODBC::GetSQLError : handleType=%i, handle=%p\n", handleType, handle); Local<Object> objError = Object::New(); Local<String> str = String::New(""); SQLINTEGER i = 0; SQLINTEGER native; SQLSMALLINT len; SQLINTEGER statusRecCount; SQLRETURN ret; char errorSQLState[14]; char errorMessage[ERROR_MESSAGE_BUFFER_BYTES]; ret = SQLGetDiagField( handleType, handle, 0, SQL_DIAG_NUMBER, &statusRecCount, SQL_IS_INTEGER, &len); // Windows seems to define SQLINTEGER as long int, unixodbc as just int... %i should cover both DEBUG_PRINTF("ODBC::GetSQLError : called SQLGetDiagField; ret=%i, statusRecCount=%i\n", ret, statusRecCount); for (i = 0; i < statusRecCount; i++){ DEBUG_PRINTF("ODBC::GetSQLError : calling SQLGetDiagRec; i=%i, statusRecCount=%i\n", i, statusRecCount); ret = SQLGetDiagRec( handleType, handle, i + 1, (SQLTCHAR *) errorSQLState, &native, (SQLTCHAR *) errorMessage, ERROR_MESSAGE_BUFFER_CHARS, &len); DEBUG_PRINTF("ODBC::GetSQLError : after SQLGetDiagRec; i=%i\n", i); if (SQL_SUCCEEDED(ret)) { DEBUG_PRINTF("ODBC::GetSQLError : errorMessage=%s, errorSQLState=%s\n", errorMessage, errorSQLState); objError->Set(String::New("error"), String::New(message)); #ifdef UNICODE str = String::Concat(str, String::New((uint16_t *) errorMessage)); objError->SetPrototype(Exception::Error(String::New((uint16_t *) errorMessage))); objError->Set(String::New("message"), str); objError->Set(String::New("state"), String::New((uint16_t *) errorSQLState)); #else str = String::Concat(str, String::New(errorMessage)); objError->SetPrototype(Exception::Error(String::New(errorMessage))); objError->Set(String::New("message"), str); objError->Set(String::New("state"), String::New(errorSQLState)); #endif } else if (ret == SQL_NO_DATA) { break; } } if (statusRecCount == 0) { //Create a default error object if there were no diag records objError->Set(String::New("error"), String::New(message)); objError->SetPrototype(Exception::Error(String::New(message))); objError->Set(String::New("message"), String::New( (const char *) "[node-odbc] An error occurred but no diagnostic information was available.")); } return scope.Close(objError); }
Local<Object> ODBC::GetSQLError (SQLSMALLINT handleType, SQLHANDLE handle, char* message) { HandleScope scope; DEBUG_PRINTF("ODBC::GetSQLError : handleType=%i, handle=%p\n", handleType, handle); Local<Object> objError = Object::New(); SQLINTEGER i = 0; SQLINTEGER native; SQLSMALLINT len; SQLINTEGER numfields; SQLRETURN ret; char errorSQLState[14]; char errorMessage[ERROR_MESSAGE_BUFFER_BYTES]; ret = SQLGetDiagField( handleType, handle, 0, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &len); // Windows seems to define SQLINTEGER as long int, unixodbc as just int... %i should cover both DEBUG_PRINTF("ODBC::GetSQLError : called SQLGetDiagField; ret=%i\n", ret); for (i = 0; i < numfields; i++){ DEBUG_PRINTF("ODBC::GetSQLError : calling SQLGetDiagRec; i=%i, numfields=%i\n", i, numfields); ret = SQLGetDiagRec( handleType, handle, i + 1, (SQLTCHAR *) errorSQLState, &native, (SQLTCHAR *) errorMessage, ERROR_MESSAGE_BUFFER_CHARS, &len); DEBUG_PRINTF("ODBC::GetSQLError : after SQLGetDiagRec; i=%i\n", i); if (SQL_SUCCEEDED(ret)) { DEBUG_TPRINTF(SQL_T("ODBC::GetSQLError : errorMessage=%s, errorSQLState=%s\n"), errorMessage, errorSQLState); objError->Set(String::New("error"), String::New(message)); #ifdef UNICODE objError->SetPrototype(Exception::Error(String::New((uint16_t *) errorMessage))); objError->Set(String::New("message"), String::New((uint16_t *) errorMessage)); objError->Set(String::New("state"), String::New((uint16_t *) errorSQLState)); #else objError->SetPrototype(Exception::Error(String::New(errorMessage))); objError->Set(String::New("message"), String::New(errorMessage)); objError->Set(String::New("state"), String::New(errorSQLState)); #endif } else if (ret == SQL_NO_DATA) { break; } } return scope.Close(objError); }