diff --git a/doc/src/release_notes.rst b/doc/src/release_notes.rst index 37989ec6..d9cad3a5 100644 --- a/doc/src/release_notes.rst +++ b/doc/src/release_notes.rst @@ -13,9 +13,9 @@ node-oracledb `v6.6.0 0; } } diff --git a/lib/thin/protocol/messages/withData.js b/lib/thin/protocol/messages/withData.js index 91fd7710..5dfa0f64 100644 --- a/lib/thin/protocol/messages/withData.js +++ b/lib/thin/protocol/messages/withData.js @@ -502,12 +502,20 @@ class MessageWithData extends Message { } } else if (oraTypeNum === constants.TNS_DATA_TYPE_BOOLEAN) { colValue = buf.readBool(); - } else if (oraTypeNum === constants.TNS_DATA_TYPE_CLOB || oraTypeNum === constants.TNS_DATA_TYPE_BLOB) { + } else if ( + oraTypeNum === constants.TNS_DATA_TYPE_CLOB || + oraTypeNum === constants.TNS_DATA_TYPE_BLOB || + oraTypeNum === constants.TNS_DATA_TYPE_BFILE + ) { + let length = 0; + let chunkSize = 0; const bvalue = buf.readUB4(); if (bvalue > 0) { // Non Null data in column colValue = new ThinLobImpl(); - const length = buf.readUB8(); - const chunkSize = buf.readUB4(); + if (oraTypeNum !== constants.TNS_DATA_TYPE_BFILE) { + length = buf.readUB8(); + chunkSize = buf.readUB4(); + } const locator = Buffer.from(buf.readBytesWithLength()); colValue.init(this.connection, locator, dbType, length, chunkSize); } @@ -856,7 +864,11 @@ class MessageWithData extends Message { } else { buf.writeUInt16BE(0x0100); } - } else if (oraTypeNum === constants.TNS_DATA_TYPE_CLOB || oraTypeNum === constants.TNS_DATA_TYPE_BLOB) { + } else if ( + oraTypeNum === constants.TNS_DATA_TYPE_CLOB || + oraTypeNum === constants.TNS_DATA_TYPE_BLOB || + oraTypeNum === constants.TNS_DATA_TYPE_BFILE + ) { buf.writeUB4(value._locator.length); buf.writeBytesWithLength(value._locator); } else if ([constants.TNS_DATA_TYPE_ROWID, constants.TNS_DATA_TYPE_UROWID].includes(oraTypeNum)) { diff --git a/lib/types.js b/lib/types.js index fe8d797f..efd04910 100644 --- a/lib/types.js +++ b/lib/types.js @@ -112,7 +112,7 @@ function getTypeByOraTypeNum(oraTypeNum, csfrm) { const DB_TYPE_BFILE = new DbType(2020, "DB_TYPE_BFILE", "BFILE", - { oraTypeNum: 114, bufferSizeFactor: 112 }); + { oraTypeNum: 114, bufferSizeFactor: 4000 }); const DB_TYPE_BINARY_DOUBLE = new DbType(2008, "DB_TYPE_BINARY_DOUBLE", "BINARY_DOUBLE", { oraTypeNum: 101, bufferSizeFactor: 8 }); diff --git a/src/njsLob.c b/src/njsLob.c index 065b2528..2fa79eae 100644 --- a/src/njsLob.c +++ b/src/njsLob.c @@ -36,21 +36,26 @@ NJS_NAPI_METHOD_DECL_ASYNC(njsLob_close); NJS_NAPI_METHOD_DECL_SYNC(njsLob_getChunkSize); NJS_NAPI_METHOD_DECL_ASYNC(njsLob_getData); +NJS_NAPI_METHOD_DECL_SYNC(njsLob_getDirFileName); +NJS_NAPI_METHOD_DECL_ASYNC(njsLob_getFileExists); NJS_NAPI_METHOD_DECL_SYNC(njsLob_getLength); NJS_NAPI_METHOD_DECL_SYNC(njsLob_getPieceSize); NJS_NAPI_METHOD_DECL_SYNC(njsLob_getType); NJS_NAPI_METHOD_DECL_ASYNC(njsLob_read); NJS_NAPI_METHOD_DECL_SYNC(njsLob_setPieceSize); NJS_NAPI_METHOD_DECL_ASYNC(njsLob_write); +NJS_NAPI_METHOD_DECL_SYNC(njsLob_setDirFileName); // asynchronous methods static NJS_ASYNC_METHOD(njsLob_closeAsync); static NJS_ASYNC_METHOD(njsLob_getDataAsync); +static NJS_ASYNC_METHOD(njsLob_getFileExistsAsync); static NJS_ASYNC_METHOD(njsLob_readAsync); static NJS_ASYNC_METHOD(njsLob_writeAsync); // post asynchronous methods static NJS_ASYNC_POST_METHOD(njsLob_getDataPostAsync); +static NJS_ASYNC_POST_METHOD(njsLob_getFileExistsPostAsync); static NJS_ASYNC_POST_METHOD(njsLob_readPostAsync); // finalize @@ -62,6 +67,10 @@ static const napi_property_descriptor njsClassProperties[] = { { "getChunkSize", NULL, njsLob_getChunkSize, NULL, NULL, NULL, napi_default, NULL }, { "getData", NULL, njsLob_getData, NULL, NULL, NULL, napi_default, NULL }, + { "getDirFileName", NULL, njsLob_getDirFileName, NULL, NULL, NULL, + napi_default, NULL }, + { "fileExists", NULL, njsLob_getFileExists, NULL, NULL, NULL, napi_default, + NULL }, { "getLength", NULL, njsLob_getLength, NULL, NULL, NULL, napi_default, NULL }, { "getPieceSize", NULL, njsLob_getPieceSize, NULL, NULL, NULL, @@ -70,6 +79,8 @@ static const napi_property_descriptor njsClassProperties[] = { { "read", NULL, njsLob_read, NULL, NULL, NULL, napi_default, NULL }, { "setPieceSize", NULL, njsLob_setPieceSize, NULL, NULL, NULL, napi_default, NULL }, + { "setDirFileName", NULL, njsLob_setDirFileName, NULL, NULL, NULL, + napi_default, NULL}, { "write", NULL, njsLob_write, NULL, NULL, NULL, napi_default, NULL }, { NULL, NULL, NULL, NULL, NULL, NULL, napi_default, NULL } }; @@ -235,7 +246,8 @@ static bool njsLob_getDataAsync(njsBaton *baton) } // determine size of buffer that is required - if (lob->dataType == NJS_DATATYPE_BLOB) { + if (lob->dataType == NJS_DATATYPE_BLOB || + lob->dataType == NJS_DATATYPE_BFILE) { baton->bufferSize = len; } else if (dpiLob_getBufferSize(lob->handle, len, &baton->bufferSize) < 0) { @@ -321,8 +333,11 @@ bool njsLob_new(njsModuleGlobals *globals, njsLobBuffer *buffer, napi_env env, //----------------------------------------------------------------------------- bool njsLob_populateBuffer(njsBaton *baton, njsLobBuffer *buffer) { - if (dpiLob_getChunkSize(buffer->handle, &buffer->chunkSize) < 0) - return njsBaton_setErrorDPI(baton); + if (buffer->dataType != DPI_ORACLE_TYPE_BFILE) { + if (dpiLob_getChunkSize(buffer->handle, &buffer->chunkSize) < 0) + return njsBaton_setErrorDPI(baton); + } + if (dpiLob_getSize(buffer->handle, &buffer->length) < 0) return njsBaton_setErrorDPI(baton); return true; @@ -407,6 +422,101 @@ static bool njsLob_readPostAsync(njsBaton *baton, napi_env env, } +//----------------------------------------------------------------------------- +// njsLob_getDirFileName() +// To obtain the directory alias and file name properties of BFILE lob object +//----------------------------------------------------------------------------- +NJS_NAPI_METHOD_IMPL_SYNC(njsLob_getDirFileName, 0, NULL) +{ + njsLob *lob = (njsLob *) callingInstance; + uint32_t dirNameLength, fileNameLength; + const char *dirName, *fileName; + napi_value temp; + + if (dpiLob_getDirectoryAndFileName(lob->handle, &dirName, &dirNameLength, + &fileName, &fileNameLength) < 0) + return njsUtils_throwErrorDPI(env, globals); + + // create result object + NJS_CHECK_NAPI(env, napi_create_object(env, returnValue)) + NJS_CHECK_NAPI(env, napi_create_string_utf8(env, dirName, + dirNameLength, &temp)) + NJS_CHECK_NAPI(env, napi_set_named_property(env, *returnValue, + "dirName", temp)) + NJS_CHECK_NAPI(env, napi_create_string_utf8(env, fileName, + fileNameLength, &temp)) + NJS_CHECK_NAPI(env, napi_set_named_property(env, *returnValue, + "fileName", temp)) + + return true; +} + + +//----------------------------------------------------------------------------- +// njsLob_getFileExists() +// To get the file-existence status of BFILE. +//----------------------------------------------------------------------------- +NJS_NAPI_METHOD_IMPL_ASYNC(njsLob_getFileExists, 0, NULL) +{ + return njsBaton_queueWork(baton, env, "fileExists", + njsLob_getFileExistsAsync, njsLob_getFileExistsPostAsync, + returnValue); +} + + +//----------------------------------------------------------------------------- +// njsLob_getFileExists() +// Worker thread function for njsLob_getFileExists(). +//----------------------------------------------------------------------------- +static bool njsLob_getFileExistsAsync(njsBaton *baton) +{ + njsLob *lob = (njsLob *) baton->callingInstance; + int exists; + + if (dpiLob_getFileExists(lob->handle, &exists) < 0) + return njsBaton_setErrorDPI(baton); + baton->fileExists = (exists != 0) ? true : false; + + return true; +} + + +//----------------------------------------------------------------------------- +// njsLob_getFileExistsPostAsync() +// To return whether the file exists (BFILE) +//----------------------------------------------------------------------------- +static bool njsLob_getFileExistsPostAsync(njsBaton *baton, napi_env env, + napi_value *result) +{ + NJS_CHECK_NAPI(env, napi_get_boolean(env, baton->fileExists, result)) + return true; +} + + +//----------------------------------------------------------------------------- +// njsLob_setDirFileName() +// TO set the directory alias and file name property on BFILE lob object +//---------------------------------------------------------------------------- +NJS_NAPI_METHOD_IMPL_SYNC(njsLob_setDirFileName, 1, NULL) +{ + njsLob *lob = (njsLob*) callingInstance; + size_t dirNameLength, fileNameLength; + char *dirName, *fileName; + + if (!njsUtils_getNamedPropertyString(env, args[0], "dirName", + &dirName, &dirNameLength)) + return false; + if (!njsUtils_getNamedPropertyString(env, args[0], "fileName", + &fileName, &fileNameLength)) + return false; + if (dpiLob_setDirectoryAndFileName(lob->handle, dirName, dirNameLength, + fileName, fileNameLength) < 0) + return njsUtils_throwErrorDPI(env, globals); + + return true; +} + + //----------------------------------------------------------------------------- // njsLob_setPieceSize() // Set accessor of "pieceSize" property. diff --git a/src/njsModule.h b/src/njsModule.h index 8a71d5f0..a8e8fd43 100644 --- a/src/njsModule.h +++ b/src/njsModule.h @@ -156,6 +156,7 @@ #define NJS_DATATYPE_CLOB DPI_ORACLE_TYPE_CLOB #define NJS_DATATYPE_NCLOB DPI_ORACLE_TYPE_NCLOB #define NJS_DATATYPE_BLOB DPI_ORACLE_TYPE_BLOB +#define NJS_DATATYPE_BFILE DPI_ORACLE_TYPE_BFILE #define NJS_DATATYPE_BOOLEAN DPI_ORACLE_TYPE_BOOLEAN #define NJS_DATATYPE_OBJECT DPI_ORACLE_TYPE_OBJECT #define NJS_DATATYPE_JSON DPI_ORACLE_TYPE_JSON @@ -434,6 +435,7 @@ struct njsBaton { bool keepInStmtCache; bool isJson; bool isOson; + bool fileExists; // LOB buffer (requires free only if string was used) uint64_t bufferSize; diff --git a/src/njsResultSet.c b/src/njsResultSet.c index 560aa76e..9677a430 100644 --- a/src/njsResultSet.c +++ b/src/njsResultSet.c @@ -344,6 +344,7 @@ static bool njsResultSet_setFetchTypes(napi_env env, njsResultSet *rs, case DPI_ORACLE_TYPE_CLOB: case DPI_ORACLE_TYPE_NCLOB: case DPI_ORACLE_TYPE_BLOB: + case DPI_ORACLE_TYPE_BFILE: case DPI_ORACLE_TYPE_OBJECT: case DPI_ORACLE_TYPE_NUMBER: case DPI_ORACLE_TYPE_NATIVE_INT: diff --git a/src/njsVariable.c b/src/njsVariable.c index 87d32f10..de441209 100644 --- a/src/njsVariable.c +++ b/src/njsVariable.c @@ -84,6 +84,7 @@ bool njsVariable_createBuffer(njsVariable *var, njsConnection *conn, case DPI_ORACLE_TYPE_CLOB: case DPI_ORACLE_TYPE_NCLOB: case DPI_ORACLE_TYPE_BLOB: + case DPI_ORACLE_TYPE_BFILE: var->nativeTypeNum = DPI_NATIVE_TYPE_LOB; break; case NJS_DATATYPE_BOOLEAN: @@ -683,6 +684,7 @@ static bool njsVariable_processBuffer(njsVariable *var, case DPI_ORACLE_TYPE_CLOB: case DPI_ORACLE_TYPE_NCLOB: case DPI_ORACLE_TYPE_BLOB: + case DPI_ORACLE_TYPE_BFILE: NJS_FREE_AND_CLEAR(buffer->lobs); if (buffer->numElements == 0) break;