node-oracledb/lib/connection.js

1559 lines
53 KiB
JavaScript
Raw Normal View History

2022-05-17 11:09:34 +08:00
// Copyright (c) 2016, 2022, Oracle and/or its affiliates.
2019-03-13 08:02:49 +08:00
//-----------------------------------------------------------------------------
//
// You may not use the identified files except in compliance with the Apache
// License, Version 2.0 (the "License.")
//
// You may obtain a copy of the License at
// http://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.
//
//-----------------------------------------------------------------------------
'use strict';
2023-02-21 09:33:06 +08:00
const AqQueue = require('./aqQueue.js');
const BaseDbObject = require('./dbObject.js');
2023-02-21 09:33:06 +08:00
const Lob = require('./lob.js');
const ResultSet = require('./resultset.js');
const SodaDatabase = require('./sodaDatabase.js');
2019-03-13 08:02:49 +08:00
const EventEmitter = require('events');
const QueryStream = require('./queryStream.js');
2023-02-21 09:13:36 +08:00
const errors = require('./errors.js');
2019-03-13 08:02:49 +08:00
const nodbUtil = require('./util.js');
2023-02-21 09:33:06 +08:00
const impl = require('./impl');
const util = require('util');
2023-02-21 07:44:26 +08:00
const constants = require('./constants.js');
const settings = require('./settings.js');
2023-02-21 07:44:26 +08:00
// define class
class Connection extends EventEmitter {
2023-02-21 07:44:26 +08:00
constructor() {
super();
2023-02-21 09:33:06 +08:00
this._dbObjectClasses = new Map();
2023-02-21 07:44:26 +08:00
this._closing = false;
}
2023-02-21 09:33:06 +08:00
//---------------------------------------------------------------------------
// _addDefaultsToExecOpts()
//
// Add values to the execute options from the global settings, if needed.
//---------------------------------------------------------------------------
_addDefaultsToExecOpts(options) {
if (options.autoCommit === undefined)
options.autoCommit = settings.autoCommit;
if (options.dbObjectAsPojo === undefined)
options.dbObjectAsPojo = settings.dbObjectAsPojo;
if (options.fetchArraySize === undefined)
options.fetchArraySize = settings.fetchArraySize;
if (options.fetchAsBuffer === undefined)
options.fetchAsBuffer = settings.fetchAsBuffer;
if (options.fetchAsString === undefined)
options.fetchAsString = settings.fetchAsString;
if (options.fetchInfo === undefined)
options.fetchInfo = [];
if (options.keepInStmtCache === undefined)
options.keepInStmtCache = true;
if (options.maxRows === undefined)
options.maxRows = settings.maxRows;
if (options.outFormat === undefined)
options.outFormat = settings.outFormat;
if (options.prefetchRows === undefined)
options.prefetchRows = settings.prefetchRows;
}
2023-02-21 09:33:06 +08:00
//---------------------------------------------------------------------------
// _buildDbObjectClass()
//
// Builds and returns a database object class given the object type
// information supplied by the implementation.
//---------------------------------------------------------------------------
_buildDbObjectClass(objType) {
2023-02-21 07:44:26 +08:00
const DbObject = function(initialValue) {
2023-02-21 09:33:06 +08:00
this._impl = new impl.DbObjectImpl();
this._impl._objType = objType;
2023-02-21 07:44:26 +08:00
if (this.isCollection) {
const proxy = new Proxy(this, BaseDbObject._collectionProxyHandler);
if (initialValue !== undefined) {
for (let i = 0; i < initialValue.length; i++) {
this.append(initialValue[i]);
}
}
return (proxy);
} else if (initialValue !== undefined) {
Object.assign(this, initialValue);
}
};
DbObject.prototype = Object.create(BaseDbObject.prototype);
DbObject.prototype.constructor = DbObject;
2023-02-21 09:33:06 +08:00
DbObject.prototype._objType = objType;
if (objType.elementTypeClass) {
const cls = this._getDbObjectClass(objType.elementTypeClass);
objType.elementTypeClass = cls;
}
if (objType.attributes) {
const props = {};
for (const attr of objType.attributes) {
if (attr.typeClass) {
attr.typeClass = this._getDbObjectClass(attr.typeClass);
}
const prop = {
get() {
return this._getAttrValue(attr);
},
set(value) {
this._setAttrValue(attr, value);
}
};
props[attr.name] = prop;
}
Object.defineProperties(DbObject.prototype, props);
}
2023-02-21 07:44:26 +08:00
DbObject.toString = function() {
2023-02-21 09:33:06 +08:00
return ('DbObjectClass [' + objType.fqn + ']');
2023-02-21 07:44:26 +08:00
};
return (DbObject);
}
2023-02-21 09:33:06 +08:00
//---------------------------------------------------------------------------
// _checkBindType()
//
// Check that the bind type matches one of the given bind types. If the bind
// type has not been specified yet, the first bind type is assumed to be the
// correct one.
//---------------------------------------------------------------------------
_checkBindType(bindInfo, pos) {
if (bindInfo.type === undefined && arguments.length > 2) {
bindInfo.type = arguments[2];
} else {
let matches = false;
for (let i = 2; i < arguments.length; i++) {
if (bindInfo.type === arguments[i]) {
matches = true;
break;
}
}
if (!matches) {
if (bindInfo.isArray && bindInfo.name) {
errors.throwErr(errors.ERR_INCOMPATIBLE_TYPE_ARRAY_BIND, pos,
bindInfo.name);
} else if (bindInfo.isArray) {
errors.throwErr(errors.ERR_INCOMPATIBLE_TYPE_ARRAY_INDEX_BIND, pos,
bindInfo.pos);
} else {
errors.throwErr(errors.ERR_BIND_VALUE_AND_TYPE_MISMATCH);
}
}
}
}
2023-02-21 09:33:06 +08:00
//---------------------------------------------------------------------------
// _getDbObjectClass()
//
// Returns the database object class given the object type information
// supplied by the implementation. The cache is searched first to see if an
// object class has already been built.
//---------------------------------------------------------------------------
_getDbObjectClass(objType) {
let cls = this._dbObjectClasses.get(objType);
2023-02-21 07:44:26 +08:00
if (!cls) {
2023-02-21 09:33:06 +08:00
cls = this._buildDbObjectClass(objType);
2023-02-21 07:44:26 +08:00
cls._connection = this;
2023-02-21 09:33:06 +08:00
cls._objType = objType;
this._dbObjectClasses.set(objType, cls);
2023-02-21 07:44:26 +08:00
}
return (cls);
}
2023-02-21 09:33:06 +08:00
//---------------------------------------------------------------------------
// _getDbObjectClassForName()
//
// Returns the database object class given the name of the database object
// type. The cache is searched first to see if an object class has already
// been built.
//---------------------------------------------------------------------------
async _getDbObjectClassForName(name) {
let cls = this._dbObjectClasses.get(name);
if (!cls) {
const objType = await this._impl.getDbObjectClass(name);
cls = this._getDbObjectClass(objType);
this._dbObjectClasses.set(name, cls);
}
return cls;
}
//---------------------------------------------------------------------------
// _isBindDir()
//
// Returns a boolean indicating if the supplied value is a valid bind
// direction.
//---------------------------------------------------------------------------
_isBindDir(value) {
return (
value === constants.BIND_IN ||
value === constants.BIND_OUT ||
value === constants.BIND_INOUT
);
}
//---------------------------------------------------------------------------
// _isBindType()
//
// Returns a boolean indicating if the supplied value is a valid bind
// type.
//---------------------------------------------------------------------------
_isBindType(value) {
return (
value === constants.DB_TYPE_BINARY_DOUBLE ||
value === constants.DB_TYPE_BINARY_FLOAT ||
value === constants.DB_TYPE_BINARY_INTEGER ||
value === constants.DB_TYPE_BLOB ||
value === constants.DB_TYPE_BOOLEAN ||
value === constants.DB_TYPE_CHAR ||
value === constants.DB_TYPE_CLOB ||
value === constants.DB_TYPE_CURSOR ||
value === constants.DB_TYPE_DATE ||
value === constants.DB_TYPE_JSON ||
value === constants.DB_TYPE_LONG ||
value === constants.DB_TYPE_LONG_RAW ||
value === constants.DB_TYPE_NCHAR ||
value === constants.DB_TYPE_NCLOB ||
value === constants.DB_TYPE_NUMBER ||
value === constants.DB_TYPE_NVARCHAR ||
value === constants.DB_TYPE_RAW ||
value === constants.DB_TYPE_TIMESTAMP ||
value === constants.DB_TYPE_TIMESTAMP_LTZ ||
value === constants.DB_TYPE_TIMESTAMP_TZ ||
value === constants.DB_TYPE_VARCHAR
);
}
//---------------------------------------------------------------------------
// _isBindValue()
//
// Returns a boolean indicating if the supplied value is one that can be
// bound.
//---------------------------------------------------------------------------
_isBindValue(value) {
return (
value === null ||
value === undefined ||
typeof value === 'number' ||
typeof value === 'string' ||
typeof value === 'boolean' ||
Array.isArray(value) ||
Buffer.isBuffer(value) ||
util.isDate(value) ||
value instanceof Lob ||
value instanceof ResultSet ||
value instanceof BaseDbObject
);
}
//---------------------------------------------------------------------------
// _processBindUnit()
//
// Processes a bind unit (object) supplied by the user and returns the value
// stored in it (if one is).
//---------------------------------------------------------------------------
async _processBindUnit(bindInfo, bindUnit, inExecuteMany) {
let okBindUnit = false;
// get and validate bind direction; if not specified, IN is assumed
if (bindUnit.dir === undefined) {
bindInfo.dir = constants.BIND_IN;
} else {
errors.assert(this._isBindDir(bindUnit.dir),
errors.ERR_INVALID_BIND_DIRECTION);
bindInfo.dir = bindUnit.dir;
okBindUnit = true;
}
// get and validate bind type; it must be one of the integer constants
// identifying types, a string identifying an object type or a constructor
// function identifying an object type
if (bindUnit.type !== undefined) {
if (typeof bindUnit.type === 'string') {
bindInfo.type = constants.DB_TYPE_OBJECT;
bindInfo.typeClass = await this._getDbObjectClassForName(bindUnit.type);
bindInfo.objType = bindInfo.typeClass._objType;
} else if (bindUnit.type.prototype instanceof BaseDbObject) {
bindInfo.type = constants.DB_TYPE_OBJECT;
bindInfo.typeClass = bindUnit.type;
bindInfo.objType = bindInfo.typeClass._objType;
} else {
errors.assert(this._isBindType(bindUnit.type),
errors.ERR_INVALID_BIND_DATA_TYPE, 2);
bindInfo.type = bindUnit.type;
}
okBindUnit = true;
// when calling executeMany(), bind type is mandatory
} else if (inExecuteMany) {
if (bindInfo.name)
errors.throwErr(errors.ERR_MISSING_TYPE_BY_NAME, bindInfo.name);
errors.throwErr(errors.ERR_MISSING_TYPE_BY_POS, bindInfo.pos);
}
// get and validate the maximum size for strings/buffers; this value is
// used for IN/OUT and OUT binds in execute() and at all times for
// executeMany()
if (bindInfo.dir !== constants.BIND_IN || inExecuteMany) {
if (bindUnit.maxSize !== undefined) {
errors.assertParamPropValue(Number.isInteger(bindUnit.maxSize) &&
bindUnit.maxSize > 0, 2, "maxSize");
bindInfo.maxSize = bindUnit.maxSize;
bindInfo.checkSize = true;
okBindUnit = true;
} else if (inExecuteMany) {
if (bindInfo.type === constants.DB_TYPE_VARCHAR ||
bindInfo.type === constants.DB_TYPE_RAW) {
if (bindInfo.name)
errors.throwErr(errors.ERR_MISSING_MAX_SIZE_BY_NAME, bindInfo.name);
errors.throwErr(errors.ERR_MISSING_MAX_SIZE_BY_POS, bindInfo.pos);
}
} else {
bindInfo.maxSize = constants.DEFAULT_MAX_SIZE_FOR_OUT_BINDS;
}
}
// get max array size (for array binds, not possible in executeMany())
bindInfo.isArray = false;
if (!inExecuteMany) {
if (bindUnit.maxArraySize !== undefined) {
errors.assertParamPropValue(Number.isInteger(bindUnit.maxArraySize) &&
bindUnit.maxArraySize > 0, 2, "maxArraySize");
bindInfo.maxArraySize = bindUnit.maxArraySize;
bindInfo.isArray = true;
}
}
// get the value, if specified (not used in executeMany())
if (!inExecuteMany && bindUnit.val !== undefined) {
return bindUnit.val;
}
if (!okBindUnit)
errors.throwErr(errors.ERR_INVALID_BIND_UNIT);
}
//---------------------------------------------------------------------------
// _processBindValue()
//
// Processes the bind value supplied by the caller. This performs all checks
// on the value and normalizes it for use by the implementation class. If no
// bind info has been defined yet, the value defines that.
//---------------------------------------------------------------------------
async _processBindValue(bindInfo, value, iterNum, allowArray) {
// null and undefined can always be bound so nothing needs to be done
if (value === undefined || value === null) {
bindInfo.values[iterNum] = undefined;
return;
}
// handle binding plain JS values to database objects
if (bindInfo.type === constants.DB_TYPE_OBJECT) {
let obj = value;
if (!(value instanceof BaseDbObject)) {
obj = new bindInfo.typeClass(value);
}
bindInfo.values[iterNum] = obj._impl;
// handle binding plain JS values to JSON
} else if (bindInfo.type === constants.DB_TYPE_JSON) {
bindInfo.values[iterNum] = this._processJsonValue(value);
// handle binding strings
} else if (typeof value === 'string') {
this._checkBindType(bindInfo, iterNum,
constants.DB_TYPE_VARCHAR,
constants.DB_TYPE_NVARCHAR,
constants.DB_TYPE_CHAR,
constants.DB_TYPE_NCHAR,
constants.DB_TYPE_CLOB,
constants.DB_TYPE_NCLOB);
bindInfo.values[iterNum] = Buffer.from(value);
if (bindInfo.type !== constants.DB_TYPE_CLOB &&
bindInfo.type !== constants.DB_TYPE_NCLOB &&
(bindInfo.maxSize === undefined || value.length > bindInfo.maxSize)) {
if (bindInfo.checkSize) {
errors.throwErr(errors.ERR_MAX_SIZE_TOO_SMALL, bindInfo.maxSize,
value.length, iterNum);
}
bindInfo.maxSize = value.length;
}
// handle binding numbers
} else if (typeof value === 'number') {
this._checkBindType(bindInfo, iterNum,
constants.DB_TYPE_NUMBER,
constants.DB_TYPE_BINARY_INTEGER,
constants.DB_TYPE_BINARY_FLOAT,
constants.DB_TYPE_BINARY_DOUBLE);
bindInfo.values[iterNum] = value;
// handle binding booleans
} else if (typeof value === 'boolean') {
this._checkBindType(bindInfo, iterNum, constants.DB_TYPE_BOOLEAN);
bindInfo.values[iterNum] = value;
// handle binding dates
} else if (util.isDate(value)) {
this._checkBindType(bindInfo, iterNum,
constants.DB_TYPE_TIMESTAMP_LTZ,
constants.DB_TYPE_TIMESTAMP_TZ,
constants.DB_TYPE_TIMESTAMP,
constants.DB_TYPE_DATE);
bindInfo.values[iterNum] = value;
// handle binding buffers
} else if (Buffer.isBuffer(value)) {
this._checkBindType(bindInfo, iterNum,
constants.DB_TYPE_RAW,
constants.DB_TYPE_BLOB);
bindInfo.values[iterNum] = value;
if (bindInfo.type === constants.DB_TYPE_RAW &&
(bindInfo.maxSize === undefined || value.length > bindInfo.maxSize)) {
if (bindInfo.checkSize) {
errors.throwErr(errors.ERR_MAX_SIZE_TOO_SMALL, bindInfo.maxSize,
value.length, iterNum);
}
bindInfo.maxSize = value.length;
}
// handle binding result sets
} else if (value instanceof ResultSet) {
this._checkBindType(bindInfo, iterNum, constants.DB_TYPE_CURSOR);
bindInfo.values[iterNum] = value._impl;
// handle binding LOBs
} else if (value instanceof Lob) {
this._checkBindType(bindInfo, iterNum, value.type);
bindInfo.values[iterNum] = value._impl;
// handle binding database objects
} else if (value instanceof BaseDbObject) {
this._checkBindType(bindInfo, iterNum, constants.DB_TYPE_OBJECT);
if (!bindInfo.typeClass) {
bindInfo.typeClass = await this._getDbObjectClass(value._objType);
bindInfo.objType = bindInfo.typeClass._objType;
}
bindInfo.values[iterNum] = value._impl;
// handle binding arrays
} else if (allowArray && Array.isArray(value)) {
bindInfo.isArray = true;
if (bindInfo.dir === constants.BIND_IN) {
bindInfo.maxArraySize = value.length || 1;
} else if (bindInfo.maxArraySize === undefined) {
errors.throwErr(errors.ERR_REQUIRED_MAX_ARRAY_SIZE);
} else if (value.length > bindInfo.maxArraySize) {
errors.throwErr(errors.ERR_INVALID_ARRAY_SIZE);
}
for (let i = 0; i < value.length; i++) {
await this._processBindValue(bindInfo, value[i], i, false);
}
// no suitable bind value found
} else {
if (bindInfo.type === undefined)
errors.throwErr(errors.ERR_INVALID_BIND_DATA_TYPE, 2);
this._checkBindType(bindInfo, iterNum);
}
}
//---------------------------------------------------------------------------
// _processExecuteBind()
//
// Processes a single execute bind supplied by the caller. This performs all
// checks on the bind and normalizes it for use by the implementation class.
//---------------------------------------------------------------------------
async _processExecuteBind(bindInfo, bindData) {
// setup defaults
bindInfo.isArray = false;
// if bind data is a value that can be bound directly, use it; otherwise,
// scan the bind unit for bind information and its value
let bindValue;
if (this._isBindValue(bindData)) {
bindInfo.dir = constants.BIND_IN;
bindValue = bindData;
} else {
bindValue = await this._processBindUnit(bindInfo, bindData, false);
}
// for IN and IN/OUT binds, process the value
if (bindInfo.dir !== constants.BIND_OUT) {
await this._processBindValue(bindInfo, bindValue, 0, true);
}
// if only null values were found (or an OUT bind was specified), type
// information may not be set, so complete bind information as a string
// and set the maxSize to 1 if it has not already been set
if (bindInfo.type === undefined) {
bindInfo.type = constants.DB_TYPE_VARCHAR;
if (bindInfo.maxSize === undefined)
bindInfo.maxSize = 1;
}
// check valid bind type for array binds
if (bindInfo.isArray &&
bindInfo.type !== constants.DB_TYPE_VARCHAR &&
bindInfo.type !== constants.DB_TYPE_NVARCHAR &&
bindInfo.type !== constants.DB_TYPE_CHAR &&
bindInfo.type !== constants.DB_TYPE_NCHAR &&
bindInfo.type !== constants.DB_TYPE_NUMBER &&
bindInfo.type !== constants.DB_TYPE_BINARY_FLOAT &&
bindInfo.type !== constants.DB_TYPE_BINARY_DOUBLE &&
bindInfo.type !== constants.DB_TYPE_DATE &&
bindInfo.type !== constants.DB_TYPE_TIMESTAMP &&
bindInfo.type !== constants.DB_TYPE_TIMESTAMP_LTZ &&
bindInfo.type !== constants.DB_TYPE_TIMESTAMP_TZ &&
bindInfo.type !== constants.DB_TYPE_RAW) {
errors.throwErr(errors.ERR_INVALID_TYPE_FOR_ARRAY_BIND);
}
}
//---------------------------------------------------------------------------
// _processExecuteBinds()
//
// Processes the binds supplied by the caller. This performs all checks on
// the binds and normalizes them for use by the implementation class.
//---------------------------------------------------------------------------
async _processExecuteBinds(binds) {
const normBinds = [];
if (Array.isArray(binds)) {
for (let i = 0; i < binds.length; i++) {
const bindInfo = normBinds[i] = {pos: i + 1, values: []};
await this._processExecuteBind(bindInfo, binds[i]);
}
} else {
errors.assertParamValue(nodbUtil.isObject(binds), 2);
const bindNames = Object.getOwnPropertyNames(binds);
for (let i = 0; i < bindNames.length; i++) {
const bindInfo = normBinds[i] = {name: bindNames[i], values: []};
await this._processExecuteBind(bindInfo, binds[bindNames[i]]);
}
}
return normBinds;
}
//---------------------------------------------------------------------------
// _processExecuteManyBinds()
//
// Processes the binds supplied by the caller. This performs all checks on
// the binds and normalizes them for use by the implementation class.
//---------------------------------------------------------------------------
async _processExecuteManyBinds(binds, bindDefs) {
const normBinds = [];
let byPosition;
// transform bindDefs into normalized binds, if available
if (bindDefs !== undefined) {
if (Array.isArray(bindDefs)) {
byPosition = true;
for (let i = 0; i < bindDefs.length; i++) {
const bindInfo = normBinds[i] = {pos: i + 1, values: []};
await this._processBindUnit(bindInfo, bindDefs[i], true);
}
} else {
byPosition = false;
const bindNames = Object.getOwnPropertyNames(bindDefs);
for (let i = 0; i < bindNames.length; i++) {
const bindInfo = normBinds[i] = {name: bindNames[i], values: []};
await this._processBindUnit(bindInfo, bindDefs[bindNames[i]], true);
}
}
// otherwise, use the first row to determine the binds to use
} else {
const row = binds[0];
errors.assertParamValue(nodbUtil.isObjectOrArray(row), 2);
if (Array.isArray(row)) {
byPosition = true;
for (let i = 0; i < row.length; i++) {
normBinds[i] = {pos: i + 1};
}
} else {
byPosition = false;
const bindNames = Object.getOwnPropertyNames(row);
for (let i = 0; i < bindNames.length; i++) {
normBinds[i] = {name: bindNames[i]};
}
}
for (let i = 0; i < normBinds.length; i++) {
normBinds[i].dir = constants.BIND_IN;
normBinds[i].isArray = false;
normBinds[i].values = [];
}
}
// process each of the rows
for (let i = 0; i < binds.length; i++) {
const row = binds[i];
errors.assert((byPosition && Array.isArray(row)) ||
(!byPosition && nodbUtil.isObject(row)), errors.ERR_MIXED_BIND);
for (let j = 0; j < normBinds.length; j++) {
const bindInfo = normBinds[j];
const value = (byPosition) ? row[j] : row[bindInfo.name];
await this._processBindValue(bindInfo, value, i, false);
}
}
// set bind type and size to a string of size 1 if no bind type was
// specified (and all values are null)
for (let i = 0; i < normBinds.length; i++) {
const bindInfo = normBinds[i];
if (bindInfo.type === undefined) {
bindInfo.type = constants.DB_TYPE_VARCHAR;
bindInfo.maxSize = 1;
}
}
return normBinds;
}
//---------------------------------------------------------------------------
// _processJsonValue()
//
// Returns a normalized JSON value. Scalar values are returned unchanged.
// Arrays are returned as a new array with processed JSON values. Objects are
// returned as new objects with keys "fields" and "values", both of which
// are arrays with processes JSON values.
//---------------------------------------------------------------------------
_processJsonValue(value) {
// handle simple scalars
if (value === undefined || value === null ||
typeof value === 'number' || typeof value === 'string' ||
typeof value === 'boolean' || Buffer.isBuffer(value) ||
util.isDate(value))
return value;
// arrays are transformed to a new array with processed values
if (Array.isArray(value)) {
const outValue = new Array(value.length);
for (let i = 0; i < value.length; i++) {
outValue[i] = this._processJsonValue(value[i]);
}
return outValue;
}
// database objects are treated as empty objects
if (value instanceof BaseDbObject)
return {fields: [], values: []};
// all other objects are transformed to an object with two arrays (fields
// and values)
const outValue = {};
outValue.fields = Object.getOwnPropertyNames(value);
outValue.values = new Array(outValue.fields.length);
for (let i = 0; i < outValue.fields.length; i++) {
outValue.values[i] = this._processJsonValue(value[outValue.fields[i]]);
}
return outValue;
}
//---------------------------------------------------------------------------
// _transformOutBind()
//
// Transform an output bind value from an implementation value to a user
// facing value (for result sets and LOBs). DML returning output variables
// are always an array of values.
//---------------------------------------------------------------------------
_transformOutBind(val, options) {
let outVal = val;
if (Array.isArray(val)) {
outVal = [];
for (let i = 0; i < val.length; i++)
outVal.push(this._transformOutBind(val[i], options));
} else if (val instanceof impl.ResultSetImpl) {
outVal = new ResultSet();
outVal._setup(this, val, options);
} else if (val instanceof impl.LobImpl) {
outVal = new Lob();
outVal._setup(val, true);
} else if (val instanceof impl.DbObjectImpl) {
const cls = this._dbObjectClasses.get(val._objType);
outVal = Object.create(cls.prototype);
outVal._impl = val;
if (options.dbObjectAsPojo) {
outVal = outVal._toPojo();
} else if (outVal.isCollection) {
outVal = new Proxy(outVal, BaseDbObject._collectionProxyHandler);
}
}
return outVal;
}
//---------------------------------------------------------------------------
// _verifyExecOpts
//
// Verify that the value passed by the user for binds is acceptable. Perform
// any transformations necessary.
//---------------------------------------------------------------------------
_verifyExecOpts(options, inExecuteMany) {
// define normalized options (value returned to caller)
const outOptions = {};
// handle common options
errors.assertParamValue(nodbUtil.isObject(options), 3);
// autoCommit must be a boolean value
if (options.autoCommit !== undefined) {
errors.assertParamPropValue(typeof options.autoCommit === 'boolean', 3,
"autoCommit");
outOptions.autoCommit = options.autoCommit;
}
// dbObjectAsPojo must be a boolean value
if (options.dbObjectAsPojo !== undefined) {
errors.assertParamPropValue(typeof options.dbObjectAsPojo === 'boolean',
3, "dbObjectAsPojo");
outOptions.dbObjectAsPojo = options.dbObjectAsPojo;
}
// keepInStmtCache must be a boolean value
if (options.keepInStmtCache !== undefined) {
errors.assertParamPropValue(typeof options.keepInStmtCache === 'boolean',
3, "keepInStmtCache");
outOptions.keepInStmtCache = options.keepInStmtCache;
}
// handle options specific to executeMany()
if (inExecuteMany) {
// bindDefs must be an object or array
if (options.bindDefs !== undefined) {
errors.assertParamPropValue(nodbUtil.isObjectOrArray(options.bindDefs),
3, "bindDefs");
outOptions.bindDefs = options.bindDefs;
}
// batchErrors must be a boolean value
if (options.batchErrors !== undefined) {
errors.assertParamPropValue(typeof options.batchErrors === 'boolean',
3, "batchErrors");
outOptions.batchErrors = options.batchErrors;
}
// dmlRowCounts must be a boolean value
if (options.dmlRowCounts !== undefined) {
errors.assertParamPropValue(typeof options.dmlRowCounts === 'boolean',
3, "dmlRowCounts");
outOptions.dmlRowCounts = options.dmlRowCounts;
}
// handle options specific to execute()
2023-02-21 07:44:26 +08:00
} else {
2023-02-21 09:33:06 +08:00
// fetchArraySize must be a positive integer
if (options.fetchArraySize !== undefined) {
errors.assertParamPropValue(Number.isInteger(options.fetchArraySize) &&
options.fetchArraySize > 0, 3, "fetchArraySize");
outOptions.fetchArraySize = options.fetchArraySize;
}
// fetchInfo must be an object with keys containing an object with a
// "type" property; these are converted to an array of objects for ease
// of processing by the implementation
if (options.fetchInfo !== undefined) {
errors.assertParamPropValue(nodbUtil.isObject(options.fetchInfo), 3,
"fetchInfo");
const keys = Object.getOwnPropertyNames(options.fetchInfo);
outOptions.fetchInfo = new Array(keys.length);
for (let i = 0; i < keys.length; i++) {
const info = options.fetchInfo[keys[i]];
if (info.type === undefined)
errors.throwErr(errors.ERR_NO_TYPE_FOR_CONVERSION);
if (info.type !== constants.DEFAULT &&
info.type !== constants.DB_TYPE_VARCHAR &&
info.type !== constants.DB_TYPE_RAW) {
errors.throwErr(errors.ERR_INVALID_TYPE_FOR_CONVERSION);
}
outOptions.fetchInfo[i] = {name: keys[i], type: info.type};
}
}
// maxRows must be a positive integer (or 0)
if (options.maxRows !== undefined) {
errors.assertParamPropValue(Number.isInteger(options.maxRows) &&
options.maxRows >= 0, 3, "maxRows");
outOptions.maxRows = options.maxRows;
}
// outFormat must be one of the two possible constants
if (options.outFormat !== undefined) {
errors.assertParamPropValue(
options.outFormat === constants.OUT_FORMAT_ARRAY ||
options.outFormat === constants.OUT_FORMAT_OBJECT, 3, "outFormat");
outOptions.outFormat = options.outFormat;
}
// prefetchRows must be a positive integer (or 0)
if (options.prefetchRows !== undefined) {
errors.assertParamPropValue(Number.isInteger(options.prefetchRows) &&
options.prefetchRows >= 0, 3, "prefetchRows");
outOptions.prefetchRows = options.prefetchRows;
}
// resultSet must be a boolean value
if (options.resultSet !== undefined) {
errors.assertParamPropValue(typeof options.resultSet === 'boolean', 3,
"resultSet");
outOptions.resultSet = options.resultSet;
}
2023-02-21 07:44:26 +08:00
}
2023-02-21 09:33:06 +08:00
return outOptions;
}
//---------------------------------------------------------------------------
// action
//
// Property for end-to-end tracing attribute.
//---------------------------------------------------------------------------
get action() {
return null;
}
set action(value) {
errors.assertPropValue(typeof value === 'string', "action");
this._impl.setAction(value);
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// breakExecution()
2023-02-21 09:33:06 +08:00
//
// Breaks execution of a running statement.
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
async breakExecution() {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 0);
2023-02-21 09:33:06 +08:00
await this._impl.breakExecution();
}
//---------------------------------------------------------------------------
// callTimeout
//
// Property for round-trip timeouts.
//---------------------------------------------------------------------------
get callTimeout() {
return this._impl.getCallTimeout();
}
set callTimeout(value) {
errors.assertPropValue(Number.isInteger(value) && value >= 0,
"callTimeout");
this._impl.setCallTimeout(value);
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// changePassword()
//
// Changes the password of the specified user.
//---------------------------------------------------------------------------
async changePassword(user, password, newPassword) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 3, 3);
errors.assertParamValue(typeof user === 'string', 1);
errors.assertParamValue(typeof password === 'string', 2);
errors.assertParamValue(typeof newPassword === 'string', 3);
2023-02-21 09:33:06 +08:00
await this._impl.changePassword(user, password, newPassword);
}
//---------------------------------------------------------------------------
// clientId
//
// Property for end-to-end tracing attribute.
//---------------------------------------------------------------------------
get clientId() {
return null;
}
set clientId(value) {
errors.assertPropValue(typeof value === 'string', "clientId");
this._impl.setClientId(value);
}
//---------------------------------------------------------------------------
// clientInfo
//
// Property for end-to-end tracing attribute.
//---------------------------------------------------------------------------
get clientInfo() {
return null;
}
set clientInfo(value) {
errors.assertPropValue(typeof value === 'string', "clientInfo");
this._impl.setClientInfo(value);
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// close()
//
// Closes the connection and makes it unusable for further work.
//---------------------------------------------------------------------------
async close(a1) {
let options = {};
2018-03-27 13:17:16 +08:00
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 1);
2023-02-21 07:44:26 +08:00
if (arguments.length == 1) {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(nodbUtil.isObject(a1), 1);
2023-02-21 07:44:26 +08:00
options = a1;
}
2018-03-27 13:17:16 +08:00
2023-02-21 07:44:26 +08:00
// If already in the process of closing, throw an error instead of doing
// a roundtrip
if (this._closing) {
2023-02-21 09:13:36 +08:00
errors.throwErr(errors.ERR_INVALID_CONNECTION);
2023-02-21 07:44:26 +08:00
}
2023-02-21 07:44:26 +08:00
this._closing = true;
try {
2023-02-21 09:33:06 +08:00
await this._impl.close(options);
2023-02-21 07:44:26 +08:00
} finally {
this._closing = false;
}
2023-02-21 09:33:06 +08:00
this._dbObjectClasses.clear();
2023-02-21 07:44:26 +08:00
this.emit('_afterConnClose');
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// commit()
//
// Commits the current transaction.
//---------------------------------------------------------------------------
async commit() {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 0);
2023-02-21 09:33:06 +08:00
await this._impl.commit();
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// createLob()
//
// Creates a temporary LOB and returns it to the caller.
//---------------------------------------------------------------------------
async createLob(type) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 1, 1);
2023-02-21 09:14:13 +08:00
errors.assertParamValue(type === constants.DB_TYPE_CLOB ||
type === constants.DB_TYPE_BLOB ||
type === constants.DB_TYPE_NCLOB, 1);
2023-02-21 09:33:06 +08:00
const lob = new Lob();
lob._setup(await this._impl.createLob(type), false);
return lob;
}
//---------------------------------------------------------------------------
// currentSchema
//
// Property for identifying the current schema to use in the database.
//---------------------------------------------------------------------------
get currentSchema() {
return this._impl.getCurrentSchema();
}
set currentSchema(value) {
errors.assertPropValue(typeof value === 'string', "currentSchema");
this._impl.setCurrentSchema(value);
}
//---------------------------------------------------------------------------
// dbOp
//
// Property for end-to-end tracing attribute.
//---------------------------------------------------------------------------
get dbOp() {
return null;
}
set dbOp(value) {
errors.assertPropValue(typeof value === 'string', "dbOp");
this._impl.setDbOp(value);
}
//---------------------------------------------------------------------------
// ecid
//
// Property for end-to-end tracing attribute.
//---------------------------------------------------------------------------
get ecid() {
return null;
}
set ecid(value) {
errors.assertPropValue(typeof value === 'string', "ecid");
this._impl.setECID(value);
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// execute()
//
// Executes a SQL statement and returns the results.
//---------------------------------------------------------------------------
async execute(sql, a2, a3) {
2023-02-21 09:33:06 +08:00
const numIters = 1;
2023-02-21 07:44:26 +08:00
let binds = [];
2023-02-21 09:33:06 +08:00
let options = {};
2023-02-21 09:33:06 +08:00
// process arguments
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 1, 3);
errors.assertParamValue(typeof sql === 'string', 1);
2023-02-21 09:33:06 +08:00
if (arguments.length >= 2) {
binds = await this._processExecuteBinds(a2);
}
if (arguments.length == 3) {
options = this._verifyExecOpts(a3, false);
2023-02-21 07:44:26 +08:00
}
2023-02-21 09:33:06 +08:00
this._addDefaultsToExecOpts(options);
2023-02-21 09:33:06 +08:00
// perform actual execute
const result = await this._impl.execute(sql, numIters, binds, options,
false);
2023-02-21 07:44:26 +08:00
// process queries; if a result set is not desired, fetch all of the rows
// from the result set and then destroy the result set
2023-02-21 09:33:06 +08:00
if (result.resultSet !== undefined) {
const resultSet = new ResultSet();
resultSet._setup(this, result.resultSet, options);
if (options.resultSet) {
result.resultSet = resultSet;
} else {
result.rows = await resultSet._getAllRows();
result.metaData = resultSet._setupData.metaData;
delete result.resultSet;
}
}
// process output binds
if (result.outBinds !== undefined) {
for (const key in result.outBinds) {
const val = this._transformOutBind(result.outBinds[key], options);
result.outBinds[key] = val;
}
2023-02-21 07:44:26 +08:00
}
2023-02-21 07:44:26 +08:00
// process implicit results; ensure all implicit results have their fetch
// array size fixed, or, if a result set is not requested, that all rows
// are fetched
if (result.implicitResults) {
for (const key in result.implicitResults) {
2023-02-21 09:33:06 +08:00
const resultSetImpl = result.implicitResults[key];
const resultSet = new ResultSet();
resultSet._setup(this, resultSetImpl, options);
if (options.resultSet) {
result.implicitResults[key] = resultSet;
} else {
result.implicitResults[key] = await resultSet._getAllRows();
2019-11-05 07:54:10 +08:00
}
}
}
2021-10-21 16:00:42 +08:00
2023-02-21 07:44:26 +08:00
return (result);
2021-10-21 16:00:42 +08:00
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// executeMany()
//
// Executes a SQL statement multiple times and returns the results.
//---------------------------------------------------------------------------
async executeMany(sql, bindsOrNumIters, a3) {
let options = {};
2023-02-21 09:33:06 +08:00
let binds = [];
let numIters;
2021-10-21 16:00:42 +08:00
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 2, 3);
errors.assertParamValue(typeof sql === 'string', 1);
2023-02-21 09:33:06 +08:00
if (arguments.length == 3) {
options = this._verifyExecOpts(a3, true);
}
this._addDefaultsToExecOpts(options);
2023-02-21 07:44:26 +08:00
if (typeof bindsOrNumIters === 'number') {
2023-02-21 09:33:06 +08:00
errors.assertParamValue(Number.isInteger(bindsOrNumIters) &&
bindsOrNumIters > 0, 2);
numIters = bindsOrNumIters;
if (options.bindDefs !== undefined) {
binds = await this._processExecuteManyBinds([], options.bindDefs);
}
2023-02-21 07:44:26 +08:00
} else {
2023-02-21 09:33:06 +08:00
errors.assertParamValue(Array.isArray(bindsOrNumIters) &&
bindsOrNumIters.length > 0, 2);
numIters = bindsOrNumIters.length;
binds = await this._processExecuteManyBinds(bindsOrNumIters,
options.bindDefs);
2023-02-21 07:44:26 +08:00
}
2019-03-13 08:02:49 +08:00
2023-02-21 09:33:06 +08:00
const result = await this._impl.execute(sql, numIters, binds, options,
true);
// process output binds
if (result.outBinds !== undefined) {
for (let i = 0; i < result.outBinds.length; i++) {
const outBind = result.outBinds[i];
for (const key in outBind) {
outBind[key] = this._transformOutBind(outBind[key], options);
}
}
2023-02-21 07:44:26 +08:00
}
2023-02-21 09:33:06 +08:00
return result;
}
//---------------------------------------------------------------------------
// externalName
//
// Property for identifying the external name to use in TPC logging.
//---------------------------------------------------------------------------
get externalName() {
return this._impl.getExternalName();
}
2023-02-21 09:33:06 +08:00
set externalName(value) {
errors.assertPropValue(typeof value === 'string', "externalName");
this._impl.setExternalName(value);
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// getDbObjectClass()
//
// Returns a database object class given its name. The cache is searched
// first, but if not found, the database is queried and the result is cached
2023-02-21 09:33:06 +08:00
// using the type information (as well as the name for easier lookup later).
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
async getDbObjectClass(name) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 1, 1);
errors.assertParamValue(typeof name === 'string', 1);
2023-02-21 09:33:06 +08:00
return await this._getDbObjectClassForName(name);
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// getQueue()
//
// Returns a queue with the specified name.
//---------------------------------------------------------------------------
async getQueue(name, a2) {
let options = {};
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 1, 2);
errors.assertParamValue(typeof name === 'string', 1);
2023-02-21 07:44:26 +08:00
if (arguments.length == 2) {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(nodbUtil.isObject(a2), 2);
2023-02-21 09:33:06 +08:00
options = {...a2};
}
2023-02-21 09:33:06 +08:00
const queue = new AqQueue();
await queue.create(this, name, options);
return queue;
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// getSodaDatabase()
//
// Returns a SodaDatabase object (high-level SODA object associated with
// the current connection).
//---------------------------------------------------------------------------
2019-03-13 08:02:49 +08:00
getSodaDatabase() {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 0);
2023-02-21 09:33:06 +08:00
const sodaDb = new SodaDatabase();
sodaDb._impl = this._impl.getSodaDatabase();
return sodaDb;
2019-03-13 08:02:49 +08:00
}
2022-02-23 08:58:21 +08:00
//---------------------------------------------------------------------------
2023-02-21 07:44:26 +08:00
// getStatementInfo()
//
// Returns information about the statement.
//---------------------------------------------------------------------------
async getStatementInfo(sql) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 1, 1);
2023-02-21 09:14:13 +08:00
errors.assertParamValue(typeof sql === 'string', 1);
2023-02-21 09:33:06 +08:00
return (await this._impl.getStatementInfo(sql));
}
//---------------------------------------------------------------------------
// internalName
//
// Property for identifying the internal name to use in TPC logging.
//---------------------------------------------------------------------------
get internalName() {
return this._impl.getInternalName();
}
set internalName(value) {
errors.assertPropValue(typeof value === 'string', "internalName");
this._impl.setInternalName(value);
2023-02-21 07:44:26 +08:00
}
//--------------------------------------------------------------------------
// isHealthy()
//
// Returns the health status of the connection. If this function returns
// false, the caller should close the connection.
// ---------------------------------------------------------------------------
2022-02-23 08:58:21 +08:00
isHealthy() {
2023-02-21 09:33:06 +08:00
return (!this._closing && this._impl.isHealthy());
}
//---------------------------------------------------------------------------
// module
//
// Property for end-to-end tracing attribute.
//---------------------------------------------------------------------------
get module() {
return null;
}
set module(value) {
errors.assertPropValue(typeof value === 'string', "module");
this._impl.setModule(value);
}
//---------------------------------------------------------------------------
// oracleServerVersion
//
// Returns an integer identifying the Oracle Server version.
//---------------------------------------------------------------------------
get oracleServerVersion() {
return this._impl.getOracleServerVersion();
}
//---------------------------------------------------------------------------
// oracleServerVersionString
//
// Returns a string identifying the Oracle Server version.
//---------------------------------------------------------------------------
get oracleServerVersionString() {
return this._impl.getOracleServerVersionString();
2022-02-23 08:58:21 +08:00
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// ping()
//
// Sends a "ping" to the database to see if it is "alive".
//---------------------------------------------------------------------------
async ping() {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 0);
2023-02-21 09:33:06 +08:00
await this._impl.ping();
2023-02-21 07:44:26 +08:00
}
2022-02-23 08:58:21 +08:00
2023-02-21 07:44:26 +08:00
//--------------------------------------------------------------------------
// queryStream()
//
// Similar to execute() except that it immediately returns a QueryStream
// object.
// ---------------------------------------------------------------------------
2023-02-21 09:33:06 +08:00
queryStream(sql, binds, options) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 1, 3);
errors.assertParamValue(typeof sql === 'string', 1);
2023-02-21 09:33:06 +08:00
if (arguments.length == 3) {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(nodbUtil.isObject(options), 3);
2023-02-21 09:33:06 +08:00
options = {...options};
} else {
options = {};
2019-03-13 08:02:49 +08:00
}
options.resultSet = true;
const stream = new QueryStream();
2019-03-13 08:02:49 +08:00
// calling execute() via nextTick to ensure that handlers are registered
// prior to the events being emitted
2023-02-21 09:13:36 +08:00
process.nextTick(async () => {
try {
2023-02-21 09:33:06 +08:00
const result = await this.execute(sql, binds || [], options);
if (!result.resultSet)
2023-02-21 09:13:36 +08:00
errors.throwErr(errors.ERR_NOT_A_QUERY);
stream._open(result.resultSet);
} catch (err) {
stream.destroy(err);
return;
}
2019-03-13 08:02:49 +08:00
});
2021-04-01 12:48:37 +08:00
return (stream);
2019-03-13 08:02:49 +08:00
}
2023-02-21 07:44:26 +08:00
//---------------------------------------------------------------------------
// rollback()
//
// Rolls back the current transaction.
//---------------------------------------------------------------------------
async rollback() {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 0);
2023-02-21 09:33:06 +08:00
await this._impl.rollback();
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// shutdown()
// Shuts down the database instance.
//---------------------------------------------------------------------------
async shutdown(a1) {
let mode = constants.SHUTDOWN_MODE_DEFAULT;
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 1);
2023-02-21 07:44:26 +08:00
if (a1 !== undefined) {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(typeof mode === 'number', 1);
2023-02-21 07:44:26 +08:00
mode = a1;
}
2023-02-21 09:33:06 +08:00
await this._impl.shutdown(mode);
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// startup()
// Starts up the database instance.
//---------------------------------------------------------------------------
async startup(a1) {
let opts = {};
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 1);
2023-02-21 07:44:26 +08:00
if (arguments.length == 1) {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(typeof opts === 'object', 1);
2023-02-21 07:44:26 +08:00
opts = a1;
}
2023-02-21 09:33:06 +08:00
await this._impl.startup(opts);
}
//---------------------------------------------------------------------------
// stmtCacheSize
//
// Property for statement cache size.
//---------------------------------------------------------------------------
get stmtCacheSize() {
return this._impl.getStmtCacheSize();
}
set stmtCacheSize(value) {
errors.assertPropValue(Number.isInteger(value) && value >= 0,
"stmtCacheSize");
this._impl.setStmtCacheSize(value);
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// subscribe()
//
// Creates a subscription which can be used to get notifications of database
// changes or of AQ messages available to dequeue.
//---------------------------------------------------------------------------
async subscribe(name, options) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 2, 2);
errors.assertParamValue(typeof name === 'string', 1);
errors.assertParamValue(nodbUtil.isObject(options), 2);
2023-02-21 09:33:06 +08:00
await this._impl.subscribe(name, options);
}
//---------------------------------------------------------------------------
// tag
//
// Property for tag to associate with the connection.
//---------------------------------------------------------------------------
get tag() {
return this._impl.getTag();
}
set tag(value) {
errors.assertPropValue(typeof value === 'string', "tag");
this._impl.setTag(value);
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// tpcBegin()
//
// Starts a two-phase-commit transaction.
//--------------------------------------------------------------------------
async tpcBegin(xid, flag, timeout) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 1, 3);
errors.assertParamValue(nodbUtil.isXid(xid), 1);
2023-02-21 07:44:26 +08:00
if (arguments.length < 3) {
timeout = 60; // seconds
} else {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(typeof timeout === 'number', 3);
2023-02-21 07:44:26 +08:00
}
if (arguments.length < 2) {
flag = constants.TPC_BEGIN_NEW;
} else {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(typeof flag === 'number', 2);
2023-02-21 07:44:26 +08:00
}
2023-02-21 09:33:06 +08:00
await this._impl.tpcBegin(xid, flag, timeout);
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// tpcCommit()
//
// Commits a two-phase-commit transaction.
//---------------------------------------------------------------------------
async tpcCommit(xid, onePhase) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 2);
2023-02-21 07:44:26 +08:00
if (arguments.length < 2) {
onePhase = false;
} else {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(typeof onePhase === 'boolean', 2);
2023-02-21 07:44:26 +08:00
}
if (arguments.length >= 1) {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(nodbUtil.isXid(xid), 1);
2023-02-21 07:44:26 +08:00
}
2023-02-21 09:33:06 +08:00
await this._impl.tpcCommit(xid, onePhase);
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// tpcEnd()
//
// Ends a two-phase-commit transaction.
//---------------------------------------------------------------------------
async tpcEnd(xid, flag) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 2);
2023-02-21 07:44:26 +08:00
if (arguments.length < 2) {
flag = constants.TPC_END_NORMAL;
} else {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(typeof flag === 'number', 2);
2023-02-21 07:44:26 +08:00
}
if (arguments.length >= 1) {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(nodbUtil.isXid(xid), 1);
2023-02-21 07:44:26 +08:00
}
2023-02-21 09:33:06 +08:00
await this._impl.tpcEnd(xid, flag);
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// tpcForget()
//
// Causes the server to forget a heuristically completed two-phase-commit
// transaction.
// ---------------------------------------------------------------------------
async tpcForget(xid) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 1, 1);
errors.assertParamValue(nodbUtil.isXid(xid), 1);
2023-02-21 07:44:26 +08:00
2023-02-21 09:33:06 +08:00
await this._impl.tpcForget(xid);
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// tpcPrepare()
//
// Prepares a two-phase-commit transaction for commit.
//---------------------------------------------------------------------------
async tpcPrepare(xid) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 1);
2023-02-21 07:44:26 +08:00
if (arguments.length >= 1) {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(nodbUtil.isXid(xid), 1);
2023-02-21 07:44:26 +08:00
}
2023-02-21 09:33:06 +08:00
return await this._impl.tpcPrepare(xid);
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// tpcRecover()
//
// Returns a list of pending two-phase-commit transactions.
//---------------------------------------------------------------------------
async tpcRecover(asString) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 1);
2023-02-21 07:44:26 +08:00
if (arguments.length == 1) {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(typeof asString === 'boolean', 1);
2023-02-21 07:44:26 +08:00
} else {
asString = true;
}
const sqlStr = `
SELECT
formatid as "formatId",
UTL_RAW.CAST_TO_VARCHAR2(globalid) as "globalTransactionId",
UTL_RAW.CAST_TO_VARCHAR2(branchid) as "branchQualifier"
FROM DBA_PENDING_TRANSACTIONS`;
const sqlBuf = `
SELECT
formatid as "formatId",
globalid as "globalTransactionId",
branchid as "branchQualifier"
FROM DBA_PENDING_TRANSACTIONS`;
const options = {
outFormat: constants.OUT_FORMAT_OBJECT,
2023-02-21 09:33:06 +08:00
resultSet: false
2023-02-21 07:44:26 +08:00
};
2023-02-21 09:33:06 +08:00
const result = await this.execute(asString ? sqlStr : sqlBuf, {}, options);
return result.rows;
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// tpcRollback()
//
// Rolls back the current changes in a two-phase-commit transaction.
//---------------------------------------------------------------------------
async tpcRollback(xid) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 0, 1);
2023-02-21 07:44:26 +08:00
if (arguments.length == 1) {
2023-02-21 09:13:36 +08:00
errors.assertParamValue(nodbUtil.isXid(xid), 1);
2023-02-21 07:44:26 +08:00
}
2023-02-21 09:33:06 +08:00
await this._impl.tpcRollback(xid);
2023-02-21 07:44:26 +08:00
}
//---------------------------------------------------------------------------
// unsubscribe()
//
// Destroy a subscription which was earlier created using subscribe().
//---------------------------------------------------------------------------
async unsubscribe(name) {
2023-02-21 09:13:36 +08:00
errors.assertArgCount(arguments, 1, 1);
errors.assertParamValue(typeof name === 'string', 1);
2023-02-21 09:33:06 +08:00
await this._impl.unsubscribe(name);
2023-02-21 07:44:26 +08:00
}
}
2019-03-13 08:02:49 +08:00
2023-02-21 07:44:26 +08:00
// adjust functions to support the old callback style and to serialize calls
// that cannot take place concurrently
2023-02-21 09:33:06 +08:00
// NOTE: breakExecution() should not be serialized
2023-02-21 07:44:26 +08:00
Connection.prototype.break =
nodbUtil.callbackify(Connection.prototype.breakExecution);
nodbUtil.wrap_fns(Connection.prototype,
"changePassword",
"close",
"commit",
"createLob",
"execute",
"executeMany",
"getDbObjectClass",
"getQueue",
"getStatementInfo",
"ping",
"rollback",
"shutdown",
"startup",
"subscribe",
"tpcBegin",
"tpcCommit",
"tpcEnd",
"tpcForget",
"tpcPrepare",
"tpcRecover",
"tpcRollback",
"unsubscribe");
// add alias for release()
Connection.prototype.release = Connection.prototype.close;
// export just the Connection class
2019-03-13 08:02:49 +08:00
module.exports = Connection;