From 76a110871dac8561fafa814b7b026513ddf21f11 Mon Sep 17 00:00:00 2001 From: Sharad Chandran R Date: Wed, 18 Dec 2024 13:02:58 +0530 Subject: [PATCH] More tests and examples to improve code coverage --- examples/plsqlrowtype.js | 13 +- examples/soda1.js | 4 + test/binding.js | 7 +- test/connection.js | 4 + test/dataTypeXML.js | 2 +- test/dbObject5.js | 7 +- test/dbconfig.js | 16 +- .../standalone/bfileTypeTest.js | 109 +++--- test/fetchRawAsString.js | 2 +- test/list.txt | 12 +- test/plsqlRowtype.js | 345 ++++++++++-------- test/properties.js | 21 +- test/soda1.js | 8 + 13 files changed, 328 insertions(+), 222 deletions(-) diff --git a/examples/plsqlrowtype.js b/examples/plsqlrowtype.js index fded49133..a080db663 100644 --- a/examples/plsqlrowtype.js +++ b/examples/plsqlrowtype.js @@ -64,6 +64,8 @@ async function run() { let conn; const table = 'STAFF'; const stmts = [ + `DROP TABLE ${table} PURGE`, + `CREATE TABLE ${table} (ID NUMBER, NAME VARCHAR2(25), AGE NUMBER(3) INVISIBLE)`, `INSERT INTO ${table} VALUES (1, 'ADSA')`, @@ -91,10 +93,17 @@ async function run() { try { conn = await oracledb.getConnection(dbConfig); for (const s of stmts) { - await conn.execute(s); + try { + await conn.execute(s); + } catch (e) { + if (e.errorNum != 942) + console.error(e); + } } const objClass = await conn.getDbObjectClass("FOO_TEST.FOO_TMP_ARRAY"); - const result = await conn.execute(`CALL FOO_TEST.prGetRecords(:out_rec)`, {out_rec: {type: objClass, dir: oracledb.BIND_OUT}}); + const result = await conn.execute(`CALL FOO_TEST.prGetRecords(:out_rec)`, + { out_rec: { type: objClass, dir: oracledb.BIND_OUT } }); + for (const val of result.outBinds.out_rec) { console.log("\nRow contents:"); console.log(val); diff --git a/examples/soda1.js b/examples/soda1.js index 10348d87f..2820e3693 100644 --- a/examples/soda1.js +++ b/examples/soda1.js @@ -126,6 +126,10 @@ async function run() { content = doc.getContentAsString(); // A JSON string console.log('Retrieved SODA document as a string:'); console.log(content); + content = doc.getContentAsBuffer(); // A Buffer + console.log('Retrieved SODA document as a buffer:'); + console.log(content); + console.log('SODA Document Version:', doc.version); // Replace document contents content = {name: "Matilda", address: {city: "Sydney"}}; diff --git a/test/binding.js b/test/binding.js index f9d25647d..8dc8f8b1c 100755 --- a/test/binding.js +++ b/test/binding.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2023, Oracle and/or its affiliates. */ +/* Copyright (c) 2015, 2024, Oracle and/or its affiliates. */ /****************************************************************************** * @@ -72,8 +72,6 @@ describe('4. binding.js', function() { { type: oracledb.STRING, dir: oracledb.BIND_OUT } ]); - // console.log(result); - assert.deepStrictEqual(result.outBinds, ['abcdef']); await connection.execute("DROP PROCEDURE nodb_bindproc1"); @@ -276,7 +274,8 @@ describe('4. binding.js', function() { {sql: 'insert into nodb_binding1 (id, name) values (:1, :2) returning ( id + 2 )into :3', rowsAffected: 1, resultVal: [[3]]}, {sql: 'insert into nodb_binding1 (id, name) values (:1, :2) returning ( id + 2 + 5)into :3', rowsAffected: 1, resultVal: [[8]]}, {sql: 'insert into nodb_binding1 (id, name) values (:1, :2) returning ( id * 2 )into :3', rowsAffected: 1, resultVal: [[2]]}, - {sql: 'insert into nodb_binding1 (id, name) values (:1, :2)returning ( id * 2 )into :3', rowsAffected: 1, resultVal: [[2]]} + {sql: 'insert into nodb_binding1 (id, name) values (:1, :2)returning ( id * 2 )into :3', rowsAffected: 1, resultVal: [[2]]}, + {sql: 'insert into nodb_binding1 (id, name) values (: 1, : 2)returning ( id * 2 )into :3', rowsAffected: 1, resultVal: [[2]]} ]; for (const sqlObj of sqlStrings) { const result = await connection.execute(sqlObj.sql, bindsOutNumber); diff --git a/test/connection.js b/test/connection.js index 4587f1bca..5235a9724 100644 --- a/test/connection.js +++ b/test/connection.js @@ -71,9 +71,13 @@ describe('1. connection.js', function() { '); \ END; "; + const commentSQL = "COMMENT ON TABLE nodb_conn_dept1 IS \ + 'This is a table with information about various departments'"; + before(async function() { connection = await oracledb.getConnection(dbConfig); await connection.execute(script); + await connection.execute(commentSQL); }); after(async function() { diff --git a/test/dataTypeXML.js b/test/dataTypeXML.js index e14877008..765bed74f 100644 --- a/test/dataTypeXML.js +++ b/test/dataTypeXML.js @@ -157,7 +157,7 @@ describe('181. dataTypeXML.js', function() { assert.strictEqual(result.rows[0].MYCONTENT, testXMLData); }); // 181.3 - it('181.4 Negative - try to insert Null', async () => { + it('181.4 Negative - try to insert empty XML', async () => { const ID = 20; const XML = ''; diff --git a/test/dbObject5.js b/test/dbObject5.js index e5584b5dd..45e9eeb43 100644 --- a/test/dbObject5.js +++ b/test/dbObject5.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, 2023, Oracle and/or its affiliates. */ +/* Copyright (c) 2019, 2024, Oracle and/or its affiliates. */ /****************************************************************************** * @@ -26,7 +26,7 @@ * 204. dbObject5.js * * DESCRIPTION - * Test the Oracle data type Object on TIMESTAMP WITH LOCAL TIME ZONE. + * Test the Oracle data type Object on DATE. * *****************************************************************************/ 'use strict'; @@ -42,7 +42,8 @@ describe('204. dbObject5.js', () => { const TABLE = 'NODB_TAB_OBJ4'; const proc1 = - `create or replace procedure nodb_getDataCursor1(p_cur out sys_refcursor) is begin + `create or replace procedure nodb_getDataCursor1(p_cur out sys_refcursor) is + begin open p_cur for SELECT * FROM diff --git a/test/dbconfig.js b/test/dbconfig.js index 1e93f9394..1c2e3b6a4 100644 --- a/test/dbconfig.js +++ b/test/dbconfig.js @@ -60,6 +60,14 @@ const config = { let counter = 0; +if (process.env.NODE_ORACLEDB_DRIVER_MODE === 'thick') { + config.test.mode = 'thick'; + console.log("Thick mode selected"); + oracledb.initOracleClient({ libDir: config.test.instantClientPath }); +} else { + console.log("Thin mode selected"); +} + if (process.env.NODE_ORACLEDB_CONNECTIONSTRING) { config.connectString = process.env.NODE_ORACLEDB_CONNECTIONSTRING; } else { @@ -148,14 +156,6 @@ if (process.env.NODE_ORACLEDB_CLIENT_LIB_DIR) { config.test.instantClientPath = process.env.NODE_ORACLEDB_CLIENT_LIB_DIR; } -if (process.env.NODE_ORACLEDB_DRIVER_MODE === 'thick') { - config.test.mode = 'thick'; - console.log("Thick mode selected"); - oracledb.initOracleClient({ libDir: config.test.instantClientPath }); -} else { - console.log("Thin mode selected"); -} - config.createUser = () => { ++counter; return "NJS_" + counter.toString() + config.user; diff --git a/test/ext/release-check-tests/standalone/bfileTypeTest.js b/test/ext/release-check-tests/standalone/bfileTypeTest.js index 88b4b784b..e7ee2799a 100644 --- a/test/ext/release-check-tests/standalone/bfileTypeTest.js +++ b/test/ext/release-check-tests/standalone/bfileTypeTest.js @@ -23,10 +23,12 @@ * limitations under the License. * * NAME - * 305. bfileTypeTest.js + * 308. bfileTypeTest.js * * DESCRIPTION * Test cases for BFILE type support. + * This test can be run only if the DB server and client are on the same + * machine and DB is not running on a Docker environment. * Environment variables to be set: * BFILEDIR - BFile Directory on the Database server side * @@ -38,7 +40,7 @@ const assert = require('assert'); const dbConfig = require('../../../dbconfig.js'); const testsUtil = require('../../../testsUtil.js'); -describe('305. bfileTestType.js', function() { +describe('308. bfileTestType.js', function() { let conn, dbaConn; const bFileDir = process.env.BFILEDIR; let mkDirCmd, rmDirCmd; @@ -172,10 +174,10 @@ describe('305. bfileTestType.js', function() { } conn = await oracledb.getConnection(dbConfig); const sql = `CREATE TABLE ${tableName} ( - ID NUMBER, - NAME VARCHAR2(256), - BFILECOL BFILE - )`; + ID NUMBER, + NAME VARCHAR2(256), + BFILECOL BFILE + )`; const plsql = testsUtil.sqlCreateTable(tableName, sql); await conn.execute(plsql); @@ -190,7 +192,6 @@ describe('305. bfileTestType.js', function() { await setPlatformConfig(); await createDir(); - // console.log('Directory Created:', bFileDir); await dbaConn.execute(` CREATE OR REPLACE DIRECTORY ${dirAlias} AS '${bFileDir}'`); await dbaConn.execute(` @@ -213,25 +214,25 @@ describe('305. bfileTestType.js', function() { await dbaConn.close(); }); - it('305.1 metadata with BFILE column type', async function() { + it('308.1 metadata with BFILE column type', async function() { const result = await conn.execute(` SELECT BFILECOL FROM TBL_BFILE `); assert.equal(result.metaData[0].dbType, oracledb.DB_TYPE_BFILE); assert.equal(result.metaData[0].fetchType, oracledb.DB_TYPE_BFILE); assert.equal(result.metaData[0].name, "BFILECOL"); - }); // 305.1 + }); // 308.1 - it('305.2 SELECT query with BFILE type', async function() { + it('308.2 SELECT query with BFILE type', async function() { const result = await conn.execute(` SELECT BFILECOL FROM TBL_BFILE WHERE ID = :ID`, [101]); const lob = result.rows[0][0]; const dirFile = lob.getDirFileName(); assert.strictEqual(dirFile.dirName, dirAlias); assert.strictEqual(dirFile.fileName, "A.JPG"); - }); // 305.2 + }); // 308.2 - it('305.3 SELECT using BFILENAME from dual', async function() { + it('308.3 SELECT using BFILENAME from dual', async function() { const fileName = 'A.JPG'; const oldOutFormat = oracledb.outFormat; @@ -244,19 +245,19 @@ describe('305. bfileTestType.js', function() { assert.strictEqual(dirFile.dirName, bFileDir); assert.strictEqual(dirFile.fileName, fileName); oracledb.outFormat = oldOutFormat; - }); // 305.3 + }); // 308.3 - it('305.4 INSERT using BFILENAME', async function() { + it('308.4 INSERT using BFILENAME', async function() { const dirName = "NONEXISTDIR"; const fileName = "B.JPG"; const sql = `INSERT INTO TBL_BFILE (ID, NAME, BFILECOL) VALUES (:ID, :NAME, BFILENAME(:DIRNAME, :FILENAME))`; - await conn.execute (sql, [105, "TC305.5", dirName, fileName]); + await conn.execute (sql, [105, "TC308.5", dirName, fileName]); await conn.commit(); - }); // 305.4 + }); // 308.4 - it('305.5 UPDATE using BFILENAME', async function() { + it('308.5 UPDATE using BFILENAME', async function() { const dirName = "NONEXISTDIR2"; const fileName = "C.JPG"; const sql = `UPDATE TBL_BFILE @@ -265,10 +266,10 @@ describe('305. bfileTestType.js', function() { WHERE ID = :ID`; await conn.execute (sql, [dirName, fileName, 105]); await conn.commit(); - }); // 305.5 + }); // 308.5 - it('305.6 OUT BIND WITH BFILE type', async function() { - const fileName = '305.6.JPG'; + it('308.6 OUT BIND WITH BFILE type', async function() { + const fileName = '308.6.JPG'; const sqlProc = ` CREATE OR REPLACE PROCEDURE NODB_BFILEPROC(BFILEVAL OUT BFILE) AS BEGIN @@ -285,18 +286,18 @@ describe('305. bfileTestType.js', function() { const dirFile = lob.getDirFileName(); assert.equal(dirFile.dirName, dirAlias); assert.equal(dirFile.fileName, fileName); - }); // 305.6 + }); // 308.6 - it('305.7 fileExists on existing file', async function() { + it('308.7 fileExists on existing file', async function() { const result = await conn.execute(` SELECT BFILECOL FROM TBL_BFILE WHERE ID = :ID`, [101]); const lob = result.rows[0][0]; const exists = await lob.fileExists(); assert.equal(exists, true); - }); // 305.7 + }); // 308.7 - it('305.8 Check BFILE existence in a loop', async function() { + it('308.8 Check BFILE existence in a loop', async function() { const result = await conn.execute(` SELECT BFILECOL FROM TBL_BFILE WHERE ID = :ID`, [101]); const lob = result.rows[0][0]; @@ -305,9 +306,9 @@ describe('305. bfileTestType.js', function() { const exists = await lob.fileExists(); assert.equal(exists, true); } - }); // 305.8 + }); // 308.8 - it('305.9 SELECT query with BFILE type and INSERT', async function() { + it('308.9 SELECT query with BFILE type and INSERT', async function() { const result = await conn.execute(` SELECT BFILECOL FROM TBL_BFILE WHERE ID = :ID`, [101]); const lob = result.rows[0][0]; @@ -322,9 +323,9 @@ describe('305. bfileTestType.js', function() { type: oracledb.DB_TYPE_BFILE}}); await conn.commit(); assert.equal(result2.rowsAffected, 1); - }); // 305.9 + }); // 308.9 - it('305.10 setDirFileName()', async function() { + it('308.10 setDirFileName()', async function() { if (!oracledb.thin) { this.skip(); } @@ -341,9 +342,9 @@ describe('305. bfileTestType.js', function() { const newDirObj = lob.getDirFileName(); assert.strictEqual(newDirObj.dirName, dirName); assert.strictEqual(newDirObj.fileName, fileName); - }); // 305.10 + }); // 308.10 - it('305.11 throws error for chunkSize', async function() { + it('308.11 throws error for chunkSize', async function() { const result = await conn.execute(` SELECT BFILECOL FROM TBL_BFILE WHERE ID = :ID`, [101]); const lob = result.rows[0][0]; @@ -351,9 +352,9 @@ describe('305. bfileTestType.js', function() { () => lob.chunkSize, /NJS-155:/ // NJS-155: operation is not supported on BFILE LOBs ); - }); // 305.11 + }); // 308.11 - it('305.12 accessing non-existent BFILE', async function() { + it('308.12 accessing non-existent BFILE', async function() { const result = await conn.execute(` SELECT BFILENAME(:dirName, :fileName) FROM TBL_BFILE`, { dirName: 'NON_EXISTENT_DIR', fileName: 'NON_EXISTENT_FILE.JPG' } @@ -364,9 +365,9 @@ describe('305. bfileTestType.js', function() { async () => await lob.fileExists(), /ORA-22285:/ //ORA-22285: non-existent directory or file for FILEEXISTS operation ); - }); // 305.12 + }); // 308.12 - it('305.13 reading BFILE content', async function() { + it('308.13 reading BFILE content', async function() { const result = await conn.execute(` SELECT BFILECOL FROM TBL_BFILE WHERE ID = :ID`, [101] ); @@ -382,9 +383,9 @@ describe('305. bfileTestType.js', function() { assert.equal(content, 'abcdefghijklmnopqrstuvwxyz zyxwvutsrqponmlkjihgfedcba\r\n'); else assert.equal(content, 'abcdefghijklmnopqrstuvwxyz zyxwvutsrqponmlkjihgfedcba\n'); - }); // 305.13 + }); // 308.13 - it('305.14 updating BFILE with some other directory', async function() { + it('308.14 updating BFILE with some other directory', async function() { const dirName = "OTHER_DIR"; const fileName = "OTHER_FILE.JPG"; let result = await conn.execute(` @@ -406,9 +407,9 @@ describe('305. bfileTestType.js', function() { dirFile = lob.getDirFileName(); assert.strictEqual(dirFile.dirName, "OTHER_DIR"); assert.strictEqual(dirFile.fileName, "OTHER_FILE.JPG"); - }); // 305.14 + }); // 308.14 - it('305.15 deleting BFILE entry', async function() { + it('308.15 deleting BFILE entry', async function() { await conn.execute(` DELETE FROM TBL_BFILE WHERE ID = :ID`, [101] ); @@ -417,9 +418,9 @@ describe('305. bfileTestType.js', function() { SELECT COUNT(*) FROM TBL_BFILE WHERE ID = :ID`, [101] ); assert.equal(result.rows[0][0], 0); - }); // 305.15 + }); // 308.15 - it('305.16 test BFILE methods on non-BFILE LOBs', async function() { + it('308.16 test BFILE methods on non-BFILE LOBs', async function() { const lobTypes = [ oracledb.BLOB, oracledb.CLOB, @@ -446,16 +447,16 @@ describe('305. bfileTestType.js', function() { /NJS-156/ // NJS-156: operation is only supported on BFILE LOBs ); } - }); // 305.16 + }); // 308.16 - it('305.17 Insert BFILE with invalid directory', async function() { + it('308.17 Insert BFILE with invalid directory', async function() { const dirName = "INVALID_DIR"; const fileName = "B.JPG"; const sql = `INSERT INTO TBL_BFILE (ID, NAME, BFILECOL) VALUES (:ID, :NAME, BFILENAME(:DIRNAME, :FILENAME))`; - await conn.execute (sql, [106, "TC305.16", dirName, fileName]); + await conn.execute (sql, [106, "TC308.16", dirName, fileName]); const result = await conn.execute(` SELECT BFILENAME(:dirName, :fileName) FROM TBL_BFILE`, { dirName: dirName, fileName: fileName } @@ -466,9 +467,9 @@ describe('305. bfileTestType.js', function() { async () => await lob.fileExists(), /ORA-22285:/ //ORA-22285: non-existent directory or file for FILEEXISTS operation ); - }); // 305.17 + }); // 308.17 - it('305.18 Test BFILE deletion with explicit commit', async function() { + it('308.18 Test BFILE deletion with explicit commit', async function() { // Insert a new row with BFILE await conn.execute(` INSERT INTO TBL_BFILE (ID, NAME, BFILECOL) VALUES @@ -486,9 +487,9 @@ describe('305. bfileTestType.js', function() { const result = await conn.execute(` SELECT COUNT(*) FROM TBL_BFILE WHERE ID = :ID`, [107]); assert.equal(result.rows[0][0], 0); - }); // 305.18 + }); // 308.18 - it('305.19 simulate file permission errors from the other user', async function() { + it('308.19 simulate file permission errors from the other user', async function() { if (dbConfig.test.drcp) this.skip(); const user = 'scott2'; const pwd = testsUtil.generateRandomPassword(); @@ -530,9 +531,9 @@ describe('305. bfileTestType.js', function() { await conn2.execute(testsUtil.sqlDropTable(tableName)); await conn2.close(); await dbaConn.execute(`DROP USER ${user} CASCADE`); - }); // 305.19 + }); // 308.19 - it('305.20 verify BFILE is empty after deletion and insertion', async function() { + it('308.20 verify BFILE is empty after deletion and insertion', async function() { const fileName = 'E.JPG'; await conn.execute(`DELETE FROM TBL_BFILE WHERE ID = :ID`, [105]); @@ -550,9 +551,9 @@ describe('305. bfileTestType.js', function() { const dirFile = lob.getDirFileName(); assert.strictEqual(dirFile.dirName, dirAlias); assert.strictEqual(dirFile.fileName, fileName); - }); // 305.20 + }); // 308.20 - it('305.21 BFILE Metadata Check for Null BFILE', async function() { + it('308.21 BFILE Metadata Check for Null BFILE', async function() { await conn.execute(` INSERT INTO TBL_BFILE (ID, NAME, BFILECOL) VALUES (:ID, :NAME, NULL)`, [109, "Null BFILE"] @@ -563,9 +564,9 @@ describe('305. bfileTestType.js', function() { SELECT BFILECOL FROM TBL_BFILE WHERE ID = :ID`, [109]); const lob = result.rows[0][0]; assert.strictEqual(lob, null); - }); // 305.21 + }); // 308.21 - it('305.22 Test BFILE with temporary table', async function() { + it('308.22 Test BFILE with temporary table', async function() { const tempTableName = 'TEMP_BFILE_TABLE'; // Create a temporary table with a BFILE column await conn.execute(` @@ -662,5 +663,5 @@ describe('305. bfileTestType.js', function() { // Drop the temporary table await conn.execute(`DROP TABLE ${tempTableName} PURGE`); } - }); // 305.22 + }); // 308.22 }); diff --git a/test/fetchRawAsString.js b/test/fetchRawAsString.js index 3a1b0a05d..ca00beee0 100644 --- a/test/fetchRawAsString.js +++ b/test/fetchRawAsString.js @@ -83,7 +83,7 @@ describe('188. fetchRawAsString.js', function() { ` e_table_missing EXCEPTION; \n` + ` PRAGMA EXCEPTION_INIT(e_table_missing, -00942);\n` + ` BEGIN \n` + - ` EXECUTE IMMEDIATE ('DROP TABLE ${tableName} PURGE' ); \n` + + ` EXECUTE IMMEDIATE ('DROP TABLE ${tableName} PURGE'); \n` + ` EXCEPTION \n` + ` WHEN e_table_missing \n` + ` THEN NULL; \n` + diff --git a/test/list.txt b/test/list.txt index 0c0e3be20..a245d81c1 100755 --- a/test/list.txt +++ b/test/list.txt @@ -975,6 +975,7 @@ Overview of node-oracledb functional tests 58.3.6 oracleServerVersion (read-only) 58.3.7 oracleServerVersionString (read-only) 58.3.8 currentSchema + 58.3.9 callTimeout 58.4 ResultSet Class 58.4.1 metaData (read-only) @@ -4455,7 +4456,7 @@ oracledb.OUT_FORMAT_OBJECT and resultSet = true 181.1 basic case, insert XML data and query back 181.2 query XML data as CLOB 181.3 another query as CLOB syntax - 181.4 Negative - try to insert Null + 181.4 Negative - try to insert Empty XML 184. sessionTag.js 184.1 Remote PL/SQL Callback @@ -5930,9 +5931,12 @@ oracledb.OUT_FORMAT_OBJECT and resultSet = true 303.1 enqueue/dequeue with modes 304. plsqlRowtype.js - 304.1 %ROWTYPE - 304.2 %ROWTYPE collection - 304.3 %ROWTYPE object create and delete in a loop to check cursor leak + 304.1 check %ROWTYPE objects + 304.1.1 %ROWTYPE + 304.1.2 %ROWTYPE collection + 304.1.3 %ROWTYPE object create and delete in a loop to check cursor leak + 304.2 bind %ROWTYPE objects in SQL statement + 304.2.1 execute PL/SQL with %ROWTYPE object data 305. dataTypeVector5.js 305.1 tests with vector distance diff --git a/test/plsqlRowtype.js b/test/plsqlRowtype.js index 96cf93373..f7bbab054 100644 --- a/test/plsqlRowtype.js +++ b/test/plsqlRowtype.js @@ -41,22 +41,22 @@ describe('304. plSqlRowType.js', function() { const table = 'NODB_ROWTYPE'; const typeName = `NODB_OBJ`; const stmts = [ - `CREATE OR REPLACE PACKAGE FOO_TEST AS - TYPE NODB_ROWTYPE_ARRAY IS TABLE OF NODB_ROWTYPE%ROWTYPE + `CREATE OR REPLACE PACKAGE FOO_TEST AS + TYPE ${table}_ARRAY IS TABLE OF ${table}%ROWTYPE INDEX BY BINARY_INTEGER; - PROCEDURE prGetRecords(out_rec OUT FOO_TEST.NODB_ROWTYPE_ARRAY); + PROCEDURE prGetRecords(out_rec OUT FOO_TEST.${table}_ARRAY); END FOO_TEST;`, `CREATE OR REPLACE PACKAGE BODY FOO_TEST IS - PROCEDURE prGetRecords(out_rec OUT FOO_TEST.NODB_ROWTYPE_ARRAY) + PROCEDURE prGetRecords(out_rec OUT FOO_TEST.${table}_ARRAY) IS - CURSOR c_NODB_ROWTYPE IS + CURSOR c_${table} IS SELECT * - FROM NODB_ROWTYPE; + FROM ${table}; BEGIN - OPEN c_NODB_ROWTYPE; - FETCH c_NODB_ROWTYPE BULK COLLECT INTO out_rec; - CLOSE c_NODB_ROWTYPE; + OPEN c_${table}; + FETCH c_${table} BULK COLLECT INTO out_rec; + CLOSE c_${table}; END prGetRecords; END FOO_TEST;` ]; @@ -67,147 +67,204 @@ describe('304. plSqlRowType.js', function() { CREATE OR REPLACE TYPE ${typeName} AS OBJECT ( id NUMBER, name NVARCHAR2(30) - );`; - - - const createTableSql = `CREATE TABLE ${table}( - NUMBERVALUE NUMBER(12), - STRINGVALUE VARCHAR2(2), - FIXEDCHARVALUE CHAR(10), - NSTRINGVALUE NVARCHAR2(60), - NFIXEDCHARVALUE NCHAR(10), - RAWVALUE RAW(15), - INTVALUE INTEGER, - SMALLINTVALUE SMALLINT, - REALVALUE REAL, - DOUBLEPRECISIONVALUE DOUBLE PRECISION, - FLOATVALUE FLOAT, - BINARYFLOATVALUE BINARY_FLOAT, - BINARYDOUBLEVALUE BINARY_DOUBLE, - DATEVALUE DATE, - TIMESTAMPVALUE TIMESTAMP, - TIMESTAMPTZVALUE TIMESTAMP WITH TIME ZONE, - TIMESTAMPLTZVALUE TIMESTAMP WITH LOCAL TIME ZONE, - CLOBVALUE CLOB, - NCLOBVALUE NCLOB, - BLOBVALUE BLOB, - OBJECTVALUE NODB_OBJ, - INVISIBLEVALUE NUMBER INVISIBLE)`; - - let expectedTypes = { - NUMBERVALUE: { type: oracledb.DB_TYPE_NUMBER, typeName: 'NUMBER' }, - STRINGVALUE: { type: oracledb.DB_TYPE_VARCHAR, typeName: 'VARCHAR2' }, - FIXEDCHARVALUE: { type: oracledb.DB_TYPE_CHAR, typeName: 'CHAR' }, - NSTRINGVALUE: { type: oracledb.DB_TYPE_NVARCHAR, typeName: 'NVARCHAR2' }, - NFIXEDCHARVALUE: { type: oracledb.DB_TYPE_NCHAR, typeName: 'NCHAR' }, - RAWVALUE: { type: oracledb.DB_TYPE_RAW, typeName: 'RAW' }, - INTVALUE: { type: oracledb.DB_TYPE_NUMBER, typeName: 'NUMBER' }, - SMALLINTVALUE: { type: oracledb.DB_TYPE_NUMBER, typeName: 'NUMBER' }, - REALVALUE: { type: oracledb.DB_TYPE_NUMBER, typeName: 'NUMBER' }, - DOUBLEPRECISIONVALUE: { - type: oracledb.DB_TYPE_NUMBER, - typeName: 'NUMBER' - }, - FLOATVALUE: { type: oracledb.DB_TYPE_NUMBER, typeName: 'NUMBER' }, - BINARYFLOATVALUE: { - type: oracledb.DB_TYPE_BINARY_FLOAT, - typeName: 'BINARY_FLOAT' - }, - BINARYDOUBLEVALUE: { - type: oracledb.DB_TYPE_BINARY_DOUBLE, - typeName: 'BINARY_DOUBLE' - }, - DATEVALUE: { type: oracledb.DB_TYPE_DATE, typeName: 'DATE' }, - TIMESTAMPVALUE: { - type: oracledb.DB_TYPE_TIMESTAMP, - typeName: 'TIMESTAMP' - }, - TIMESTAMPTZVALUE: { - type: oracledb.DB_TYPE_TIMESTAMP_TZ, - typeName: 'TIMESTAMP WITH TIME ZONE' - }, - TIMESTAMPLTZVALUE: { - type: oracledb.DB_TYPE_TIMESTAMP_LTZ, - typeName: 'TIMESTAMP WITH LOCAL TIME ZONE' - }, - CLOBVALUE: { type: oracledb.DB_TYPE_CLOB, typeName: 'CLOB' }, - NCLOBVALUE: { type: oracledb.DB_TYPE_NCLOB, typeName: 'NCLOB' }, - BLOBVALUE: { type: oracledb.DB_TYPE_BLOB, typeName: 'BLOB' }, - }; - - before(async function() { - pool = await oracledb.createPool({ - user: dbConfig.user, - password: dbConfig.password, - connectString: dbConfig.connectString, - poolMin: 1}); - connection = await oracledb.getConnection(dbConfig); - await testsUtil.createType(connection, typeName, ObjSql); - await testsUtil.createTable(connection, table, createTableSql); - for (const s of stmts) { - await connection.execute(s); - } - const objType = await connection.getDbObjectClass("NODB_OBJ"); - const OBJECTVALUE = { - type: oracledb.DB_TYPE_OBJECT, - typeName: objType.prototype.fqn, - typeClass: objType - }; - expectedTypes = {...expectedTypes, OBJECTVALUE }; - }); - - after(async function() { - await testsUtil.dropTable(connection, table); - await testsUtil.dropType(connection, typeName); - await connection.execute(dropPackageSql); - await connection.close(); - if (sysDBAConn) { - await sysDBAConn.close(); - } - if (pool) { - await pool.close(0); - } - }); - - it('304.1 %ROWTYPE', async function() { - const name = "NODB_ROWTYPE%ROWTYPE"; - const objClass = await connection.getDbObjectClass(name); - const types = objClass.prototype.attributes; - assert.deepStrictEqual(expectedTypes, types); - }); // 304.1 + );`; - it('304.2 %ROWTYPE collection', async function() { - const name = "FOO_TEST.NODB_ROWTYPE_ARRAY"; - const objClass = await connection.getDbObjectClass(name); - const types = objClass.prototype.elementTypeClass.prototype.attributes; - assert.deepStrictEqual(expectedTypes, types); - }); // 304.2 + describe('304.1 check %ROWTYPE objects', function() { - it('304.3 %ROWTYPE object create and delete in a loop to check cursor leak', async function() { - if (!dbConfig.test.DBA_PRIVILEGE) this.skip(); + const createTableSql = `CREATE TABLE ${table} ( + NUMBERVALUE NUMBER(12), + STRINGVALUE VARCHAR2(2), + FIXEDCHARVALUE CHAR(10), + NSTRINGVALUE NVARCHAR2(60), + NFIXEDCHARVALUE NCHAR(10), + RAWVALUE RAW(15), + INTVALUE INTEGER, + SMALLINTVALUE SMALLINT, + REALVALUE REAL, + DOUBLEPRECISIONVALUE DOUBLE PRECISION, + FLOATVALUE FLOAT, + BINARYFLOATVALUE BINARY_FLOAT, + BINARYDOUBLEVALUE BINARY_DOUBLE, + DATEVALUE DATE, + TIMESTAMPVALUE TIMESTAMP, + TIMESTAMPTZVALUE TIMESTAMP WITH TIME ZONE, + TIMESTAMPLTZVALUE TIMESTAMP WITH LOCAL TIME ZONE, + CLOBVALUE CLOB, + NCLOBVALUE NCLOB, + BLOBVALUE BLOB, + OBJECTVALUE NODB_OBJ, + INVISIBLEVALUE NUMBER INVISIBLE)`; - const name = "NODB_ROWTYPE%ROWTYPE"; - const iterations = 100; - const dbaConfig = { - user: dbConfig.test.DBA_user, - password: dbConfig.test.DBA_password, - connectionString: dbConfig.connectString, - privilege: oracledb.SYSDBA + let expectedTypes = { + NUMBERVALUE: { type: oracledb.DB_TYPE_NUMBER, typeName: 'NUMBER' }, + STRINGVALUE: { type: oracledb.DB_TYPE_VARCHAR, typeName: 'VARCHAR2' }, + FIXEDCHARVALUE: { type: oracledb.DB_TYPE_CHAR, typeName: 'CHAR' }, + NSTRINGVALUE: { type: oracledb.DB_TYPE_NVARCHAR, typeName: 'NVARCHAR2' }, + NFIXEDCHARVALUE: { type: oracledb.DB_TYPE_NCHAR, typeName: 'NCHAR' }, + RAWVALUE: { type: oracledb.DB_TYPE_RAW, typeName: 'RAW' }, + INTVALUE: { type: oracledb.DB_TYPE_NUMBER, typeName: 'NUMBER' }, + SMALLINTVALUE: { type: oracledb.DB_TYPE_NUMBER, typeName: 'NUMBER' }, + REALVALUE: { type: oracledb.DB_TYPE_NUMBER, typeName: 'NUMBER' }, + DOUBLEPRECISIONVALUE: { + type: oracledb.DB_TYPE_NUMBER, + typeName: 'NUMBER' + }, + FLOATVALUE: { type: oracledb.DB_TYPE_NUMBER, typeName: 'NUMBER' }, + BINARYFLOATVALUE: { + type: oracledb.DB_TYPE_BINARY_FLOAT, + typeName: 'BINARY_FLOAT' + }, + BINARYDOUBLEVALUE: { + type: oracledb.DB_TYPE_BINARY_DOUBLE, + typeName: 'BINARY_DOUBLE' + }, + DATEVALUE: { type: oracledb.DB_TYPE_DATE, typeName: 'DATE' }, + TIMESTAMPVALUE: { + type: oracledb.DB_TYPE_TIMESTAMP, + typeName: 'TIMESTAMP' + }, + TIMESTAMPTZVALUE: { + type: oracledb.DB_TYPE_TIMESTAMP_TZ, + typeName: 'TIMESTAMP WITH TIME ZONE' + }, + TIMESTAMPLTZVALUE: { + type: oracledb.DB_TYPE_TIMESTAMP_LTZ, + typeName: 'TIMESTAMP WITH LOCAL TIME ZONE' + }, + CLOBVALUE: { type: oracledb.DB_TYPE_CLOB, typeName: 'CLOB' }, + NCLOBVALUE: { type: oracledb.DB_TYPE_NCLOB, typeName: 'NCLOB' }, + BLOBVALUE: { type: oracledb.DB_TYPE_BLOB, typeName: 'BLOB' }, }; - const connection = await pool.getConnection(); - const sid = await testsUtil.getSid(connection); - await connection.close(); - sysDBAConn = await oracledb.getConnection(dbaConfig); - const openCount = await testsUtil.getOpenCursorCount(sysDBAConn, sid); - for (let i = 0; i < iterations; i++) { + + before(async function() { + pool = await oracledb.createPool({ + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + poolMin: 1}); + connection = await oracledb.getConnection(dbConfig); + await testsUtil.createType(connection, typeName, ObjSql); + await testsUtil.createTable(connection, table, createTableSql); + for (const s of stmts) { + await connection.execute(s); + } + const objType = await connection.getDbObjectClass(`${typeName}`); + const OBJECTVALUE = { + type: oracledb.DB_TYPE_OBJECT, + typeName: objType.prototype.fqn, + typeClass: objType + }; + expectedTypes = {...expectedTypes, OBJECTVALUE }; + }); + + after(async function() { + await testsUtil.dropTable(connection, table); + await testsUtil.dropType(connection, typeName); + await connection.execute(dropPackageSql); + await connection.close(); + if (sysDBAConn) { + await sysDBAConn.close(); + sysDBAConn = null; + } + if (pool) { + await pool.close(0); + } + }); + + it('304.1.1 %ROWTYPE', async function() { + const name = 'NODB_ROWTYPE%ROWTYPE'; + const objClass = await connection.getDbObjectClass(name); + const types = objClass.prototype.attributes; + assert.deepStrictEqual(expectedTypes, types); + }); // 304.1.1 + + it('304.1.2 %ROWTYPE collection', async function() { + const name = 'FOO_TEST.NODB_ROWTYPE_ARRAY'; + const objClass = await connection.getDbObjectClass(name); + const types = objClass.prototype.elementTypeClass.prototype.attributes; + assert.deepStrictEqual(expectedTypes, types); + }); // 304.1.2 + + it('304.1.3 %ROWTYPE object create and delete in a loop to check cursor leak', async function() { + if (!dbConfig.test.DBA_PRIVILEGE) this.skip(); + + const name = 'NODB_ROWTYPE%ROWTYPE'; + const iterations = 100; + const dbaConfig = { + user: dbConfig.test.DBA_user, + password: dbConfig.test.DBA_password, + connectionString: dbConfig.connectString, + privilege: oracledb.SYSDBA + }; const connection = await pool.getConnection(); - await connection.getDbObjectClass(name); + const sid = await testsUtil.getSid(connection); + await connection.close(); + sysDBAConn = await oracledb.getConnection(dbaConfig); + const openCount = await testsUtil.getOpenCursorCount(sysDBAConn, sid); + for (let i = 0; i < iterations; i++) { + const connection = await pool.getConnection(); + await connection.getDbObjectClass(name); + await connection.close(); + } + const newOpenCount = await testsUtil.getOpenCursorCount(sysDBAConn, sid); + + // ensure cursors are not linearly opened as iterations causing leak. + assert(newOpenCount - openCount < 5); + }); // 304.1.3 + }); // 304.1 + + describe('304.2 bind %ROWTYPE objects in SQL statement', function() { + + const createTableSql = `CREATE TABLE ${table} ( + ID NUMBER, + NAME VARCHAR2(25), + AGE NUMBER(3) INVISIBLE)`; + + before(async function() { + pool = await oracledb.createPool({ + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + poolMin: 1}); + connection = await oracledb.getConnection(dbConfig); + await testsUtil.createTable(connection, table, createTableSql); + for (const s of stmts) { + await connection.execute(s); + } + + // Insert a row + await connection.execute(`INSERT INTO ${table} VALUES (1, 'ADSA')`); + }); + + after(async function() { + await testsUtil.dropTable(connection, table); + await connection.execute(dropPackageSql); await connection.close(); - } - const newOpenCount = await testsUtil.getOpenCursorCount(sysDBAConn, sid); + if (sysDBAConn) { + await sysDBAConn.close(); + } + if (pool) { + await pool.close(0); + } + }); + + it('304.2.1 execute PL/SQL with %ROWTYPE object data', async function() { + const name = 'FOO_TEST.NODB_ROWTYPE_ARRAY'; + const objClass = await connection.getDbObjectClass(name); + const result = await connection.execute(`CALL FOO_TEST.prGetRecords(:out_rec)`, + { out_rec: { type: objClass, dir: oracledb.BIND_OUT } }); + + const valArr = []; + for (const val of result.outBinds.out_rec) { + valArr.push(val); + } + assert.strictEqual(valArr[0]['ID'], 1); + assert.strictEqual(valArr[0]['NAME'], 'ADSA'); - // ensure cursors are not linearly opened as iterations causing leak. - assert(newOpenCount - openCount < 5); - }); // 304.3 + assert.strictEqual(objClass.prototype.elementTypeClass.prototype.attributes.ID.typeName, 'NUMBER'); + assert.strictEqual(objClass.prototype.elementTypeClass.prototype.attributes.NAME.typeName, 'VARCHAR2'); + }); // 304.2.1 + + }); // 304.2 }); // 304 diff --git a/test/properties.js b/test/properties.js index 7fc49fd89..267a14c9c 100644 --- a/test/properties.js +++ b/test/properties.js @@ -658,7 +658,7 @@ describe('58. properties.js', function() { assert.equal(connection.clientId, null); assert.equal(typeof connection.stmtCacheSize, 'number'); - assert.ok(connection.stmtCacheSize > 0); + assert(connection.stmtCacheSize > 0); }); it('58.3.2 stmtCacheSize (read-only)', function() { @@ -770,6 +770,25 @@ describe('58. properties.js', function() { ); }); + it('58.3.9 callTimeout', function() { + // An exception will occur if node-oracledb Thick mode is not using + // Oracle Client library version 18.1 or later. + if (testsUtil.getClientVersion < 1801000000) this.skip(); + + const origCallTimeout = connection.callTimeout; + assert.strictEqual(typeof origCallTimeout, 'number'); + + assert.doesNotThrow( + function() { + connection.callTimeout = 2000; // set Call Timeout to 2s + } + ); + + //Reset connection callTimeout to original value + connection.callTimeout = origCallTimeout; + assert.strictEqual(connection.callTimeout, origCallTimeout); + }); + }); // 58.3 describe('58.4 ResultSet Class', function() { diff --git a/test/soda1.js b/test/soda1.js index 8b4fa5d8e..f46a4fe2d 100644 --- a/test/soda1.js +++ b/test/soda1.js @@ -149,6 +149,10 @@ describe('164. soda1.js', () => { const content = element.getContent(); assert.strictEqual(content.name, myContent.name); assert.strictEqual(content.address.city, myContent.address.city); + const version = element.version; + assert.strictEqual(typeof version, 'string'); + assert.notStrictEqual(version, null); + assert.notStrictEqual(version, undefined); }); await conn.commit(); @@ -242,6 +246,7 @@ describe('164. soda1.js', () => { // Fetch the document back const doc2 = await collection.find().key(myKey).getOne(); const content2 = doc2.getContent(); // A JavaScript object + const content2Buffer = Buffer.from(JSON.stringify(content2), 'utf-8'); // Buffer testsUtil.removeID(content1); testsUtil.removeID(content2); assert.deepStrictEqual(content2, content1); @@ -250,6 +255,9 @@ describe('164. soda1.js', () => { assert.strictEqual(JSON.stringify(content2), content3); + const content3Buffer = doc2.getContentAsBuffer(); // get content as buffer + assert.deepStrictEqual(content2Buffer, content3Buffer); + // Replace document contents const content4 = { name: "Matilda", address: {city: "Sydney"} }; await collection.find().key(myKey).replaceOne(content4);