Add new attributes for Oracle error number and offset for Oracle client errors

This commit is contained in:
Christopher Jones 2018-02-06 13:28:16 +11:00
parent 9f1a74b014
commit dca2b038c5
7 changed files with 66 additions and 26 deletions

View File

@ -21,6 +21,9 @@ limitations under the License.
- 1.1 [Getting Started with Node-oracledb](#getstarted)
2. [Errors](#errorobj)
- 2.1 [Error Properties](#properror)
- 2.1.1 [`errorNum`](#properrerrornum)
- 2.1.2 [`message`](#properrmessage)
- 2.1.3 [`offset`](#properroffset)
3. [Oracledb Class](#oracledbclass)
- 3.1 [Oracledb Constants](#oracledbconstants)
- 3.1.1 [Query `outFormat` Constants](#oracledbconstantsoutformat)
@ -316,7 +319,18 @@ ignored.
### <a name="properror"></a> 2.1 Error Properties
The *Error* object contains a message property.
The *Error* object contains `errorNum`, `message` and `offset` properties.
#### <a name="properrerrornum"></a> 2.1.1 `errorNum`
```
Number errorNum
```
The Oracle error number. If the error is not from Oracle, this value
is undefined.
#### <a name="properrmessage"></a> 2.1.2 `message`
```
String message
@ -343,6 +357,15 @@ ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
```
#### <a name="properroffset"></a> 2.1.3 `offset`
```
Number offset
```
The character offset into the SQL text that resulted in the Oracle
error. The value may be `0` in non-SQL contexts. If the error is not
from Oracle, this value is undefined.
## <a name="oracledbclass"></a> 3. Oracledb Class

View File

@ -300,6 +300,7 @@ void njsBaton::AsyncAfterWorkCallback(uv_work_t *req, int status)
Nan::TryCatch tc;
Local<Value> *callbackArgs = new Local<Value>[baton->numCallbackArgs];
unsigned int i, numCallbackArgs = baton->numCallbackArgs;
Local<Object> errorObj;
// set all parameters but the first as undefined; the first parameter is
// always expected to be the error and should be null
@ -316,6 +317,14 @@ void njsBaton::AsyncAfterWorkCallback(uv_work_t *req, int status)
if (!baton->error.empty()) {
callbackArgs[0] = v8::Exception::Error(Nan::New<v8::String>(
baton->error).ToLocalChecked());
if (baton->dpiError) {
errorObj = callbackArgs[0]->ToObject();
Nan::Set(errorObj,
Nan::New<v8::String>("errorNum").ToLocalChecked(),
Nan::New<v8::Number>(baton->errorInfo.code));
Nan::Set(errorObj, Nan::New<v8::String>("offset").ToLocalChecked(),
Nan::New<v8::Number>(baton->errorInfo.offset));
}
for (i = 1; i < numCallbackArgs; i++)
callbackArgs[i] = Nan::Undefined();
}
@ -350,7 +359,13 @@ void njsBaton::AsyncAfterWorkCallback(uv_work_t *req, int status)
//-----------------------------------------------------------------------------
void njsBaton::GetDPIError(void)
{
error = njsOracledb::GetDPIError();
dpiContext_getError(njsOracledb::GetDPIContext(), &errorInfo);
if (errorInfo.code == 1406)
error = njsMessages::Get(errInsufficientBufferForBinds);
else {
error = std::string(errorInfo.message, errorInfo.messageLength);
dpiError = true;
}
ClearAsyncData();
}

View File

@ -288,6 +288,8 @@ public:
char *bufferPtr;
uint64_t lobOffset;
uint64_t lobAmount;
dpiErrorInfo errorInfo;
bool dpiError;
njsCommon *callingObj;
Nan::Persistent<Object> jsCallingObj;
Nan::Persistent<Object> jsOracledb;
@ -306,7 +308,7 @@ public:
fetchAsBufferTypes(NULL), protoILob(NULL), externalAuth(false),
getRS(false), autoCommit(false), extendedMetaData(false),
isReturning(false), isPLSQL(false), bufferSize(0), bufferPtr(NULL),
lobOffset(0), lobAmount(0) {
lobOffset(0), lobAmount(0), dpiError(false) {
this->jsCallback.Reset(callback);
this->jsCallingObj.Reset(callingObj);
this->callingObj = Nan::ObjectWrap::Unwrap<njsCommon>(callingObj);

View File

@ -1290,10 +1290,8 @@ void njsConnection::SetTextAttribute(Nan::NAN_SETTER_ARGS_TYPE args,
return;
}
v8::String::Utf8Value utfstr(value->ToString());
if ((*setter)(connection->dpiConnHandle, *utfstr, utfstr.length()) < 0) {
std::string errMsg = njsOracledb::GetDPIError();
Nan::ThrowError(errMsg.c_str());
}
if ((*setter)(connection->dpiConnHandle, *utfstr, utfstr.length()) < 0)
njsOracledb::ThrowDPIError();
}
@ -1705,8 +1703,7 @@ NAN_GETTER(njsConnection::GetStmtCacheSize)
}
uint32_t cacheSize;
if (dpiConn_getStmtCacheSize(connection->dpiConnHandle, &cacheSize) < 0) {
std::string errMsg = njsOracledb::GetDPIError();
Nan::ThrowError(errMsg.c_str());
njsOracledb::ThrowDPIError();
return;
}
info.GetReturnValue().Set(cacheSize);
@ -1804,8 +1801,7 @@ NAN_GETTER(njsConnection::GetOracleServerVersion)
const char *releaseString;
if (dpiConn_getServerVersion(connection->dpiConnHandle, &releaseString,
&releaseStringLength, &versionInfo) < 0) {
std::string errMsg = njsOracledb::GetDPIError();
Nan::ThrowError(errMsg.c_str());
njsOracledb::ThrowDPIError();
return;
}
uint32_t oracleServerVersion =

View File

@ -208,8 +208,7 @@ NAN_METHOD(njsOracledb::New)
dpiVersionInfo versionInfo;
if (dpiContext_getClientVersion(globalDPIContext, &versionInfo) < 0) {
std::string errMsg = GetDPIError();
Nan::ThrowError(errMsg.c_str());
ThrowDPIError();
return;
}
njsOracledb *oracledb = new njsOracledb();
@ -762,8 +761,7 @@ NAN_GETTER(njsOracledb::GetOracleClientVersion)
return;
if (dpiContext_getClientVersion(globalDPIContext, &versionInfo) < 0) {
std::string errMsg = GetDPIError();
Nan::ThrowError(errMsg.c_str());
ThrowDPIError();
return;
}
@ -1012,17 +1010,25 @@ void njsOracledb::SetFetchAsBufferTypesOnBaton(njsBaton *baton) const
//-----------------------------------------------------------------------------
// njsOracledb::GetDPIError()
// Gets the error information from DPI and returns it.
// njsOracledb::ThrowDPIError()
// Gets the error information from ODPI-C and throws an exception.
//-----------------------------------------------------------------------------
std::string njsOracledb::GetDPIError(void)
void njsOracledb::ThrowDPIError(void)
{
dpiErrorInfo errorInfo;
Local<Value> exception;
Local<Object> errorObj;
std::string errMsg;
dpiContext_getError(globalDPIContext, &errorInfo);
if (errorInfo.code == 1406)
return njsMessages::Get(errInsufficientBufferForBinds);
return std::string(errorInfo.message, errorInfo.messageLength);
errMsg = std::string(errorInfo.message, errorInfo.messageLength);
exception = Nan::Error(errMsg.c_str());
errorObj = exception->ToObject();
Nan::Set(errorObj, Nan::New<v8::String>("errorNum").ToLocalChecked(),
Nan::New<v8::Number>(errorInfo.code));
Nan::Set(errorObj, Nan::New<v8::String>("offset").ToLocalChecked(),
Nan::New<v8::Number>(errorInfo.offset));
Nan::ThrowError(exception);
}

View File

@ -124,8 +124,8 @@ public:
njsErrorType GetInvalidErrorType() const { return errSuccess; }
void SetFetchAsStringTypesOnBaton(njsBaton *baton) const;
void SetFetchAsBufferTypesOnBaton(njsBaton *baton) const;
static std::string GetDPIError(void);
static dpiContext *GetDPIContext() { return globalDPIContext; }
static void ThrowDPIError(void);
private:

View File

@ -216,8 +216,7 @@ NAN_GETTER(njsPool::GetConnectionsOpen)
}
uint32_t value;
if (dpiPool_getOpenCount(pool->dpiPoolHandle, &value) < 0) {
std::string errMsg = njsOracledb::GetDPIError();
Nan::ThrowError(errMsg.c_str());
njsOracledb::ThrowDPIError();
return;
}
info.GetReturnValue().Set(value);
@ -239,8 +238,7 @@ NAN_GETTER(njsPool::GetConnectionsInUse)
}
uint32_t value;
if (dpiPool_getBusyCount(pool->dpiPoolHandle, &value) < 0) {
std::string errMsg = njsOracledb::GetDPIError();
Nan::ThrowError(errMsg.c_str());
njsOracledb::ThrowDPIError();
return;
}
info.GetReturnValue().Set(value);