diff --git a/doc/src/api_manual/connection.rst b/doc/src/api_manual/connection.rst index c81aa0cf0..a098ed5d5 100644 --- a/doc/src/api_manual/connection.rst +++ b/doc/src/api_manual/connection.rst @@ -342,6 +342,32 @@ The properties of a *Connection* object are listed below. value is *False*, then the specified connection does not have an active transaction. +.. attribute:: connection.warning + + .. versionadded:: 6.3 + + This read-only property provides an :ref:`error ` object that + gives information about any database warnings (such as password being in + the grace period) that were generated during + :meth:`connection establishment ` (both + standalone connections and pooled connections). This attribute is present + if a warning is thrown by the database but the operation is otherwise + completed successfully. The connection will be usable despite the warning. + + For :ref:`standalone connections `, the error object + returned by ``connection.warning`` will be present for the lifetime of the + connection. + + For :ref:`pooled connections `, the error object returned by + ``connection.warning`` will be cleared when a connection is released to + the pool using :meth:`connection.close()`. + + In node-oracledb Thick mode, warnings may be generated during pool + creation itself. These warnings will be placed on the new connections + created by the pool, provided no warnings were generated by the individual + connection creations, in which case those connection warnings will be + returned. + .. _connectionmethods: Connection Methods @@ -1120,6 +1146,14 @@ Connection Methods This property is a number. For `DML `__ statements this contains the number of rows affected, for example the number of rows inserted. For non-DML statements such as queries and PL/SQL statements, ``rowsAffected`` is undefined. Due to Node.js type limitations, the largest value shown will be 232 - 1, even if more rows were affected. Larger values will wrap. + * - ``warning`` + - .. _execwarning: + + This property provides an :ref:`error ` object that gives information about any database warnings (such as PL/SQL compilation warnings) that were generated during the last call to :meth:`connection.execute()`. + + See :ref:`plsqlcompwarnings` for more information. + + .. versionadded:: 6.3 .. method:: connection.executeMany() @@ -1365,6 +1399,15 @@ Connection Methods It is only present if a DML statement was executed. Due to Node.js type limitations, the largest value shown will be 232 - 1, even if more rows were affected. Larger values will wrap. + * - ``warning`` + - Object + - .. _execmanywarning: + + This property provides an :ref:`error ` object that gives information about any database warnings (such as PL/SQL compilation warnings) that were generated during the last call to :meth:`connection.executeMany()`. + + See :ref:`plsqlcompwarnings` for more information. + + .. versionadded:: 6.3 .. method:: connection.getDbObjectClass() diff --git a/doc/src/release_notes.rst b/doc/src/release_notes.rst index 12ffa8d65..5bf9854dd 100644 --- a/doc/src/release_notes.rst +++ b/doc/src/release_notes.rst @@ -13,12 +13,16 @@ node-oracledb `v6.3.0 ` property to the + :ref:`result ` object for database warnings (such as PL/SQL + compilation warnings) that are generated by calls to + :meth:`connection.execute()`. Also, added the + :ref:`warning ` property to the + :ref:`result ` object of + :meth:`connection.executeMany()`. + +#) Added a :attr:`connection.warning` property for warnings (such as the + password being in the grace period) that are generated during connection. #) VARCHAR2 and LOB columns which contain JSON, and have the "IS JSON" check constraint enabled, can now be fetched in the same way as columns of type diff --git a/doc/src/user_guide/migrate.rst b/doc/src/user_guide/migrate.rst index 797442272..cc3839b7b 100644 --- a/doc/src/user_guide/migrate.rst +++ b/doc/src/user_guide/migrate.rst @@ -4,6 +4,65 @@ Upgrading to the Latest node-oracledb Releases ********************************************** +.. _upgradev62v63: + +Upgrading from node-oracledb 6.2 to 6.3 +======================================= + +- Review the :ref:`releasenotes` and take advantage of new features. + +- Using the new :ref:`warning ` property of the + :ref:`result object ` in :meth:`connection.execute()`, your + application can manually check for database warnings such as + :ref:`plsqlcompwarnings`. Also, you can use the new + :ref:`warning ` property in the + :ref:`result object ` of + :meth:`connection.executeMany()` to check for similar warnings. + +- The new :attr:`connection.warning` property can be used to check for + warnings that are generated during connection such as the password being in + the grace period. + +- By setting the new :attr:`oracledb.future.oldJsonColumnAsObj` property to + *true*, you can fetch the VARCHAR2 and LOB columns which contain JSON in the + same way as :ref:`columns of type JSON `. See + :ref:`json12ctype` for more information. In a future version of + node-oracledb, the setting of this attribute will no longer be required + since this will become the default behavior. + +- With the new :ref:`oracledb.DB_TYPE_XMLTYPE ` + constant, you can now represent data of type ``SYS.XMLTYPE`` in the + ``fetchType`` and ``dbType`` :ref:`metadata ` information + attributes. + +- node-oracledb now supports using Azure and Oracle Cloud Infrastructure (OCI) + Software Development Kits (SDKs) to generate + :ref:`authentication tokens `. + +- With the new connection properties :attr:`connection.dbDomain`, + :attr:`connection.dbName`, :attr:`connection.maxOpenCursors`, + :attr:`connection.serviceName` and :attr:`connection.transactionInProgress`, + you can identify the database domain name, database instance name, maximum + number of cursors that can be opened per connection, database service name, + and status of any ongoing transactions on the connection respectively. + +- The new :ref:`metadata ` information attribute ``isJson`` + indicates whether the fetched column contains JSON data. + +- The new :ref:`metadata ` information attributes + ``annotations``, ``domainName``, and ``domainSchema`` identifies the + `annotations `__ object, the name of the + `SQL domain `_, and the schema name of the + `SQL domain `__ associated with the fetched + column. Annotations and SQL domains are supported from Oracle Database 23c + onwards. For node-oracledb Thick mode, Oracle Client 23c is also required. + +- In node-oracledb Thin mode, ``SYS.XMLTYPE`` data can now be + :ref:`fetched as strings `. + .. _upgradev61v62: Upgrading from node-oracledb 6.1 to 6.2 diff --git a/doc/src/user_guide/plsql_execution.rst b/doc/src/user_guide/plsql_execution.rst index f0f463bd1..956779f70 100644 --- a/doc/src/user_guide/plsql_execution.rst +++ b/doc/src/user_guide/plsql_execution.rst @@ -446,18 +446,27 @@ tree/main/examples/plsqlproc.js>`__ and `plsqlfunc.js PL/SQL Compilation Warnings --------------------------- -When creating PL/SQL procedures and functions in node-oracledb, -compilation warnings must be manually checked for. This can be done by -querying ``USER_ERRORS`` like: +When creating PL/SQL procedures and functions (or creating types) in +node-oracledb using SQL statements, the statement might succeed without +throwing an error, but there may be additional informational messages. (These +messages are sometimes known in Oracle as "success with info" messages). Your +application can manually check for these messages using the +:ref:`warning ` property of the +:ref:`result object ` in :meth:`connection.execute()` or +:meth:`connection.executemany()`. A subsequent query from a table like +``USER_ERRORS`` will show more details. For example: .. code-block:: javascript - await connection.execute( + const result = await connection.execute( `CREATE OR REPLACE PROCEDURE badproc AS BEGIN INVALID END;`); + if (result.warning && result.warning.code == "NJS-700") + console.log(result.warning.message) + const r = await connection.execute( `SELECT line, position, text FROM user_errors @@ -471,8 +480,20 @@ querying ``USER_ERRORS`` like: console.error('at line', r.rows[0].LINE, 'position', r.rows[0].POSITION); } -Output is like:: +In node-oracledb Thin mode, the output would be:: + + NJS-700: creation succeeded with compilation errors + PLS-00103: Encountered the symbol "END" when expecting one of the following: + + := . ( @ % ; + The symbol ";" was substituted for "END" to continue. + + at line 4 position 8 + +In node-oracledb Thick mode, the output would be:: + NJS-700: creation succeeded with compilation errors + ORA-24344: success with compilation error PLS-00103: Encountered the symbol "END" when expecting one of the following: := . ( @ % ; diff --git a/test/dbObject4.js b/test/dbObject4.js index 03b628d18..f0ba8c1ef 100644 --- a/test/dbObject4.js +++ b/test/dbObject4.js @@ -37,7 +37,7 @@ const dbConfig = require('./dbconfig.js'); const testsUtil = require('./testsUtil.js'); describe('203. dbObject4.js', () => { - let conn; + let conn, testCount = 0; const TYPE = 'NODB_TYP_OBJ_4'; const TABLE = 'NODB_TAB_OBJ4'; @@ -106,7 +106,13 @@ describe('203. dbObject4.js', () => { await conn.close(); }); // after() - it('203.1 insert an object with LTZ type attribute', async () => { + it('203.1 insert an object with LTZ type attribute', async function() { + /* + * The Oracle Instant Client version should be 19.20 or greater as there is a + * bug in setting the timezone with the lower Oracle Instant Client versions. + */ + const isRunnable = await testsUtil.checkPrerequisites(1920000000, undefined); + if (!isRunnable) this.skip(); const seq = 101; let sql = `INSERT INTO ${TABLE} VALUES (:1, :2)`; @@ -129,6 +135,7 @@ describe('203. dbObject4.js', () => { assert.strictEqual(result.rows[0][1]['ENTRY'].getTime(), date1.getTime()); assert.strictEqual(result.rows[0][1]['EXIT'].getTime(), date2.getTime()); assert.strictEqual(result.rows[0][0], seq); + testCount++; }); // 203.1 it('203.2 insert null value for LTZ type attribute', async () => { @@ -152,6 +159,7 @@ describe('203. dbObject4.js', () => { assert.strictEqual(result.rows[0][1]['ENTRY'], null); assert.strictEqual(result.rows[0][1]['EXIT'], null); assert.strictEqual(result.rows[0][0], seq); + testCount++; }); // 203.2 it('203.3 insert undefined value for LTZ type attribute', async () => { @@ -175,6 +183,7 @@ describe('203. dbObject4.js', () => { assert.strictEqual(result.rows[0][1]['ENTRY'], null); assert.strictEqual(result.rows[0][1]['EXIT'], null); assert.strictEqual(result.rows[0][0], seq); + testCount++; }); // 203.3 it('203.4 insert an empty JSON', async () => { @@ -193,6 +202,7 @@ describe('203. dbObject4.js', () => { assert.strictEqual(result.rows[0][1]['ENTRY'], null); assert.strictEqual(result.rows[0][1]['EXIT'], null); + testCount++; }); // 203.4 it('203.5 call procedure with 2 OUT binds of DbObject', async function() { @@ -207,11 +217,11 @@ describe('203. dbObject4.js', () => { ); let resultSet = await result.outBinds.p_cur1.getRows(); - assert.equal(resultSet.length, 4); + assert.equal(resultSet.length, testCount); result.outBinds.p_cur1.close(); resultSet = await result.outBinds.p_cur2.getRows(); - assert.equal(resultSet.length, 4); + assert.equal(resultSet.length, testCount); result.outBinds.p_cur2.close(); }); // 203.5; diff --git a/test/passwordExpiryWarning.js b/test/passwordExpiryWarning.js new file mode 100644 index 000000000..d5314ec24 --- /dev/null +++ b/test/passwordExpiryWarning.js @@ -0,0 +1,272 @@ +/* Copyright (c) 2023, Oracle and/or its affiliates. */ + +/****************************************************************************** + * + * This software is dual-licensed to you under the Universal Permissive License + * (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License + * 2.0 as shown at https://www.apache.org/licenses/LICENSE-2.0. You may choose + * either license. + * + * If you elect to accept the software under the Apache License, Version 2.0, + * the following applies: + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * NAME + * 292. passwordExpiryWarning.js + * + * DESCRIPTION + * Test cases related to handling of SUCCESS_WITH_INFO warnings when + * user password is about to expire. + * + *****************************************************************************/ +'use strict'; + +const oracledb = require('oracledb'); +const dbConfig = require('./dbconfig.js'); +const assert = require('assert'); +const testsUtil = require('./testsUtil.js'); + + +describe('292. passwordExpiryWarning.js', function() { + const userName = 'testUser292'; + const password = 'testUser292'; + const newPassword = 'testnew292'; + + const plsql = ` + BEGIN + DECLARE + e_user_missing EXCEPTION; + PRAGMA EXCEPTION_INIT(e_user_missing, -01918); + BEGIN + EXECUTE IMMEDIATE('DROP USER ${userName} CASCADE'); + EXCEPTION + WHEN e_user_missing + THEN NULL; + END; + EXECUTE IMMEDIATE('CREATE USER ${userName} IDENTIFIED BY ${password}'); + EXECUTE IMMEDIATE('GRANT CONNECT, RESOURCE, UNLIMITED TABLESPACE \n + TO ${userName}'); + EXECUTE IMMEDIATE('CREATE PROFILE SHORT_LIFE_PROFILE1 LIMIT \n + PASSWORD_LIFE_TIME 1/24/60/60 PASSWORD_GRACE_TIME 1/24/60'); + EXECUTE IMMEDIATE('ALTER USER ${userName} profile SHORT_LIFE_PROFILE1'); + END; + `; + + const dbaCredential = { + user: dbConfig.test.DBA_user, + password: dbConfig.test.DBA_password, + connectString: dbConfig.connectString, + privilege: oracledb.SYSDBA + }; + + before(async function() { + const connAsDBA = await oracledb.getConnection(dbaCredential); + await connAsDBA.execute(plsql); + await testsUtil.sleep(2000); + await connAsDBA.close(); + }); + + after(async function() { + const connAsDBA = await oracledb.getConnection(dbaCredential); + await connAsDBA.execute (`ALTER USER ${userName} PROFILE DEFAULT`); + await connAsDBA.execute (`DROP PROFILE SHORT_LIFE_PROFILE1`); + await connAsDBA.execute(`DROP USER ${userName} CASCADE`); + await connAsDBA.close(); + }); + + + it('292.1 password expiry warning', async () => { + const credentials = { + user: userName, + password: password, + connectString: dbConfig.connectString + }; + + const isDB23c = await testsUtil.checkPrerequisites(undefined, 2300000000); + const conn = await oracledb.getConnection(credentials); + if (isDB23c) { + assert.strictEqual(conn.warning.code, 'ORA-28098'); + assert.strictEqual(conn.warning.errorNum, 28098); + } else { + assert.strictEqual(conn.warning.code, 'ORA-28002'); + assert.strictEqual(conn.warning.errorNum, 28002); + } + await conn.close(); + }); // 292.1 + + it('292.2 password expiry warning on a homogeneous pool', async () => { + const credentials = { + user: userName, + password: password, + connectString: dbConfig.connectString, + poolMin: 10, + poolMax: 50, + poolIncrement: 10, + poolTimeout: 60, + homogeneous: true + }; + const isDB23c = await testsUtil.checkPrerequisites(undefined, 2300000000); + const pool = await oracledb.createPool(credentials); + const conn = await pool.getConnection(); + await testsUtil.sleep(1000); + if (isDB23c) { + assert.strictEqual(conn.warning.message.startsWith("ORA-28098:"), true); + } else { + assert.strictEqual(conn.warning.message.startsWith("ORA-28002:"), true); + } + await conn.close(); + await pool.close(0); + }); // 292.2 + + it('292.3 password expiry warning on a heterogeneous pool', async function() { + if (oracledb.thin) { + this.skip(); + } + const credentials = { + user: userName, + password: password, + connectString: dbConfig.connectString, + poolMin: 10, + poolMax: 50, + poolIncrement: 10, + poolTimeout: 60, + homogeneous: false + }; + const isDB23c = await testsUtil.checkPrerequisites(undefined, 2300000000); + const pool = await oracledb.createPool(credentials); + const conn = await pool.getConnection({ + user: userName, + password: password + }); + if (isDB23c) { + assert.strictEqual(conn.warning.message.startsWith("ORA-28098:"), true); + } else { + assert.strictEqual(conn.warning.message.startsWith("ORA-28002:"), true); + } + await conn.close(); + await pool.close(0); + }); // 292.3 + + it('292.4 with poolMin=0 with regular user and password', async function() { + const credentials = { + user: dbConfig.user, + password: dbConfig.password, + connectString: dbConfig.connectString, + poolMin: 0, + poolMax: 50, + poolIncrement: 10, + poolTimeout: 60, + homogeneous: true + }; + + const pool = await oracledb.createPool(credentials); + const conn = await pool.getConnection(); + assert.strictEqual(conn.warning, undefined); + + await conn.close(); + await pool.close(); + }); //292.4 + + + it('292.5 with poolMin=0 with password in grace time', async function() { + const credentials = { + user: userName, + password: password, + connectString: dbConfig.connectString, + poolMin: 0, + poolMax: 5, + poolIncrement: 1, + poolTimeout: 60, + homogeneous: true + }; + + const isDB23c = await testsUtil.checkPrerequisites(undefined, 2300000000); + const pool = await oracledb.createPool(credentials); + const conn = await pool.getConnection(); + if (isDB23c) { + assert.strictEqual(conn.warning.code, 'ORA-28098'); + } else { + assert.strictEqual(conn.warning.code, 'ORA-28002'); + } + + await conn.close(); + + // Check that the warning is cleared on the next connection + const conn2 = await pool.getConnection(); + assert.strictEqual(conn2.warning, undefined); + await conn2.close(); + + await pool.close(); + }); // 292.5 + + it('292.6 with poolMin=1 with password in grace time', async function() { + const credentials = { + user: userName, + password: password, + connectString: dbConfig.connectString, + poolMin: 1, + poolMax: 5, + poolIncrement: 1, + poolTimeout: 60, + homogeneous: true + }; + + const isDB23c = await testsUtil.checkPrerequisites(undefined, 2300000000); + const pool = await oracledb.createPool(credentials); + const conn = await pool.getConnection(); + if (isDB23c) { + assert.strictEqual(conn.warning.code, 'ORA-28098'); + } else { + assert.strictEqual(conn.warning.code, 'ORA-28002'); + } + + await conn.close(); + + // Check that the warning is cleared on the next connection + const conn2 = await pool.getConnection(); + assert.strictEqual(conn2.warning, undefined); + await conn2.close(); + + await pool.close(); + }); // 292.6 + + it('292.7 no warning after password change on new connection', async () => { + const credentials = { + user: userName, + password: password, + connectString: dbConfig.connectString + }; + const newCredentials = { + user: userName, + password: newPassword, + connectString: dbConfig.connectString + }; + + const isDB23c = await testsUtil.checkPrerequisites(undefined, 2300000000); + const conn = await oracledb.getConnection(credentials); + if (isDB23c) { + assert.strictEqual(conn.warning.code, 'ORA-28098'); + assert.strictEqual(conn.warning.errorNum, 28098); + } else { + assert.strictEqual(conn.warning.code, 'ORA-28002'); + assert.strictEqual(conn.warning.errorNum, 28002); + } + await conn.changePassword(userName, password, newPassword); + const conn1 = await oracledb.getConnection(newCredentials); + assert.strictEqual(conn1.warning, undefined); + await conn.close(); + await conn1.close(); + }); // 292.7 + +}); diff --git a/test/plsqlWarnings.js b/test/plsqlWarnings.js new file mode 100644 index 000000000..221ac6623 --- /dev/null +++ b/test/plsqlWarnings.js @@ -0,0 +1,77 @@ +/* Copyright (c) 2023, Oracle and/or its affiliates. */ + +/****************************************************************************** + * + * This software is dual-licensed to you under the Universal Permissive License + * (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License + * 2.0 as shown at https://www.apache.org/licenses/LICENSE-2.0. You may choose + * either license. + * + * If you elect to accept the software under the Apache License, Version 2.0, + * the following applies: + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * NAME + * 293. plsqlWarning.js + * + * DESCRIPTION + * Test cases related to handling of SUCCESS_WITH_INFO warnings when + * compile/execute PL/SQL procedures + * + *****************************************************************************/ +'use strict'; + +const oracledb = require('oracledb'); +const dbConfig = require('./dbconfig.js'); +const assert = require('assert'); + + +describe('293. plsqlWarnings.js', function() { + it('293.1 Warning on executing PL/SQL procedure', async () => { + const plsql = ` + CREATE OR REPLACE PROCEDURE GETDATEPROC(OUTTIME OUT TIMESTAMP) AS + BEGIN + SELECT CURRENT_TIME INTO :OUTTIME FROM DUAL; + END; + `; + + const conn = await oracledb.getConnection(dbConfig); + const result = await conn.execute(plsql); + assert.strictEqual(result.warning.message.startsWith("NJS-700:"), true); + + // cleanup + await conn.execute(`DROP PROCEDURE GETDATEPROC`); + await conn.close(); + }); // 293.1 + + // GH issue #823: https://github.com/oracle/node-oracledb/issues/823 + it('293.2 Warning from PL/SQL query on a non-existing table', async () => { + const plsql = ` + create or replace procedure test293_2 as + l_number number; + begin + select 1 into l_number from table_that_does_not_exist; + end; + `; + + const conn = await oracledb.getConnection(dbConfig); + const result = await conn.execute(plsql); + assert.strictEqual(result.warning.message.startsWith("NJS-700:"), true); + + // cleanup + await conn.execute(`DROP PROCEDURE test293_2`); + await conn.close(); + }); // 293.2 + +}); diff --git a/test/sodaOpLock.js b/test/sodaOpLock.js index eac5e903a..346c4c7b7 100644 --- a/test/sodaOpLock.js +++ b/test/sodaOpLock.js @@ -133,7 +133,6 @@ describe('287. sodaOpLock.js', () => { // Lock all documents const docs = await coll.find().lock().getDocuments(); - await docs.forEach(function(element) { const content = element.getContent(); assert.strictEqual(content.name, myContent.name); @@ -147,6 +146,7 @@ describe('287. sodaOpLock.js', () => { assert.strictEqual(res.dropped, true); }); // 287.2 + it('287.3 lock on fetching multiple documents', async () => { const sd = conn.getSodaDatabase(); const collectionName = 'soda_lock_test_287_3'; @@ -222,12 +222,17 @@ describe('287. sodaOpLock.js', () => { }) ); + await conn.commit(); + await assert.rejects( async () => await collection.find() .lock().filter({ "office": {"$like": "Shenzhen"} }) .count(), /ORA-40821:/ //ORA-40821: LOCK attribute cannot be set for count operation ); + + const res = await collection.drop(); + assert.strictEqual(res.dropped, true); }); // 287.5 it('287.6 lock on key()', async function() { @@ -306,11 +311,14 @@ describe('287. sodaOpLock.js', () => { }) ); + await conn.commit(); // Fetch back await assert.rejects( async () => await collection.find().lock().count(), /ORA-40821:/ //ORA-40821: LOCK attribute cannot be set for count operation ); + const res = await collection.drop(); + assert.strictEqual(res.dropped, true); }); // 287.8 it('287.9 lock on keys().count()', async () => { @@ -330,6 +338,9 @@ describe('287. sodaOpLock.js', () => { async () => await collection.find().lock().keys(keysToCount).count(), /ORA-40821:/ //ORA-40821: LOCK attribute cannot be set for count operation ); + await conn.commit(); + const res = await collection.drop(); + assert.strictEqual(res.dropped, true); }); // 287.9 it('287.10 lock on getCursor()', async () => { @@ -377,13 +388,15 @@ describe('287. sodaOpLock.js', () => { return collection.insertOne(content); }) ); - + await conn.commit(); // Fetch back const numberToSkip = 3; await assert.rejects( async () => await collection.find().lock().skip(numberToSkip).getCursor(), /ORA-40820:/ //ORA-40820: Cannot set LOCK attribute on the operation if SKIP or LIMIT attributes are set ); + const res = await collection.drop(); + assert.strictEqual(res.dropped, true); }); // 287.11 it('287.12 lock on getDocuments()', async () => { @@ -468,12 +481,14 @@ describe('287. sodaOpLock.js', () => { return collection.insertOne(content); }) ); - + await conn.commit(); // Fetch back const limitNumbers = 3; await assert.rejects( async () => await collection.find().lock().limit(limitNumbers).getCursor(), /ORA-40820:/ //ORA-40820: Cannot set LOCK attribute on the operation if SKIP or LIMIT attributes are set ); + const res = await collection.drop(); + assert.strictEqual(res.dropped, true); }); // 287.15 }); diff --git a/test/testsUtil.js b/test/testsUtil.js index 688f89a32..b28d13e22 100644 --- a/test/testsUtil.js +++ b/test/testsUtil.js @@ -194,6 +194,9 @@ testsUtil.isSodaRunnable = async function() { if ((clientVersion >= 1909000000) && (serverVersion < 1909000000)) return false; + // Using JSON type collections in SODA requires same or higher Oracle Client versions + if (clientVersion < serverVersion) return false; + const sodaRole = await sodaUtil.isSodaRoleGranted(); if (!sodaRole) return false;