diff --git a/binding.gyp b/binding.gyp index a6e6553b..541fd573 100644 --- a/binding.gyp +++ b/binding.gyp @@ -11,7 +11,6 @@ "src/njsTokenCallback.c", "src/njsConnection.c", "src/njsDbObject.c", - "src/njsErrors.c", "src/njsJsonBuffer.c", "src/njsLob.c", "src/njsModule.c", diff --git a/lib/connection.js b/lib/connection.js index 52395370..96bed2ad 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -40,6 +40,11 @@ const util = require('util'); const constants = require('./constants.js'); const settings = require('./settings.js'); +// global mapping of subscriptions; these cannot be tied to a particular +// connection or pool since subscriptions can be created with one connection +// and destroyed with another! +const _subscriptions = new Map(); + // define class class Connection extends EventEmitter { @@ -834,6 +839,7 @@ class Connection extends EventEmitter { set action(value) { errors.assertPropValue(typeof value === 'string', "action"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setAction(value); } @@ -844,6 +850,7 @@ class Connection extends EventEmitter { //--------------------------------------------------------------------------- async breakExecution() { errors.assertArgCount(arguments, 0, 0); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.breakExecution(); } @@ -853,12 +860,15 @@ class Connection extends EventEmitter { // Property for round-trip timeouts. //--------------------------------------------------------------------------- get callTimeout() { - return this._impl.getCallTimeout(); + if (this._impl) + return this._impl.getCallTimeout(); + return undefined; } set callTimeout(value) { errors.assertPropValue(Number.isInteger(value) && value >= 0, "callTimeout"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setCallTimeout(value); } @@ -872,6 +882,7 @@ class Connection extends EventEmitter { errors.assertParamValue(typeof user === 'string', 1); errors.assertParamValue(typeof password === 'string', 2); errors.assertParamValue(typeof newPassword === 'string', 3); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.changePassword(user, password, newPassword); } @@ -886,6 +897,7 @@ class Connection extends EventEmitter { set clientId(value) { errors.assertPropValue(typeof value === 'string', "clientId"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setClientId(value); } @@ -900,6 +912,7 @@ class Connection extends EventEmitter { set clientInfo(value) { errors.assertPropValue(typeof value === 'string', "clientInfo"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setClientInfo(value); } @@ -915,13 +928,9 @@ class Connection extends EventEmitter { if (arguments.length == 1) { errors.assertParamValue(nodbUtil.isObject(a1), 1); options = a1; + errors.assertParamPropBool(options, 1, "drop"); } - - // If already in the process of closing, throw an error instead of doing - // a roundtrip - if (this._closing) { - errors.throwErr(errors.ERR_INVALID_CONNECTION); - } + errors.assert(this._impl && !this._closing, errors.ERR_INVALID_CONNECTION); this._closing = true; try { @@ -930,6 +939,7 @@ class Connection extends EventEmitter { this._closing = false; } + delete this._impl; this._dbObjectClasses.clear(); this.emit('_afterConnClose'); } @@ -941,6 +951,7 @@ class Connection extends EventEmitter { //--------------------------------------------------------------------------- async commit() { errors.assertArgCount(arguments, 0, 0); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.commit(); } @@ -954,6 +965,7 @@ class Connection extends EventEmitter { errors.assertParamValue(type === constants.DB_TYPE_CLOB || type === constants.DB_TYPE_BLOB || type === constants.DB_TYPE_NCLOB, 1); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); const lob = new Lob(); lob._setup(await this._impl.createLob(type), false); return lob; @@ -965,11 +977,14 @@ class Connection extends EventEmitter { // Property for identifying the current schema to use in the database. //--------------------------------------------------------------------------- get currentSchema() { - return this._impl.getCurrentSchema(); + if (this._impl) + return this._impl.getCurrentSchema(); + return undefined; } set currentSchema(value) { errors.assertPropValue(typeof value === 'string', "currentSchema"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setCurrentSchema(value); } @@ -984,6 +999,7 @@ class Connection extends EventEmitter { set dbOp(value) { errors.assertPropValue(typeof value === 'string', "dbOp"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setDbOp(value); } @@ -998,6 +1014,7 @@ class Connection extends EventEmitter { set ecid(value) { errors.assertPropValue(typeof value === 'string', "ecid"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setECID(value); } @@ -1021,10 +1038,17 @@ class Connection extends EventEmitter { options = this._verifyExecOpts(a3, false); } this._addDefaultsToExecOpts(options); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); // perform actual execute - const result = await this._impl.execute(sql, numIters, binds, options, - false); + let result; + try { + result = await this._impl.execute(sql, numIters, binds, options, false); + } catch (err) { + if (err.errorNum === 1406) + errors.throwErr(errors.ERR_INSUFFICIENT_BUFFER_FOR_BINDS); + throw err; + } // process queries; if a result set is not desired, fetch all of the rows // from the result set and then destroy the result set @@ -1097,6 +1121,7 @@ class Connection extends EventEmitter { binds = await this._processExecuteManyBinds(bindsOrNumIters, options.bindDefs); } + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); const result = await this._impl.execute(sql, numIters, binds, options, true); @@ -1120,11 +1145,14 @@ class Connection extends EventEmitter { // Property for identifying the external name to use in TPC logging. //--------------------------------------------------------------------------- get externalName() { - return this._impl.getExternalName(); + if (this._impl) + return this._impl.getExternalName(); + return undefined; } set externalName(value) { errors.assertPropValue(typeof value === 'string', "externalName"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setExternalName(value); } @@ -1138,6 +1166,7 @@ class Connection extends EventEmitter { async getDbObjectClass(name) { errors.assertArgCount(arguments, 1, 1); errors.assertParamValue(typeof name === 'string', 1); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); return await this._getDbObjectClassForName(name); } @@ -1155,6 +1184,7 @@ class Connection extends EventEmitter { errors.assertParamValue(nodbUtil.isObject(a2), 2); options = {...a2}; } + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); const queue = new AqQueue(); await queue.create(this, name, options); return queue; @@ -1168,6 +1198,7 @@ class Connection extends EventEmitter { //--------------------------------------------------------------------------- getSodaDatabase() { errors.assertArgCount(arguments, 0, 0); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); const sodaDb = new SodaDatabase(); sodaDb._impl = this._impl.getSodaDatabase(); return sodaDb; @@ -1181,6 +1212,7 @@ class Connection extends EventEmitter { async getStatementInfo(sql) { errors.assertArgCount(arguments, 1, 1); errors.assertParamValue(typeof sql === 'string', 1); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); return (await this._impl.getStatementInfo(sql)); } @@ -1190,11 +1222,14 @@ class Connection extends EventEmitter { // Property for identifying the internal name to use in TPC logging. //--------------------------------------------------------------------------- get internalName() { - return this._impl.getInternalName(); + if (this._impl) + return this._impl.getInternalName(); + return undefined; } set internalName(value) { errors.assertPropValue(typeof value === 'string', "internalName"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setInternalName(value); } @@ -1205,7 +1240,8 @@ class Connection extends EventEmitter { // false, the caller should close the connection. // --------------------------------------------------------------------------- isHealthy() { - return (!this._closing && this._impl.isHealthy()); + return (this._impl !== undefined && !this._closing && + this._impl.isHealthy()); } //--------------------------------------------------------------------------- @@ -1219,6 +1255,7 @@ class Connection extends EventEmitter { set module(value) { errors.assertPropValue(typeof value === 'string', "module"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setModule(value); } @@ -1228,7 +1265,9 @@ class Connection extends EventEmitter { // Returns an integer identifying the Oracle Server version. //--------------------------------------------------------------------------- get oracleServerVersion() { - return this._impl.getOracleServerVersion(); + if (this._impl) + return this._impl.getOracleServerVersion(); + return undefined; } //--------------------------------------------------------------------------- @@ -1237,7 +1276,9 @@ class Connection extends EventEmitter { // Returns a string identifying the Oracle Server version. //--------------------------------------------------------------------------- get oracleServerVersionString() { - return this._impl.getOracleServerVersionString(); + if (this._impl) + return this._impl.getOracleServerVersionString(); + return undefined; } //--------------------------------------------------------------------------- @@ -1247,6 +1288,7 @@ class Connection extends EventEmitter { //--------------------------------------------------------------------------- async ping() { errors.assertArgCount(arguments, 0, 0); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.ping(); } @@ -1293,6 +1335,7 @@ class Connection extends EventEmitter { //--------------------------------------------------------------------------- async rollback() { errors.assertArgCount(arguments, 0, 0); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.rollback(); } @@ -1308,6 +1351,7 @@ class Connection extends EventEmitter { errors.assertParamValue(typeof mode === 'number', 1); mode = a1; } + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.shutdown(mode); } @@ -1317,15 +1361,19 @@ class Connection extends EventEmitter { // Starts up the database instance. //--------------------------------------------------------------------------- async startup(a1) { - let opts = {}; + let options = {}; errors.assertArgCount(arguments, 0, 1); if (arguments.length == 1) { - errors.assertParamValue(typeof opts === 'object', 1); - opts = a1; + errors.assertParamValue(typeof options === 'object', 1); + options = a1; + errors.assertParamPropBool(options, 1, "force"); + errors.assertParamPropBool(options, 1, "restrict"); + errors.assertParamPropString(options, 1, "pfile"); } + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); - await this._impl.startup(opts); + await this._impl.startup(options); } //--------------------------------------------------------------------------- @@ -1334,12 +1382,15 @@ class Connection extends EventEmitter { // Property for statement cache size. //--------------------------------------------------------------------------- get stmtCacheSize() { - return this._impl.getStmtCacheSize(); + if (this._impl) + return this._impl.getStmtCacheSize(); + return undefined; } set stmtCacheSize(value) { errors.assertPropValue(Number.isInteger(value) && value >= 0, "stmtCacheSize"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setStmtCacheSize(value); } @@ -1353,7 +1404,43 @@ class Connection extends EventEmitter { errors.assertArgCount(arguments, 2, 2); errors.assertParamValue(typeof name === 'string', 1); errors.assertParamValue(nodbUtil.isObject(options), 2); - await this._impl.subscribe(name, options); + options = {...options}; + errors.assertParamPropUnsignedInt(options, 2, "namespace"); + if (options.namespace === undefined) + options.namespace = constants.SUBSCR_NAMESPACE_DBCHANGE; + errors.assertParamPropString(options, 2, "ipAddress"); + errors.assertParamPropUnsignedInt(options, 2, "port"); + errors.assertParamPropUnsignedInt(options, 2, "timeout"); + errors.assertParamPropUnsignedInt(options, 2, "operations"); + errors.assertParamPropUnsignedInt(options, 2, "qos"); + errors.assertParamPropUnsignedInt(options, 2, "groupingClass"); + errors.assertParamPropUnsignedInt(options, 2, "groupingValue"); + errors.assertParamPropUnsignedInt(options, 2, "groupingType"); + errors.assertParamPropBool(options, 2, "clientInitiated"); + errors.assertParamPropFunction(options, 2, "callback"); + errors.assert(options.callback, errors.ERR_MISSING_SUBSCR_CALLBACK); + if (options.namespace === constants.SUBSCR_NAMESPACE_DBCHANGE) { + errors.assertParamPropString(options, 2, "sql"); + errors.assert(options.sql && options.sql.length > 0, + errors.ERR_MISSING_SUBSCR_SQL); + if (options.binds !== undefined) { + options.binds = await this._processExecuteBinds(options.binds); + } + } + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); + + const inSubscr = _subscriptions.get(name); + let outValue = await this._impl.subscribe(inSubscr, options); + let subscription; + if (options.namespace === constants.SUBSCR_NAMESPACE_DBCHANGE) { + subscription = outValue.subscription; + delete outValue.subscription; + } else { + subscription = outValue; + outValue = undefined; + } + _subscriptions.set(name, subscription); + return outValue; } //--------------------------------------------------------------------------- @@ -1362,11 +1449,14 @@ class Connection extends EventEmitter { // Property for tag to associate with the connection. //--------------------------------------------------------------------------- get tag() { - return this._impl.getTag(); + if (this._impl) + return this._impl.getTag(); + return undefined; } set tag(value) { errors.assertPropValue(typeof value === 'string', "tag"); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); this._impl.setTag(value); } @@ -1390,6 +1480,7 @@ class Connection extends EventEmitter { } else { errors.assertParamValue(typeof flag === 'number', 2); } + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.tpcBegin(xid, flag, timeout); } @@ -1409,6 +1500,7 @@ class Connection extends EventEmitter { if (arguments.length >= 1) { errors.assertParamValue(nodbUtil.isXid(xid), 1); } + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.tpcCommit(xid, onePhase); } @@ -1429,6 +1521,7 @@ class Connection extends EventEmitter { if (arguments.length >= 1) { errors.assertParamValue(nodbUtil.isXid(xid), 1); } + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.tpcEnd(xid, flag); } @@ -1442,6 +1535,7 @@ class Connection extends EventEmitter { async tpcForget(xid) { errors.assertArgCount(arguments, 1, 1); errors.assertParamValue(nodbUtil.isXid(xid), 1); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.tpcForget(xid); } @@ -1456,6 +1550,7 @@ class Connection extends EventEmitter { if (arguments.length >= 1) { errors.assertParamValue(nodbUtil.isXid(xid), 1); } + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); return await this._impl.tpcPrepare(xid); } @@ -1505,6 +1600,7 @@ class Connection extends EventEmitter { if (arguments.length == 1) { errors.assertParamValue(nodbUtil.isXid(xid), 1); } + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); await this._impl.tpcRollback(xid); } @@ -1517,7 +1613,10 @@ class Connection extends EventEmitter { async unsubscribe(name) { errors.assertArgCount(arguments, 1, 1); errors.assertParamValue(typeof name === 'string', 1); - await this._impl.unsubscribe(name); + errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); + errors.assert(_subscriptions.has(name), errors.ERR_INVALID_SUBSCR); + await this._impl.unsubscribe(_subscriptions.get(name)); + _subscriptions.delete(name); } } diff --git a/lib/errors.js b/lib/errors.js index 7e2c9376..29b219c4 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -119,6 +119,7 @@ messages.set(ERR_INVALID_PROPERTY_VALUE_IN_PARAM, 'invalid value for "%s" in parameter %d'); messages.set(ERR_INVALID_NUMBER_OF_PARAMETERS, 'invalid number of parameters'); +// used in C -- keep synchronized! messages.set(ERR_UNSUPPORTED_DATA_TYPE, 'unsupported data type %d in column %d'); messages.set(ERR_BIND_VALUE_AND_TYPE_MISMATCH, @@ -129,6 +130,7 @@ messages.set(ERR_INVALID_BIND_DIRECTION, 'invalid bind direction'); messages.set(ERR_NO_TYPE_FOR_CONVERSION, 'type was not specified for conversion'); +// used in C -- keep synchronized! messages.set(ERR_INSUFFICIENT_BUFFER_FOR_BINDS, 'buffer is too small for OUT binds'); messages.set(ERR_BUSY_RS, @@ -143,6 +145,7 @@ messages.set(ERR_INVALID_LOB, 'invalid Lob'); messages.set(ERR_BUSY_LOB, 'concurrent operations on LOB are not allowed'); +// used in C -- keep synchronized! messages.set(ERR_INSUFFICIENT_MEMORY, 'memory allocation failed'); messages.set(ERR_INVALID_TYPE_FOR_ARRAY_BIND, @@ -222,6 +225,7 @@ messages.set(ERR_QUEUE_MAX_EXCEEDED, 'connection request rejected. Pool queue length queueMax %d reached'); messages.set(ERR_CLIENT_LIB_ALREADY_INITIALIZED, 'Oracle Client library has already been initialized'); +// used in C -- keep synchronized! messages.set(ERR_UNSUPPORTED_DATA_TYPE_IN_JSON, 'unsupported data type %d in JSON value'); messages.set(ERR_CONVERT_TO_JSON_VALUE, @@ -277,6 +281,69 @@ function assertArgCount(args, minArgCount, maxArgCount) { ERR_INVALID_NUMBER_OF_PARAMETERS); } +//----------------------------------------------------------------------------- +// assertParamPropBool() +// +// Asserts that the property value of a parmeter is a boolean value (or +// undefined). +//----------------------------------------------------------------------------- +function assertParamPropBool(obj, parameterNum, propName) { + if (obj[propName] !== undefined) { + assertParamPropValue(typeof obj[propName] === 'boolean', parameterNum, + propName); + } +} + +//----------------------------------------------------------------------------- +// assertParamPropFunction() +// +// Asserts that the property value of a parmeter is a function (or undefined). +//----------------------------------------------------------------------------- +function assertParamPropFunction(obj, parameterNum, propName) { + if (obj[propName] !== undefined) { + assertParamPropValue(typeof obj[propName] === 'function', parameterNum, + propName); + } +} + +//----------------------------------------------------------------------------- +// assertParamPropInt() +// +// Asserts that the property value of a parmeter is an integer value (or +// undefined). +//----------------------------------------------------------------------------- +function assertParamPropInt(obj, parameterNum, propName) { + if (obj[propName] !== undefined) { + assertParamPropValue(Number.isInteger(obj[propName]), parameterNum, + propName); + } +} + +//----------------------------------------------------------------------------- +// assertParamPropUnsignedInt() +// +// Asserts that the property value of a parmeter is a positive integer value +// (or undefined). +//----------------------------------------------------------------------------- +function assertParamPropUnsignedInt(obj, parameterNum, propName) { + if (obj[propName] !== undefined) { + assertParamPropValue(Number.isInteger(obj[propName]) && obj[propName] >= 0, + parameterNum, propName); + } +} + +//----------------------------------------------------------------------------- +// assertParamPropString() +// +// Asserts that the property value of a parmeter is a function (or undefined). +//----------------------------------------------------------------------------- +function assertParamPropString(obj, parameterNum, propName) { + if (obj[propName] !== undefined) { + assertParamPropValue(typeof obj[propName] === 'string', parameterNum, + propName); + } +} + //----------------------------------------------------------------------------- // assertParamPropValue() // @@ -410,6 +477,11 @@ module.exports = { ERR_MISSING_FILE, assert, assertArgCount, + assertParamPropBool, + assertParamPropFunction, + assertParamPropInt, + assertParamPropString, + assertParamPropUnsignedInt, assertParamPropValue, assertParamValue, assertPropValue, diff --git a/lib/oracledb.js b/lib/oracledb.js index 016d04a5..80bfe2f7 100644 --- a/lib/oracledb.js +++ b/lib/oracledb.js @@ -522,17 +522,19 @@ function initOracleClient(arg1) { errors.assertArgCount(arguments, 0, 1); if (arg1 !== undefined) { errors.assertParamValue(nodbUtil.isObject(arg1), 1); - options = arg1; + options = {...arg1}; + errors.assertParamPropString(options, 1, "libDir"); + errors.assertParamPropString(options, 1, "configDir"); + errors.assertParamPropString(options, 1, "errorUrl"); + errors.assertParamPropString(options, 1, "driverName"); } if (_initOracleClientArgs === undefined) { - const adjustedOptions = Object.defineProperties({}, - Object.getOwnPropertyDescriptors(options)); if (options.driverName === undefined) - adjustedOptions.driverName = constants.DEFAULT_DRIVER_NAME; + options.driverName = constants.DEFAULT_DRIVER_NAME; if (options.errorUrl === undefined) - adjustedOptions.errorUrl = constants.DEFAULT_ERROR_URL; + options.errorUrl = constants.DEFAULT_ERROR_URL; try { - oracledbCLib.initOracleClient(adjustedOptions, impl, settings); + oracledbCLib.initOracleClient(options, impl, settings); } catch (err) { if (err.message.match(/DPI-1047/)) { err.message += "\n" + nodbUtil.getInstallHelp(); diff --git a/lib/pool.js b/lib/pool.js index a0823fde..4a422d06 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -638,26 +638,22 @@ class Pool extends EventEmitter { // check arguments errors.assertArgCount(arguments, 1, 1); errors.assertParamValue(nodbUtil.isObject(options)); + errors.assertParamPropUnsignedInt(options, 1, "queueMax"); + errors.assertParamPropUnsignedInt(options, 1, "queueTimeout"); + errors.assertParamPropBool(options, 1, "enableStatistics"); + errors.assertParamPropBool(options, 1, "resetStatistics"); + errors.assertParamPropUnsignedInt(options, 1, "poolMin"); + errors.assertParamPropUnsignedInt(options, 1, "poolMax"); + errors.assertParamPropUnsignedInt(options, 1, "poolMaxPerShard"); + errors.assertParamPropUnsignedInt(options, 1, "poolIncrement"); + errors.assertParamPropInt(options, 1, "poolPingInterval"); + errors.assertParamPropUnsignedInt(options, 1, "poolTimeout"); + errors.assertParamPropUnsignedInt(options, 1, "stmtCacheSize"); + errors.assertParamPropBool(options, 1, "sodaMetaDataCache"); // reconfiguration can happen only when status is OPEN this._checkPoolOpen(false); - if ((options.queueMax !== undefined) && - (typeof options.queueMax !== "number")) - errors.throwErr(errors.ERR_INVALID_PROPERTY_VALUE, "queueMax"); - - if ((options.queueTimeout !== undefined) && - (typeof options.queueTimeout !== "number")) - errors.throwErr(errors.ERR_INVALID_PROPERTY_VALUE, "queueTimeout"); - - if ((options.enableStatistics !== undefined) && - (typeof options.enableStatistics !== "boolean")) - errors.throwErr(errors.ERR_INVALID_PROPERTY_VALUE, "enableStatistics"); - - if ((options.resetStatistics !== undefined) && - (typeof options.resetStatistics != "boolean")) - errors.throwErr(errors.ERR_INVALID_PROPERTY_VALUE, "resetStatistics"); - this._status = constants.POOL_STATUS_RECONFIGURING; try { // poolMin/poolMax/poolIncrement/poolPingInterval/poolTimeout/ @@ -709,6 +705,8 @@ class Pool extends EventEmitter { async setAccessToken(options) { errors.assertArgCount(arguments, 1, 1); errors.assertParamValue(nodbUtil.isObject(options), 1); + errors.assertParamPropString(options, 1, "token"); + errors.assertParamPropString(options, 1, "privateKey"); await this._impl.setAccessToken(options); } diff --git a/lib/resultset.js b/lib/resultset.js index 675a0741..10499a66 100644 --- a/lib/resultset.js +++ b/lib/resultset.js @@ -80,6 +80,7 @@ class ResultSet { } finally { await this._impl.close(); + delete this._impl; } } @@ -220,7 +221,7 @@ class ResultSet { //--------------------------------------------------------------------------- async close() { errors.assertArgCount(arguments, 0, 0); - errors.assert(this._impl, errors.ERR_INVALID_RS); + errors.assert(this._impl && this._connection._impl, errors.ERR_INVALID_RS); if (this._convertedToStream) { errors.throwErr(errors.ERR_CANNOT_INVOKE_RS_METHODS); @@ -242,7 +243,7 @@ class ResultSet { //--------------------------------------------------------------------------- async getRow() { errors.assertArgCount(arguments, 0, 0); - errors.assert(this._impl, errors.ERR_INVALID_RS); + errors.assert(this._impl && this._connection._impl, errors.ERR_INVALID_RS); if (this._convertedToStream && !this._allowGetRowCall) { errors.throwErr(errors.ERR_CANNOT_INVOKE_RS_METHODS); @@ -272,7 +273,7 @@ class ResultSet { let rowsNeeded; errors.assertArgCount(arguments, 0, 1); - errors.assert(this._impl, errors.ERR_INVALID_RS); + errors.assert(this._impl && this._connection._impl, errors.ERR_INVALID_RS); if (arguments.length == 0) { numRows = 0; diff --git a/lib/sodaDatabase.js b/lib/sodaDatabase.js index ade0c21e..0a00b229 100644 --- a/lib/sodaDatabase.js +++ b/lib/sodaDatabase.js @@ -82,6 +82,8 @@ class SodaDatabase { if (arguments.length > 1) { errors.assertParamValue(nodbUtil.isObject(a2), 2); options = a2; + errors.assertParamPropString(options, 2, "key"); + errors.assertParamPropString(options, 2, "mediaType"); } if (typeof content === 'string') { @@ -107,6 +109,14 @@ class SodaDatabase { if (arguments.length == 1) { errors.assertParamValue(nodbUtil.isObject(a1), 1); options = a1; + if (options.startsWith !== undefined) { + errors.assertParamPropValue(typeof options.startsWith === 'string', 1, + "startsWith"); + } + if (options.limit !== undefined) { + errors.assertParamPropValue(Number.isInteger(options.limit), 1, + "limit"); + } } return await this._impl.getCollectionNames(options); } diff --git a/lib/sodaDocCursor.js b/lib/sodaDocCursor.js index e37256aa..34339d84 100644 --- a/lib/sodaDocCursor.js +++ b/lib/sodaDocCursor.js @@ -39,7 +39,9 @@ class SodaDocCursor { //-------------------------------------------------------------------------- async close() { errors.assertArgCount(arguments, 0, 0); + errors.assert(this._impl, errors.ERR_INVALID_SODA_DOC_CURSOR); await this._impl.close(); + delete this._impl; } //--------------------------------------------------------------------------- @@ -49,6 +51,7 @@ class SodaDocCursor { //--------------------------------------------------------------------------- async getNext() { errors.assertArgCount(arguments, 0, 0); + errors.assert(this._impl, errors.ERR_INVALID_SODA_DOC_CURSOR); const docImpl = await this._impl.getNext(); if (docImpl) { const doc = new SodaDocument(); diff --git a/lib/util.js b/lib/util.js index d9a12695..2ed963c1 100644 --- a/lib/util.js +++ b/lib/util.js @@ -237,10 +237,11 @@ function isSodaDocument(value) { } function isXid(value) { - return (isObject(value) && - (value.formatId !== undefined) && - (value.globalTransactionId !== undefined) && - (value.branchQualifier !== undefined)); + return (isObject(value) && Number.isInteger(value.formatId) && + (Buffer.isBuffer(value.globalTransactionId) || + typeof value.globalTransactionId === 'string') && + (Buffer.isBuffer(value.branchQualifier) || + typeof value.branchQualifier === 'string')); } function verifySodaDoc(content) { diff --git a/src/njsAqDeqOptions.c b/src/njsAqDeqOptions.c index 01785f9e..2083d41f 100644 --- a/src/njsAqDeqOptions.c +++ b/src/njsAqDeqOptions.c @@ -104,11 +104,11 @@ const njsClassDef njsClassDefAqDeqOptions = { // other methods used internally static bool njsAqDeqOptions_getTextAttribute(napi_env env, - njsModuleGlobals *globals, njsBaseInstance *instance, + njsModuleGlobals *globals, void *instance, int (*getter)(dpiDeqOptions*, const char **, uint32_t *), napi_value *returnValue); static bool njsAqDeqOptions_setTextAttribute(napi_env env, - njsModuleGlobals *globals, njsBaseInstance *instance, napi_value value, + njsModuleGlobals *globals, void *instance, napi_value value, int (*setter)(dpiDeqOptions*, const char *, uint32_t)); @@ -217,7 +217,7 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsAqDeqOptions_getNavigation, 0, NULL) // Get accessor of text properties. //----------------------------------------------------------------------------- static bool njsAqDeqOptions_getTextAttribute(napi_env env, - njsModuleGlobals *globals, njsBaseInstance *instance, + njsModuleGlobals *globals, void *instance, int (*getter)(dpiDeqOptions*, const char **, uint32_t *), napi_value *returnValue) { @@ -368,7 +368,7 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsAqDeqOptions_setNavigation, 1, NULL) // Set accessor of text properties. //----------------------------------------------------------------------------- static bool njsAqDeqOptions_setTextAttribute(napi_env env, - njsModuleGlobals *globals, njsBaseInstance *instance, napi_value value, + njsModuleGlobals *globals, void *instance, napi_value value, int (*setter)(dpiDeqOptions*, const char *, uint32_t)) { njsAqDeqOptions *options = (njsAqDeqOptions*) instance; diff --git a/src/njsAqMessage.c b/src/njsAqMessage.c index 20d5fc30..fad74573 100644 --- a/src/njsAqMessage.c +++ b/src/njsAqMessage.c @@ -93,8 +93,7 @@ bool njsAqMessage_createFromHandle(njsBaton *baton, dpiMsgProps *handle, // create new instance if (!njsUtils_genericNew(env, &njsClassDefAqMessage, - baton->globals->jsAqMessageConstructor, messageObj, - (njsBaseInstance**) &msg)) + baton->globals->jsAqMessageConstructor, messageObj, (void**) &msg)) return false; // perform some initializations diff --git a/src/njsAqQueue.c b/src/njsAqQueue.c index 9b4fd114..b2b494ed 100644 --- a/src/njsAqQueue.c +++ b/src/njsAqQueue.c @@ -89,7 +89,7 @@ bool njsAqQueue_setRecipients(njsBaton *baton, dpiMsgProps *handle, dpiMsgRecipient *recipients = malloc(sizeof(dpiMsgRecipient) * recipCount); if (!recipients) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); for (i = 0; i < recipCount; i++) { recipients[i].name = recipArr[i]; @@ -245,8 +245,7 @@ bool njsAqQueue_createFromHandle(njsBaton *baton, napi_env env, // create new instance if (!njsUtils_genericNew(env, &njsClassDefAqQueue, - baton->globals->jsAqQueueConstructor, queueObj, - (njsBaseInstance**) &queue)) + baton->globals->jsAqQueueConstructor, queueObj, (void**) &queue)) return false; // perform some initializations @@ -259,7 +258,7 @@ bool njsAqQueue_createFromHandle(njsBaton *baton, napi_env env, return njsUtils_throwErrorDPI(env, baton->globals); if (!njsUtils_genericNew(env, &njsClassDefAqDeqOptions, baton->globals->jsAqDeqOptionsConstructor, &deqOptionsObj, - (njsBaseInstance**) &deqOptions)) + (void**) &deqOptions)) return false; if (dpiDeqOptions_addRef(deqOptionsHandle) < 0) return njsUtils_throwErrorDPI(env, baton->globals); @@ -270,7 +269,7 @@ bool njsAqQueue_createFromHandle(njsBaton *baton, napi_env env, return njsUtils_throwErrorDPI(env, baton->globals); if (!njsUtils_genericNew(env, &njsClassDefAqEnqOptions, baton->globals->jsAqEnqOptionsConstructor, &enqOptionsObj, - (njsBaseInstance**) &enqOptions)) + (void**) &enqOptions)) return false; if (dpiEnqOptions_addRef(enqOptionsHandle) < 0) return njsUtils_throwErrorDPI(env, baton->globals); @@ -340,7 +339,7 @@ static bool njsAqQueue_deqManyAsync(njsBaton *baton) baton->msgProps = calloc(baton->numMsgProps, sizeof(dpiMsgProps*)); if (!baton->msgProps) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (dpiQueue_deqMany(queue->handle, &baton->numMsgProps, baton->msgProps) < 0) return njsBaton_setErrorDPI(baton); @@ -437,7 +436,7 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsAqQueue_enqMany, 1, NULL) &baton->numMsgProps)) baton->msgProps = calloc(baton->numMsgProps, sizeof(dpiMsgProps*)); if (!baton->msgProps) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); for (i = 0; i < baton->numMsgProps; i++) { NJS_CHECK_NAPI(env, napi_get_element(env, args[0], i, &message)) if (!njsAqQueue_createMessage(baton, queue, env, message, diff --git a/src/njsBaton.c b/src/njsBaton.c index 84cc4cea..013b9681 100644 --- a/src/njsBaton.c +++ b/src/njsBaton.c @@ -182,10 +182,6 @@ void njsBaton_free(njsBaton *baton, napi_env env) { uint32_t i; - // if this baton is considered the active baton, clear it - if (baton->callingInstance && baton == baton->callingInstance->activeBaton) - baton->callingInstance->activeBaton = NULL; - // free and clear strings NJS_FREE_AND_CLEAR(baton->sql); NJS_FREE_AND_CLEAR(baton->user); @@ -391,29 +387,6 @@ void njsBaton_freeShardingKeys(uint8_t *numShardingKeyColumns, } -//----------------------------------------------------------------------------- -// njsBaton_getBoolFromArg() -// Gets a boolean value from the specified JavaScript object property, if -// possible. If the given property is undefined, no error is set and the value -// is left untouched; otherwise, if the value is not a boolean, the error is -// set on the baton. -//----------------------------------------------------------------------------- -bool njsBaton_getBoolFromArg(njsBaton *baton, napi_env env, napi_value *args, - int argIndex, const char *propertyName, bool *result, bool *found) -{ - napi_value value; - - if (!njsBaton_getValueFromArg(baton, env, args, argIndex, propertyName, - napi_boolean, &value, found)) - return false; - if (!value) - return true; - NJS_CHECK_NAPI(env, napi_get_value_bool(env, value, result)) - - return true; -} - - //----------------------------------------------------------------------------- // njsBaton_getErrorInfo() // Get information on the error in preparation for invoking the callback. If @@ -476,7 +449,7 @@ bool njsBaton_getFetchInfoFromArg(njsBaton *baton, napi_env env, // allocate space for fetchInfo structures tempFetchInfo = calloc(*numFetchInfo, sizeof(njsFetchInfo)); if (!tempFetchInfo) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); *fetchInfo = tempFetchInfo; // process each key @@ -498,38 +471,7 @@ bool njsBaton_getFetchInfoFromArg(njsBaton *baton, napi_env env, //----------------------------------------------------------------------------- -// njsBaton_getIntFromArg() -// Gets an integer value from the specified JavaScript object property, if -// possible. If the given property is undefined, no error is set and the value -// is left untouched; otherwise, if the value is not a number, the error is set -// on the baton. -//----------------------------------------------------------------------------- -bool njsBaton_getIntFromArg(njsBaton *baton, napi_env env, napi_value *args, - int argIndex, const char *propertyName, int32_t *result, bool *found) -{ - double doubleValue; - napi_value value; - - // get the value from the object and verify it is a number - if (!njsBaton_getValueFromArg(baton, env, args, argIndex, propertyName, - napi_number, &value, found)) - return false; - if (!value) - return true; - NJS_CHECK_NAPI(env, napi_get_value_double(env, value, &doubleValue)) - - // if the value is not an integer or negative, return an error - *result = (int32_t) doubleValue; - if ((double) *result != doubleValue) - return njsBaton_setError(baton, errInvalidPropertyValueInParam, - propertyName, argIndex + 1); - - return true; -} - - -//----------------------------------------------------------------------------- -// njsBaton::GetNumOutBinds() +// njsBaton_getNumOutBinds() // Return the number of IN/OUT and OUT binds created by the baton. //----------------------------------------------------------------------------- uint32_t njsBaton_getNumOutBinds(njsBaton *baton) @@ -589,220 +531,6 @@ bool njsBaton_getSodaDocument(njsBaton *baton, njsSodaDatabase *db, } -//----------------------------------------------------------------------------- -// njsBaton_getStringFromArg() -// Gets a string value from the specified JavaScript object property, if -// possible. If the given property is undefined, no error is set and the value -// is left untouched; otherwise, if the value is not a string, the error is set -// on the baton. -//----------------------------------------------------------------------------- -bool njsBaton_getStringFromArg(njsBaton *baton, napi_env env, napi_value *args, - int argIndex, const char *propertyName, char **result, - size_t *resultLength, bool *found) -{ - if (!njsUtils_getStringFromArg(env, args, argIndex, propertyName, result, - resultLength, found, baton->error)) { - baton->hasError = true; - return false; - } - return true; -} - - -//----------------------------------------------------------------------------- -// njsBaton_getSubscription() -// Acquires the subscription stored with the given name. If it does not -// exist, it will either be created or an error will be noted on the baton. -//----------------------------------------------------------------------------- -bool njsBaton_getSubscription(njsBaton *baton, napi_env env, napi_value name, - bool unsubscribe) -{ - napi_value allSubscriptions, subscription; - napi_valuetype valueType; - - // get subscription object, if it exists - NJS_CHECK_NAPI(env, napi_get_reference_value(env, - baton->globals->jsSubscriptions, &allSubscriptions)) - NJS_CHECK_NAPI(env, napi_get_property(env, allSubscriptions, name, - &subscription)) - NJS_CHECK_NAPI(env, napi_typeof(env, subscription, &valueType)) - - // if it exists, get subscription data - if (valueType == napi_external) { - NJS_CHECK_NAPI(env, napi_get_value_external(env, subscription, - (void**) &baton->subscription)) - - // set an error if the subscription does not exist and it should not be - // created - } else if (unsubscribe) { - return njsBaton_setError(baton, errInvalidSubscription); - - // otherwise, create a new subscription and store it in the all - // subscriptions object - } else { - if (!njsSubscription_new(baton, env, &subscription, - &baton->subscription)) - return false; - NJS_CHECK_NAPI(env, napi_set_property(env, allSubscriptions, name, - subscription)) - } - - // if unsubscribing, remove subscription from all subscriptions and nothing - // further needs to be done - if (unsubscribe) { - NJS_CHECK_NAPI(env, napi_delete_property(env, allSubscriptions, name, - NULL)) - return true; - } - - // otherwise, store a reference to the subscription object on the baton - // to ensure that it does not go out of scope - NJS_CHECK_NAPI(env, napi_create_reference(env, subscription, 1, - &baton->jsSubscriptionRef)) - - return true; -} - - -//----------------------------------------------------------------------------- -// njsBaton_getUnsignedIntFromArg() -// Gets an unsigned integer value from the specified JavaScript object -// property, if possible. If the given property is undefined, no error is set -// and the value is left untouched; otherwise, if the value is not a number, -// the error is set on the baton. -//----------------------------------------------------------------------------- -bool njsBaton_getUnsignedIntFromArg(njsBaton *baton, napi_env env, - napi_value *args, int argIndex, const char *propertyName, - uint32_t *result, bool *found) -{ - double doubleValue; - napi_value value; - - // get the value from the object and verify it is a number - if (!njsBaton_getValueFromArg(baton, env, args, argIndex, propertyName, - napi_number, &value, found)) - return false; - if (!value) - return true; - NJS_CHECK_NAPI(env, napi_get_value_double(env, value, &doubleValue)) - - // if the value is not an integer or negative, return an error - *result = (uint32_t) doubleValue; - if (doubleValue < 0 || (double) *result != doubleValue) - return njsBaton_setError(baton, errInvalidPropertyValueInParam, - propertyName, argIndex + 1); - - return true; -} - - -//----------------------------------------------------------------------------- -// njsBaton_getValueFromArg() -// Gets the value from the specified JavaScript object property, if possible. -// If the given property is undefined, no error is set and the value is -// returned as NULL. If the value is null, a "value" error is set on the baton; -// otherwise, if the value is not the specified type, a "type" error is -// set on the baton. -//----------------------------------------------------------------------------- -bool njsBaton_getValueFromArg(njsBaton *baton, napi_env env, napi_value *args, - int argIndex, const char *propertyName, napi_valuetype expectedType, - napi_value *value, bool *found) -{ - if (!njsUtils_getValueFromArg(env, args, argIndex, propertyName, - expectedType, value, found, baton->error)) { - baton->hasError = true; - return false; - } - return true; -} - - -//----------------------------------------------------------------------------- -// njsBaton_getStrBufFromArg() -// To obtain a string or Buffer value from the given object based on the -// propertyName if exists. If the given property is undefined, no error is -// set and the value is left untouched; otherwise, if the value is not -// string/buffer the erroris set on the baton -//----------------------------------------------------------------------------- -bool njsBaton_getStrBufFromArg(njsBaton *baton, napi_env env, napi_value *args, - int argIndex, const char *propertyName, char **result, - size_t *resultLength, bool *found) -{ - napi_valuetype actualType; - napi_value value; - void *buf; - size_t bufLen; - - // initialize found, if applicable - if (found) - *found = false; - - // acquire the value and get its type - NJS_CHECK_NAPI(env, napi_get_named_property(env, args[argIndex], - propertyName, &value)) - NJS_CHECK_NAPI(env, napi_typeof(env, value, &actualType)) - - // a value of undefined is accepted (property not defined) - if (actualType == napi_undefined) { - return true; - } else if (actualType != napi_string && !njsUtils_isBuffer(env, value)) { - njsBaton_setError(baton, errInvalidPropertyValueInParam, propertyName, - argIndex + 1); - return false; - } - - if (actualType == napi_string) { - if (!njsUtils_copyStringFromJS(env, value, result, resultLength)) - return false; - } else { - NJS_CHECK_NAPI(env, napi_get_buffer_info(env, value, &buf, &bufLen)) - if (!njsUtils_copyString(env, buf, bufLen, result, resultLength)) - return false; - } - - if (found) - *found = true; - - return true; -} - - -//----------------------------------------------------------------------------- -// njsBaton_getXid() -// Populates XID structure of baton from the given argument -//----------------------------------------------------------------------------- -bool njsBaton_getXid(njsBaton *baton, napi_env env, napi_value arg) -{ - napi_valuetype vtype; - int32_t fmtId; - size_t len; - - NJS_CHECK_NAPI(env, napi_typeof(env, arg, &vtype)) - if (vtype != napi_undefined && vtype != napi_null) { - baton->xid = calloc(1, sizeof(dpiXid)); - if (!baton->xid) { - return njsBaton_setError(baton, errInsufficientMemory); - } - if (!njsBaton_getIntFromArg(baton, env, &arg, 0, "formatId", &fmtId, - NULL)) - return false; - baton->xid->formatId = (long) fmtId; - - if (!njsBaton_getStrBufFromArg(baton, env, &arg, 0, - "globalTransactionId", - (char **)&baton->xid->globalTransactionId, &len, NULL)) - return false; - baton->xid->globalTransactionIdLength = (uint32_t)len; - - if (!njsBaton_getStrBufFromArg(baton, env, &arg, 0, "branchQualifier", - (char **)&baton->xid->branchQualifier, &len, NULL)) - return false; - baton->xid->branchQualifierLength = len; - } - return true; -} - - //----------------------------------------------------------------------------- // njsBaton_initCommonCreateParams() // Initialize common creation parameters for pools and standalone @@ -949,17 +677,57 @@ bool njsBaton_reportError(njsBaton *baton, napi_env env) //----------------------------------------------------------------------------- -// njsBaton_setError() -// Set the error on the baton to the given error message. False is returned -// as a convenience to the caller. +// njsBaton_setErrorInsufficientBufferForBinds() +// Sets the error on the baton to indicate that insufficient buffer space +// was made available for an OUT bind. Returns false as a convenience to the +// caller. //----------------------------------------------------------------------------- -bool njsBaton_setError(njsBaton *baton, int errNum, ...) +bool njsBaton_setErrorInsufficientBufferForBinds(njsBaton *baton) { - va_list vaList; + strcpy(baton->error, NJS_ERR_INSUFFICIENT_BUFFER_FOR_BINDS); + baton->hasError = true; + return false; +} - va_start(vaList, errNum); - njsErrors_getMessageVaList(baton->error, errNum, vaList); - va_end(vaList); + +//----------------------------------------------------------------------------- +// njsBaton_setErrorInsufficientMemory() +// Set the error on the baton to indicate insufficient memory was available. +// Returns false as a convenience to the caller. +//----------------------------------------------------------------------------- +bool njsBaton_setErrorInsufficientMemory(njsBaton *baton) +{ + strcpy(baton->error, NJS_ERR_INSUFFICIENT_MEMORY); + baton->hasError = true; + return false; +} + + +//----------------------------------------------------------------------------- +// njsBaton_setErrorUnsupportedDataType() +// Set the error on the baton to indicate that an unsupported data type was +// encountered during a fetch. Returns false as a convenience to the caller. +//----------------------------------------------------------------------------- +bool njsBaton_setErrorUnsupportedDataType(njsBaton *baton, + uint32_t oracleTypeNum, uint32_t columnNum) +{ + (void) snprintf(baton->error, sizeof(baton->error), + NJS_ERR_UNSUPPORTED_DATA_TYPE, oracleTypeNum, columnNum); + baton->hasError = true; + return false; +} + + +//----------------------------------------------------------------------------- +// njsBaton_setErrorUnsupportedDataTypeInJson() +// Set the error on the baton to indicate that an unsupported data type was +// encountered in a JSON value. Returns false as a convenience to the caller. +//----------------------------------------------------------------------------- +bool njsBaton_setErrorUnsupportedDataTypeInJson(njsBaton *baton, + uint32_t oracleTypeNum) +{ + (void) snprintf(baton->error, sizeof(baton->error), + NJS_ERR_UNSUPPORTED_DATA_TYPE_IN_JSON, oracleTypeNum); baton->hasError = true; return false; } @@ -973,12 +741,8 @@ bool njsBaton_setError(njsBaton *baton, int errNum, ...) bool njsBaton_setErrorDPI(njsBaton *baton) { dpiContext_getError(baton->globals->context, &baton->errorInfo); - if (baton->errorInfo.code == 1406) { - njsBaton_setError(baton, errInsufficientBufferForBinds); - } else { - baton->dpiError = true; - baton->hasError = true; - } + baton->dpiError = true; + baton->hasError = true; return false; } diff --git a/src/njsConnection.c b/src/njsConnection.c index 7805cc9d..5e7c603e 100644 --- a/src/njsConnection.c +++ b/src/njsConnection.c @@ -113,9 +113,6 @@ static NJS_ASYNC_POST_METHOD(njsConnection_getStatementInfoPostAsync); static NJS_ASYNC_POST_METHOD(njsConnection_tpcPreparePostAsync); static NJS_ASYNC_POST_METHOD(njsConnection_subscribePostAsync); -// processing arguments methods -static NJS_PROCESS_ARGS_METHOD(njsConnection_subscribeProcessArgs); - // finalize static NJS_NAPI_FINALIZE(njsConnection_finalize); @@ -218,7 +215,6 @@ const njsClassDef njsClassDefConnection = { }; // other methods used internally -static bool njsConnection_check(njsBaton *baton); static bool njsConnection_getBatchErrors(njsBaton *baton, napi_env env, napi_value *batchErrors); static bool njsConnection_getExecuteManyOutBinds(njsBaton *baton, napi_env env, @@ -232,14 +228,12 @@ static bool njsConnection_getOutBinds(njsBaton *baton, napi_env env, static bool njsConnection_getRowCounts(njsBaton *baton, napi_env env, napi_value *rowCounts); static bool njsConnection_prepareAndBind(njsConnection *conn, njsBaton *baton); -static bool njsConnection_processImplicitResults(njsBaton *baton); -static bool njsConnection_setTextAttribute(napi_env env, - njsBaseInstance *instance, njsModuleGlobals *globals, - napi_value value, int (*setter)(dpiConn*, const char *, uint32_t)); - - static bool njsConnection_processBinds(njsBaton *baton, napi_env env, napi_value binds); +static bool njsConnection_processImplicitResults(njsBaton *baton); +static bool njsConnection_setTextAttribute(napi_env env, void *instance, + njsModuleGlobals *globals, napi_value value, + int (*setter)(dpiConn*, const char *, uint32_t)); //----------------------------------------------------------------------------- // njsConnection_breakExecution() @@ -249,8 +243,6 @@ static bool njsConnection_processBinds(njsBaton *baton, napi_env env, //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_breakExecution, 0, NULL) { - if (!njsConnection_check(baton)) - return false; return njsBaton_queueWork(baton, env, "Break", njsConnection_breakExecutionAsync, NULL, returnValue); } @@ -282,8 +274,6 @@ static bool njsConnection_breakExecutionAsync(njsBaton *baton) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_changePassword, 3, NULL) { - if (!njsConnection_check(baton)) - return false; if (!njsUtils_copyStringFromJS(env, args[0], &baton->user, &baton->userLength)) return false; @@ -316,20 +306,6 @@ static bool njsConnection_changePasswordAsync(njsBaton *baton) } -//----------------------------------------------------------------------------- -// njsConnection_check() -// Checks to see that the connection is valid. -//----------------------------------------------------------------------------- -static bool njsConnection_check(njsBaton *baton) -{ - njsConnection *conn = (njsConnection*) baton->callingInstance; - - if (!conn->handle) - return njsBaton_setError(baton, errInvalidConnection); - return true; -} - - //----------------------------------------------------------------------------- // njsConnection_close() // Releases the connection from use by JS. This releases the connection back @@ -343,10 +319,8 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_close, 1, NULL) { njsConnection *conn = (njsConnection*) baton->callingInstance; - if (!njsConnection_check(baton)) - return false; - if (!njsBaton_getBoolFromArg(baton, env, args, 0, "drop", - &baton->dropSession, NULL)) + if (!njsUtils_getNamedPropertyBool(env, args[0], "drop", + &baton->dropSession)) return false; baton->dpiConnHandle = conn->handle; conn->handle = NULL; @@ -392,8 +366,6 @@ static bool njsConnection_closeAsync(njsBaton *baton) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_commit, 0, NULL) { - if (!njsConnection_check(baton)) - return false; return njsBaton_queueWork(baton, env, "Commit", njsConnection_commitAsync, NULL, returnValue); } @@ -523,8 +495,6 @@ static bool njsConnection_connectPostAsync(njsBaton *baton, napi_env env, //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_createLob, 1, NULL) { - if (!njsConnection_check(baton)) - return false; NJS_CHECK_NAPI(env, napi_get_value_uint32(env, args[0], &baton->lobType)) return njsBaton_queueWork(baton, env, "CreateLob", njsConnection_createLobAsync, njsConnection_createLobPostAsync, @@ -542,7 +512,7 @@ static bool njsConnection_createLobAsync(njsBaton *baton) baton->lob = calloc(1, sizeof(njsLobBuffer)); if (!baton->lob) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (dpiConn_newTempLob(conn->handle, baton->lobType, &baton->lob->handle) < 0) return njsBaton_setErrorDPI(baton); @@ -586,8 +556,6 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_execute, 5, NULL) napi_value temp; // validate connection and process arguments - if (!njsConnection_check(baton)) - return false; if (!njsBaton_setJsValues(baton, env)) return false; if (!njsUtils_copyStringFromJS(env, args[0], &baton->sql, @@ -687,7 +655,7 @@ static bool njsConnection_executeAsync(njsBaton *baton) baton->queryVars = calloc(baton->numQueryVars, sizeof(njsVariable)); if (!baton->queryVars) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (!njsVariable_initForQuery(baton->queryVars, baton->numQueryVars, baton->dpiStmtHandle, baton)) return false; @@ -865,7 +833,7 @@ static bool njsConnection_executeManyAsync(njsBaton *baton) baton->batchErrorInfos = calloc(baton->numBatchErrorInfos, sizeof(dpiErrorInfo)); if (!baton->batchErrorInfos) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (dpiStmt_getBatchErrors(baton->dpiStmtHandle, baton->numBatchErrorInfos, baton->batchErrorInfos) < 0) return njsBaton_setErrorDPI(baton); @@ -1057,8 +1025,6 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsConnection_getCurrentSchema, 0, NULL) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_getDbObjectClass, 1, NULL) { - if (!njsConnection_check(baton)) - return false; if (!njsUtils_copyStringFromJS(env, args[0], &baton->name, &baton->nameLength)) return false; @@ -1346,9 +1312,6 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_getQueue, 2, NULL) napi_value typeObj, jsObjType; njsDbObjectType *objType; - if (!njsConnection_check(baton)) - return false; - // get name for queue (first argument) if (!njsUtils_copyStringFromJS(env, args[0], &baton->name, &baton->nameLength)) @@ -1467,8 +1430,6 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsConnection_getStmtCacheSize, 0, NULL) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_getStatementInfo, 1, NULL) { - if (!njsConnection_check(baton)) - return false; if (!njsUtils_copyStringFromJS(env, args[0], &baton->sql, &baton->sqlLength)) return false; @@ -1516,12 +1477,12 @@ static bool njsConnection_getStatementInfoAsync(njsBaton *baton) // allocate memory for the bind variable names baton->bindNames = calloc(baton->numBindNames, sizeof(const char*)); if (!baton->bindNames) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); // allocate memory for the bind variable name lengths baton->bindNameLengths = calloc(baton->numBindNames, sizeof(uint32_t)); if (!baton->bindNameLengths) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); // get bind names if (dpiStmt_getBindNames(baton->dpiStmtHandle, &baton->numBindNames, @@ -1534,7 +1495,7 @@ static bool njsConnection_getStatementInfoAsync(njsBaton *baton) if (baton->numQueryVars > 0) { baton->queryVars = calloc(baton->numQueryVars, sizeof(njsVariable)); if (!baton->queryVars) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (!njsVariable_initForQuery(baton->queryVars, baton->numQueryVars, baton->dpiStmtHandle, baton)) return false; @@ -1615,8 +1576,7 @@ bool njsConnection_newFromBaton(njsBaton *baton, napi_env env, // create new instance if (!njsUtils_genericNew(env, &njsClassDefConnection, - baton->globals->jsConnectionConstructor, connObj, - (njsBaseInstance**) &conn)) + baton->globals->jsConnectionConstructor, connObj, (void**) &conn)) return false; // transfer the ODPI-C connection handle to the new object @@ -1660,8 +1620,6 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsConnection_isHealthy, 0, NULL) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_ping, 0, NULL) { - if (!njsConnection_check(baton)) - return false; return njsBaton_queueWork(baton, env, "Ping", njsConnection_pingAsync, NULL, returnValue); } @@ -1821,7 +1779,7 @@ static bool njsConnection_processBinds(njsBaton *baton, napi_env env, // allocate memory for the bind variables baton->bindVars = calloc(baton->numBindVars, sizeof(njsVariable)); if (!baton->bindVars) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); // initialize bind variables from supplied information for (i = 0; i < baton->numBindVars; i++) { @@ -1864,7 +1822,7 @@ static bool njsConnection_processImplicitResults(njsBaton *baton) tempImplicitResult = calloc(1, sizeof(njsImplicitResult)); if (!tempImplicitResult) { dpiStmt_release(stmt); - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); } tempImplicitResult->stmt = stmt; if (implicitResult) { @@ -1881,7 +1839,7 @@ static bool njsConnection_processImplicitResults(njsBaton *baton) implicitResult->queryVars = calloc(implicitResult->numQueryVars, sizeof(njsVariable)); if (!implicitResult->queryVars) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (!njsVariable_initForQuery(implicitResult->queryVars, implicitResult->numQueryVars, implicitResult->stmt, baton)) return false; @@ -1900,8 +1858,6 @@ static bool njsConnection_processImplicitResults(njsBaton *baton) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_rollback, 0, NULL) { - if (!njsConnection_check(baton)) - return false; return njsBaton_queueWork(baton, env, "Rollback", njsConnection_rollbackAsync, NULL, returnValue); } @@ -2058,19 +2014,15 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsConnection_setTag, 1, NULL) // Sets the specified text attribute by calling the specified ODPI-C // function, after validating the connection and the input. //----------------------------------------------------------------------------- -static bool njsConnection_setTextAttribute(napi_env env, - njsBaseInstance *instance, njsModuleGlobals *globals, - napi_value value, int (*setter)(dpiConn*, const char *, uint32_t)) +static bool njsConnection_setTextAttribute(napi_env env, void *instance, + njsModuleGlobals *globals, napi_value value, + int (*setter)(dpiConn*, const char *, uint32_t)) { njsConnection *conn = (njsConnection*) instance; char *buffer = NULL; size_t bufferLength; int status; - // validate connection - if (!conn->handle) - return njsUtils_throwError(env, errInvalidConnection); - // get contents of string if (!njsUtils_copyStringFromJS(env, value, &buffer, &bufferLength)) return false; @@ -2094,8 +2046,6 @@ static bool njsConnection_setTextAttribute(napi_env env, //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_shutdown, 1, NULL) { - if (!njsConnection_check(baton)) - return false; NJS_CHECK_NAPI(env, napi_get_value_uint32(env, args[0], &baton->shutdownMode)) return njsBaton_queueWork(baton, env, "Shutdown", @@ -2129,14 +2079,12 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_startup, 1, NULL) { bool force = false, rest = false; - if (!njsConnection_check(baton)) + if (!njsUtils_getNamedPropertyBool(env, args[0], "force", &force)) return false; - if (!njsBaton_getBoolFromArg(baton, env, args, 0, "force", &force, NULL)) + if (!njsUtils_getNamedPropertyBool(env, args[0], "restrict", &rest)) return false; - if (!njsBaton_getBoolFromArg(baton, env, args, 0, "restrict", &rest, NULL)) - return false; - if (!njsBaton_getStringFromArg(baton, env, args, 0, "pfile", &baton->pfile, - &baton->pfileLength, NULL)) + if (!njsUtils_getNamedPropertyString(env, args[0], "pfile", &baton->pfile, + &baton->pfileLength)) return false; if (force) @@ -2178,10 +2126,70 @@ static bool njsConnection_startupAsync(njsBaton *baton) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_subscribe, 2, NULL) { - if (!njsConnection_check(baton)) - return false; - if (!njsConnection_subscribeProcessArgs(baton, env, args)) - return false; + napi_value callback, binds; + napi_valuetype valueType; + + // get subscription + NJS_CHECK_NAPI(env, napi_typeof(env, args[0], &valueType)) + if (valueType == napi_external) { + NJS_CHECK_NAPI(env, napi_get_value_external(env, args[0], + (void**) &baton->subscription)) + } else { + if (!njsSubscription_new(baton, env)) + return false; + } + + // if subscription doesn't exist, get options for creating subscription + if (!baton->subscription->handle) { + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[1], "namespace", + &baton->subscription->subscrNamespace)) + return false; + if (!njsUtils_getNamedPropertyString(env, args[1], "ipAddress", + &baton->ipAddress, &baton->ipAddressLength)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[1], "port", + &baton->portNumber)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[1], "timeout", + &baton->timeout)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[1], "operations", + &baton->operations)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[1], "qos", + &baton->qos)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[1], + "groupingClass", &baton->subscrGroupingClass)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[1], + "groupingValue", &baton->subscrGroupingValue)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[1], "groupingType", + &baton->subscrGroupingType)) + return false; + if (!njsUtils_getNamedPropertyBool(env, args[1], "clientInitiated", + &baton->clientInitiated)) + return false; + if (!njsUtils_getNamedProperty(env, args[1], "callback", &callback)) + return false; + NJS_CHECK_NAPI(env, napi_create_reference(env, callback, 1, + &baton->subscription->jsCallback)) + } + + // get options that are used for registering queries + if (baton->subscription->subscrNamespace == + DPI_SUBSCR_NAMESPACE_DBCHANGE) { + if (!njsUtils_getNamedPropertyString(env, args[1], "sql", &baton->sql, + &baton->sqlLength)) + return false; + if (!njsUtils_getNamedProperty(env, args[1], "binds", &binds)) + return false; + baton->bindArraySize = 1; + if (binds && !njsConnection_processBinds(baton, env, binds)) + return false; + } + return njsBaton_queueWork(baton, env, "Subscribe", njsConnection_subscribeAsync, njsConnection_subscribePostAsync, returnValue); @@ -2268,13 +2276,17 @@ static bool njsConnection_subscribeAsync(njsBaton *baton) static bool njsConnection_subscribePostAsync(njsBaton *baton, napi_env env, napi_value *result) { - napi_value regId; + napi_value regId, subscription; // start notifications if (!njsSubscription_startNotifications(baton->subscription, env, baton)) return false; + // get subscription to store in subscription mapping + NJS_CHECK_NAPI(env, napi_get_reference_value(env, baton->jsSubscriptionRef, + &subscription)) + // create result object for CQN only; AQ notifications do not produce a // meaningful value if (baton->subscription->subscrNamespace == @@ -2284,83 +2296,12 @@ static bool njsConnection_subscribePostAsync(njsBaton *baton, napi_env env, (uint32_t) baton->subscription->regId, ®Id)) NJS_CHECK_NAPI(env, napi_set_named_property(env, *result, "regId", regId)) - } + NJS_CHECK_NAPI(env, napi_set_named_property(env, *result, + "subscription", subscription)) - return true; -} - - -//----------------------------------------------------------------------------- -// njsConnection_subscribeProcessArgs() -// Processes the arguments provided by the caller and place them on the -// baton. -//----------------------------------------------------------------------------- -static bool njsConnection_subscribeProcessArgs(njsBaton *baton, napi_env env, - napi_value *args) -{ - napi_value callback, binds; - - // first get the subscription given the name - if (!njsUtils_copyStringFromJS(env, args[0], &baton->name, - &baton->nameLength)) - return false; - if (!njsBaton_getSubscription(baton, env, args[0], false)) - return false; - - // if subscription doesn't exist, get options for creating subscription - if (!baton->subscription->handle) { - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 1, "namespace", - &baton->subscription->subscrNamespace, NULL)) - return false; - if (!njsBaton_getStringFromArg(baton, env, args, 1, "ipAddress", - &baton->ipAddress, &baton->ipAddressLength, NULL)) - return false; - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 1, "port", - &baton->portNumber, NULL)) - return false; - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 1, "timeout", - &baton->timeout, NULL)) - return false; - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 1, "operations", - &baton->operations, NULL)) - return false; - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 1, "qos", - &baton->qos, NULL)) - return false; - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 1, - "groupingClass", &baton->subscrGroupingClass, NULL)) - return false; - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 1, - "groupingValue", &baton->subscrGroupingValue, NULL)) - return false; - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 1, - "groupingType", &baton->subscrGroupingType, NULL)) - return false; - if (!njsBaton_getBoolFromArg(baton, env, args, 1, "clientInitiated", - &baton->clientInitiated, NULL)) - return false; - if (!njsBaton_getValueFromArg(baton, env, args, 1, "callback", - napi_function, &callback, NULL)) - return false; - if (!callback) - return njsBaton_setError(baton, errMissingSubscrCallback); - NJS_CHECK_NAPI(env, napi_create_reference(env, callback, 1, - &baton->subscription->jsCallback)) - } - - // get options that are used for registering queries - if (baton->subscription->subscrNamespace == - DPI_SUBSCR_NAMESPACE_DBCHANGE) { - if (!njsBaton_getStringFromArg(baton, env, args, 1, "sql", &baton->sql, - &baton->sqlLength, NULL)) - return false; - if (baton->sqlLength == 0) - return njsBaton_setError(baton, errMissingSubscrSql); - if (!njsBaton_getValueFromArg(baton, env, args, 1, "binds", - napi_object, &binds, NULL)) - return false; - if (binds && !njsConnection_processBinds(baton, env, binds)) - return false; + // otherwise, return the subscription directly + } else { + *result = subscription; } return true; @@ -2378,9 +2319,7 @@ static bool njsConnection_subscribeProcessArgs(njsBaton *baton, napi_env env, //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_tpcBegin, 3, NULL) { - if (!njsConnection_check(baton)) - return false; - if (!njsBaton_getXid(baton, env, args[0])) + if (!njsUtils_getXid(env, args[0], &baton->xid)) return false; NJS_CHECK_NAPI(env, napi_get_value_uint32(env, args[1], &baton->tpcFlags)) NJS_CHECK_NAPI(env, napi_get_value_uint32(env, args[2], @@ -2417,9 +2356,7 @@ static bool njsConnection_tpcBeginAsync(njsBaton *baton) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_tpcCommit, 2, NULL) { - if (!njsConnection_check(baton)) - return false; - if (!njsBaton_getXid(baton, env, args[0])) + if (!njsUtils_getXid(env, args[0], &baton->xid)) return false; NJS_CHECK_NAPI(env, napi_get_value_bool(env, args[1], &baton->tpcOnePhase)) return njsBaton_queueWork(baton, env, "tpcCommit", @@ -2453,9 +2390,7 @@ static bool njsConnection_tpcCommitAsync(njsBaton *baton) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_tpcEnd, 2, NULL) { - if (!njsConnection_check(baton)) - return false; - if (!njsBaton_getXid(baton, env, args[0])) + if (!njsUtils_getXid(env, args[0], &baton->xid)) return false; NJS_CHECK_NAPI(env, napi_get_value_uint32(env, args[1], &baton->tpcFlags)) return njsBaton_queueWork(baton, env, "tpcEnd", njsConnection_tpcEndAsync, @@ -2486,9 +2421,7 @@ static bool njsConnection_tpcEndAsync(njsBaton *baton) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_tpcForget, 1, NULL) { - if (!njsConnection_check(baton)) - return false; - if (!njsBaton_getXid(baton, env, args[0])) + if (!njsUtils_getXid(env, args[0], &baton->xid)) return false; return njsBaton_queueWork(baton, env, "tpcForget", njsConnection_tpcForgetAsync, NULL, returnValue); @@ -2516,9 +2449,7 @@ static bool njsConnection_tpcForgetAsync(njsBaton *baton) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_tpcPrepare, 1, NULL) { - if (!njsConnection_check(baton)) - return false; - if (!njsBaton_getXid(baton, env, args[0])) + if (!njsUtils_getXid(env, args[0], &baton->xid)) return false; return njsBaton_queueWork(baton, env, "tpcPrepare", njsConnection_tpcPrepareAsync, njsConnection_tpcPreparePostAsync, @@ -2563,9 +2494,7 @@ static bool njsConnection_tpcPreparePostAsync(njsBaton *baton, napi_env env, //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_tpcRollback, 1, NULL) { - if (!njsConnection_check(baton)) - return false; - if (!njsBaton_getXid(baton, env, args[0])) + if (!njsUtils_getXid(env, args[0], &baton->xid)) return false; return njsBaton_queueWork(baton, env, "tpcRollback", njsConnection_tpcRollbackAsync, NULL, returnValue); @@ -2598,10 +2527,8 @@ static bool njsConnection_tpcRollbackAsync(njsBaton *baton) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsConnection_unsubscribe, 1, NULL) { - if (!njsConnection_check(baton)) - return false; - if (!njsBaton_getSubscription(baton, env, args[0], true)) - return false; + NJS_CHECK_NAPI(env, napi_get_value_external(env, args[0], + (void**) &baton->subscription)) return njsBaton_queueWork(baton, env, "Unsubscribe", njsConnection_unsubscribeAsync, NULL, returnValue); } diff --git a/src/njsDbObject.c b/src/njsDbObject.c index aa5257c2..e1eef05c 100644 --- a/src/njsDbObject.c +++ b/src/njsDbObject.c @@ -417,7 +417,7 @@ bool njsDbObject_getSubClass(njsBaton *baton, dpiObjectType *objectTypeHandle, // allocate memory for structure; memory is zero-ed tempObjectType = (njsDbObjectType*) calloc(1, sizeof(njsDbObjectType)); if (!tempObjectType) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); // populate object type (C) and prototype (JS) with all information about // the object type @@ -510,7 +510,7 @@ bool njsDbObject_new(njsDbObjectType *objType, dpiObject *objHandle, // create new object if (!njsUtils_genericNew(env, &njsClassDefDbObject, - globals->jsDbObjectConstructor, value, (njsBaseInstance**) &obj)) + globals->jsDbObjectConstructor, value, (void**) &obj)) return false; // get the object type and store a reference to it on the new object @@ -691,12 +691,7 @@ static bool njsDbObject_transformFromOracle(njsDbObject *obj, napi_env env, } // unsupported - if (attr) - return njsUtils_throwError(env, errConvertFromObjAttr, - attr->nameLength, attr->name, obj->type->fqnLength, - obj->type->fqn); - return njsUtils_throwError(env, errConvertFromObjElement, - obj->type->fqnLength, obj->type->fqn); + return njsUtils_genericThrowError(env, __FILE__, __LINE__); } @@ -799,11 +794,7 @@ static bool njsDbObject_transformToOracle(njsDbObject *obj, napi_env env, break; } - if (attr) - return njsUtils_throwError(env, errConvertToObjAttr, attr->nameLength, - attr->name, obj->type->fqnLength, obj->type->fqn); - return njsUtils_throwError(env, errConvertToObjElement, - obj->type->fqnLength, obj->type->fqn); + return njsUtils_genericThrowError(env, __FILE__, __LINE__); } @@ -844,7 +835,7 @@ static bool njsDbObject_wrap(napi_env env, napi_value jsObj, njsDbObject **obj) // create a new object instance tempObj = calloc(1, sizeof(njsDbObject)); if (!tempObj) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); tempObj->type = objType; if (napi_wrap(env, jsObj, tempObj, njsDbObject_finalize, NULL, NULL) != napi_ok) { @@ -918,12 +909,12 @@ static bool njsDbObjectType_populate(njsDbObjectType *objType, objType->attributes = calloc(info->numAttributes, sizeof(njsDbObjectAttr)); if (!objType->attributes) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); // determine the attributes associated with the object type attrHandles = calloc(info->numAttributes, sizeof(dpiObjectAttr*)); if (!attrHandles) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (dpiObjectType_getAttributes(objectTypeHandle, objType->numAttributes, attrHandles) < 0) { free(attrHandles); @@ -987,7 +978,7 @@ static bool njsDbObjectType_populate(njsDbObjectType *objType, objType->fqnLength = info->schemaLength + info->nameLength + 1; objType->fqn = malloc(objType->fqnLength + 1); if (!objType->fqn) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); (void) snprintf(objType->fqn, objType->fqnLength + 1, "%.*s.%.*s", (int) info->schemaLength, info->schema, (int) info->nameLength, info->name); diff --git a/src/njsErrors.c b/src/njsErrors.c deleted file mode 100644 index 7dee7492..00000000 --- a/src/njsErrors.c +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2015, 2022, 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 http://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 -// njsErrors.c -// -// DESCRIPTION -// All error messages and the functions for getting them. -// -//----------------------------------------------------------------------------- - -#include "njsModule.h" - -static const char *njsErrorMessages[] = { - "NJS-000: success", // errSuccess - "NJS-001: expected callback as last parameter", // errMissingCallback - "NJS-002: invalid pool", // errInvalidPool - "NJS-003: invalid connection", // errInvalidConnection - "NJS-004: invalid value for property %s", // errInvalidPropertyValue - "NJS-005: invalid value for parameter %d", // errInvalidParameterValue - "NJS-007: invalid value for \"%s\" in parameter %d", // errInvalidPropertyValueInParam - "NJS-009: invalid number of parameters", // errInvalidNumberOfParameters - "NJS-010: unsupported data type %d in column %u", // errUnsupportedDataType - "NJS-011: encountered bind value and type mismatch", // errBindValueAndTypeMismatch - "NJS-012: encountered invalid bind data type in parameter %d", // errInvalidBindDataType - "NJS-013: invalid bind direction", // errInvalidBindDirection - "NJS-015: type was not specified for conversion", // errNoTypeForConversion - "NJS-016: buffer is too small for OUT binds", // errInsufficientBufferForBinds - "NJS-017: concurrent operations on ResultSet are not allowed", // errBusyResultSet - "NJS-018: invalid ResultSet", // errInvalidResultSet - "NJS-019: ResultSet cannot be returned for non-query statements", // errInvalidNonQueryExecution - "NJS-021: invalid type for conversion specified", // errInvalidTypeForConversion - "NJS-022: invalid Lob", // errInvalidLob - "NJS-023: concurrent operations on LOB are not allowed", // errBusyLob - "NJS-024: memory allocation failed", // errInsufficientMemory - "NJS-034: data type is unsupported for array bind", // errInvalidTypeForArrayBind - "NJS-035: maxArraySize is required for IN OUT array bind", // errReqdMaxArraySize - "NJS-036: given array is of size greater than maxArraySize", // errInvalidArraySize - "NJS-037: invalid data type at array index %d for bind \":%.*s\"", // errIncompatibleTypeArrayBind - "NJS-040: connection request timeout. Request exceeded queueTimeout of %d", // errConnRequestTimeout - "NJS-041: cannot convert ResultSet to QueryStream after invoking methods", // errCannotConvertRsToStream - "NJS-042: cannot invoke ResultSet methods after converting to QueryStream", // errCannotInvokeRsMethods - "NJS-043: ResultSet already converted to QueryStream", // errResultSetAlreadyConverted - "NJS-044: bind object must contain one of the following keys: \"dir\", \"type\", \"maxSize\", or \"val\"", // errNamedJSON - "NJS-045: cannot load a node-oracledb binary for Node.js %s", // errCannotLoadBinary - "NJS-046: pool alias \"%s\" already exists in the connection pool cache", // errPoolWithAliasAlreadyExists - "NJS-047: pool alias \"%s\" not found in connection pool cache", // errPoolWithAliasNotFound - "NJS-052: invalid data type at array index %d for bind position %d", // errIncompatibleTypeArrayIndexBind - "NJS-053: an array value was expected", //errNonArrayProvided - "NJS-055: binding by position and name cannot be mixed", // errMixedBind - "NJS-056: maxSize must be specified and not zero for bind position %u", // errMissingMaxSizeByPos - "NJS-057: maxSize must be specified and not zero for bind \"%.*s\"", // errMissingMaxSizeByName - "NJS-058: maxSize of %u is too small for value of length %u in row %u", // errMaxSizeTooSmall - "NJS-059: type must be specified for bind position %u", // errMissingTypeByPos - "NJS-060: type must be specified for bind \"%.*s\"", // errMissingTypeByName - "NJS-061: invalid subscription", // errInvalidSubscription - "NJS-062: subscription notification callback missing", // errMissingSubscrCallback - "NJS-063: subscription notification SQL missing", // errMissingSubscrSql - "NJS-064: connection pool is closing", // errPoolClosing - "NJS-065: connection pool was closed", // errPoolClosed - "NJS-066: invalid SODA document cursor", // errInvalidSodaDocCursor - "NJS-067: a pre-built node-oracledb binary was not found for %s", // errNoBinaryAvailable - "NJS-068: invalid error number %d supplied", // errInvalidErrNum - "NJS-069: node-oracledb %s requires Node.js %s or later", // errNodeTooOld - "NJS-070: message must be a string, buffer, database object or an object containing a payload property which itself is a string, buffer or database object", // errInvalidAqMessage - "NJS-071: cannot convert from element of type \"%.*s\" to JavaScript value", // errConvertFromObjElement - "NJS-072: cannot convert from attribute \"%.*s\" of type \"%.*s\" to JavaScript value", // errConvertFromObjAttr - "NJS-073: cannot convert from JavaScript value to element of type %.*s", // errConvertToObjElement - "NJS-074: cannot convert from JavaScript value to attribute \"%.*s\" of type \"%.*s\"", // errConvertToObjAttr - "NJS-075: only one of connectString and connectionString can be used", // errDblConnectionString - "NJS-076: connection request rejected. Pool queue length queueMax %d reached", // errQueueMax - "NJS-077: Oracle Client library has already been initialized", // errClientLibAlreadyInitialized - "NJS-078: unsupported data type %u in JSON value", // errUnsupportedDataTypeInJson - "NJS-079: cannot convert from JavaScript value to JSON value", // errConvertToJsonValue - "NJS-080: only one of user and username can be used", //errDblUsername - "NJS-081: concurrent operations on a connection are disabled", //errConcurrentOps - "NJS-082: connection pool is being reconfigured", // errPoolReconfiguring - "NJS-083: pool statistics not enabled", // errPoolStatisticsDisabled - "NJS-084: invalid access token", // errTokenBasedAuth - "NJS-085: invalid connection pool configuration with token based authentication. The homogeneous and externalAuth attributes must be set to true", // errPoolTokenBasedAuth - "NJS-086: invalid standalone configuration with token based authentication. The externalAuth attribute must be set to true", // errStandaloneTokenBasedAuth - "NJS-087: access token has expired", //errExpiredToken - "NJS-088: accessTokenCallback cannot be specified when accessToken is a function", //errAccessTokenCallback - "NJS-089: internal error: invalid global setting attribute num %d", // errInvalidGlobalSettingAttrNum - "NJS-090: initOracleClient() was already called with different arguments!", //errInitOracleClientArgs - "NJS-091: file %s is missing", //errMissingFile -}; - - -//----------------------------------------------------------------------------- -// njsErrors_getMessage() -// Get the error message given the error number and any number of arguments. -// If the error number is invalid, the error message is changed to indicate as -// much. -//----------------------------------------------------------------------------- -void njsErrors_getMessage(char *buffer, int errNum, ...) -{ - va_list vaList; - - va_start(vaList, errNum); - njsErrors_getMessageVaList(buffer, errNum, vaList); - va_end(vaList); -} - - -//----------------------------------------------------------------------------- -// njsErrors_getMessageVaList() -// Get the error message given the error number and a variable list of -// arguments. If the error number is invalid, the error message is changed to -// indicate as much. -//----------------------------------------------------------------------------- -void njsErrors_getMessageVaList(char *buffer, int errNum, va_list vaList) -{ - if (errNum > 0 && errNum < errMaxErrors) { - (void) vsnprintf(buffer, NJS_MAX_ERROR_MSG_LEN + 1, - njsErrorMessages[errNum], vaList); - } else { - njsErrors_getMessage(buffer, errInvalidErrNum, errNum); - } -} diff --git a/src/njsJsonBuffer.c b/src/njsJsonBuffer.c index 00bef6f4..f43a9116 100644 --- a/src/njsJsonBuffer.c +++ b/src/njsJsonBuffer.c @@ -112,7 +112,7 @@ static bool njsJsonBuffer_getString(njsJsonBuffer *buf, njsBaton *baton, buf->allocatedBuffers += 16; tempBuffers = malloc(buf->allocatedBuffers * sizeof(char*)); if (!tempBuffers) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (buf->numBuffers > 0) { memcpy(tempBuffers, buf->buffers, buf->numBuffers * sizeof(char*)); free(buf->buffers); @@ -123,7 +123,7 @@ static bool njsJsonBuffer_getString(njsJsonBuffer *buf, njsBaton *baton, &tempLength)) temp = malloc(tempLength + 1); if (!temp) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); buf->buffers[buf->numBuffers++] = temp; NJS_CHECK_NAPI(env, napi_get_value_string_utf8(env, inValue, temp, tempLength + 1, &tempLength)) @@ -197,7 +197,7 @@ static bool njsJsonBuffer_populateNode(njsJsonBuffer *buf, dpiJsonNode *node, array->elementValues = calloc(array->numElements, sizeof(dpiDataBuffer)); if (!array->elements || !array->elementValues) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); for (i = 0; i < array->numElements; i++) { NJS_CHECK_NAPI(env, napi_get_element(env, value, i, &temp)) array->elements[i].value = &array->elementValues[i]; @@ -208,66 +208,59 @@ static bool njsJsonBuffer_populateNode(njsJsonBuffer *buf, dpiJsonNode *node, return true; } - // handle objects - if (valueType == napi_object) { - - // handle dates - NJS_CHECK_NAPI(env, napi_is_date(env, value, &check)) - if (check) { - node->oracleTypeNum = DPI_ORACLE_TYPE_TIMESTAMP; - node->nativeTypeNum = DPI_NATIVE_TYPE_DOUBLE; - NJS_CHECK_NAPI(env, napi_coerce_to_number(env, value, &temp)) - NJS_CHECK_NAPI(env, napi_get_value_double(env, temp, - &node->value->asDouble)) - return true; - } - - // handle buffers - NJS_CHECK_NAPI(env, napi_is_buffer(env, value, &check)) - if (check) { - NJS_CHECK_NAPI(env, napi_get_buffer_info(env, value, - (void**) &tempBuffer, &tempBufferLength)) - node->oracleTypeNum = DPI_ORACLE_TYPE_RAW; - node->nativeTypeNum = DPI_NATIVE_TYPE_BYTES; - node->value->asBytes.ptr = tempBuffer; - node->value->asBytes.length = (uint32_t) tempBufferLength; - return true; - } - - // all other objects have been transformed to an object containing the - // key "fields" and the key "values" - node->oracleTypeNum = DPI_ORACLE_TYPE_JSON_OBJECT; - node->nativeTypeNum = DPI_NATIVE_TYPE_JSON_OBJECT; - obj = &node->value->asJsonObject; - NJS_CHECK_NAPI(env, napi_get_named_property(env, value, "fields", - &fieldNames)) - NJS_CHECK_NAPI(env, napi_get_array_length(env, fieldNames, - &obj->numFields)) - NJS_CHECK_NAPI(env, napi_get_named_property(env, value, "values", - &fieldValues)) - obj->fieldNames = calloc(obj->numFields, sizeof(char*)); - obj->fieldNameLengths = calloc(obj->numFields, sizeof(uint32_t)); - obj->fields = calloc(obj->numFields, sizeof(dpiJsonNode)); - obj->fieldValues = calloc(obj->numFields, sizeof(dpiDataBuffer)); - if (!obj->fieldNames || !obj->fieldNameLengths || !obj->fields || - !obj->fieldValues) - return njsBaton_setError(baton, errInsufficientMemory); - for (i = 0; i < obj->numFields; i++) { - NJS_CHECK_NAPI(env, napi_get_element(env, fieldNames, i, &name)) - if (!njsJsonBuffer_getString(buf, baton, env, name, - &obj->fieldNames[i], &obj->fieldNameLengths[i])) - return false; - NJS_CHECK_NAPI(env, napi_get_element(env, fieldValues, i, &temp)) - obj->fields[i].value = &obj->fieldValues[i]; - if (!njsJsonBuffer_populateNode(buf, &obj->fields[i], env, temp, - baton)) - return false; - } + // handle dates + NJS_CHECK_NAPI(env, napi_is_date(env, value, &check)) + if (check) { + node->oracleTypeNum = DPI_ORACLE_TYPE_TIMESTAMP; + node->nativeTypeNum = DPI_NATIVE_TYPE_DOUBLE; + NJS_CHECK_NAPI(env, napi_coerce_to_number(env, value, &temp)) + NJS_CHECK_NAPI(env, napi_get_value_double(env, temp, + &node->value->asDouble)) return true; - } - return njsBaton_setError(baton, errConvertToJsonValue); + // handle buffers + NJS_CHECK_NAPI(env, napi_is_buffer(env, value, &check)) + if (check) { + NJS_CHECK_NAPI(env, napi_get_buffer_info(env, value, + (void**) &tempBuffer, &tempBufferLength)) + node->oracleTypeNum = DPI_ORACLE_TYPE_RAW; + node->nativeTypeNum = DPI_NATIVE_TYPE_BYTES; + node->value->asBytes.ptr = tempBuffer; + node->value->asBytes.length = (uint32_t) tempBufferLength; + return true; + } + + // all other objects have been transformed to an object containing the + // key "fields" and the key "values" + node->oracleTypeNum = DPI_ORACLE_TYPE_JSON_OBJECT; + node->nativeTypeNum = DPI_NATIVE_TYPE_JSON_OBJECT; + obj = &node->value->asJsonObject; + NJS_CHECK_NAPI(env, napi_get_named_property(env, value, "fields", + &fieldNames)) + NJS_CHECK_NAPI(env, napi_get_array_length(env, fieldNames, + &obj->numFields)) + NJS_CHECK_NAPI(env, napi_get_named_property(env, value, "values", + &fieldValues)) + obj->fieldNames = calloc(obj->numFields, sizeof(char*)); + obj->fieldNameLengths = calloc(obj->numFields, sizeof(uint32_t)); + obj->fields = calloc(obj->numFields, sizeof(dpiJsonNode)); + obj->fieldValues = calloc(obj->numFields, sizeof(dpiDataBuffer)); + if (!obj->fieldNames || !obj->fieldNameLengths || !obj->fields || + !obj->fieldValues) + return njsBaton_setErrorInsufficientMemory(baton); + for (i = 0; i < obj->numFields; i++) { + NJS_CHECK_NAPI(env, napi_get_element(env, fieldNames, i, &name)) + if (!njsJsonBuffer_getString(buf, baton, env, name, + &obj->fieldNames[i], &obj->fieldNameLengths[i])) + return false; + NJS_CHECK_NAPI(env, napi_get_element(env, fieldValues, i, &temp)) + obj->fields[i].value = &obj->fieldValues[i]; + if (!njsJsonBuffer_populateNode(buf, &obj->fields[i], env, temp, + baton)) + return false; + } + return true; } diff --git a/src/njsLob.c b/src/njsLob.c index f90da6e7..5579bd83 100644 --- a/src/njsLob.c +++ b/src/njsLob.c @@ -79,23 +79,6 @@ const njsClassDef njsClassDefLob = { "LobImpl", sizeof(njsLob), njsLob_finalize, njsClassProperties, false }; -// other methods used internally -static bool njsLob_check(njsLob *lob, njsBaton *baton); - - -//----------------------------------------------------------------------------- -// njsLob_check() -// Create the baton used for asynchronous methods and initialize all -// values. If this fails for some reason, an exception is thrown. -//----------------------------------------------------------------------------- -bool njsLob_check(njsLob *lob, njsBaton *baton) -{ - if (!lob->handle) - return njsBaton_setError(baton, errInvalidLob); - lob->activeBaton = baton; - return true; -} - //----------------------------------------------------------------------------- // njsLob_close() @@ -107,9 +90,6 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsLob_close, 0, NULL) { njsLob *lob = (njsLob*) baton->callingInstance; - if (!njsLob_check(lob, baton)) - return false; - lob->activeBaton = NULL; baton->dpiLobHandle = lob->handle; lob->handle = NULL; return njsBaton_queueWork(baton, env, "Close", njsLob_closeAsync, NULL, @@ -215,10 +195,6 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsLob_getType, 0, NULL) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsLob_getData, 0, NULL) { - njsLob *lob = (njsLob*) baton->callingInstance; - - if (!njsLob_check(lob, baton)) - return false; return njsBaton_queueWork(baton, env, "GetData", njsLob_getDataAsync, njsLob_getDataPostAsync, returnValue); } @@ -252,7 +228,7 @@ static bool njsLob_getDataAsync(njsBaton *baton) if (ok && baton->bufferSize > 0) { baton->bufferPtr = malloc(baton->bufferSize); if (!baton->bufferPtr) - ok = njsBaton_setError(baton, errInsufficientMemory); + ok = njsBaton_setErrorInsufficientMemory(baton); } // read from the LOB into the provided buffer @@ -299,7 +275,7 @@ bool njsLob_new(njsModuleGlobals *globals, njsLobBuffer *buffer, napi_env env, // create new instance if (!njsUtils_genericNew(env, &njsClassDefLob, globals->jsLobConstructor, - lobObj, (njsBaseInstance**) &lob)) + lobObj, (void**) &lob)) return false; // transfer data from LOB buffer to instance @@ -344,10 +320,6 @@ bool njsLob_populateBuffer(njsBaton *baton, njsLobBuffer *buffer) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsLob_read, 1, NULL) { - njsLob *lob = (njsLob*) baton->callingInstance; - - if (!njsLob_check(lob, baton)) - return false; NJS_CHECK_NAPI(env, napi_get_value_uint32(env, args[0], &baton->lobOffset)) return njsBaton_queueWork(baton, env, "Read", njsLob_readAsync, njsLob_readPostAsync, returnValue); @@ -378,7 +350,7 @@ static bool njsLob_readAsync(njsBaton *baton) if (ok) { lob->bufferPtr = malloc(lob->bufferSize); if (!lob->bufferPtr) - ok = njsBaton_setError(baton, errInsufficientMemory); + ok = njsBaton_setErrorInsufficientMemory(baton); } } @@ -441,13 +413,9 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsLob_setPieceSize, 1, NULL) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsLob_write, 2, NULL) { - njsLob *lob = (njsLob*) baton->callingInstance; size_t bufferSize; bool isBuffer; - if (!njsLob_check(lob, baton)) - return false; - // get the offset (characters for CLOBs, bytes for BLOBs) NJS_CHECK_NAPI(env, napi_get_value_uint32(env, args[0], &baton->lobOffset)) diff --git a/src/njsModule.c b/src/njsModule.c index 9c6dd202..c9c17718 100644 --- a/src/njsModule.c +++ b/src/njsModule.c @@ -67,7 +67,7 @@ static bool njsModule_extendClass(napi_env env, napi_value module, allProperties = calloc(numProperties, sizeof(napi_property_descriptor)); if (!allProperties) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); // populate the properties memcpy(allProperties, classDef->properties, @@ -122,7 +122,6 @@ static void njsModule_finalizeGlobals(napi_env env, void *finalize_data, NJS_DELETE_REF_AND_CLEAR(globals->jsSodaDocCursorConstructor); NJS_DELETE_REF_AND_CLEAR(globals->jsSodaDocumentConstructor); NJS_DELETE_REF_AND_CLEAR(globals->jsSodaOperationConstructor); - NJS_DELETE_REF_AND_CLEAR(globals->jsSubscriptions); free(globals); } @@ -202,11 +201,6 @@ static bool njsModule_populateGlobals(napi_env env, napi_value module, NJS_CHECK_NAPI(env, napi_set_named_property(env, settings, "oracleClientVersionString", temp)) - // create object for storing subscriptions - NJS_CHECK_NAPI(env, napi_create_object(env, &temp)) - NJS_CHECK_NAPI(env, napi_create_reference(env, temp, 1, - &globals->jsSubscriptions)) - return true; } @@ -230,17 +224,17 @@ static bool njsModule_initDPI(napi_env env, napi_value *args, dpiErrorInfo errorInfo; // get any arguments from JavaScript - if (!njsUtils_getStringFromArg(env, args, 0, "libDir", libDir, - libDirLength, NULL, NULL)) + if (!njsUtils_getNamedPropertyString(env, args[0], "libDir", libDir, + libDirLength)) return false; - if (!njsUtils_getStringFromArg(env, args, 0, "configDir", configDir, - configDirLength, NULL, NULL)) + if (!njsUtils_getNamedPropertyString(env, args[0], "configDir", configDir, + configDirLength)) return false; - if (!njsUtils_getStringFromArg(env, args, 0, "errorUrl", errorUrl, - errorUrlLength, NULL, NULL)) + if (!njsUtils_getNamedPropertyString(env, args[0], "errorUrl", errorUrl, + errorUrlLength)) return false; - if (!njsUtils_getStringFromArg(env, args, 0, "driverName", driverName, - driverNameLength, NULL, NULL)) + if (!njsUtils_getNamedPropertyString(env, args[0], "driverName", + driverName, driverNameLength)) return false; // initialize structure @@ -326,7 +320,7 @@ static bool njsModule_initHelper(napi_env env, napi_value exports) // function definition so that it can be directly referenced globals = calloc(1, sizeof(njsModuleGlobals)); if (!globals) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); NJS_CHECK_NAPI(env, napi_create_external(env, globals, njsModule_finalizeGlobals, NULL, &jsGlobals)) NJS_CHECK_NAPI(env, napi_set_named_property(env, exports, "_globals", diff --git a/src/njsModule.h b/src/njsModule.h index 35bcbf4e..78568616 100644 --- a/src/njsModule.h +++ b/src/njsModule.h @@ -66,15 +66,15 @@ // define macro for synchronous Node-API methods #define NJS_NAPI_METHOD_DECL_SYNC(name) \ static bool name##_(napi_env, napi_value*, napi_value, njsModuleGlobals*, \ - njsBaseInstance*, napi_value*); \ + void*, napi_value*); \ static napi_value name(napi_env, napi_callback_info) #define NJS_NAPI_METHOD_IMPL_SYNC(name, numArgs, classDef) \ static napi_value name(napi_env env, napi_callback_info info) { \ napi_value callingObj, args[numArgs + 1], returnValue = NULL; \ - njsBaseInstance* callingInstance; \ + void* callingInstance; \ njsModuleGlobals *globals; \ if (!njsUtils_validateArgs(env, info, numArgs, args, &globals, \ - &callingObj, classDef, (njsBaseInstance**) &callingInstance)) \ + &callingObj, classDef, (void**) &callingInstance)) \ return NULL; \ if (!name##_(env, args, callingObj, globals, callingInstance, \ &returnValue)) { \ @@ -84,7 +84,7 @@ } \ static bool name##_(napi_env env, napi_value *args, \ napi_value callingObj, njsModuleGlobals *globals, \ - njsBaseInstance *callingInstance, napi_value *returnValue) + void *callingInstance, napi_value *returnValue) // define macro for asynchronous Node-API methods #define NJS_NAPI_METHOD_DECL_ASYNC(name) \ @@ -160,101 +160,15 @@ #define NJS_DATATYPE_OBJECT DPI_ORACLE_TYPE_OBJECT #define NJS_DATATYPE_JSON DPI_ORACLE_TYPE_JSON -// global settings attributes used in C -#define NJS_GLOBAL_ATTR_AUTOCOMMIT 7000 -#define NJS_GLOBAL_ATTR_CONNECTION_CLASS 7001 -#define NJS_GLOBAL_ATTR_EDITION 7003 -#define NJS_GLOBAL_ATTR_EVENTS 7004 -#define NJS_GLOBAL_ATTR_EXTERNAL_AUTH 7006 -#define NJS_GLOBAL_ATTR_FETCH_AS_BUFFER 7008 -#define NJS_GLOBAL_ATTR_FETCH_AS_STRING 7009 -#define NJS_GLOBAL_ATTR_POOL_INCREMENT 7012 -#define NJS_GLOBAL_ATTR_POOL_MAX 7013 -#define NJS_GLOBAL_ATTR_POOL_MAX_PER_SHARD 7014 -#define NJS_GLOBAL_ATTR_POOL_MIN 7015 -#define NJS_GLOBAL_ATTR_POOL_PING_INTERVAL 7016 -#define NJS_GLOBAL_ATTR_POOL_TIMEOUT 7017 -#define NJS_GLOBAL_ATTR_STMT_CACHE_SIZE 7019 - -// error messages used within the driver -typedef enum { - errSuccess = 0, - errMissingCallback, - errInvalidPool, - errInvalidConnection, - errInvalidPropertyValue, - errInvalidParameterValue, - errInvalidPropertyValueInParam, - errInvalidNumberOfParameters, - errUnsupportedDataType, - errBindValueAndTypeMismatch, - errInvalidBindDataType, - errInvalidBindDirection, - errNoTypeForConversion, - errInsufficientBufferForBinds, - errBusyResultSet, - errInvalidResultSet, - errInvalidNonQueryExecution, - errInvalidTypeForConversion, - errInvalidLob, - errBusyLob, - errInsufficientMemory, - errInvalidTypeForArrayBind, - errReqdMaxArraySize, - errInvalidArraySize, - errIncompatibleTypeArrayBind, - errConnRequestTimeout, - errCannotConvertRsToStream, - errCannotInvokeRsMethods, - errResultSetAlreadyConverted, - errNamedJSON, - errCannotLoadBinary, - errPoolWithAliasAlreadyExists, - errPoolWithAliasNotFound, - errIncompatibleTypeArrayIndexBind, - errNonArrayProvided, - errMixedBind, - errMissingMaxSizeByPos, - errMissingMaxSizeByName, - errMaxSizeTooSmall, - errMissingTypeByPos, - errMissingTypeByName, - errInvalidSubscription, - errMissingSubscrCallback, - errMissingSubscrSql, - errPoolClosing, - errPoolClosed, - errInvalidSodaDocCursor, - errNoBinaryAvailable, - errInvalidErrNum, - errNodeTooOld, - errInvalidAqMessage, - errConvertFromObjElement, - errConvertFromObjAttr, - errConvertToObjElement, - errConvertToObjAttr, - errDblConnectionString, - errQueueMax, - errClientLibAlreadyInitialized, - errUnsupportedDataTypeInJson, - errConvertToJsonValue, - errDblUsername, - errConcurrentOps, - errPoolReconfiguring, - errPoolStatisticsDisabled, - errTokenBasedAuth, - errPoolTokenBasedAuth, - errStandaloneTokenBasedAuth, - errExpiredToken, - errAccessTokenCallback, - errInvalidGlobalSettingAttrNum, - errInitOracleClientArgs, - errMissingFile, - - // New ones should be added here - - errMaxErrors // Max # of errors plus one -} njsErrorType; +// error messages used in the C code +#define NJS_ERR_UNSUPPORTED_DATA_TYPE \ + "NJS-010: unsupported data type %d in column %u" +#define NJS_ERR_INSUFFICIENT_BUFFER_FOR_BINDS \ + "NJS-016: buffer is too small for OUT binds" +#define NJS_ERR_INSUFFICIENT_MEMORY \ + "NJS-024: memory allocation failed" +#define NJS_ERR_UNSUPPORTED_DATA_TYPE_IN_JSON \ + "NJS-078: unsupported data type %d in JSON value" // pool statuses #define NJS_POOL_STATUS_OPEN 6000 @@ -280,7 +194,6 @@ typedef struct njsAqDeqOptions njsAqDeqOptions; typedef struct njsAqEnqOptions njsAqEnqOptions; typedef struct njsAqMessage njsAqMessage; typedef struct njsAqQueue njsAqQueue; -typedef struct njsBaseInstance njsBaseInstance; typedef struct njsBaton njsBaton; typedef struct njsClassDef njsClassDef; typedef struct njsConnection njsConnection; @@ -332,49 +245,36 @@ extern const njsClassDef njsClassDefSodaOperation; // structures //----------------------------------------------------------------------------- -// all structures exposed publicly have these members -#define NJS_INSTANCE_HEAD \ - njsBaton *activeBaton; - // data for class AqDeqOptions exposed to JS. struct njsAqDeqOptions { - NJS_INSTANCE_HEAD dpiDeqOptions *handle; }; // data for class AqEnqOptions exposed to JS. struct njsAqEnqOptions { - NJS_INSTANCE_HEAD dpiEnqOptions *handle; uint16_t deliveryMode; }; // data for class AqMessage exposed to JS. struct njsAqMessage { - NJS_INSTANCE_HEAD dpiMsgProps *handle; njsDbObjectType *objectType; }; // data for class AqQueue exposed to JS. struct njsAqQueue { - NJS_INSTANCE_HEAD dpiQueue *handle; njsConnection *conn; njsDbObjectType *payloadObjectType; }; -// base instance (used for commonly held attributes) -struct njsBaseInstance { - NJS_INSTANCE_HEAD -}; - // data for asynchronous functions struct njsBaton { // assumed to be available at all times njsModuleGlobals *globals; - njsBaseInstance *callingInstance; + void *callingInstance; // error handling bool dpiError; @@ -587,7 +487,6 @@ struct njsClassDef { // data for class Connection exposed to JS. struct njsConnection { - NJS_INSTANCE_HEAD dpiConn *handle; char *tag; size_t tagLength; @@ -620,7 +519,6 @@ struct njsJsonBuffer { // data for class Lob exposed to JS. struct njsLob { - NJS_INSTANCE_HEAD dpiLob *handle; uint32_t dataType; char *bufferPtr; @@ -656,12 +554,10 @@ struct njsModuleGlobals { napi_ref jsSodaDocCursorConstructor; napi_ref jsSodaDocumentConstructor; napi_ref jsSodaOperationConstructor; - napi_ref jsSubscriptions; }; // data for class Pool exposed to JS. struct njsPool { - NJS_INSTANCE_HEAD dpiPool *handle; uint32_t poolMin; uint32_t poolMax; @@ -676,7 +572,6 @@ struct njsPool { // data for class ResultSet exposed to JS. struct njsResultSet { - NJS_INSTANCE_HEAD dpiStmt *handle; njsConnection *conn; uint32_t numQueryVars; @@ -688,32 +583,27 @@ struct njsResultSet { // data for class SodaCollection exposed to JS. struct njsSodaCollection { - NJS_INSTANCE_HEAD dpiSodaColl *handle; njsSodaDatabase *db; }; // data for class SodaDatabase exposed to JS. struct njsSodaDatabase { - NJS_INSTANCE_HEAD dpiSodaDb *handle; }; // data for class SodaDocCursor exposed to JS. struct njsSodaDocCursor { - NJS_INSTANCE_HEAD dpiSodaDocCursor *handle; }; // data for class SodaDocument exposed to JS. struct njsSodaDocument { - NJS_INSTANCE_HEAD dpiSodaDoc *handle; }; // data for class SodaOperation exposed to JS. struct njsSodaOperation { - NJS_INSTANCE_HEAD njsSodaCollection *coll; }; @@ -727,10 +617,9 @@ struct njsSubscription { njsModuleGlobals *globals; uint32_t subscrNamespace; uint64_t regId; - char *name; - size_t nameLength; napi_ref jsCallback; napi_env env; + bool notifications; }; // data for keeping track of variables used for binding/fetching data @@ -770,7 +659,6 @@ struct njsVariableBuffer { // data for DbObject class exposed to JS struct njsDbObject { - NJS_INSTANCE_HEAD dpiObject *handle; njsDbObjectType *type; }; @@ -842,30 +730,11 @@ bool njsBaton_commonConnectProcessArgs(njsBaton *baton, napi_env env, bool njsBaton_create(njsBaton *baton, napi_env env, napi_callback_info info, size_t numArgs, napi_value *args, const njsClassDef *classDef); void njsBaton_free(njsBaton *baton, napi_env env); -bool njsBaton_getBoolFromArg(njsBaton *baton, napi_env env, napi_value *args, - int argIndex, const char *propertyName, bool *result, bool *found); bool njsBaton_getFetchInfoFromArg(njsBaton *baton, napi_env env, napi_value props, uint32_t *numFetchInfo, njsFetchInfo **fetchInfo); -bool njsBaton_getIntFromArg(njsBaton *baton, napi_env env, napi_value *args, - int argIndex, const char *propertyName, int32_t *result, bool *found); uint32_t njsBaton_getNumOutBinds(njsBaton *baton); bool njsBaton_getSodaDocument(njsBaton *baton, njsSodaDatabase *db, napi_env env, napi_value obj, dpiSodaDoc **handle); -bool njsBaton_getStringFromArg(njsBaton *baton, napi_env env, napi_value *args, - int argIndex, const char *propertyName, char **result, - size_t *resultLength, bool *found); -bool njsBaton_getStrBufFromArg(njsBaton *baton, napi_env env, napi_value *args, - int argIndex, const char *propertyName, char **result, - size_t *resultLength, bool *found); -bool njsBaton_getSubscription(njsBaton *baton, napi_env env, napi_value name, - bool unsubscribe); -bool njsBaton_getUnsignedIntFromArg(njsBaton *baton, napi_env env, - napi_value *args, int argIndex, const char *propertyName, - uint32_t *result, bool *found); -bool njsBaton_getValueFromArg(njsBaton *baton, napi_env env, napi_value *args, - int argIndex, const char *propertyName, napi_valuetype expectedType, - napi_value *value, bool *found); -bool njsBaton_getXid(njsBaton *baton, napi_env env, napi_value arg); bool njsBaton_initCommonCreateParams(njsBaton *baton, dpiCommonCreateParams *params); bool njsBaton_isBindValue(njsBaton *baton, napi_env env, napi_value value); @@ -876,7 +745,12 @@ bool njsBaton_queueWork(njsBaton *baton, napi_env env, const char *methodName, bool (*afterWorkCallback)(njsBaton*, napi_env, napi_value*), napi_value *promise); bool njsBaton_reportError(njsBaton *baton, napi_env env); -bool njsBaton_setError(njsBaton *baton, int errNum, ...); +bool njsBaton_setErrorInsufficientBufferForBinds(njsBaton *baton); +bool njsBaton_setErrorInsufficientMemory(njsBaton *baton); +bool njsBaton_setErrorUnsupportedDataType(njsBaton *baton, + uint32_t oracleTypeNum, uint32_t columnNum); +bool njsBaton_setErrorUnsupportedDataTypeInJson(njsBaton *baton, + uint32_t oracleTypeNum); bool njsBaton_setErrorDPI(njsBaton *baton); bool njsBaton_setJsValues(njsBaton *baton, napi_env env); @@ -972,8 +846,7 @@ bool njsSodaOperation_createFromCollection(napi_env env, //----------------------------------------------------------------------------- void njsSubscription_eventHandler(njsSubscription *subscr, dpiSubscrMessage *incomingMessage); -bool njsSubscription_new(njsBaton *baton, napi_env env, napi_value *obj, - njsSubscription **subscr); +bool njsSubscription_new(njsBaton *baton, napi_env env); bool njsSubscription_startNotifications(njsSubscription *subscr, napi_env env, njsBaton *baton); bool njsSubscription_stopNotifications(njsSubscription *subscr); @@ -985,15 +858,6 @@ bool njsSubscription_stopNotifications(njsSubscription *subscr); bool njsUtils_addTypeProperties(napi_env env, napi_value obj, const char *propertyNamePrefix, uint32_t oracleTypeNum, njsDbObjectType *objType); -napi_value njsUtils_convertToBoolean(napi_env env, bool value); -napi_value njsUtils_convertToInt(napi_env env, int32_t value); -napi_value njsUtils_convertToString(napi_env env, const char *value, - uint32_t valueLength); -napi_value njsUtils_convertToUnsignedInt(napi_env env, uint32_t value); -napi_value njsUtils_convertToUnsignedIntArray(napi_env env, - uint32_t numValues, uint32_t *values); -bool njsUtils_copyArray(napi_env env, void *sourceArray, uint32_t numElements, - size_t elementSize, void **destArray, uint32_t *destNumElements); bool njsUtils_copyString(napi_env env, char *source, size_t sourceLength, char **dest, size_t *destLength); bool njsUtils_copyStringFromJS(napi_env env, napi_value value, char **result, @@ -1002,8 +866,7 @@ bool njsUtils_createBaton(napi_env env, napi_callback_info info, size_t numArgs, napi_value *args, const njsClassDef *classDef, njsBaton **baton); bool njsUtils_genericNew(napi_env env, const njsClassDef *classDef, - napi_ref constructorRef, napi_value *instanceObj, - njsBaseInstance **instance); + napi_ref constructorRef, napi_value *instanceObj, void **instance); bool njsUtils_genericThrowError(napi_env env, const char *fileName, int lineNum); bool njsUtils_getError(napi_env env, dpiErrorInfo *errorInfo, @@ -1022,28 +885,19 @@ bool njsUtils_getNamedPropertyString(napi_env env, napi_value value, bool njsUtils_getNamedPropertyStringArray(napi_env env, napi_value value, const char *name, uint32_t *resultNumElems, char ***resultElems, uint32_t **resultElemLengths); +bool njsUtils_getNamedPropertyStringOrBuffer(napi_env env, napi_value value, + const char *name, char **result, size_t *resultLength); bool njsUtils_getNamedPropertyUnsignedInt(napi_env env, napi_value value, const char *name, uint32_t *outValue); bool njsUtils_getNamedPropertyUnsignedIntArray(napi_env env, napi_value value, const char *name, uint32_t *numElements, uint32_t **elements); -bool njsUtils_getStringFromArg(napi_env env, napi_value *args, - int argIndex, const char *propertyName, char **result, - size_t *resultLength, bool *found, char *errorBuffer); -bool njsUtils_getValueFromArg(napi_env env, napi_value *args, - int argIndex, const char *propertyName, napi_valuetype expectedType, - napi_value *value, bool *found, char *errorBuffer); -bool njsUtils_isBuffer(napi_env env, napi_value value); +bool njsUtils_getXid(napi_env env, napi_value xidObj, dpiXid **xid); bool njsUtils_isInstance(napi_env env, napi_value value, const char *name); -bool njsUtils_throwError(napi_env env, int errNum, ...); +bool njsUtils_throwInsufficientMemory(napi_env env); bool njsUtils_throwErrorDPI(napi_env env, njsModuleGlobals *globals); bool njsUtils_validateArgs(napi_env env, napi_callback_info info, size_t numArgs, napi_value *args, njsModuleGlobals **globals, - napi_value *callingObj, const njsClassDef *classDef, - njsBaseInstance **instance); -bool njsUtils_validateArgType(napi_env env, napi_value *args, - napi_valuetype expectedType, int index); -bool njsUtils_validatePropType(napi_env env, napi_value value, - napi_valuetype expectedType, const char *name); + napi_value *callingObj, const njsClassDef *classDef, void **instance); //----------------------------------------------------------------------------- diff --git a/src/njsPool.c b/src/njsPool.c index 24422b28..6bb863cb 100644 --- a/src/njsPool.c +++ b/src/njsPool.c @@ -61,9 +61,6 @@ static NJS_ASYNC_METHOD(njsPool_setAccessTokenAsync); static NJS_ASYNC_POST_METHOD(njsPool_createPostAsync); static NJS_ASYNC_POST_METHOD(njsPool_getConnectionPostAsync); -// processing arguments methods -static NJS_PROCESS_ARGS_METHOD(njsPool_reconfigureProcessArgs); - // finalize static NJS_NAPI_FINALIZE(njsPool_finalize); @@ -119,8 +116,8 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsPool_close, 1, NULL) { njsPool *pool = (njsPool*) baton->callingInstance; - if (!njsBaton_getBoolFromArg(baton, env, args, 0, "forceClose", - &baton->force, NULL)) + if (!njsUtils_getNamedPropertyBool(env, args[0], "forceClose", + &baton->force)) return false; baton->accessTokenCallback = pool->accessTokenCallback; pool->accessTokenCallback = NULL; @@ -341,10 +338,6 @@ static void njsPool_finalize(napi_env env, void *finalizeData, //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsPool_getConnection, 1, NULL) { - njsPool *pool = (njsPool*) baton->callingInstance; - - if (!pool->handle) - return njsBaton_setError(baton, errInvalidPool); if (!njsUtils_getNamedPropertyString(env, args[0], "connectionClass", &baton->connectionClass, &baton->connectionClassLength)) return false; @@ -411,7 +404,7 @@ static bool njsPool_getConnectionAsync(njsBaton *baton) baton->tag = malloc(params.outTagLength); if (!baton->tag) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); strncpy(baton->tag, params.outTag, params.outTagLength); baton->tagLength = params.outTagLength; } @@ -455,10 +448,42 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsPool_reconfigure, 1, NULL) { njsPool *pool = (njsPool*) baton->callingInstance; - if (!pool->handle) - return njsBaton_setError(baton, errInvalidPool); - if (!njsPool_reconfigureProcessArgs(baton, env, args)) + // set defaults + baton->poolMin = pool->poolMin; + baton->poolMax = pool->poolMax; + baton->poolIncrement = pool->poolIncrement; + baton->poolPingInterval = pool->poolPingInterval; + baton->poolTimeout = pool->poolTimeout; + baton->stmtCacheSize = pool->stmtCacheSize; + baton->poolMaxPerShard = pool->poolMaxPerShard; + baton->sodaMetadataCache = pool->sodaMetadataCache; + + // check arguments + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[0], "poolMin", + &baton->poolMin)) return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[0], "poolMax", + &baton->poolMax)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[0], "poolMaxPerShard", + &baton->poolMaxPerShard)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[0], "poolIncrement", + &baton->poolIncrement)) + return false; + if (!njsUtils_getNamedPropertyInt(env, args[0], "poolPingInterval", + &baton->poolPingInterval)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[0], "poolTimeout", + &baton->poolTimeout)) + return false; + if (!njsUtils_getNamedPropertyUnsignedInt(env, args[0], "stmtCacheSize", + &baton->stmtCacheSize)) + return false; + if (!njsUtils_getNamedPropertyBool(env, args[0], "sodaMetaDataCache", + &baton->sodaMetadataCache)) + return false; + return njsBaton_queueWork(baton, env, "Reconfigure", njsPool_reconfigureAsync, NULL, returnValue); } @@ -526,61 +551,6 @@ static bool njsPool_reconfigureAsync(njsBaton *baton) } -//----------------------------------------------------------------------------- -// njsPool_reconfigureProcessArgs() -// Process the arguemnts for njsPool_reconfigure(). -//----------------------------------------------------------------------------- -static bool njsPool_reconfigureProcessArgs(njsBaton *baton, napi_env env, - napi_value *args) -{ - njsPool *pool = (njsPool *) baton->callingInstance; - - baton->poolMin = pool->poolMin; - baton->poolMax = pool->poolMax; - baton->poolIncrement = pool->poolIncrement; - baton->poolPingInterval = pool->poolPingInterval; - baton->poolTimeout = pool->poolTimeout; - baton->stmtCacheSize = pool->stmtCacheSize; - baton->poolMaxPerShard = pool->poolMaxPerShard; - baton->sodaMetadataCache = pool->sodaMetadataCache; - - // check arguments - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 0, "poolMin", - &baton->poolMin, NULL)) - return false; - - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 0, "poolMax", - &baton->poolMax, NULL)) - return false; - - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 0, "poolIncrement", - &baton->poolIncrement, NULL)) - return false; - - if (!njsBaton_getIntFromArg(baton, env, args, 0, "poolPingInterval", - &baton->poolPingInterval, NULL)) - return false; - - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 0, "poolTimeout", - &baton->poolTimeout, NULL)) - return false; - - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 0, "stmtCacheSize", - &baton->stmtCacheSize, NULL)) - return false; - - if (!njsBaton_getUnsignedIntFromArg(baton, env, args, 0, "poolMaxPerShard", - &baton->poolMaxPerShard, NULL)) - return false; - - if (!njsBaton_getBoolFromArg(baton, env, args, 0, "sodaMetaDataCache", - &baton->sodaMetadataCache, NULL)) - return false; - - return true; -} - - //----------------------------------------------------------------------------- // njsPool_getConnectionsInUse() // Get accessor of "connectionsInUse" property. @@ -760,15 +730,11 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsPool_returnAccessToken, 2, NULL) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsPool_setAccessToken, 1, NULL) { - njsPool *pool = (njsPool*) baton->callingInstance; - - if (!pool->handle) - return njsBaton_setError(baton, errInvalidPool); - if (!njsBaton_getStringFromArg(baton, env, args, 0, "token", - &baton->token, &baton->tokenLength, NULL)) + if (!njsUtils_getNamedPropertyString(env, args[0], "token", &baton->token, + &baton->tokenLength)) return false; - if (!njsBaton_getStringFromArg(baton, env, args, 0, "privateKey", - &baton->privateKey, &baton->privateKeyLength, NULL)) + if (!njsUtils_getNamedPropertyString(env, args[0], "privateKey", + &baton->privateKey, &baton->privateKeyLength)) return false; return njsBaton_queueWork(baton, env, "token", njsPool_setAccessTokenAsync, NULL, returnValue); diff --git a/src/njsResultSet.c b/src/njsResultSet.c index 6861be6b..a55a1287 100644 --- a/src/njsResultSet.c +++ b/src/njsResultSet.c @@ -64,22 +64,6 @@ const njsClassDef njsClassDefResultSet = { njsClassProperties, false }; -// other methods used internally -static bool njsResultSet_check(njsResultSet *rs, njsBaton *baton); - -//----------------------------------------------------------------------------- -// njsResultSet_check() -// Checks the result set to ensure it is valid and then marks the current -// baton as the active one (to prevent concurrent access). -//----------------------------------------------------------------------------- -static bool njsResultSet_check(njsResultSet *rs, njsBaton *baton) -{ - if (!rs->handle || !rs->conn->handle) - return njsBaton_setError(baton, errInvalidResultSet); - rs->activeBaton = baton; - return true; -} - //----------------------------------------------------------------------------- // njsResultSet_close() @@ -91,8 +75,6 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsResultSet_close, 0, NULL) { njsResultSet *rs = (njsResultSet*) baton->callingInstance; - if (!njsResultSet_check(rs, baton)) - return false; baton->dpiStmtHandle = rs->handle; rs->handle = NULL; return njsBaton_queueWork(baton, env, "Close", njsResultSet_closeAsync, @@ -170,14 +152,8 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsResultSet_getMetaData, 0, NULL) //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsResultSet_getRows, 1, NULL) { - njsResultSet *rs = (njsResultSet*) baton->callingInstance; - - if (!njsResultSet_check(rs, baton)) - return false; - NJS_CHECK_NAPI(env, napi_get_value_uint32(env, args[0], - &baton->fetchArraySize)) - + &baton->fetchArraySize)) return njsBaton_queueWork(baton, env, "GetRows", njsResultSet_getRowsAsync, njsResultSet_getRowsPostAsync, returnValue); } @@ -309,8 +285,7 @@ bool njsResultSet_new(njsBaton *baton, napi_env env, njsConnection *conn, // create new instance if (!njsUtils_genericNew(env, &njsClassDefResultSet, - baton->globals->jsResultSetConstructor, rsObj, - (njsBaseInstance**) &rs)) + baton->globals->jsResultSetConstructor, rsObj, (void**) &rs)) return false; // store a reference to the parent object (a connection or a parent result diff --git a/src/njsSodaCollection.c b/src/njsSodaCollection.c index a473dc2a..d6da6836 100644 --- a/src/njsSodaCollection.c +++ b/src/njsSodaCollection.c @@ -439,7 +439,7 @@ static bool njsSodaCollection_insertManyProcessArgs(njsBaton *baton, &baton->numSodaDocs)) baton->sodaDocs = calloc(baton->numSodaDocs, sizeof(dpiSodaDoc*)); if (!baton->sodaDocs) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); // acquire a SODA document handle for each entry in the array for (i = 0; i < baton->numSodaDocs; i++) { @@ -490,7 +490,7 @@ static bool njsSodaCollection_insertManyAndGetAsync(njsBaton *baton) flags |= DPI_SODA_FLAGS_ATOMIC_COMMIT; resultDocs = calloc(baton->numSodaDocs, sizeof(dpiSodaDoc*)); if (!resultDocs) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (dpiSodaColl_insertManyWithOptions(coll->handle, baton->numSodaDocs, baton->sodaDocs, baton->sodaOperOptions, flags, resultDocs) < 0) { free(resultDocs); @@ -646,7 +646,7 @@ bool njsSodaCollection_newFromBaton(njsBaton *baton, napi_env env, // create new instance if (!njsUtils_genericNew(env, &njsClassDefSodaCollection, baton->globals->jsSodaCollectionConstructor, collObj, - (njsBaseInstance**) &coll)) + (void**) &coll)) return false; // store a copy of the database instance on the collection object to @@ -682,7 +682,7 @@ static bool njsSodaCollection_processHintOption(njsBaton *baton, napi_env env, if (baton->hintLength) { baton->sodaOperOptions = calloc(1, sizeof(dpiSodaOperOptions)); if (!baton->sodaOperOptions) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); baton->sodaOperOptions->hint = baton->hint; baton->sodaOperOptions->hintLength = (uint32_t) baton->hintLength; } diff --git a/src/njsSodaDatabase.c b/src/njsSodaDatabase.c index b33ab04b..d6bcabcf 100644 --- a/src/njsSodaDatabase.c +++ b/src/njsSodaDatabase.c @@ -156,13 +156,13 @@ NJS_NAPI_METHOD_IMPL_SYNC(njsSodaDatabase_createDocument, 2, NULL) &contentLength)) // acquire the key value, if one was specified - if (!njsUtils_getStringFromArg(env, args, 1, "key", &key, &keyLength, - NULL, NULL)) + if (!njsUtils_getNamedPropertyString(env, args[1], "key", &key, + &keyLength)) return false; // acquire the mediaType value, if one was specified - if (!njsUtils_getStringFromArg(env, args, 1, "mediaType", &mediaType, - &mediaTypeLength, NULL, NULL)) { + if (!njsUtils_getNamedPropertyString(env, args[1], "mediaType", &mediaType, + &mediaTypeLength)) { if (key) free(key); return false; @@ -218,12 +218,11 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsSodaDatabase_getCollectionNames, 1, NULL) { baton->sodaCollNames = calloc(1, sizeof(dpiSodaCollNames)); if (!baton->sodaCollNames) - return njsBaton_setError(baton, errInsufficientMemory); - if (!njsBaton_getStringFromArg(baton, env, args, 0, "startsWith", - &baton->startsWith, &baton->startsWithLength, NULL)) + return njsUtils_throwInsufficientMemory(env); + if (!njsUtils_getNamedPropertyString(env, args[0], "startsWith", + &baton->startsWith, &baton->startsWithLength)) return false; - if (!njsBaton_getIntFromArg(baton, env, args, 0, "limit", &baton->limit, - NULL)) + if (!njsUtils_getNamedPropertyInt(env, args[0], "limit", &baton->limit)) return false; return njsBaton_queueWork(baton, env, "GetCollectionNames", njsSodaDatabase_getCollectionNamesAsync, @@ -301,8 +300,7 @@ bool njsSodaDatabase_createFromHandle(napi_env env, napi_value connObj, // create new instance if (!njsUtils_genericNew(env, &njsClassDefSodaDatabase, - globals->jsSodaDatabaseConstructor, dbObj, - (njsBaseInstance**) &db)) + globals->jsSodaDatabaseConstructor, dbObj, (void**) &db)) return false; // perform initialization diff --git a/src/njsSodaDocCursor.c b/src/njsSodaDocCursor.c index def15133..67287de7 100644 --- a/src/njsSodaDocCursor.c +++ b/src/njsSodaDocCursor.c @@ -72,8 +72,6 @@ NJS_NAPI_METHOD_IMPL_ASYNC(njsSodaDocCursor_close, 0, NULL) { njsSodaDocCursor *cursor = (njsSodaDocCursor*) baton->callingInstance; - if (!cursor->handle) - return njsBaton_setError(baton, errInvalidSodaDocCursor); baton->dpiSodaDocCursorHandle = cursor->handle; cursor->handle = NULL; return njsBaton_queueWork(baton, env, "Close", njsSodaDocCursor_closeAsync, @@ -124,10 +122,6 @@ static void njsSodaDocCursor_finalize(napi_env env, void *finalizeData, //----------------------------------------------------------------------------- NJS_NAPI_METHOD_IMPL_ASYNC(njsSodaDocCursor_getNext, 0, NULL) { - njsSodaDocCursor *cursor = (njsSodaDocCursor*) baton->callingInstance; - - if (!cursor->handle) - return njsBaton_setError(baton, errInvalidSodaDocCursor); return njsBaton_queueWork(baton, env, "GetNext", njsSodaDocCursor_getNextAsync, njsSodaDocCursor_getNextPostAsync, returnValue); @@ -178,7 +172,7 @@ bool njsSodaDocCursor_newFromBaton(njsBaton *baton, napi_env env, // create new instance if (!njsUtils_genericNew(env, &njsClassDefSodaDocCursor, baton->globals->jsSodaDocCursorConstructor, cursorObj, - (njsBaseInstance**) &cursor)) + (void**) &cursor)) return false; // storing reference to operation which in turn stores reference to diff --git a/src/njsSodaDocument.c b/src/njsSodaDocument.c index 5cc77242..7321f323 100644 --- a/src/njsSodaDocument.c +++ b/src/njsSodaDocument.c @@ -71,7 +71,7 @@ const njsClassDef njsClassDefSodaDocument = { // other methods used internally static bool njsSodaDocument_genericGetter(napi_env env, - njsModuleGlobals *globals, njsBaseInstance *instance, + njsModuleGlobals *globals, void *instance, int (*dpiGetterFn)(dpiSodaDoc*, const char**, uint32_t *), napi_value *returnValue); @@ -87,8 +87,7 @@ bool njsSodaDocument_createFromHandle(napi_env env, dpiSodaDoc *handle, // create new instance if (!njsUtils_genericNew(env, &njsClassDefSodaDocument, - globals->jsSodaDocumentConstructor, docObj, - (njsBaseInstance**) &doc)) + globals->jsSodaDocumentConstructor, docObj, (void**) &doc)) return false; // perform initializations @@ -121,7 +120,7 @@ static void njsSodaDocument_finalize(napi_env env, void *finalizeData, // SODA document. //----------------------------------------------------------------------------- static bool njsSodaDocument_genericGetter(napi_env env, - njsModuleGlobals *globals, njsBaseInstance *instance, + njsModuleGlobals *globals, void *instance, int (*dpiGetterFn)(dpiSodaDoc*, const char**, uint32_t *), napi_value *returnValue) { diff --git a/src/njsSodaOperation.c b/src/njsSodaOperation.c index dc970263..2e115891 100644 --- a/src/njsSodaOperation.c +++ b/src/njsSodaOperation.c @@ -155,8 +155,7 @@ bool njsSodaOperation_createFromCollection(napi_env env, // create new instance if (!njsUtils_genericNew(env, &njsClassDefSodaOperation, - globals->jsSodaOperationConstructor, opObj, - (njsBaseInstance**) &op)) + globals->jsSodaOperationConstructor, opObj, (void**) &op)) return false; // perform some initializations @@ -281,7 +280,7 @@ static bool njsSodaOperation_getDocumentsAsync(njsBaton *baton) numAllocated += 16; tempArray = malloc(numAllocated * sizeof(dpiSodaDoc*)); if (!tempArray) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (baton->sodaDocs) { memcpy(tempArray, baton->sodaDocs, baton->numSodaDocs * sizeof(dpiSodaDoc*)); @@ -396,7 +395,7 @@ static bool njsSodaOperation_processOptions(njsBaton *baton, napi_env env, // allocate memory for ODPI-C operations structure baton->sodaOperOptions = calloc(1, sizeof(dpiSodaOperOptions)); if (!baton->sodaOperOptions) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); // set fetch array size, but ONLY if the client version exceeds 19.5 if (dpiContext_getClientVersion(baton->globals->context, diff --git a/src/njsSubscription.c b/src/njsSubscription.c index 857f5338..2bd38819 100644 --- a/src/njsSubscription.c +++ b/src/njsSubscription.c @@ -254,7 +254,7 @@ static bool njsSubscription_createMessageTable(napi_env env, void njsSubscription_eventHandler(njsSubscription *subscr, dpiSubscrMessage *incomingMessage) { - if (subscr->handle && subscr->name) { + if (subscr->handle) { uv_mutex_lock(&subscr->mutex); uv_barrier_init(&subscr->barrier, 2); subscr->message = incomingMessage; @@ -274,7 +274,6 @@ static void njsSubscription_finalize(napi_env env, void *finalizeData, { njsSubscription *subscr = (njsSubscription*) finalizeData; - NJS_FREE_AND_CLEAR(subscr->name); if (subscr->handle) { dpiSubscr_release(subscr->handle); subscr->handle = NULL; @@ -289,24 +288,26 @@ static void njsSubscription_finalize(napi_env env, void *finalizeData, // njsSubscription_new() // Creates a new subscription object. //----------------------------------------------------------------------------- -bool njsSubscription_new(njsBaton *baton, napi_env env, napi_value *obj, - njsSubscription **subscr) +bool njsSubscription_new(njsBaton *baton, napi_env env) { njsSubscription *tempSubscr; + napi_value subscrObj; tempSubscr = calloc(1, sizeof(njsSubscription)); if (!tempSubscr) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (napi_create_external(env, tempSubscr, njsSubscription_finalize, - tempSubscr, obj) != napi_ok) { + tempSubscr, &subscrObj) != napi_ok) { free(tempSubscr); return njsUtils_genericThrowError(env, __FILE__, __LINE__); } + NJS_CHECK_NAPI(env, napi_create_reference(env, subscrObj, 1, + &baton->jsSubscriptionRef)) tempSubscr->globals = baton->globals; tempSubscr->env = env; tempSubscr->subscrNamespace = DPI_SUBSCR_NAMESPACE_DBCHANGE; + baton->subscription = tempSubscr; - *subscr = tempSubscr; return true; } @@ -335,19 +336,7 @@ static void njsSubscription_onStopNotifications(uv_handle_t *handle) static bool njsSubscription_onStopNotificationsHelper(napi_env env, njsSubscription *subscr) { - napi_value name, allSubscriptions; - - // delete property in all subscriptions object, if needed - NJS_CHECK_NAPI(env, napi_create_string_utf8(env, subscr->name, - subscr->nameLength, &name)) - NJS_CHECK_NAPI(env, napi_get_reference_value(env, - subscr->globals->jsSubscriptions, &allSubscriptions)) - NJS_CHECK_NAPI(env, napi_delete_property(env, allSubscriptions, name, - NULL)) - - // perform cleanup uv_mutex_destroy(&subscr->mutex); - NJS_FREE_AND_CLEAR(subscr->name); if (subscr->handle) { dpiSubscr_release(subscr->handle); subscr->handle = NULL; @@ -422,11 +411,10 @@ bool njsSubscription_startNotifications(njsSubscription *subscr, { uv_loop_t *loop; - if (!subscr->name) { + if (!subscr->notifications) { // keep the name on the subscription - subscr->name = baton->name; - subscr->nameLength = baton->nameLength; + subscr->notifications = true; baton->name = NULL; baton->nameLength = 0; @@ -454,9 +442,10 @@ bool njsSubscription_startNotifications(njsSubscription *subscr, //----------------------------------------------------------------------------- bool njsSubscription_stopNotifications(njsSubscription *subscr) { - if (subscr->name) { + if (subscr->notifications) { uv_close((uv_handle_t*) &subscr->async, njsSubscription_onStopNotifications); + subscr->notifications = false; } return true; } diff --git a/src/njsTokenCallback.c b/src/njsTokenCallback.c index a24f2910..83e33509 100644 --- a/src/njsTokenCallback.c +++ b/src/njsTokenCallback.c @@ -82,11 +82,11 @@ bool njsTokenCallback_new(njsBaton *baton, napi_env env, callback = calloc(1, sizeof(njsTokenCallback)); if (!callback) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); baton->accessTokenCallback = callback; callback->accessToken = calloc(1, sizeof(dpiAccessToken)); if (!callback->accessToken) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); callback->env = env; callback->globals = baton->globals; NJS_CHECK_NAPI(env, napi_create_reference(env, userCallback, 1, diff --git a/src/njsUtils.c b/src/njsUtils.c index 51066fae..6989164e 100644 --- a/src/njsUtils.c +++ b/src/njsUtils.c @@ -157,125 +157,6 @@ bool njsUtils_addTypeProperties(napi_env env, napi_value obj, } -//----------------------------------------------------------------------------- -// njsUtils_convertToBoolean() -// Convert a C boolean value to a JavaScript boolean value. -//----------------------------------------------------------------------------- -napi_value njsUtils_convertToBoolean(napi_env env, bool value) -{ - napi_value jsValue; - - if (napi_get_boolean(env, value, &jsValue) != napi_ok) { - njsUtils_genericThrowError(env, __FILE__, __LINE__); - return NULL; - } - - return jsValue; -} - - -//----------------------------------------------------------------------------- -// njsUtils_convertToInt() -// Convert a C integer to a JavaScript number value. -//----------------------------------------------------------------------------- -napi_value njsUtils_convertToInt(napi_env env, int32_t value) -{ - napi_value jsValue; - - if (napi_create_int32(env, value, &jsValue) != napi_ok) { - njsUtils_genericThrowError(env, __FILE__, __LINE__); - return NULL; - } - - return jsValue; -} - - -//----------------------------------------------------------------------------- -// njsUtils_convertToString() -// Convert a C string value to a JavaScript string value. -//----------------------------------------------------------------------------- -napi_value njsUtils_convertToString(napi_env env, const char *value, - uint32_t valueLength) -{ - napi_value jsValue; - - if (napi_create_string_utf8(env, value, valueLength, - &jsValue) != napi_ok) { - njsUtils_genericThrowError(env, __FILE__, __LINE__); - return NULL; - } - - return jsValue; -} - - -//----------------------------------------------------------------------------- -// njsUtils_convertToUnsignedInt() -// Convert a C unsigned integer to a JavaScript number value. -//----------------------------------------------------------------------------- -napi_value njsUtils_convertToUnsignedInt(napi_env env, uint32_t value) -{ - napi_value jsValue; - - if (napi_create_uint32(env, value, &jsValue) != napi_ok) { - njsUtils_genericThrowError(env, __FILE__, __LINE__); - return NULL; - } - - return jsValue; -} - - -//----------------------------------------------------------------------------- -// njsUtils_convertToUnsignedIntArray() -// Convert an array of C unsigned integers to a JavaScript array value. -//----------------------------------------------------------------------------- -napi_value njsUtils_convertToUnsignedIntArray(napi_env env, uint32_t numValues, - uint32_t *values) -{ - napi_value jsValue, temp; - uint32_t i; - - if (napi_create_array_with_length(env, numValues, &jsValue) != napi_ok) { - njsUtils_genericThrowError(env, __FILE__, __LINE__); - return NULL; - } - for (i = 0; i < numValues; i++) { - if (napi_create_uint32(env, values[i], &temp) != napi_ok) { - njsUtils_genericThrowError(env, __FILE__, __LINE__); - return NULL; - } - if (napi_set_element(env, jsValue, i, temp) != napi_ok) { - njsUtils_genericThrowError(env, __FILE__, __LINE__); - return NULL; - } - } - - return jsValue; -} - - -//----------------------------------------------------------------------------- -// njsUtils_copyArray() -// Copy an array with the specified number of elements to the destination, -// returning a boolean indicating if this was done successfully or not. -//----------------------------------------------------------------------------- -bool njsUtils_copyArray(napi_env env, void *sourceArray, uint32_t numElements, - size_t elementSize, void **destArray, uint32_t *destNumElements) -{ - if (sourceArray) { - *destArray = malloc(numElements * elementSize); - if (!*destArray) - return njsUtils_throwError(env, errInsufficientMemory); - memcpy(*destArray, sourceArray, numElements * elementSize); - *destNumElements = numElements; - } - - return true; -} - - //----------------------------------------------------------------------------- // njsUtils_copyString() // Copy an array with the specified number of elements to the destination, @@ -287,7 +168,7 @@ bool njsUtils_copyString(napi_env env, char *source, size_t sourceLength, if (source && sourceLength > 0) { *dest = malloc(sourceLength); if (!*dest) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); memcpy(*dest, source, sourceLength); *destLength = sourceLength; } @@ -313,7 +194,7 @@ bool njsUtils_copyStringFromJS(napi_env env, napi_value value, char **result, free(*result); *result = malloc(*resultLength + 1); if (!*result) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); // get the string value contents NJS_CHECK_NAPI(env, napi_get_value_string_utf8(env, value, *result, @@ -335,10 +216,8 @@ bool njsUtils_createBaton(napi_env env, napi_callback_info info, // allocate and zero memory tempBaton = calloc(1, sizeof(njsBaton)); - if (!tempBaton) { - njsUtils_throwError(env, errInsufficientMemory); - return false; - } + if (!tempBaton) + return njsUtils_throwInsufficientMemory(env); // perform common checks and populate common attributes in the baton if (!njsBaton_create(tempBaton, env, info, numArgs, args, classDef)) { @@ -357,8 +236,7 @@ bool njsUtils_createBaton(napi_env env, napi_callback_info info, // size and finalize function. //----------------------------------------------------------------------------- bool njsUtils_genericNew(napi_env env, const njsClassDef *classDef, - napi_ref constructorRef, napi_value *instanceObj, - njsBaseInstance **instance) + napi_ref constructorRef, napi_value *instanceObj, void **instance) { napi_value constructor; size_t numProperties; @@ -374,10 +252,8 @@ bool njsUtils_genericNew(napi_env env, const njsClassDef *classDef, // allocate memory for structure; memory is zero-ed data = calloc(1, classDef->structSize); - if (!data) { - njsUtils_throwError(env, errInsufficientMemory); - return false; - } + if (!data) + return njsUtils_throwInsufficientMemory(env); // wrap the structure for use by JavaScript if (napi_wrap(env, *instanceObj, data, classDef->finalizeFn, NULL, @@ -394,7 +270,7 @@ bool njsUtils_genericNew(napi_env env, const njsClassDef *classDef, numProperties, classDef->properties)) } - *instance = (njsBaseInstance*) data; + *instance = data; return true; } @@ -562,7 +438,7 @@ bool njsUtils_getNamedPropertyShardingKey(napi_env env, napi_value value, return true; shards = calloc(arrLen, sizeof(dpiShardingKeyColumn)); if (!shards) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); *shardingKeyColumns = shards; *numShardingKeyColumns = (uint8_t) arrLen; @@ -673,11 +549,11 @@ bool njsUtils_getNamedPropertyStringArray(napi_env env, napi_value value, // allocate memory for the results tempStrings = calloc(arrayLength, sizeof(char*)); if (!tempStrings) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); *resultElems = tempStrings; tempLengths = calloc(arrayLength, sizeof(uint32_t)); if (!tempLengths) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); *resultElemLengths = tempLengths; // populate the results @@ -694,6 +570,37 @@ bool njsUtils_getNamedPropertyStringArray(napi_env env, napi_value value, } +//----------------------------------------------------------------------------- +// njsUtils_getNamedPropertyStringOrBuffer() +// Returns the value of the named property, which is assumed to be a string +// or Buffer value. If the value is not found, the string value is left +// unchanged. +//----------------------------------------------------------------------------- +bool njsUtils_getNamedPropertyStringOrBuffer(napi_env env, napi_value value, + const char *name, char **result, size_t *resultLength) +{ + napi_value resultObj; + size_t bufLen; + bool check; + void *buf; + + if (!njsUtils_getNamedProperty(env, value, name, &resultObj)) + return false; + if (resultObj) { + NJS_CHECK_NAPI(env, napi_is_buffer(env, resultObj, &check)) + if (!check) + return njsUtils_copyStringFromJS(env, resultObj, result, + resultLength); + NJS_CHECK_NAPI(env, napi_get_buffer_info(env, resultObj, &buf, + &bufLen)) + if (!njsUtils_copyString(env, buf, bufLen, result, resultLength)) + return false; + } + + return true; +} + + //----------------------------------------------------------------------------- // njsUtils_getNamedPropertyUnsignedInt() // Returns the value of the named property, which is assumed to be an @@ -744,7 +651,7 @@ bool njsUtils_getNamedPropertyUnsignedIntArray(napi_env env, napi_value value, NJS_CHECK_NAPI(env, napi_get_array_length(env, array, numElements)) *elements = calloc(*numElements, sizeof(uint32_t)); if (!elements && *numElements > 0) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); for (i = 0; i < *numElements; i++) { NJS_CHECK_NAPI(env, napi_get_element(env, array, i, &element)) NJS_CHECK_NAPI(env, napi_get_value_uint32(env, element, @@ -756,115 +663,60 @@ bool njsUtils_getNamedPropertyUnsignedIntArray(napi_env env, napi_value value, //----------------------------------------------------------------------------- -// njsUtils_getStringFromArg() -// Gets a string value from the specified JavaScript object property, if -// possible. If the given property is undefined, no error is set and the value -// is left untouched; otherwise, if the value is not a string, the error -// message is populated. +// njsUtils_getXid() +// Returns the XID from the specified N-API value. //----------------------------------------------------------------------------- -bool njsUtils_getStringFromArg(napi_env env, napi_value *args, - int argIndex, const char *propertyName, char **result, - size_t *resultLength, bool *found, char *errorBuffer) +bool njsUtils_getXid(napi_env env, napi_value value, dpiXid **xid) { - char localError[NJS_MAX_ERROR_MSG_LEN + 1]; - napi_value value; + napi_valuetype valueType; + dpiXid *tempXid; + int32_t fmtId; + size_t len; - // if no error buffer was provided, call the routine a second time with - // the local error buffer; if an error was written, throw it - if (!errorBuffer) { - localError[0] = '\0'; - if (!njsUtils_getStringFromArg(env, args, argIndex, propertyName, - result, resultLength, found, localError)) { - if (localError[0] != '\0') - napi_throw_error(env, NULL, localError); - return false; - } + // if value is undefined, nothing further to do! + NJS_CHECK_NAPI(env, napi_typeof(env, value, &valueType)) + if (valueType == napi_undefined) { + *xid = NULL; return true; } - // get the value from the object and verify it is a string - if (!njsUtils_getValueFromArg(env, args, argIndex, propertyName, - napi_string, &value, found, errorBuffer)) + // allocate memory for the XID structure + tempXid = calloc(1, sizeof(dpiXid)); + if (!tempXid) + return njsUtils_throwInsufficientMemory(env); + *xid = tempXid; + + // get formatId + if (!njsUtils_getNamedPropertyInt(env, value, "formatId", &fmtId)) return false; - if (!value) - return true; + tempXid->formatId = (long) fmtId; - return njsUtils_copyStringFromJS(env, value, result, resultLength); -} - - -//----------------------------------------------------------------------------- -// njsUtils_getValueFromArg() -// Gets the value from the specified JavaScript object property, if possible. -// If the given property is undefined, no error is set and the value is -// returned as NULL. If the value is null, a "value" error is set; otherwise, -// if the value is not the specified type, a "type" error is set. -//----------------------------------------------------------------------------- -bool njsUtils_getValueFromArg(napi_env env, napi_value *args, - int argIndex, const char *propertyName, napi_valuetype expectedType, - napi_value *value, bool *found, char *errorBuffer) -{ - napi_valuetype actualType; - - // initialize found, if applicable - if (found) - *found = false; - - // acquire the value and get its type - NJS_CHECK_NAPI(env, napi_get_named_property(env, args[argIndex], - propertyName, value)) - NJS_CHECK_NAPI(env, napi_typeof(env, *value, &actualType)) - - // a value of undefined is accepted (property not defined) - if (actualType == napi_undefined) { - *value = NULL; - return true; - - // other types other than the expected type generate an error - } else if (actualType != expectedType) { - njsErrors_getMessage(errorBuffer, errInvalidPropertyValueInParam, - propertyName, argIndex + 1); + // get globalTransactionId + if (!njsUtils_getNamedPropertyStringOrBuffer(env, value, + "globalTransactionId", (char**) &tempXid->globalTransactionId, + &len)) return false; - } + tempXid->globalTransactionIdLength = (uint32_t) len; + + // get branchQualifier + if (!njsUtils_getNamedPropertyStringOrBuffer(env, value, "branchQualifier", + (char**) &tempXid->branchQualifier, &len)) + return false; + tempXid->branchQualifierLength = len; - if (found) - *found = true; return true; + } //----------------------------------------------------------------------------- -// njsUtils_isBuffer() -// Return true if the specified value refers to a buffer object. +// njsUtils_throwInsufficientMemory() +// Throw an error indicating that insufficient memory could be allocated. The +// value false is returned as a convenience to the caller. //----------------------------------------------------------------------------- -bool njsUtils_isBuffer(napi_env env, napi_value value) +bool njsUtils_throwInsufficientMemory(napi_env env) { - napi_status status; - bool isBuffer; - - status = napi_is_buffer(env, value, &isBuffer); - if (status != napi_ok) - return false; - return isBuffer; -} - - -//----------------------------------------------------------------------------- -// njsUtils_throwError() -// Get the error message given the error number and any number of arguments. -// Throw the error as a JS error. If the error number is invalid, the error -// message is changed to indicate as much. False is returned as a convenience -// to the caller. -//----------------------------------------------------------------------------- -bool njsUtils_throwError(napi_env env, int errNum, ...) -{ - char errorMessage[NJS_MAX_ERROR_MSG_LEN + 1]; - va_list vaList; - - va_start(vaList, errNum); - njsErrors_getMessageVaList(errorMessage, errNum, vaList); - va_end(vaList); - napi_throw_error(env, NULL, errorMessage); + napi_throw_error(env, NULL, NJS_ERR_INSUFFICIENT_MEMORY); return false; } @@ -894,8 +746,7 @@ bool njsUtils_throwErrorDPI(napi_env env, njsModuleGlobals *globals) //----------------------------------------------------------------------------- bool njsUtils_validateArgs(napi_env env, napi_callback_info info, size_t numArgs, napi_value *args, njsModuleGlobals **globals, - napi_value *callingObj, const njsClassDef *classDef, - njsBaseInstance **instance) + napi_value *callingObj, const njsClassDef *classDef, void **instance) { napi_value localCallingObj; size_t actualArgs; @@ -905,8 +756,7 @@ bool njsUtils_validateArgs(napi_env env, napi_callback_info info, NJS_CHECK_NAPI(env, napi_get_cb_info(env, info, &actualArgs, args, &localCallingObj, (void**) globals)) if (actualArgs != numArgs) - return njsUtils_throwError(env, errInvalidNumberOfParameters, - actualArgs, numArgs); + return njsUtils_genericThrowError(env, __FILE__, __LINE__); // unwrap instance, if applicable if (callingObj) @@ -919,7 +769,7 @@ bool njsUtils_validateArgs(napi_env env, napi_callback_info info, } else if (classDef) { *instance = calloc(1, classDef->structSize); if (!*instance) - return njsUtils_throwError(env, errInsufficientMemory); + return njsUtils_throwInsufficientMemory(env); if (napi_wrap(env, localCallingObj, *instance, classDef->finalizeFn, NULL, NULL) != napi_ok) { free(*instance); @@ -932,39 +782,3 @@ bool njsUtils_validateArgs(napi_env env, napi_callback_info info, } return true; } - - -//----------------------------------------------------------------------------- -// njsUtils_validateArgType() -// Gets the value from the specified JavaScript object property, if possible. -// If the given property is undefined, no error is set and the value is -// returned as NULL. If the value is null, a "value" error is thrown; -// otherwise, if the value is not the specified type, a "type" error is thrown. -//----------------------------------------------------------------------------- -bool njsUtils_validateArgType(napi_env env, napi_value *args, - napi_valuetype expectedType, int index) -{ - napi_valuetype actualType; - - NJS_CHECK_NAPI(env, napi_typeof(env, args[index], &actualType)) - if (actualType != expectedType) - return njsUtils_throwError(env, errInvalidParameterValue, index + 1); - return true; -} - - -//----------------------------------------------------------------------------- -// njsUtils_validatePropType() -// Verifies that the value is the correct type, and if not throws an -// exception and returns false. -//----------------------------------------------------------------------------- -bool njsUtils_validatePropType(napi_env env, napi_value value, - napi_valuetype expectedType, const char *name) -{ - napi_valuetype actualType; - - NJS_CHECK_NAPI(env, napi_typeof(env, value, &actualType)) - if (actualType != expectedType) - return njsUtils_throwError(env, errInvalidPropertyValue, name); - return true; -} diff --git a/src/njsVariable.c b/src/njsVariable.c index b41d2f6a..b322013f 100644 --- a/src/njsVariable.c +++ b/src/njsVariable.c @@ -101,7 +101,7 @@ bool njsVariable_createBuffer(njsVariable *var, njsConnection *conn, // allocate buffer var->buffer = calloc(1, sizeof(njsVariableBuffer)); if (!var->buffer) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); // create ODPI-C variable if (dpiConn_newVar(conn->handle, var->varTypeNum, var->nativeTypeNum, @@ -427,7 +427,7 @@ static bool njsVariable_getJsonNodeValue(njsBaton *baton, dpiJsonNode *node, break; } - return njsBaton_setError(baton, errUnsupportedDataTypeInJson, + return njsBaton_setErrorUnsupportedDataTypeInJson(baton, node->oracleTypeNum); } @@ -479,7 +479,7 @@ bool njsVariable_getScalarValue(njsVariable *var, njsConnection *conn, break; case DPI_NATIVE_TYPE_BYTES: if (data->value.asBytes.length > var->maxSize) - return njsBaton_setError(baton, errInsufficientBufferForBinds); + return njsBaton_setErrorInsufficientBufferForBinds(baton); if (data->value.asBytes.length == 0) { NJS_CHECK_NAPI(env, napi_get_null(env, value)) } else if (var->varTypeNum == DPI_ORACLE_TYPE_RAW || @@ -558,7 +558,7 @@ bool njsVariable_initForQuery(njsVariable *vars, uint32_t numVars, // allocate buffer vars[i].buffer = calloc(1, sizeof(njsVariable)); if (!vars[i].buffer) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); // get query information for the specified column vars[i].pos = i + 1; @@ -568,7 +568,7 @@ bool njsVariable_initForQuery(njsVariable *vars, uint32_t numVars, return njsBaton_setErrorDPI(baton); vars[i].name = malloc(queryInfo.nameLength); if (!vars[i].name) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); memcpy(vars[i].name, queryInfo.name, queryInfo.nameLength); vars[i].nameLength = queryInfo.nameLength; vars[i].maxArraySize = baton->fetchArraySize; @@ -649,7 +649,7 @@ bool njsVariable_initForQuery(njsVariable *vars, uint32_t numVars, case DPI_ORACLE_TYPE_JSON: break; default: - return njsBaton_setError(baton, errUnsupportedDataType, + return njsBaton_setErrorUnsupportedDataType(baton, queryInfo.typeInfo.oracleTypeNum, i + 1); } @@ -823,7 +823,7 @@ bool njsVariable_process(njsVariable *vars, uint32_t numVars, uint32_t numRows, var->dmlReturningBuffers = calloc(numRows, sizeof(njsVariableBuffer)); if (!var->dmlReturningBuffers) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); for (row = 0; row < numRows; row++) { buffer = &var->dmlReturningBuffers[row]; if (dpiVar_getReturnedData(var->dpiVarHandle, row, @@ -902,7 +902,7 @@ static bool njsVariable_processBuffer(njsVariable *var, break; buffer->lobs = calloc(buffer->numElements, sizeof(njsLobBuffer)); if (!buffer->lobs) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); for (i = 0; i < buffer->numElements; i++) { lob = &buffer->lobs[i]; lob->dataType = var->varTypeNum; @@ -928,7 +928,7 @@ static bool njsVariable_processBuffer(njsVariable *var, buffer->queryVars = calloc(buffer->numQueryVars, sizeof(njsVariable)); if (!buffer->queryVars) - return njsBaton_setError(baton, errInsufficientMemory); + return njsBaton_setErrorInsufficientMemory(baton); if (!njsVariable_initForQuery(buffer->queryVars, buffer->numQueryVars, stmt, baton)) return false; @@ -1064,10 +1064,6 @@ bool njsVariable_setScalarValue(njsVariable *var, uint32_t pos, napi_env env, // get LOB instance NJS_CHECK_NAPI(env, napi_unwrap(env, value, (void**) &lob)) - if (!lob->handle) - return njsBaton_setError(baton, errInvalidLob); - if (lob->activeBaton && lob->activeBaton != baton) - return njsBaton_setError(baton, errBusyLob); tempLobHandle = lob->handle; // for INOUT binds a copy of the LOB is made and the copy bound diff --git a/test/poolReconfigure.js b/test/poolReconfigure.js index 4fdb9d01..a7571d7c 100644 --- a/test/poolReconfigure.js +++ b/test/poolReconfigure.js @@ -1128,28 +1128,28 @@ describe('255. poolReconfigure.js', function() { async function() { await pool.reconfigure({poolMin: -1}); }, - /NJS-007/ + /NJS-007:/ ); await assert.rejects( async function() { await pool.reconfigure({poolMin: NaN}); }, - /NJS-007/ + /NJS-007:/ ); await assert.rejects( async function() { await pool.reconfigure({poolMin: null}); }, - /NJS-007/ + /NJS-007:/ ); await assert.rejects( async function() { await pool.reconfigure({poolMin: '10'}); }, - /NJS-007/ + /NJS-007:/ ); } catch (err) { should.not.exist(err); @@ -1206,14 +1206,14 @@ describe('255. poolReconfigure.js', function() { async function() { await pool.reconfigure({poolIncrement: null}); }, - /NJS-007/ + /NJS-007:/ ); await assert.rejects( async function() { await pool.reconfigure({poolIncrement: "100"}); }, - /NJS-007/ + /NJS-007:/ ); }); @@ -1223,28 +1223,28 @@ describe('255. poolReconfigure.js', function() { async function() { await pool.reconfigure({enableStatistics: null}); }, - /NJS-004/ + /NJS-007:/ ); await assert.rejects( async function() { await pool.reconfigure({enableStatistics: -100}); }, - /NJS-004/ + /NJS-007:/ ); await assert.rejects( async function() { await pool.reconfigure({enableStatistics: NaN}); }, - /NJS-004/ + /NJS-007:/ ); await assert.rejects( async function() { await pool.reconfigure({enableStatistics: "true"}); }, - /NJS-004/ + /NJS-007:/ ); });