From 94ad326d9cb6b8ea4d70c38904be73ec77d735c4 Mon Sep 17 00:00:00 2001 From: Sharad Chandran R Date: Thu, 20 Jun 2024 12:23:31 +0530 Subject: [PATCH] Fixed bug which throws NJS-112 error during fetching of JSON and Vector columns as string after table recreation with statement caching --- doc/src/release_notes.rst | 10 +++ lib/thin/protocol/messages/withData.js | 6 +- test/dataTypeJson.js | 94 ++++++++++++++++++++++++++ test/dataTypeVector1.js | 48 +++++++++++++ test/list.txt | 4 ++ 5 files changed, 161 insertions(+), 1 deletion(-) diff --git a/doc/src/release_notes.rst b/doc/src/release_notes.rst index 2f20e710..f775f721 100644 --- a/doc/src/release_notes.rst +++ b/doc/src/release_notes.rst @@ -7,6 +7,16 @@ node-oracledb Release Notes For deprecated and desupported features, see :ref:`Deprecations and desupported features `. +node-oracledb `v6.6.0 `__ (TBD) +--------------------------------------------------------------------------------------------------------- + +Thin Mode Changes ++++++++++++++++++ + +#) Fixed bug which throws an `NJS-112` error during fetching of JSON and + vector columns after table recreation. This is similar to the + fix provided for GitHub issue #1565. + node-oracledb `v6.5.1 `__ (23 May 2024) --------------------------------------------------------------------------------------------------------- diff --git a/lib/thin/protocol/messages/withData.js b/lib/thin/protocol/messages/withData.js index 10a63b75..91fd7710 100644 --- a/lib/thin/protocol/messages/withData.js +++ b/lib/thin/protocol/messages/withData.js @@ -140,7 +140,11 @@ class MessageWithData extends Message { if ((cVar.fetchInfo.dbType._oraTypeNum === constants.TNS_DATA_TYPE_CLOB && pVar.fetchInfo.fetchType._oraTypeNum === constants.TNS_DATA_TYPE_LONG) || (cVar.fetchInfo.dbType._oraTypeNum === constants.TNS_DATA_TYPE_BLOB - && pVar.fetchInfo.fetchType._oraTypeNum === constants.TNS_DATA_TYPE_LONG_RAW)) { + && pVar.fetchInfo.fetchType._oraTypeNum === constants.TNS_DATA_TYPE_LONG_RAW) + || (cVar.fetchInfo.dbType._oraTypeNum === constants.TNS_DATA_TYPE_JSON + && pVar.fetchInfo.fetchType._oraTypeNum === constants.TNS_DATA_TYPE_VARCHAR) + || (cVar.fetchInfo.dbType._oraTypeNum === constants.TNS_DATA_TYPE_VECTOR + && pVar.fetchInfo.fetchType._oraTypeNum === constants.TNS_DATA_TYPE_LONG)) { cVar.type = pVar.fetchInfo.fetchType; cVar.maxSize = pVar.maxSize; } diff --git a/test/dataTypeJson.js b/test/dataTypeJson.js index 17fc363a..90b5a6c8 100644 --- a/test/dataTypeJson.js +++ b/test/dataTypeJson.js @@ -1026,4 +1026,98 @@ describe('244.dataTypeJson.js', function() { }); // 244.12 + describe('244.13 Read JSON data on meta data change', function() { + + const tableNameJSON = 'nodb_myjson_recreate'; + let sequence = 1; + const sqlCreate = " CREATE TABLE " + tableNameJSON + " ( \n" + + " id NUMBER, \n" + + " content JSON \n" + + " )"; + + before('create table, insert data', async function() { + if (!isRunnable) { + this.skip(); + } + await testsUtil.createTable(connection, tableNameJSON, sqlCreate); + }); // before() + + after(async function() { + if (!isRunnable) { + this.skip(); + } + oracledb.stmtCacheSize = default_stmtCacheSize; + oracledb.fetchAsString = []; + await testsUtil.dropTable(connection, tableNameJSON); + }); // after() + + async function recreateTable() { + await testsUtil.dropTable(connection, tableNameJSON); + await testsUtil.createTable(connection, tableNameJSON, sqlCreate); + } + + const testInsertAndFetch = async function(seq, jsonVal, resultStr, selectOpts) { + let sql = "insert into " + tableNameJSON + " ( id, content ) values (:i, :c)"; + const binds = [ + { val: seq, type: oracledb.NUMBER, dir: oracledb.BIND_IN }, + { val: jsonVal, type: oracledb.DB_TYPE_JSON, dir: oracledb.BIND_IN } + ]; + + await connection.execute(sql, binds); + sql = "select content as C from " + tableNameJSON + " where id = " + seq; + const result = await connection.execute(sql, [], selectOpts); + assert.strictEqual(result.rows[0][0], resultStr); + }; + + it('244.13.1 table recreate - with oracledb.fetchAsString', async function() { + oracledb.fetchAsString = [ oracledb.DB_TYPE_JSON ]; + const jsonVals = [{ "key5": "2018/11/01 18:30:00" }]; + const resultStr = ["{\"key5\":\"2018/11/01 18:30:00\"}"]; + + // Add the JSON Field with Long Field Name to the JSON Values Array + // for Oracle DB 23.4 (and Oracle Client 23.4) + if (isOracle_23_4) { + const longFieldName = 'A'.repeat(1000); + const jsonVal = {}; + jsonVal[longFieldName] = "2018/11/01 18:30:00"; + jsonVals.push(jsonVal); + resultStr.push(`{"${longFieldName}":"2018/11/01 18:30:00"}`); + } + + for (let i = 0; i < jsonVals.length; i++) { + await testInsertAndFetch(sequence, jsonVals[i], resultStr[i], {}); + sequence++; + } + + await recreateTable(); + sequence = 1; + + for (let i = 0; i < jsonVals.length; i++) { + await testInsertAndFetch(sequence, jsonVals[i], resultStr[i], {}); + sequence++; + } + + }); // 244.13.1 + + it('244.13.2 table recreate - with fetchInfo oracledb.STRING', async function() { + oracledb.fetchAsString = []; + const jsonVal = { "key5": "2018/11/01 18:30:00" }; + const resultStr = "{\"key5\":\"2018/11/01 18:30:00\"}"; + + const options = { + fetchInfo: { C: { type: oracledb.STRING } } + }; + + // Test Insert and Fetch of JSON Data + await testInsertAndFetch(sequence, jsonVal, resultStr, options); + // Recreate the same table + await recreateTable(); + // Test Insert and Fetch of JSON Data again + await testInsertAndFetch(sequence, jsonVal, resultStr, options); + sequence++; + + }); // 244.13.2 + + }); // 244.13 + }); diff --git a/test/dataTypeVector1.js b/test/dataTypeVector1.js index a429a212..397b5ff7 100644 --- a/test/dataTypeVector1.js +++ b/test/dataTypeVector1.js @@ -1897,4 +1897,52 @@ describe('294. dataTypeVector1.js', function() { ); } }); // 294.72 + + it('294.73 fetch VECTOR column as string with table recreate', async function() { + oracledb.fetchTypeHandler = function() { + return {type: oracledb.STRING}; + }; + + const table = 'nodb_vectorDbTable1'; + const sqlCreate = `CREATE TABLE IF NOT EXISTS ${table} ( + IntCol NUMBER, + Vector64Col vector(10, float64) + )`; + let plsqlCreate = testsUtil.sqlCreateTable(table, sqlCreate); + await connection.execute(plsqlCreate); + + // Create a Float64Array + const float64Array = new Float64Array( + [-999999.12345, 987654.321, -12345.6789, 56789.0123, + -314159.2654, 291828.1828, -99999.9999, 43210.9876, -87654.321, 65432.1098]); + + const sqlInsert = `INSERT INTO ${table} (IntCol, Vector64Col) VALUES(:id, :vec64)`; + const bindOpts = { + id: 2, + vec64: float64Array + }; + await connection.execute(sqlInsert, bindOpts); + + let result = await connection.execute(`SELECT Vector64Col FROM ${table}`); + + // Convert the vector data returned as a string back to Float64Array + const resultFloat64Array1 = new Float64Array(JSON.parse(result.rows[0][0])); + + assert.deepStrictEqual(resultFloat64Array1, float64Array); + await connection.execute(testsUtil.sqlDropTable(table)); + + // Recreate the table with same data and redo the fetch + plsqlCreate = testsUtil.sqlCreateTable(table, sqlCreate); + await connection.execute(plsqlCreate); + await connection.execute(sqlInsert, bindOpts); + + result = await connection.execute(`SELECT Vector64Col FROM ${table}`); + + // Convert the vector data returned as a string back to Float64Array + const resultFloat64Array2 = new Float64Array(JSON.parse(result.rows[0][0])); + + assert.deepStrictEqual(resultFloat64Array2, float64Array); + await connection.execute(testsUtil.sqlDropTable(table)); + + }); // 294.73 }); diff --git a/test/list.txt b/test/list.txt index 8d136f98..d740ad6e 100755 --- a/test/list.txt +++ b/test/list.txt @@ -4940,6 +4940,9 @@ oracledb.OUT_FORMAT_OBJECT and resultSet = true 244.11.3 fetch JSON with relative offsets and shared fields, not values 244.12 Verify auto-generated SODA document key 244.12.1 Verify Json Id on select + 244.13 Read JSON data on meta data change + 244.13.1 table recreate - with oracledb.fetchAsString + 244.13.2 table recreate - with fetchInfo oracledb.STRING 245. fetchLobAsStrBuf.js 245.1 CLOB,BLOB Insert @@ -5775,6 +5778,7 @@ oracledb.OUT_FORMAT_OBJECT and resultSet = true 294.70 typed arrays with undefined value 294.71 typed arrays with null values 294.72 inserting empty vector in Fixed and Flex vector columns + 294.73 fetch VECTOR column as string with table recreate 295. dataTypeVector2.js 295.1 verify fetch information for older clients