2023-02-21 12:18:47 +08:00
|
|
|
// Copyright (c) 2016, 2023, Oracle and/or its affiliates.
|
2019-03-13 08:02:49 +08:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
2023-02-21 09:43:43 +08:00
|
|
|
// 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.
|
2019-03-13 08:02:49 +08:00
|
|
|
//
|
2023-02-21 09:43:43 +08:00
|
|
|
// 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.
|
2019-03-13 08:02:49 +08:00
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
2023-02-21 09:43:43 +08:00
|
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
2019-03-13 08:02:49 +08:00
|
|
|
//
|
2023-02-21 09:43:43 +08:00
|
|
|
// 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.
|
2019-03-13 08:02:49 +08:00
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-02-29 10:48:48 +08:00
|
|
|
|
2016-05-16 07:53:23 +08:00
|
|
|
'use strict';
|
|
|
|
|
2023-02-21 09:33:06 +08:00
|
|
|
const AqQueue = require('./aqQueue.js');
|
2019-06-23 06:36:03 +08:00
|
|
|
const BaseDbObject = require('./dbObject.js');
|
2023-06-05 20:37:00 +08:00
|
|
|
const { Buffer } = require('buffer');
|
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');
|
2019-11-19 10:29:21 +08:00
|
|
|
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');
|
2023-06-05 20:37:00 +08:00
|
|
|
const process = require('process');
|
2023-02-21 09:33:06 +08:00
|
|
|
const util = require('util');
|
2023-02-21 07:44:26 +08:00
|
|
|
const constants = require('./constants.js');
|
|
|
|
const settings = require('./settings.js');
|
2023-05-24 01:54:53 +08:00
|
|
|
const transformer = require('./transformer.js');
|
2023-03-14 14:46:40 +08:00
|
|
|
const types = require('./types.js');
|
2016-02-29 10:48:48 +08:00
|
|
|
|
2023-02-21 10:50:27 +08:00
|
|
|
// 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();
|
|
|
|
|
2023-02-21 07:44:26 +08:00
|
|
|
// define class
|
|
|
|
class Connection extends EventEmitter {
|
2016-05-16 07:53:23 +08:00
|
|
|
|
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;
|
2020-02-16 08:06:45 +08:00
|
|
|
}
|
2016-05-16 07:53:23 +08:00
|
|
|
|
2023-02-21 09:33:06 +08:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// _addDefaultsToExecOpts()
|
|
|
|
//
|
|
|
|
// Add values to the execute options from the global settings, if needed.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
_addDefaultsToExecOpts(options) {
|
2023-02-21 14:27:09 +08:00
|
|
|
options.connection = this;
|
2023-02-21 09:33:06 +08:00
|
|
|
if (options.keepInStmtCache === undefined)
|
|
|
|
options.keepInStmtCache = true;
|
2023-02-21 10:48:15 +08:00
|
|
|
settings.addToOptions(options,
|
|
|
|
"autoCommit",
|
|
|
|
"dbObjectAsPojo",
|
|
|
|
"fetchArraySize",
|
2023-03-14 14:46:40 +08:00
|
|
|
"fetchTypeHandler",
|
2023-02-21 10:48:15 +08:00
|
|
|
"maxRows",
|
|
|
|
"outFormat",
|
|
|
|
"prefetchRows");
|
2020-02-16 08:06:45 +08:00
|
|
|
}
|
2016-02-29 10:48:48 +08:00
|
|
|
|
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-05-24 00:01:55 +08:00
|
|
|
this._impl = new impl.DbObjectImpl(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;
|
|
|
|
}
|
2023-02-21 14:02:51 +08:00
|
|
|
nodbUtil.addTypeProperties(objType, "elementType");
|
2023-02-21 09:33:06 +08:00
|
|
|
if (objType.attributes) {
|
|
|
|
const props = {};
|
|
|
|
for (const attr of objType.attributes) {
|
|
|
|
if (attr.typeClass) {
|
|
|
|
attr.typeClass = this._getDbObjectClass(attr.typeClass);
|
|
|
|
}
|
2023-02-21 14:02:51 +08:00
|
|
|
nodbUtil.addTypeProperties(attr, "type");
|
2023-02-21 09:33:06 +08:00
|
|
|
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);
|
2018-08-22 11:26:42 +08:00
|
|
|
}
|
2018-03-27 14:05:27 +08:00
|
|
|
|
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) {
|
2023-05-24 00:01:55 +08:00
|
|
|
if (objType.prototype instanceof BaseDbObject)
|
|
|
|
return objType;
|
2023-02-21 09:33:06 +08:00
|
|
|
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;
|
2023-06-20 18:37:25 +08:00
|
|
|
objType._connection = this._impl;
|
2023-02-21 09:33:06 +08:00
|
|
|
this._dbObjectClasses.set(objType, cls);
|
2023-02-21 07:44:26 +08:00
|
|
|
}
|
|
|
|
return (cls);
|
2019-06-23 06:36:03 +08:00
|
|
|
}
|
2016-02-29 10:48:48 +08:00
|
|
|
|
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
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// _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') {
|
2023-03-14 14:46:40 +08:00
|
|
|
bindInfo.type = types.DB_TYPE_OBJECT;
|
2023-02-21 09:33:06 +08:00
|
|
|
bindInfo.typeClass = await this._getDbObjectClassForName(bindUnit.type);
|
|
|
|
bindInfo.objType = bindInfo.typeClass._objType;
|
|
|
|
} else if (bindUnit.type.prototype instanceof BaseDbObject) {
|
2023-03-14 14:46:40 +08:00
|
|
|
bindInfo.type = types.DB_TYPE_OBJECT;
|
2023-02-21 09:33:06 +08:00
|
|
|
bindInfo.typeClass = bindUnit.type;
|
|
|
|
bindInfo.objType = bindInfo.typeClass._objType;
|
|
|
|
} else {
|
2023-03-14 14:46:40 +08:00
|
|
|
errors.assert(bindUnit.type instanceof types.DbType,
|
2023-02-21 09:33:06 +08:00
|
|
|
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) {
|
2023-03-14 14:46:40 +08:00
|
|
|
if (bindInfo.type === types.DB_TYPE_VARCHAR ||
|
|
|
|
bindInfo.type === types.DB_TYPE_RAW) {
|
2023-02-21 09:33:06 +08:00
|
|
|
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.
|
|
|
|
//---------------------------------------------------------------------------
|
2023-05-24 01:54:53 +08:00
|
|
|
async _processBindValue(bindInfo, value, options) {
|
|
|
|
const transformed = transformer.transformValueIn(bindInfo, value, options);
|
|
|
|
if (bindInfo.isArray) {
|
|
|
|
bindInfo.values = transformed.concat(bindInfo.values.slice(transformed.length));
|
2023-02-21 09:33:06 +08:00
|
|
|
} else {
|
2023-05-24 01:54:53 +08:00
|
|
|
bindInfo.values[options.pos] = transformed;
|
|
|
|
}
|
|
|
|
if (bindInfo.type === types.DB_TYPE_OBJECT &&
|
|
|
|
bindInfo.typeClass === undefined) {
|
|
|
|
bindInfo.typeClass = await this._getDbObjectClass(value._objType);
|
|
|
|
bindInfo.objType = bindInfo.typeClass._objType;
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// _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) {
|
2023-05-24 01:54:53 +08:00
|
|
|
const options = {pos: 0, allowArray: true};
|
|
|
|
await this._processBindValue(bindInfo, bindValue, options);
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2023-03-14 14:46:40 +08:00
|
|
|
bindInfo.type = types.DB_TYPE_VARCHAR;
|
2023-02-21 09:33:06 +08:00
|
|
|
if (bindInfo.maxSize === undefined)
|
|
|
|
bindInfo.maxSize = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check valid bind type for array binds
|
|
|
|
if (bindInfo.isArray &&
|
2023-03-14 14:46:40 +08:00
|
|
|
bindInfo.type !== types.DB_TYPE_VARCHAR &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_NVARCHAR &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_CHAR &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_NCHAR &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_NUMBER &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_BINARY_FLOAT &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_BINARY_DOUBLE &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_DATE &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_TIMESTAMP &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_TIMESTAMP_LTZ &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_TIMESTAMP_TZ &&
|
|
|
|
bindInfo.type !== types.DB_TYPE_RAW) {
|
2023-02-21 09:33:06 +08:00
|
|
|
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];
|
2023-05-24 01:54:53 +08:00
|
|
|
const options = {pos: i, allowArray: false};
|
2023-02-21 09:33:06 +08:00
|
|
|
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];
|
2023-05-24 01:54:53 +08:00
|
|
|
await this._processBindValue(bindInfo, value, options);
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2023-03-14 14:46:40 +08:00
|
|
|
bindInfo.type = types.DB_TYPE_VARCHAR;
|
2023-02-21 09:33:06 +08:00
|
|
|
bindInfo.maxSize = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return normBinds;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// _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();
|
2023-02-21 14:27:09 +08:00
|
|
|
outVal._setup(this, val);
|
2023-02-21 09:33:06 +08:00
|
|
|
} 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");
|
2023-02-21 14:21:26 +08:00
|
|
|
const names = Object.getOwnPropertyNames(options.fetchInfo);
|
|
|
|
const map = new Map(settings.fetchTypeMap);
|
|
|
|
for (const name of names) {
|
|
|
|
const info = options.fetchInfo[name];
|
2023-02-21 09:33:06 +08:00
|
|
|
if (info.type === undefined)
|
|
|
|
errors.throwErr(errors.ERR_NO_TYPE_FOR_CONVERSION);
|
|
|
|
if (info.type !== constants.DEFAULT &&
|
2023-03-14 14:46:40 +08:00
|
|
|
info.type !== types.DB_TYPE_VARCHAR &&
|
|
|
|
info.type !== types.DB_TYPE_RAW) {
|
2023-02-21 09:33:06 +08:00
|
|
|
errors.throwErr(errors.ERR_INVALID_TYPE_FOR_CONVERSION);
|
|
|
|
}
|
2023-02-21 14:21:26 +08:00
|
|
|
map.set(name, info.type);
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
2023-02-21 14:21:26 +08:00
|
|
|
outOptions.fetchTypeMap = map;
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
2023-03-14 14:46:40 +08:00
|
|
|
// fetchTypeHandler must be a function which is called for each column to
|
|
|
|
// be fetched and accepts the metadata for a column
|
|
|
|
if (options.fetchTypeHandler !== undefined) {
|
|
|
|
const type = (typeof options.fetchTypeHandler);
|
|
|
|
errors.assertParamPropValue(type === 'function', 3, "fetchTypeHandler");
|
|
|
|
outOptions.fetchTypeHandler = options.fetchTypeHandler;
|
|
|
|
}
|
|
|
|
|
2023-02-21 09:33:06 +08:00
|
|
|
// 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");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
this._impl.setAction(value);
|
2022-04-19 07:51:24 +08:00
|
|
|
}
|
|
|
|
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
await this._impl.breakExecution();
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// callTimeout
|
|
|
|
//
|
|
|
|
// Property for round-trip timeouts.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get callTimeout() {
|
2023-02-21 10:50:27 +08:00
|
|
|
if (this._impl)
|
|
|
|
return this._impl.getCallTimeout();
|
|
|
|
return undefined;
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
set callTimeout(value) {
|
|
|
|
errors.assertPropValue(Number.isInteger(value) && value >= 0,
|
|
|
|
"callTimeout");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
this._impl.setCallTimeout(value);
|
2022-04-19 07:51:24 +08:00
|
|
|
}
|
|
|
|
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
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");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
this._impl.setClientInfo(value);
|
2020-02-16 08:06:45 +08:00
|
|
|
}
|
2016-02-29 10:48:48 +08:00
|
|
|
|
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;
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assertParamPropBool(options, 1, "drop");
|
2023-02-21 07:44:26 +08:00
|
|
|
}
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl && !this._closing, errors.ERR_INVALID_CONNECTION);
|
2020-02-16 08:06:45 +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;
|
|
|
|
}
|
2019-11-05 08:17:39 +08:00
|
|
|
|
2023-02-21 10:50:27 +08:00
|
|
|
delete this._impl;
|
2023-02-21 09:33:06 +08:00
|
|
|
this._dbObjectClasses.clear();
|
2023-02-21 07:44:26 +08:00
|
|
|
this.emit('_afterConnClose');
|
2019-06-23 06:36:03 +08:00
|
|
|
}
|
2020-02-18 13:31:38 +08:00
|
|
|
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
await this._impl.commit();
|
2020-02-18 13:31:38 +08:00
|
|
|
}
|
|
|
|
|
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-03-14 14:46:40 +08:00
|
|
|
errors.assertParamValue(type === types.DB_TYPE_CLOB ||
|
|
|
|
type === types.DB_TYPE_BLOB ||
|
|
|
|
type === types.DB_TYPE_NCLOB, 1);
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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() {
|
2023-02-21 10:50:27 +08:00
|
|
|
if (this._impl)
|
|
|
|
return this._impl.getCurrentSchema();
|
|
|
|
return undefined;
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
set currentSchema(value) {
|
|
|
|
errors.assertPropValue(typeof value === 'string', "currentSchema");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
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");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
this._impl.setDbOp(value);
|
|
|
|
}
|
|
|
|
|
2023-05-23 22:20:06 +08:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// thin()
|
|
|
|
//
|
|
|
|
// return true, if driver mode is thin while acquiring connection
|
|
|
|
// return false, if driver mode is thick while acquiring connection
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get thin() {
|
|
|
|
return settings.thin;
|
|
|
|
}
|
|
|
|
|
2023-02-21 09:33:06 +08:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// ecid
|
|
|
|
//
|
|
|
|
// Property for end-to-end tracing attribute.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get ecid() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
set ecid(value) {
|
|
|
|
errors.assertPropValue(typeof value === 'string', "ecid");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
this._impl.setECID(value);
|
2020-02-18 13:31:38 +08:00
|
|
|
}
|
|
|
|
|
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 = {};
|
2020-02-18 13:31:38 +08:00
|
|
|
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2018-05-30 09:18:42 +08:00
|
|
|
|
2023-02-21 09:33:06 +08:00
|
|
|
// perform actual execute
|
2023-02-21 10:50:27 +08:00
|
|
|
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;
|
|
|
|
}
|
2018-05-30 09:18:42 +08:00
|
|
|
|
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();
|
2023-02-21 14:27:09 +08:00
|
|
|
resultSet._setup(this, result.resultSet);
|
|
|
|
result.metaData = resultSet._impl.metaData;
|
2023-02-21 09:33:06 +08:00
|
|
|
if (options.resultSet) {
|
|
|
|
result.resultSet = resultSet;
|
|
|
|
} else {
|
|
|
|
result.rows = await resultSet._getAllRows();
|
|
|
|
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
|
|
|
}
|
2018-05-30 09:18:42 +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();
|
2023-02-21 14:27:09 +08:00
|
|
|
resultSet._setup(this, resultSetImpl);
|
2023-02-21 09:33:06 +08:00
|
|
|
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
|
|
|
}
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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
|
|
|
}
|
2019-06-23 06:36:03 +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() {
|
2023-02-21 10:50:27 +08:00
|
|
|
if (this._impl)
|
|
|
|
return this._impl.getExternalName();
|
|
|
|
return undefined;
|
2021-05-03 13:10:09 +08:00
|
|
|
}
|
|
|
|
|
2023-02-21 09:33:06 +08:00
|
|
|
set externalName(value) {
|
|
|
|
errors.assertPropValue(typeof value === 'string', "externalName");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
this._impl.setExternalName(value);
|
|
|
|
}
|
2021-05-03 13:10:09 +08:00
|
|
|
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
return await this._getDbObjectClassForName(name);
|
2019-11-05 08:18:55 +08:00
|
|
|
}
|
|
|
|
|
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};
|
2021-05-03 13:10:09 +08:00
|
|
|
}
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
const queue = new AqQueue();
|
|
|
|
await queue.create(this, name, options);
|
|
|
|
return queue;
|
2021-05-03 13:10:09 +08:00
|
|
|
}
|
|
|
|
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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
|
|
|
}
|
2018-09-26 16:31:14 +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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 14:02:51 +08:00
|
|
|
const info = await this._impl.getStatementInfo(sql);
|
|
|
|
if (info.metaData) {
|
|
|
|
for (let i = 0; i < info.metaData.length; i++) {
|
2023-02-21 14:21:26 +08:00
|
|
|
const m = info.metaData[i];
|
|
|
|
nodbUtil.addTypeProperties(m, "dbType");
|
2023-03-14 14:46:40 +08:00
|
|
|
m.fetchType = types.DB_TYPE_FETCH_TYPE_MAP.get(m.dbType);
|
2023-02-21 14:02:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return info;
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
2023-08-17 15:04:21 +08:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// instanceName
|
|
|
|
//
|
|
|
|
// Returns the Oracle Database instance name associated with the connection.
|
|
|
|
// This is the equivalent of the SQL expression:
|
|
|
|
// sys_context('userenv', 'instance_name')
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get instanceName() {
|
|
|
|
if (this._impl)
|
|
|
|
return this._impl.getInstanceName();
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2023-02-21 09:33:06 +08:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// internalName
|
|
|
|
//
|
|
|
|
// Property for identifying the internal name to use in TPC logging.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get internalName() {
|
2023-02-21 10:50:27 +08:00
|
|
|
if (this._impl)
|
|
|
|
return this._impl.getInternalName();
|
|
|
|
return undefined;
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
set internalName(value) {
|
|
|
|
errors.assertPropValue(typeof value === 'string', "internalName");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
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 10:50:27 +08:00
|
|
|
return (this._impl !== undefined && !this._closing &&
|
|
|
|
this._impl.isHealthy());
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// module
|
|
|
|
//
|
|
|
|
// Property for end-to-end tracing attribute.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get module() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
set module(value) {
|
|
|
|
errors.assertPropValue(typeof value === 'string', "module");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
this._impl.setModule(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// oracleServerVersion
|
|
|
|
//
|
|
|
|
// Returns an integer identifying the Oracle Server version.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get oracleServerVersion() {
|
2023-02-21 10:50:27 +08:00
|
|
|
if (this._impl)
|
|
|
|
return this._impl.getOracleServerVersion();
|
|
|
|
return undefined;
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// oracleServerVersionString
|
|
|
|
//
|
|
|
|
// Returns a string identifying the Oracle Server version.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get oracleServerVersionString() {
|
2023-02-21 10:50:27 +08:00
|
|
|
if (this._impl)
|
|
|
|
return this._impl.getOracleServerVersionString();
|
|
|
|
return undefined;
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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;
|
|
|
|
|
2020-02-16 08:06:45 +08:00
|
|
|
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 () => {
|
2020-02-16 08:06:45 +08:00
|
|
|
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);
|
2020-02-16 08:06:45 +08:00
|
|
|
} 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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 07:44:26 +08:00
|
|
|
|
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) {
|
2023-02-21 10:50:27 +08:00
|
|
|
let options = {};
|
2023-02-21 07:44:26 +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 10:50:27 +08:00
|
|
|
errors.assertParamValue(typeof options === 'object', 1);
|
|
|
|
options = a1;
|
|
|
|
errors.assertParamPropBool(options, 1, "force");
|
|
|
|
errors.assertParamPropBool(options, 1, "restrict");
|
|
|
|
errors.assertParamPropString(options, 1, "pfile");
|
2023-02-21 07:44:26 +08:00
|
|
|
}
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 07:44:26 +08:00
|
|
|
|
2023-02-21 10:50:27 +08:00
|
|
|
await this._impl.startup(options);
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// stmtCacheSize
|
|
|
|
//
|
|
|
|
// Property for statement cache size.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get stmtCacheSize() {
|
2023-02-21 10:50:27 +08:00
|
|
|
if (this._impl)
|
|
|
|
return this._impl.getStmtCacheSize();
|
|
|
|
return undefined;
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
set stmtCacheSize(value) {
|
|
|
|
errors.assertPropValue(Number.isInteger(value) && value >= 0,
|
|
|
|
"stmtCacheSize");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
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 10:50:27 +08:00
|
|
|
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;
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// tag
|
|
|
|
//
|
|
|
|
// Property for tag to associate with the connection.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
get tag() {
|
2023-02-21 10:50:27 +08:00
|
|
|
if (this._impl)
|
|
|
|
return this._impl.getTag();
|
|
|
|
return undefined;
|
2023-02-21 09:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
set tag(value) {
|
|
|
|
errors.assertPropValue(typeof value === 'string', "tag");
|
2023-02-21 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2023-02-21 09:33:06 +08:00
|
|
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
2016-02-29 10:48:48 +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 10:50:27 +08:00
|
|
|
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION);
|
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 10:50:27 +08:00
|
|
|
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);
|
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);
|
2023-05-03 21:58:48 +08:00
|
|
|
nodbUtil.wrapFns(Connection.prototype,
|
2023-02-21 07:44:26 +08:00
|
|
|
"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;
|