Comparing version 6.5.1 to 6.6.0
@@ -109,2 +109,3 @@ # Node-oracledb Examples | ||
[`plsqlvarrayrecord.js`](plsqlvarrayrecord.js) | Shows binding a VARRAY of RECORD in PL/SQL | ||
[`plsqlrowtype.js`](plsqlrowtype.js) | Shows binding of PL/SQL %ROWTYPE object | ||
[`raw.js`](raw.js) | Shows using a Buffer to insert and select a RAW | ||
@@ -138,1 +139,2 @@ [`refcursor.js`](refcursor.js) | Shows using a ResultSet to fetch rows from a REF CURSOR | ||
[`webapp.js`](webapp.js) | A simple web application using a connection pool | ||
[`xmltypeInDbObject.js`](xmltypeInDbObject.js) | Work with XMLType data in DbObject (Thin mode only) |
@@ -205,5 +205,3 @@ // Copyright (c) 2016, 2024, Oracle and/or its affiliates. | ||
Array.isArray(value) || | ||
value instanceof Float32Array || | ||
value instanceof Float64Array || | ||
value instanceof Int8Array || | ||
nodbUtil.isVectorValue(value) || | ||
Buffer.isBuffer(value) || | ||
@@ -1416,3 +1414,3 @@ util.types.isDate(value) || | ||
errors.assertParamValue(nodbUtil.isXid(xid), 1); | ||
const normalizedXid = nodbUtil.normalizeXid(xid); | ||
if (arguments.length < 3) { | ||
@@ -1428,5 +1426,10 @@ timeout = 60; // seconds | ||
errors.assertParamValue(typeof flag === 'number', 2); | ||
const options = [constants.TPC_BEGIN_NEW, constants.TPC_BEGIN_JOIN, | ||
constants.TPC_BEGIN_RESUME, constants.TPC_BEGIN_PROMOTE]; | ||
if (options.indexOf(flag) < 0) { | ||
errors.throwErr(errors.ERR_INVALID_TPC_BEGIN_FLAGS); | ||
} | ||
} | ||
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); | ||
await this._impl.tpcBegin(xid, flag, timeout); | ||
await this._impl.tpcBegin(normalizedXid, flag, timeout); | ||
} | ||
@@ -1447,7 +1450,9 @@ | ||
} | ||
let normalizedXid; | ||
if (arguments.length >= 1) { | ||
errors.assertParamValue(nodbUtil.isXid(xid), 1); | ||
normalizedXid = nodbUtil.normalizeXid(xid); | ||
} | ||
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); | ||
await this._impl.tpcCommit(xid, onePhase); | ||
await this._impl.tpcCommit(normalizedXid, onePhase); | ||
} | ||
@@ -1467,10 +1472,15 @@ | ||
errors.assertParamValue(typeof flag === 'number', 2); | ||
const options = [constants.TPC_END_NORMAL, constants.TPC_END_SUSPEND]; | ||
if (!options.includes(flag)) { | ||
errors.throwErr(errors.ERR_INVALID_TPC_END_FLAGS); | ||
} | ||
} | ||
let normalizedXid; | ||
if (arguments.length >= 1) { | ||
errors.assertParamValue(nodbUtil.isXid(xid), 1); | ||
normalizedXid = nodbUtil.normalizeXid(xid); | ||
} | ||
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); | ||
await this._impl.tpcEnd(xid, flag); | ||
await this._impl.tpcEnd(normalizedXid, flag); | ||
} | ||
@@ -1487,5 +1497,6 @@ | ||
errors.assertParamValue(nodbUtil.isXid(xid), 1); | ||
const normalizedXid = nodbUtil.normalizeXid(xid); | ||
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); | ||
await this._impl.tpcForget(xid); | ||
await this._impl.tpcForget(normalizedXid); | ||
} | ||
@@ -1500,8 +1511,10 @@ | ||
errors.assertArgCount(arguments, 0, 1); | ||
let normalizedXid; | ||
if (arguments.length >= 1) { | ||
errors.assertParamValue(nodbUtil.isXid(xid), 1); | ||
normalizedXid = nodbUtil.normalizeXid(xid); | ||
} | ||
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); | ||
return await this._impl.tpcPrepare(xid); | ||
return await this._impl.tpcPrepare(normalizedXid); | ||
} | ||
@@ -1551,8 +1564,10 @@ | ||
errors.assertArgCount(arguments, 0, 1); | ||
let normalizedXid; | ||
if (arguments.length == 1) { | ||
errors.assertParamValue(nodbUtil.isXid(xid), 1); | ||
normalizedXid = nodbUtil.normalizeXid(xid); | ||
} | ||
errors.assert(this._impl, errors.ERR_INVALID_CONNECTION); | ||
await this._impl.tpcRollback(xid); | ||
await this._impl.tpcRollback(normalizedXid); | ||
} | ||
@@ -1581,2 +1596,4 @@ | ||
nodbUtil.callbackify(Connection.prototype.breakExecution); | ||
Connection.prototype.tpcRecover = | ||
nodbUtil.callbackify(Connection.prototype.tpcRecover); | ||
nodbUtil.wrapFns(Connection.prototype, | ||
@@ -1602,3 +1619,2 @@ "changePassword", | ||
"tpcPrepare", | ||
"tpcRecover", | ||
"tpcRollback", | ||
@@ -1605,0 +1621,0 @@ "unsubscribe"); |
@@ -208,3 +208,4 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
VECTOR_FORMAT_INT8: 4, | ||
VECTOR_FORMAT_BINARY: 5, | ||
}; |
@@ -159,2 +159,9 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
const ERR_DML_RETURNING_DUP_BINDS = 149; | ||
const ERR_INVALID_TPC_BEGIN_FLAGS = 150; | ||
const ERR_INVALID_TPC_END_FLAGS = 151; | ||
const ERR_UNKNOWN_TRANSACTION_STATE = 152; | ||
const ERR_INVALID_TRANSACTION_SIZE = 153; | ||
const ERR_INVALID_BRANCH_SIZE = 154; | ||
const ERR_OPERATION_NOT_SUPPORTED_ON_BFILE = 155; | ||
const ERR_OPERATION_ONLY_SUPPORTED_ON_BFILE = 156; | ||
@@ -183,2 +190,9 @@ // Oracle Net layer errors start from 500 | ||
const ERR_CONNECTION_EOF = 521; | ||
const ERR_AZURE_CONFIG_PROVIDER_AUTH_FAILED = 522; | ||
const ERR_CONFIG_PROVIDER_FAILED_TO_RETRIEVE_CONFIG = 523; | ||
const ERR_CONFIG_PROVIDER_NOT_SUPPORTED = 524; | ||
const ERR_CONFIG_PROVIDER_LOAD_FAILED = 525; | ||
const ERR_OCIOBJECT_CONFIG_PROVIDER_AUTH_FAILED = 526; | ||
const ERR_AZURE_VAULT_AUTH_FAILED = 527; | ||
const ERR_AZURE_SERVICE_PRINCIPAL_AUTH_FAILED = 528; | ||
@@ -439,2 +453,16 @@ // Oracle SUCCESS_WITH_INFO warning start from 700 | ||
'the bind variable placeholder "%s" cannot be used both before and after the RETURNING clause in a DML RETURNING statement'); | ||
messages.set(ERR_INVALID_TPC_BEGIN_FLAGS, // NJS-150 | ||
'invalid flags for tpcBegin() in Two Phase Commit'); | ||
messages.set(ERR_INVALID_TPC_END_FLAGS, // NJS-151 | ||
'invalid flags for tpcEnd() in Two Phase Commit'); | ||
messages.set(ERR_UNKNOWN_TRANSACTION_STATE, // NJS-152 | ||
'internal error: unknown transaction state {state} in Two Phase Commit'); | ||
messages.set(ERR_INVALID_TRANSACTION_SIZE, // NJS-153 | ||
'size of the transaction ID is %d and cannot exceed 64'); | ||
messages.set(ERR_INVALID_BRANCH_SIZE, // NJS-154 | ||
'size of the branch ID is %d and cannot exceed 64'); | ||
messages.set(ERR_OPERATION_NOT_SUPPORTED_ON_BFILE, // NJS-155 | ||
'operation is not supported on BFILE LOBs'); | ||
messages.set(ERR_OPERATION_ONLY_SUPPORTED_ON_BFILE, // NJS-156 | ||
'operation is only supported on BFILE LOBs'); | ||
@@ -485,3 +513,16 @@ // Oracle Net layer errors | ||
'connection to host %s port %d received end-of-file on communication channel. (CONNECTION_ID=%s)'); | ||
messages.set(ERR_AZURE_CONFIG_PROVIDER_AUTH_FAILED, // NJS-522 | ||
'Azure Authentication Failed: The authentication parameter value %s may be incorrect'); | ||
messages.set(ERR_CONFIG_PROVIDER_FAILED_TO_RETRIEVE_CONFIG, // NJS-523 | ||
'Failed to retrieve configuration from Centralized Configuration Provider:\n %s'); | ||
messages.set(ERR_CONFIG_PROVIDER_NOT_SUPPORTED, // NJS-524 | ||
'Configuration Provider not supported: %s'); | ||
messages.set(ERR_CONFIG_PROVIDER_LOAD_FAILED, // NJS-525 | ||
'Centralized Config Provider failed to load required libraries. Please install the required libraries.\n %s'); | ||
messages.set(ERR_OCIOBJECT_CONFIG_PROVIDER_AUTH_FAILED, // NJS-526 | ||
'OCI authentication failed: The authentication parameter value %s may be incorrect'); | ||
messages.set(ERR_AZURE_VAULT_AUTH_FAILED, // NJS-527 | ||
'Azure Vault: Provide correct azure vault authentication details'); | ||
messages.set(ERR_AZURE_SERVICE_PRINCIPAL_AUTH_FAILED, // NJS-528 | ||
'Azure service principal authentication requires either a client certificate path or a client secret string'); | ||
// Oracle SUCCESS_WITH_INFO warning | ||
@@ -796,2 +837,9 @@ | ||
ERR_CONNECTION_EOF, | ||
ERR_AZURE_CONFIG_PROVIDER_AUTH_FAILED, | ||
ERR_OCIOBJECT_CONFIG_PROVIDER_AUTH_FAILED, | ||
ERR_AZURE_VAULT_AUTH_FAILED, | ||
ERR_AZURE_SERVICE_PRINCIPAL_AUTH_FAILED, | ||
ERR_CONFIG_PROVIDER_FAILED_TO_RETRIEVE_CONFIG, | ||
ERR_CONFIG_PROVIDER_NOT_SUPPORTED, | ||
ERR_CONFIG_PROVIDER_LOAD_FAILED, | ||
ERR_INVALID_BIND_NAME, | ||
@@ -849,3 +897,10 @@ ERR_WRONG_NUMBER_OF_POSITIONAL_BINDS, | ||
ERR_DML_RETURNING_DUP_BINDS, | ||
ERR_INVALID_TPC_BEGIN_FLAGS, | ||
ERR_INVALID_TPC_END_FLAGS, | ||
ERR_UNKNOWN_TRANSACTION_STATE, | ||
ERR_INVALID_TRANSACTION_SIZE, | ||
ERR_INVALID_BRANCH_SIZE, | ||
ERR_CONNECTION_CLOSED_CODE: `${ERR_PREFIX}-${ERR_CONNECTION_CLOSED}`, | ||
ERR_OPERATION_NOT_SUPPORTED_ON_BFILE, | ||
ERR_OPERATION_ONLY_SUPPORTED_ON_BFILE, | ||
WRN_COMPILATION_CREATE, | ||
@@ -852,0 +907,0 @@ assert, |
@@ -35,3 +35,4 @@ // Copyright (c) 2024, Oracle and/or its affiliates. | ||
TNS_VECTOR_MAGIC_BYTE: 0xDB, | ||
TNS_VECTOR_VERSION: 0, | ||
TNS_VECTOR_VERSION_BASE: 0, | ||
TNS_VECTOR_VERSION_WITH_BINARY: 1, | ||
@@ -103,2 +104,3 @@ // vector flags | ||
VECTOR_FORMAT_INT8: constants.VECTOR_FORMAT_INT8, | ||
VECTOR_FORMAT_BINARY: constants.VECTOR_FORMAT_BINARY, | ||
@@ -105,0 +107,0 @@ TNS_NULL_LENGTH_INDICATOR: 255, |
@@ -53,7 +53,7 @@ // Copyright (c) 2024, Oracle and/or its affiliates. | ||
const version = this.readUInt8(); | ||
if (version != constants.TNS_VECTOR_VERSION) | ||
if (version > constants.TNS_VECTOR_VERSION_WITH_BINARY) | ||
errors.throwErr(errors.ERR_VECTOR_VERSION_NOT_SUPPORTED, version); | ||
const flags = this.readUInt16BE(); | ||
const vectorFormat = this.readUInt8(); | ||
const numElements = this.readUInt32BE(); | ||
let numElements = this.readUInt32BE(); | ||
let elementSize, result; | ||
@@ -69,6 +69,14 @@ if (vectorFormat === constants.VECTOR_FORMAT_FLOAT32) { | ||
result = new Int8Array(numElements); | ||
} else if (vectorFormat === constants.VECTOR_FORMAT_BINARY) { | ||
elementSize = 1; | ||
// The number of dimensions are assumed to be multiple of 8. | ||
numElements = numElements / 8; | ||
result = new Uint8Array(numElements); | ||
} else { | ||
errors.throwErr(errors.ERR_VECTOR_FORMAT_NOT_SUPPORTED, vectorFormat); | ||
} | ||
if (flags & constants.TNS_VECTOR_FLAG_NORM) | ||
// For binary vector, NORM will never be present but space for NORM is reserved to keep | ||
// same header lengh across the different vector formats. | ||
if (vectorFormat === constants.VECTOR_FORMAT_BINARY || flags & constants.TNS_VECTOR_FLAG_NORM) | ||
this.skipBytes(8); | ||
@@ -105,2 +113,6 @@ | ||
let writeFn = this.writeBinaryFloat.bind(this); | ||
let numElements = value.length; | ||
let vectorVersion = constants.TNS_VECTOR_VERSION_BASE; | ||
let flags = constants.TNS_VECTOR_FLAG_NORMSRC | ||
| constants.TNS_VECTOR_FLAG_NORM; // NORM is present and reserve space. | ||
@@ -113,14 +125,17 @@ if (Array.isArray(value) || value instanceof Float64Array) { | ||
writeFn = this.writeSB1.bind(this); | ||
} else if (value.constructor.name === 'Uint8Array') { | ||
vectorFormat = constants.VECTOR_FORMAT_BINARY; | ||
// The number of dimensions are assumed to be multiple of 8. | ||
numElements = numElements * 8; | ||
vectorVersion = constants.TNS_VECTOR_VERSION_WITH_BINARY; | ||
flags = constants.TNS_VECTOR_FLAG_NORMSRC; // only space is reserved. | ||
writeFn = this.writeUInt8.bind(this); | ||
} | ||
// Let server generate the norm (TNS_VECTOR_FLAG_NORMSRC) | ||
const flags = constants.TNS_VECTOR_FLAG_NORM | ||
| constants.TNS_VECTOR_FLAG_NORMSRC; | ||
// write header | ||
this.writeUInt8(constants.TNS_VECTOR_MAGIC_BYTE); | ||
this.writeUInt8(constants.TNS_VECTOR_VERSION); | ||
this.writeUInt8(vectorVersion); | ||
this.writeUInt16BE(flags); | ||
this.writeUInt8(vectorFormat); | ||
this.writeUInt32BE(value.length); | ||
this.writeUInt32BE(numElements); | ||
this.reserveBytes(8); | ||
@@ -127,0 +142,0 @@ |
@@ -57,2 +57,11 @@ // Copyright (c) 2022, Oracle and/or its affiliates. | ||
//--------------------------------------------------------------------------- | ||
// fileExists() | ||
// | ||
// Checks if BFILE present or not. | ||
//--------------------------------------------------------------------------- | ||
fileExists() { | ||
errors.throwNotImplemented("check if BFILE exists"); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// getData() | ||
@@ -67,2 +76,11 @@ // | ||
//--------------------------------------------------------------------------- | ||
// getDirFileName() | ||
// | ||
// returns directory and filename of LOB (BFILE). | ||
//---------------------------------------------------------------------------- | ||
getDirFileName() { | ||
errors.throwNotImplemented("getting directory and filename of LOB(BFILE)"); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// read() | ||
@@ -77,2 +95,11 @@ // | ||
//--------------------------------------------------------------------------- | ||
// setDirFileName() | ||
// | ||
// sets directory and filename for LOB (BFILE) | ||
//--------------------------------------------------------------------------- | ||
setDirFileName() { | ||
errors.throwNotImplemented("setting directory and filename of LOB(BFILE)"); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// write() | ||
@@ -79,0 +106,0 @@ // |
@@ -239,3 +239,4 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
info.fetchType === types.DB_TYPE_NCLOB || | ||
info.fetchType === types.DB_TYPE_BLOB) { | ||
info.fetchType === types.DB_TYPE_BLOB || | ||
info.fetchType === types.DB_TYPE_BFILE) { | ||
this.lobIndices.push(i); | ||
@@ -279,4 +280,28 @@ } else if (info.fetchType === types.DB_TYPE_OBJECT) { | ||
//--------------------------------------------------------------------------- | ||
// _getAllRows() [INTERNAL] | ||
// | ||
// Fetches all the rows from the database to use internally. | ||
//--------------------------------------------------------------------------- | ||
async _getAllRows() { | ||
const fetchArraySize = 100; | ||
// fetch all rows | ||
let rowsFetched = []; | ||
while (true) { // eslint-disable-line | ||
// constant default value for fetchArraySize | ||
const rows = await this.getRows(fetchArraySize, {}); | ||
if (rows) { | ||
await this._processRows(rows, false); | ||
rowsFetched = rowsFetched.concat(rows); | ||
} | ||
if (rows.length < fetchArraySize) { | ||
break; | ||
} | ||
} | ||
return rowsFetched; | ||
} | ||
} | ||
module.exports = ResultSetImpl; |
@@ -49,2 +49,18 @@ // Copyright (c) 2016, 2024, Oracle and/or its affiliates. | ||
// called by BFILE specific functions to throw errors for other | ||
// datatypes. | ||
_checkIsBfile() { | ||
if (this.type !== types.DB_TYPE_BFILE) { | ||
errors.throwErr(errors.ERR_OPERATION_ONLY_SUPPORTED_ON_BFILE); | ||
} | ||
} | ||
// called by functions not allowed for BFILE and throw errors if | ||
// such operations are performed on BFILE. | ||
_checkNotBfile() { | ||
if (this.type === types.DB_TYPE_BFILE) { | ||
errors.throwErr(errors.ERR_OPERATION_NOT_SUPPORTED_ON_BFILE); | ||
} | ||
} | ||
// called by stream.destroy() and ensures that the LOB is closed if it has | ||
@@ -105,3 +121,6 @@ // not already been closed (never called directly) | ||
this._impl = lobImpl; | ||
this._chunkSize = lobImpl.getChunkSize(); | ||
// chunk size is not defined for BFILE LOBs | ||
if (this.type !== types.DB_TYPE_BFILE) { | ||
this._chunkSize = lobImpl.getChunkSize(); | ||
} | ||
this._pieceSize = lobImpl.getPieceSize(); | ||
@@ -158,2 +177,3 @@ this._length = lobImpl.getLength(); | ||
get chunkSize() { | ||
this._checkNotBfile(); | ||
return this._chunkSize; | ||
@@ -216,2 +236,32 @@ } | ||
//--------------------------------------------------------------------------- | ||
// getDirFileName() | ||
// To obtain the BFILE Lob object properties dirName & fileName | ||
//--------------------------------------------------------------------------- | ||
getDirFileName() { | ||
this._checkIsBfile(); | ||
return this._impl.getDirFileName(); | ||
} | ||
//-------------------------------------------------------------------------- | ||
// setDirFileName() | ||
// To set the BFILE Lob object properties dirName & fileName | ||
//-------------------------------------------------------------------------- | ||
setDirFileName(a1) { | ||
this._checkIsBfile(); | ||
errors.assertArgCount(arguments, 1, 1); | ||
errors.assertParamValue(nodbUtil.isObject(a1), 1); | ||
this._impl.setDirFileName(a1); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// fileExists | ||
// | ||
// To obtain file existence status of BFILE file | ||
//--------------------------------------------------------------------------- | ||
async fileExists() { | ||
this._checkIsBfile(); | ||
return await this._impl.fileExists(); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// length | ||
@@ -255,2 +305,3 @@ // | ||
"close", | ||
"fileExists", | ||
"getData"); | ||
@@ -257,0 +308,0 @@ Lob.prototype._serializedRead = nodbUtil.serialize(Lob.prototype._readData); |
@@ -132,2 +132,3 @@ // Copyright (c) 2015, 2023, Oracle and/or its affiliates. | ||
options = await _checkConfigProvider(options); | ||
// only one of "user" and "username" may be specified (and must be strings) | ||
@@ -181,2 +182,9 @@ if (options.user !== undefined) { | ||
//wallet content must be a string | ||
if (options.walletContent !== undefined) { | ||
errors.assertParamPropValue(typeof options.walletContent === 'string', 1, | ||
"walletContent"); | ||
outOptions.walletContent = options.walletContent; | ||
} | ||
// edition must be a string | ||
@@ -765,2 +773,47 @@ if (options.edition !== undefined) { | ||
//----------------------------------------------------------------------------- | ||
// _checkConfigProvider() | ||
// | ||
// Look for the config provider in the connection string and retreives | ||
// object stored in the config Provider. | ||
// Returns object based on precedence between input object and the one retrieved | ||
// from Config Provider. | ||
//----------------------------------------------------------------------------- | ||
async function _checkConfigProvider(options) { | ||
const url = options.connectString || options.connectionString; | ||
if (!url) | ||
return options; | ||
let parsedUrl = url; | ||
let urlExtendedPart; | ||
const baseRegex = new RegExp("^config-(?<provider>[A-Za-z0-9]+)(://)(?<provider_arg>[^?]+)"); | ||
if (url.indexOf('?') != -1) { | ||
parsedUrl = url.substring(0, url.indexOf('?')); | ||
urlExtendedPart = url.substring(url.indexOf('?'), url.length); //extended part | ||
} | ||
const match = parsedUrl.match(baseRegex); | ||
if (match) { | ||
const provider = match.groups.provider; | ||
const provider_arg = match.groups.provider_arg; | ||
let configPckg; | ||
try { | ||
configPckg = require('./configProviders/' + provider); | ||
} catch (err) { | ||
errors.throwErr(errors.ERR_CONFIG_PROVIDER_NOT_SUPPORTED, provider); | ||
} | ||
const configProvider = new configPckg(provider_arg, urlExtendedPart); | ||
try { | ||
configProvider.init(); | ||
} catch (err) { | ||
errors.throwErr(errors.ERR_CONFIG_PROVIDER_LOAD_FAILED, err.message); | ||
} | ||
let secondOpts; | ||
try { | ||
secondOpts = await configProvider.returnConfig(); | ||
} catch (err) { | ||
errors.throwErr(errors.ERR_CONFIG_PROVIDER_FAILED_TO_RETRIEVE_CONFIG, err.message); | ||
} | ||
options = configProvider.modifyOptionsPrecedence(secondOpts, options); | ||
} | ||
return options; | ||
} | ||
@@ -1013,2 +1066,3 @@ //----------------------------------------------------------------------------- | ||
VECTOR_FORMAT_INT8: constants.VECTOR_FORMAT_INT8, | ||
VECTOR_FORMAT_BINARY: constants.VECTOR_FORMAT_BINARY, | ||
@@ -1015,0 +1069,0 @@ // database type aliases |
@@ -63,3 +63,9 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
if (this._protocol.txnInProgress) { | ||
await this.rollback(); | ||
if (this.tpcContext) { | ||
const message = this.createTpcRollbackMessage(); | ||
await this._protocol._processMessage(message); | ||
} else { | ||
await this.rollback(); | ||
} | ||
this.tpcContext = null; | ||
} | ||
@@ -389,2 +395,5 @@ if (this._drcpEnabled) { | ||
await this._getElementTypeObj(info); | ||
if (info.elementTypeClass.isXmlType) { | ||
info.elementType = types.DB_TYPE_XMLTYPE; | ||
} | ||
} | ||
@@ -444,2 +453,23 @@ } else { | ||
end;`; | ||
// get column and datatype information in case of %ROWTYPE handling. | ||
const getColumnsSQL = ` | ||
SELECT | ||
column_name, | ||
data_type, | ||
data_type_owner, | ||
case | ||
when data_type in | ||
('CHAR', 'NCHAR', 'VARCHAR2', 'NVARCHAR2', 'RAW') | ||
then data_length | ||
else 0 | ||
end, | ||
nvl(data_precision, 0), | ||
nvl(data_scale, 0) | ||
from all_tab_cols | ||
where owner = :owner | ||
and table_name = :name | ||
and hidden_column != 'YES' | ||
order by column_id`; | ||
const binds = [ | ||
@@ -523,23 +553,65 @@ { | ||
// process TDS and attributes cursor | ||
info.version = result.outBinds.version; | ||
const attrRows = await result.outBinds.attrs_rc.getRows(1000, {}); | ||
if (attrRows.length > 0) { | ||
// Its an object not a collection. | ||
if (info.name.endsWith('%ROWTYPE')) { | ||
const bindVal = [ | ||
{ | ||
name: "owner", | ||
type: types.DB_TYPE_VARCHAR, | ||
maxSize: 128, | ||
dir: constants.BIND_IN, | ||
values: [result.outBinds.schema], | ||
}, | ||
{ | ||
name: "name", | ||
type: types.DB_TYPE_VARCHAR, | ||
maxSize: 128, | ||
dir: constants.BIND_IN, | ||
values: [info.name.substring(0, info.name.length - 8)] | ||
} | ||
]; | ||
const val = await this.execute( | ||
getColumnsSQL, 1, bindVal, options, false | ||
); | ||
const attrRows = await val.resultSet._getAllRows(); | ||
info.attributes = []; | ||
for (const row of attrRows) { | ||
const attr = { name: row[1] }; | ||
if (row[4]) { | ||
attr.type = types.DB_TYPE_OBJECT; | ||
attr.typeClass = this._getDbObjectType(row[4], row[3], row[5], row[6]); | ||
if (attr.typeClass.partial) { | ||
this._partialDbObjectTypes.push(attr.typeClass); | ||
const metaData = { | ||
name: row[0], | ||
dataType: row[1], | ||
dataTypeOwner: row[2], | ||
maxSize: row[3], | ||
dataPrecision: row[4], | ||
dataScale: row[5], | ||
}; | ||
if (!metaData.dataTypeOwner) { | ||
const startPos = row[1].indexOf('('); | ||
const endPos = row[1].indexOf(')'); | ||
if (endPos > startPos) { | ||
metaData.dataType = metaData.dataType.substring(0, startPos) + | ||
metaData.dataType.substring( | ||
endPos + 1, metaData.dataType.length | ||
); | ||
} | ||
} else { | ||
attr.type = types.getTypeByColumnTypeName(row[3]); | ||
} | ||
info.attributes.push(attr); | ||
this._addAttr(info.attributes, metaData); | ||
} | ||
} else { | ||
info.version = result.outBinds.version; | ||
const attrRows = await result.outBinds.attrs_rc._getAllRows(); | ||
if (attrRows.length > 0) { | ||
// Its an object not a collection. | ||
info.attributes = []; | ||
for (const row of attrRows) { | ||
const metaData = { | ||
name: row[1], | ||
dataType: row[3], | ||
dataTypeOwner: row[4], | ||
packageName: row[5], | ||
oid: row[6] | ||
}; | ||
this._addAttr(info.attributes, metaData); | ||
} | ||
} | ||
await this._parseTDS(result.outBinds.tds, info); | ||
} | ||
await this._parseTDS(result.outBinds.tds, info); | ||
info.partial = false; | ||
@@ -551,2 +623,33 @@ return info; | ||
//--------------------------------------------------------------------------- | ||
// _addAttr() | ||
// | ||
// Populates "attributes" object present in "attrList". | ||
//--------------------------------------------------------------------------- | ||
_addAttr(attributes, attrInfo) { | ||
const attr = { name: attrInfo.name }; | ||
if (attrInfo.dataTypeOwner) { | ||
attr.type = types.DB_TYPE_OBJECT; | ||
attr.typeClass = this._getDbObjectType( | ||
attrInfo.dataTypeOwner, | ||
attrInfo.dataType, | ||
attrInfo.packageName, | ||
attrInfo.oid | ||
); | ||
if (attr.typeClass.isXmlType) { | ||
attr.type = types.DB_TYPE_XMLTYPE; | ||
} | ||
if (attr.typeClass.partial) { | ||
this._partialDbObjectTypes.push(attr.typeClass); | ||
} | ||
} else { | ||
attr.type = types.getTypeByColumnTypeName(attrInfo.dataType); | ||
attr.maxSize = attrInfo.maxSize; | ||
attr.precision = attrInfo.dataPrecision; | ||
attr.scale = attrInfo.dataScale; | ||
} | ||
attributes.push(attr); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// _populatePartialDbObjectTypes() | ||
@@ -641,2 +744,3 @@ // | ||
this.comboKey = null; // used in changePassword API | ||
this.tpcContext = null; | ||
@@ -957,2 +1061,10 @@ this.nscon = new nsi(); | ||
setExternalName(value) { | ||
this.externalName = value; | ||
} | ||
setInternalName(value) { | ||
this.internalName = value; | ||
} | ||
setClientInfo(clientInfo) { | ||
@@ -996,3 +1108,99 @@ this._clientInfoModified = true; | ||
// Check the state returned by the tpcCommit() call. | ||
checkTpcCommitState(state, onePhase) { | ||
if ((onePhase && state !== constants.TNS_TPC_TXN_STATE_READ_ONLY | ||
&& state !== constants.TNS_TPC_TXN_STATE_COMMITTED) || | ||
(!onePhase && state !== constants.TNS_TPC_TXN_STATE_FORGOTTEN)) { | ||
errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, state); | ||
} | ||
} | ||
// Creates a two-phase commit message suitable for committing a transaction. | ||
createTpcCommitMessage(xid, onePhase) { | ||
const message = new messages.TransactionChangeStateMessage(this); | ||
message.operation = constants.TNS_TPC_TXN_COMMIT; | ||
message.state = (onePhase == 0) ? constants.TNS_TPC_TXN_STATE_COMMITTED : | ||
constants.TNS_TPC_TXN_STATE_READ_ONLY; | ||
message.xid = xid; | ||
message.context = this.tpcContext; | ||
return message; | ||
} | ||
// Creates a two-phase commit rollback message suitable for use in both | ||
// the close() method and explicitly by the user. | ||
createTpcRollbackMessage(xid = null) { | ||
const message = new messages.TransactionChangeStateMessage(this); | ||
message.operation = constants.TNS_TPC_TXN_ABORT; | ||
message.state = constants.TNS_TPC_TXN_STATE_ABORTED; | ||
message.xid = xid; | ||
message.context = this.tpcContext; | ||
return message; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// tpcBegin() | ||
//--------------------------------------------------------------------------- | ||
async tpcBegin(xid, flags, timeout) { | ||
const message = new messages.TransactionSwitchMessage(this); | ||
message.operation = constants.TNS_TPC_TXN_START; | ||
message.xid = xid; | ||
message.flags = flags; | ||
message.timeout = timeout; | ||
await this._protocol._processMessage(message); | ||
this.tpcContext = message.context; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// tpcCommit() | ||
//--------------------------------------------------------------------------- | ||
async tpcCommit(xid, onePhase) { | ||
const message = this.createTpcCommitMessage(xid, onePhase); | ||
await this._protocol._processMessage(message); | ||
this.checkTpcCommitState(message.state, onePhase); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// tpcEnd() | ||
//--------------------------------------------------------------------------- | ||
async tpcEnd(xid, flags) { | ||
const message = new messages.TransactionSwitchMessage(this); | ||
message.operation = constants.TNS_TPC_TXN_DETACH; | ||
message.xid = xid; | ||
message.context = this.tpcContext; | ||
message.flags = flags; | ||
await this._protocol._processMessage(message); | ||
this.tpcContext = null; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// tpcPrepare() | ||
//--------------------------------------------------------------------------- | ||
async tpcPrepare(xid) { | ||
const message = new messages.TransactionChangeStateMessage(this); | ||
message.operation = constants.TNS_TPC_TXN_PREPARE; | ||
message.xid = xid; | ||
message.context = this.tpcContext; | ||
await this._protocol._processMessage(message); | ||
if (message.state === constants.TNS_TPC_TXN_STATE_REQUIRES_COMMIT) { | ||
return true; | ||
} else if (message.state === constants.TNS_TPC_TXN_STATE_READ_ONLY) { | ||
return false; | ||
} | ||
errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, message.state); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// tpcRollback() | ||
//--------------------------------------------------------------------------- | ||
async tpcRollback(xid) { | ||
const message = this.createTpcRollbackMessage(xid); | ||
await this._protocol._processMessage(message); | ||
if (message.state !== constants.TNS_TPC_TXN_STATE_ABORTED) { | ||
errors.throwErr(errors.ERR_UNKNOWN_TRANSACTION_STATE, message.state); | ||
} | ||
} | ||
//--------------------------------------------------------------------------- | ||
// Returns the statement cache size for the statement cache maintained by | ||
@@ -1020,2 +1228,6 @@ // the connection object | ||
getExternalName() { | ||
return this.externalName; | ||
} | ||
//--------------------------------------------------------------------------- | ||
@@ -1028,2 +1240,6 @@ // Returns the Oracle Database instance name associated with the connection. | ||
getInternalName() { | ||
return this.internalName; | ||
} | ||
//--------------------------------------------------------------------------- | ||
@@ -1030,0 +1246,0 @@ // Returns the Oracle Database domain name associated with the connection. |
@@ -400,2 +400,3 @@ // Copyright (c) 2023, 2024, Oracle and/or its affiliates. | ||
case types.DB_TYPE_OBJECT: | ||
case types.DB_TYPE_XMLTYPE: | ||
isNull = buf.getIsAtomicNull(); | ||
@@ -405,2 +406,5 @@ if (isNull) | ||
obj = new ThinDbObjectImpl(typeClass); | ||
if (obj._objType.isXmlType) { | ||
return readXML(obj._objType._connection, buf.readBytesWithLength()); | ||
} | ||
if (obj._objType.isCollection || this._objType.isCollection) { | ||
@@ -407,0 +411,0 @@ obj.packedData = Buffer.from(buf.readBytesWithLength()); |
@@ -34,2 +34,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
const errors = require('../errors.js'); | ||
const types = require('../types.js'); | ||
@@ -58,2 +59,7 @@ class ThinLobImpl extends LobImpl { | ||
return (message.data) ? message.data : null; | ||
} else if ( | ||
options.operation === constants.TNS_LOB_OP_FILE_EXISTS || | ||
options.operation === constants.TNS_LOB_OP_FILE_ISOPEN | ||
) { | ||
return message.boolFlag; | ||
} else { | ||
@@ -64,2 +70,7 @@ return message.amount; | ||
//--------------------------------------------------------------------------- | ||
// getChunkSize() | ||
// | ||
// Internal method for returning the chunk size of the LOB. | ||
//--------------------------------------------------------------------------- | ||
getChunkSize() { | ||
@@ -69,2 +80,8 @@ return this._chunkSize; | ||
//--------------------------------------------------------------------------- | ||
// _getChunkSizeAsync() | ||
// | ||
// Internal method for returning the chunk size of the LOB fetched from | ||
// the database. | ||
//--------------------------------------------------------------------------- | ||
async _getChunkSizeAsync() { | ||
@@ -80,2 +97,7 @@ this.checkConn(); | ||
//--------------------------------------------------------------------------- | ||
// getLength() | ||
// | ||
// Internal method for returning the length of a LOB. | ||
//--------------------------------------------------------------------------- | ||
getLength() { | ||
@@ -85,2 +107,8 @@ return this._length; | ||
//--------------------------------------------------------------------------- | ||
// getPieceSize() | ||
// | ||
// Internal method returning the size to use for each piece that is | ||
// transferred when reading from the LOB. | ||
//--------------------------------------------------------------------------- | ||
getPieceSize() { | ||
@@ -90,2 +118,7 @@ return this._pieceSize; | ||
//--------------------------------------------------------------------------- | ||
// setPieceSize() | ||
// | ||
// Internal method to set the pieceSize for LOBs. | ||
//--------------------------------------------------------------------------- | ||
setPieceSize(value) { | ||
@@ -95,2 +128,7 @@ this._pieceSize = value; | ||
//--------------------------------------------------------------------------- | ||
// getType() | ||
// | ||
// Internal method returning the datatype of LOBs. | ||
//--------------------------------------------------------------------------- | ||
getType() { | ||
@@ -100,9 +138,35 @@ return this.dbType; | ||
//--------------------------------------------------------------------------- | ||
// getData() | ||
// | ||
// Internal method returning the data obtained from the database. | ||
//--------------------------------------------------------------------------- | ||
async getData(offset = 1, len = this._length) { | ||
let shouldClose = false; | ||
if (!len) { | ||
len = this._length; | ||
} | ||
return await this.read(offset, len); | ||
if (this.dbType === types.DB_TYPE_BFILE) { | ||
if (!await this.isFileOpen()) { | ||
shouldClose = true; | ||
await this.openFile(); | ||
} | ||
} | ||
let data; | ||
// if read fails and BFILE was opened by application, we close it. | ||
try { | ||
data = await this.read(offset, len); | ||
} finally { | ||
if (shouldClose) { | ||
await this.closeFile(); | ||
} | ||
} | ||
return data; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// read() | ||
// | ||
// Internal method for reading a portion (or all) of the data in the LOB. | ||
//--------------------------------------------------------------------------- | ||
async read(offset, length) { | ||
@@ -120,2 +184,7 @@ this.checkConn(); | ||
//--------------------------------------------------------------------------- | ||
// write() | ||
// | ||
// Internal method for writing data to the LOB object. | ||
//--------------------------------------------------------------------------- | ||
async write(offset, data) { | ||
@@ -133,2 +202,7 @@ this.checkConn(); | ||
//--------------------------------------------------------------------------- | ||
// getCsfrm() | ||
// | ||
// Return the character set encoding used by the LOB. | ||
//--------------------------------------------------------------------------- | ||
getCsfrm() { | ||
@@ -169,2 +243,46 @@ if (this.dbType._csfrm !== constants.CSFRM_NCHAR) { | ||
//--------------------------------------------------------------------------- | ||
// fileExists() | ||
// | ||
// Internal method for returning whether the file referenced by a BFILE | ||
// exists. | ||
//--------------------------------------------------------------------------- | ||
async fileExists() { | ||
this.checkConn(); | ||
const options = { | ||
operation: constants.TNS_LOB_OP_FILE_EXISTS, | ||
sourceLobImpl: this, | ||
}; | ||
return await this._sendMessage(options); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// getDirFileName() | ||
// | ||
// Internal method for returning the directory alias and name of the file | ||
// referenced by a BFILE | ||
//--------------------------------------------------------------------------- | ||
getDirFileName() { | ||
const dirNameOffset = constants.TNS_LOB_LOC_FIXED_OFFSET + 2; | ||
const dirNameLen = this._locator.readUInt16BE( | ||
constants.TNS_LOB_LOC_FIXED_OFFSET | ||
); | ||
const fileNameOffset = constants.TNS_LOB_LOC_FIXED_OFFSET + dirNameLen + 4; | ||
const fileNameLen = this._locator.readUInt16BE( | ||
dirNameOffset + dirNameLen | ||
); | ||
const dirName = this._locator.slice( | ||
dirNameOffset, dirNameOffset + dirNameLen | ||
).toString(); | ||
const fileName = this._locator.slice( | ||
fileNameOffset, fileNameOffset + fileNameLen | ||
).toString(); | ||
return { dirName: dirName, fileName: fileName }; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// checkConn() | ||
// | ||
// Internal method to check the connection. | ||
//--------------------------------------------------------------------------- | ||
checkConn() { | ||
@@ -175,2 +293,7 @@ if (!this.conn.nscon.connected) | ||
//--------------------------------------------------------------------------- | ||
// close() | ||
// | ||
// Internal method to close the LOBs using piggyback mechanism. | ||
//--------------------------------------------------------------------------- | ||
close() { | ||
@@ -185,2 +308,21 @@ this.checkConn(); | ||
//--------------------------------------------------------------------------- | ||
// closeFile() | ||
// | ||
// Internal method to close the opened file for BFILE LOBs. | ||
//--------------------------------------------------------------------------- | ||
async closeFile() { | ||
this.checkConn(); | ||
const options = { | ||
operation: constants.TNS_LOB_OP_FILE_CLOSE, | ||
sourceLobImpl: this, | ||
}; | ||
await this._sendMessage(options); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// init() | ||
// | ||
// Internal method to initialize LOBs. | ||
//--------------------------------------------------------------------------- | ||
init(conn, locator, dbType, len, chunkSize) { | ||
@@ -201,4 +343,54 @@ this.dirtyLength = false; | ||
//--------------------------------------------------------------------------- | ||
// isFileOpen() | ||
// | ||
// Internal method to check if the file is already open. | ||
//--------------------------------------------------------------------------- | ||
async isFileOpen() { | ||
const options = { | ||
operation: constants.TNS_LOB_OP_FILE_ISOPEN, | ||
sourceLobImpl: this | ||
}; | ||
await this._sendMessage(options); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// openFile() | ||
// | ||
// Internal method for opening file (BFILE). | ||
//--------------------------------------------------------------------------- | ||
async openFile() { | ||
this.checkConn(); | ||
const options = { | ||
operation: constants.TNS_LOB_OP_FILE_OPEN, | ||
sourceLobImpl: this, | ||
amount: constants.TNS_LOB_OPEN_READ_ONLY, | ||
sendAmount: true | ||
}; | ||
return await this._sendMessage(options); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// setDirFileName() | ||
// | ||
// Internal method for setting the directory alias and name of the file | ||
// referenced by a BFILE | ||
//--------------------------------------------------------------------------- | ||
setDirFileName(dirObject) { | ||
const dirNameLen = Buffer.byteLength(dirObject.dirName); | ||
const dirNameOffset = constants.TNS_LOB_LOC_FIXED_OFFSET + 2; | ||
const fileNameOffset = dirNameOffset + dirNameLen + 2; | ||
const fileNameLen = Buffer.byteLength(dirObject.fileName); | ||
const newLocLen = fileNameOffset + fileNameLen; | ||
const newLocator = Buffer.allocUnsafe(newLocLen); | ||
this._locator.copy(newLocator, 0, 0, constants.TNS_LOB_LOC_FIXED_OFFSET + 1); | ||
newLocator.writeUInt16BE(dirNameLen, constants.TNS_LOB_LOC_FIXED_OFFSET); | ||
newLocator.write(dirObject.dirName, dirNameOffset); | ||
newLocator.writeInt16BE(fileNameLen, dirNameOffset + dirNameLen); | ||
newLocator.write(dirObject.fileName, fileNameOffset); | ||
this._locator = newLocator; | ||
} | ||
} | ||
module.exports = ThinLobImpl; |
@@ -67,2 +67,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
this._walletPassword = params.walletPassword; | ||
this._walletContent = params.walletContent; | ||
this._obfuscatedPassword = []; | ||
@@ -92,2 +93,9 @@ this._obfuscatedWalletPassword = []; | ||
} | ||
// wallet content obfuscation | ||
if (this._walletContent !== undefined) { | ||
const obj = protocolUtil.setObfuscatedValue(this._walletContent); | ||
this._walletContent = obj.value; | ||
this._obfuscatedWalletContent = obj.obfuscatedValue; | ||
this._userConfig.walletConent = null; | ||
} | ||
// token obfuscation | ||
@@ -177,2 +185,9 @@ if (this._token !== undefined) { | ||
// deobfuscate wallet content | ||
if (clonedAttrs.walletContent === null) { | ||
clonedAttrs.walletContent = | ||
protocolUtil.getDeobfuscatedValue(this._walletContent, | ||
this._obfuscatedWalletContent); | ||
} | ||
// deobfuscate token and private key | ||
@@ -179,0 +194,0 @@ // check for token expiry |
@@ -121,2 +121,4 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
constants.TNS_CCAP_VECTOR_SUPPORT; | ||
this.compileCaps[constants.TNS_CCAP_VECTOR_FEATURES] = | ||
constants.TNS_CCAP_VECTOR_FEATURE_BINARY; | ||
} | ||
@@ -123,0 +125,0 @@ |
@@ -495,2 +495,6 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
TNS_LOB_OP_ARRAY: 0x80000, | ||
TNS_LOB_OP_FILE_OPEN: 0x0100, | ||
TNS_LOB_OP_FILE_CLOSE: 0x0200, | ||
TNS_LOB_OP_FILE_ISOPEN: 0x0400, | ||
TNS_LOB_OP_FILE_EXISTS: 0x0800, | ||
@@ -502,2 +506,3 @@ // LOB locator constants | ||
TNS_LOB_QLOCATOR_VERSION: 4, | ||
TNS_LOB_LOC_FIXED_OFFSET: 16, | ||
@@ -518,2 +523,3 @@ // LOB locator flags (byte 1) | ||
TNS_LOB_OPEN_READ_WRITE: 2, | ||
TNS_LOB_OPEN_READ_ONLY: 11, | ||
TNS_LOB_PREFETCH_FLAG: 0x2000000, | ||
@@ -554,2 +560,4 @@ | ||
TNS_FUNC_CANCEL_ALL: 120, // piggyback fn | ||
TNS_FUNC_TPC_TXN_SWITCH: 103, | ||
TNS_FUNC_TPC_TXN_CHANGE_STATE: 104, | ||
@@ -585,3 +593,4 @@ // character sets and encodings | ||
TNS_CCAP_TTC5: 44, | ||
TNS_CCAP_MAX: 51, | ||
TNS_CCAP_VECTOR_FEATURES: 52, | ||
TNS_CCAP_MAX: 53, | ||
@@ -642,2 +651,3 @@ // compile time capability values | ||
TNS_CCAP_VECTOR_SUPPORT: 0x08, | ||
TNS_CCAP_VECTOR_FEATURE_BINARY: 0x01, | ||
@@ -669,2 +679,20 @@ // runtime capability indices | ||
// transaction switching op codes | ||
TNS_TPC_TXN_START: 0x01, | ||
TNS_TPC_TXN_DETACH: 0x02, | ||
// transaction change state op codes | ||
TNS_TPC_TXN_COMMIT: 0x01, | ||
TNS_TPC_TXN_ABORT: 0x02, | ||
TNS_TPC_TXN_PREPARE: 0x03, | ||
TNS_TPC_TXN_FORGET: 0x04, | ||
// transaction states | ||
TNS_TPC_TXN_STATE_PREPARE: 0, | ||
TNS_TPC_TXN_STATE_REQUIRES_COMMIT: 1, | ||
TNS_TPC_TXN_STATE_COMMITTED: 2, | ||
TNS_TPC_TXN_STATE_ABORTED: 3, | ||
TNS_TPC_TXN_STATE_READ_ONLY: 4, | ||
TNS_TPC_TXN_STATE_FORGOTTEN: 5, | ||
// other constants | ||
@@ -671,0 +699,0 @@ TNS_ESCAPE_CHAR: 253, |
@@ -41,2 +41,4 @@ // Copyright (c) 2023, Oracle and/or its affiliates. | ||
const FastAuthMessage = require('./fastAuth.js'); | ||
const TransactionChangeStateMessage = require('./transactionChangeState.js'); | ||
const TransactionSwitchMessage = require('./transactionSwitch.js'); | ||
@@ -55,3 +57,5 @@ module.exports = { | ||
RollbackMessage, | ||
SessionReleaseMessage | ||
SessionReleaseMessage, | ||
TransactionChangeStateMessage, | ||
TransactionSwitchMessage | ||
}; |
@@ -93,4 +93,9 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
buf.writeUInt8(0); | ||
if (this.operation === constants.TNS_LOB_OP_CREATE_TEMP | ||
|| this.operation === constants.TNS_LOB_OP_IS_OPEN) { | ||
const operations = [ | ||
constants.TNS_LOB_OP_CREATE_TEMP, | ||
constants.TNS_LOB_OP_IS_OPEN, | ||
constants.TNS_LOB_OP_FILE_EXISTS, | ||
constants.TNS_LOB_OP_FILE_ISOPEN, | ||
]; | ||
if (operations.includes(this.operation)) { | ||
buf.writeUInt8(1); | ||
@@ -156,3 +161,6 @@ } else { | ||
if (data !== null) { | ||
if (oraTypeNum === constants.TNS_DATA_TYPE_BLOB) { | ||
if ( | ||
oraTypeNum === constants.TNS_DATA_TYPE_BLOB || | ||
oraTypeNum === constants.TNS_DATA_TYPE_BFILE | ||
) { | ||
data = Buffer.from(data); | ||
@@ -194,4 +202,8 @@ } else if (this.sourceLobImpl.getCsfrm() === constants.CSFRM_NCHAR) { | ||
} | ||
if (this.operation === constants.TNS_LOB_OP_IS_OPEN) { | ||
temp8 = buf.readUB1(); | ||
if ( | ||
this.operation === constants.TNS_LOB_OP_IS_OPEN | ||
|| this.operation === constants.TNS_LOB_OP_FILE_EXISTS | ||
|| this.operation === constants.TNS_LOB_OP_FILE_ISOPEN | ||
) { | ||
temp8 = buf.readUInt8(); | ||
this.boolFlag = temp8 > 0; | ||
@@ -198,0 +210,0 @@ } |
@@ -143,3 +143,7 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
|| (cVar.fetchInfo.dbType._oraTypeNum === constants.TNS_DATA_TYPE_BLOB | ||
&& pVar.fetchInfo.fetchType._oraTypeNum === constants.TNS_DATA_TYPE_LONG_RAW)) { | ||
&& pVar.fetchInfo.fetchType._oraTypeNum === constants.TNS_DATA_TYPE_LONG_RAW) | ||
|| (cVar.fetchInfo.dbType._oraTypeNum === constants.TNS_DATA_TYPE_JSON | ||
&& pVar.fetchInfo.fetchType._oraTypeNum === constants.TNS_DATA_TYPE_VARCHAR) | ||
|| (cVar.fetchInfo.dbType._oraTypeNum === constants.TNS_DATA_TYPE_VECTOR | ||
&& pVar.fetchInfo.fetchType._oraTypeNum === constants.TNS_DATA_TYPE_LONG)) { | ||
cVar.type = pVar.fetchInfo.fetchType; | ||
@@ -502,8 +506,18 @@ cVar.maxSize = pVar.maxSize; | ||
colValue = buf.readBool(); | ||
} else if (oraTypeNum === constants.TNS_DATA_TYPE_CLOB || oraTypeNum === constants.TNS_DATA_TYPE_BLOB) { | ||
} else if ( | ||
oraTypeNum === constants.TNS_DATA_TYPE_CLOB || | ||
oraTypeNum === constants.TNS_DATA_TYPE_BLOB || | ||
oraTypeNum === constants.TNS_DATA_TYPE_BFILE | ||
) { | ||
let length = 0; | ||
let chunkSize = 0; | ||
const bvalue = buf.readUB4(); | ||
if (bvalue > 0) { // Non Null data in column | ||
colValue = new ThinLobImpl(); | ||
const length = buf.readUB8(); | ||
const chunkSize = buf.readUB4(); | ||
if (oraTypeNum === constants.TNS_DATA_TYPE_BFILE) { | ||
buf.skipUB4(); | ||
} else { | ||
length = buf.readUB8(); | ||
chunkSize = buf.readUB4(); | ||
} | ||
const locator = Buffer.from(buf.readBytesWithLength()); | ||
@@ -624,2 +638,3 @@ colValue.init(this.connection, locator, dbType, length, chunkSize); | ||
variable.type === types.DB_TYPE_BLOB || | ||
variable.type === types.DB_TYPE_BFILE || | ||
variable.type === types.DB_TYPE_JSON || | ||
@@ -706,3 +721,4 @@ variable.type === types.DB_TYPE_VECTOR) { | ||
variable.type === types.DB_TYPE_CLOB || | ||
variable.type === types.DB_TYPE_NCLOB) { | ||
variable.type === types.DB_TYPE_NCLOB || | ||
variable.type === types.DB_TYPE_BFILE) { | ||
contFlag = constants.TNS_LOB_PREFETCH_FLAG; | ||
@@ -859,3 +875,7 @@ } else if (variable.type === types.DB_TYPE_JSON) { | ||
} | ||
} else if (oraTypeNum === constants.TNS_DATA_TYPE_CLOB || oraTypeNum === constants.TNS_DATA_TYPE_BLOB) { | ||
} else if ( | ||
oraTypeNum === constants.TNS_DATA_TYPE_CLOB || | ||
oraTypeNum === constants.TNS_DATA_TYPE_BLOB || | ||
oraTypeNum === constants.TNS_DATA_TYPE_BFILE | ||
) { | ||
buf.writeUB4(value._locator.length); | ||
@@ -862,0 +882,0 @@ buf.writeBytesWithLength(value._locator); |
@@ -304,3 +304,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
this.ntAdapter.largeSDU = this.sAtts.largeSDU; | ||
this.sAtts.nt.wallet = null; | ||
this.sAtts.clearWallet(); | ||
this.sAtts.nt.walletPassword = null; | ||
@@ -332,2 +332,3 @@ return (true); | ||
} | ||
this.sAtts.clearWallet(); | ||
connected = false; | ||
@@ -334,0 +335,0 @@ savedErr = err; |
@@ -35,2 +35,3 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
const MAX_IFILE_DEPTH = 4; | ||
/** | ||
@@ -63,5 +64,8 @@ * Returns File path of the tnsnames.ora if it exists. | ||
let prevmtime = 0; | ||
class NLParamParser { | ||
class NLParamParser { | ||
constructor() { | ||
this.waiters = []; | ||
this.readInProgress = false; | ||
} | ||
/** | ||
@@ -74,9 +78,25 @@ * Reads the given file line by line and stores the | ||
async initializeNlpa(file_path) { | ||
const stat = fs.statSync(file_path); | ||
if (!(stat.mtime - prevmtime)) { | ||
/* File has been read */ | ||
if (this.readInProgress) { | ||
await new Promise((resolve) => { | ||
this.waiters.push(resolve); | ||
}); | ||
} | ||
if (!this.checkModfTime()) { | ||
/* No File has been modified */ | ||
return this.ht; | ||
} | ||
this.ht = new Map(); | ||
this.modTime = new Map(); //stores modified time of each IFile | ||
this.readInProgress = true; | ||
await this.start(file_path, 0); //start with 0 depth (tnsnames.ora) | ||
return this.ht; | ||
} | ||
async start(file_path, depth) { | ||
if (depth > MAX_IFILE_DEPTH) | ||
return; //ignore after max depth | ||
const stat = fs.statSync(file_path); | ||
// store file path and its modified time. | ||
this.modTime.set(file_path, stat.mtime); | ||
// Creating a readable stream from file | ||
@@ -90,48 +110,45 @@ // readline module reads line by line | ||
}); | ||
this.ht = new Map(); | ||
const start = async () =>{ | ||
let nvElem = ""; | ||
for await (let line of file) { | ||
if (line.length == 0) { // ignore empty lines | ||
let nvElem = ""; | ||
for await (let line of file) { | ||
if (line.length == 0) { // ignore empty lines | ||
continue; | ||
} else if (line[0] == '#') { // comment line | ||
continue; | ||
} else if ((line[0] == ' ') || // continued input on new line | ||
(line[0] == '\t') || | ||
(line[0] == ')') || | ||
(line[0] == '(')) { | ||
line = line.replace(/\s+/g, ''); | ||
line = this.checkNLPforComments(line); | ||
if (line.length == 0) | ||
continue; | ||
} else if (line[0] == '#') { // comment line | ||
continue; | ||
} else if ((line[0] == ' ') || // continued input on new line | ||
(line[0] == '\t') || | ||
(line[0] == ')') || | ||
(line[0] == '(')) { | ||
line = line.replace(/\s+/g, ''); | ||
line = this.checkNLPforComments(line); | ||
if (line.length == 0) | ||
continue; | ||
else { | ||
nvElem = nvElem + line; | ||
} | ||
else { | ||
nvElem = nvElem + line; | ||
} | ||
} else { // new NV Element starting here | ||
if (nvElem.length == 0) { | ||
} else { // new NV Element starting here | ||
if (nvElem.length == 0) { | ||
line = this.checkNLPforComments(line); | ||
nvElem = nvElem + line; | ||
line = this.checkNLPforComments(line); | ||
nvElem = nvElem + line; | ||
} else if (nvElem.length != 0) { | ||
this.addNLPListElement(nvElem); // Add Parameter to Hashtable | ||
nvElem = ""; // Clear first, before storing current line | ||
} else if (nvElem.length != 0) { | ||
await this.addNLPListElement(nvElem, depth); // Add Parameter to Hashtable | ||
nvElem = ""; // Clear first, before storing current line | ||
line = this.checkNLPforComments(line); | ||
nvElem = nvElem + line; | ||
} | ||
line = this.checkNLPforComments(line); | ||
nvElem = nvElem + line; | ||
} | ||
} | ||
if (nvElem.length != 0) { // at eof, still one more parameter to read | ||
this.addNLPListElement(nvElem); | ||
nvElem = ""; // clear nvElem buffer after added | ||
} | ||
prevmtime = stat.mtime; | ||
return this.ht; | ||
}; | ||
return await start(); | ||
} | ||
if (nvElem.length != 0) { // at eof, still one more parameter to read | ||
await this.addNLPListElement(nvElem, depth); | ||
nvElem = ""; // clear nvElem buffer after added | ||
} | ||
this.readInProgress = false; | ||
let waiter; | ||
while ((waiter = this.waiters.pop())) { | ||
waiter(); | ||
} | ||
} | ||
/** | ||
@@ -162,2 +179,19 @@ * Given a string, this method looks if the '#' character is present. | ||
} | ||
// check if any of the IFiles has been changed | ||
checkModfTime() { | ||
if (this.modTime) { | ||
for (const [key, value] of this.modTime) { | ||
if (fs.existsSync(key)) { | ||
const stat = fs.statSync(key); | ||
if ((stat.mtime - value > 0)) { | ||
return true; | ||
} | ||
} else | ||
return true; | ||
} | ||
} else { | ||
return true; | ||
} | ||
return false; | ||
} | ||
/** | ||
@@ -167,3 +201,3 @@ * adds name value pairs from the input buffer into the hash table. | ||
*/ | ||
addNLPListElement(ibuf) { | ||
async addNLPListElement(ibuf, depth) { | ||
const res = ibuf.split(/\r?\n/).filter(element => element); | ||
@@ -178,10 +212,13 @@ for (let i = 0; i < res.length; i++) { | ||
nvp.name = uname; | ||
const unames = uname.split(","); //multiple aliases (alias1, alias2, alias3) | ||
for (let i = 0; i < unames.length; i++) { | ||
this.ht.set(unames[i], nvp); | ||
// support for ifile | ||
if (uname == 'IFILE') { | ||
await this.start(nvp.atom, depth + 1); | ||
} else { | ||
const unames = uname.split(","); //multiple aliases (alias1, alias2, alias3) | ||
for (let i = 0; i < unames.length; i++) { | ||
this.ht.set(unames[i], nvp); | ||
} | ||
} | ||
} | ||
} | ||
toString() { | ||
@@ -188,0 +225,0 @@ let out = ""; |
@@ -80,2 +80,5 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
} | ||
if (typeof params.walletContent === 'string') { | ||
this.nt.wallet = params.walletContent; | ||
} | ||
if (params.expireTime > 0) { | ||
@@ -140,2 +143,11 @@ this.nt.expireTime = params.expireTime * 1000 * 60; | ||
/** | ||
* Clear wallet | ||
*/ | ||
clearWallet() { | ||
if (this.nt.wallet && Buffer.isBuffer(this.nt.wallet)) | ||
this.nt.wallet.fill(0); | ||
this.nt.wallet = null; | ||
} | ||
/** | ||
* Prepare attributes for connection, Generate Connection ID and read Wallet file | ||
@@ -156,3 +168,3 @@ * | ||
if (protocol && (protocol.toUpperCase() == "TCPS" && this.nt.walletFile)) { | ||
if (protocol && (protocol.toUpperCase() == "TCPS" && !this.nt.wallet && this.nt.walletFile)) { | ||
this.nt.wallet = await this.readWalletFile(); | ||
@@ -159,0 +171,0 @@ } |
@@ -231,4 +231,3 @@ // Copyright (c) 2023, 2024, Oracle and/or its affiliates. | ||
// handle vectors | ||
} else if (value instanceof Float32Array || value instanceof Float64Array || | ||
value instanceof Int8Array) { | ||
} else if (nodbUtil.isVectorValue(value)) { | ||
checkType(info, options, types.DB_TYPE_VECTOR); | ||
@@ -235,0 +234,0 @@ return value; |
@@ -115,3 +115,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
"DB_TYPE_BFILE", "BFILE", | ||
{ oraTypeNum: 114, bufferSizeFactor: 112 }); | ||
{ oraTypeNum: 114, bufferSizeFactor: 4000 }); | ||
const DB_TYPE_BINARY_DOUBLE = new DbType(2008, | ||
@@ -118,0 +118,0 @@ "DB_TYPE_BINARY_DOUBLE", "BINARY_DOUBLE", |
@@ -280,2 +280,32 @@ // Copyright (c) 2016, 2023, Oracle and/or its affiliates. | ||
function normalizeXid(value) { | ||
let normalizedXid; | ||
if (Buffer.isBuffer(value.globalTransactionId) && | ||
Buffer.isBuffer(value.branchQualifier)) { | ||
normalizedXid = value; | ||
} else { | ||
normalizedXid = { | ||
formatId: value.formatId, | ||
globalTransactionId: value.globalTransactionId, | ||
branchQualifier: value.branchQualifier | ||
}; | ||
if (typeof value.globalTransactionId === 'string') { | ||
normalizedXid.globalTransactionId = Buffer.from(value.globalTransactionId); | ||
} | ||
if (typeof value.branchQualifier === 'string') { | ||
normalizedXid.branchQualifier = Buffer.from(value.branchQualifier); | ||
} | ||
} | ||
if (normalizedXid.globalTransactionId.length > 64) { | ||
errors.throwErr(errors.ERR_INVALID_TRANSACTION_SIZE, | ||
normalizedXid.globalTransactionId.length); | ||
} | ||
if (normalizedXid.branchQualifier.length > 64) { | ||
errors.throwErr(errors.ERR_INVALID_BRANCH_SIZE, | ||
normalizedXid.branchQualifier.length); | ||
} | ||
return normalizedXid; | ||
} | ||
function verifySodaDoc(content) { | ||
@@ -366,4 +396,5 @@ if (isSodaDocument(content)) | ||
return (value instanceof Float32Array || | ||
value instanceof Float64Array || | ||
value instanceof Int8Array); | ||
value instanceof Float64Array || | ||
value instanceof Int8Array || (Object.getPrototypeOf(value) | ||
=== Uint8Array.prototype)); | ||
} | ||
@@ -408,2 +439,3 @@ | ||
isXid, | ||
normalizeXid, | ||
makeDate, | ||
@@ -410,0 +442,0 @@ preventConcurrent, |
@@ -33,5 +33,5 @@ // Copyright (c) 2023, 2024, Oracle and/or its affiliates. | ||
VERSION_MAJOR: 6, | ||
VERSION_MINOR: 5, | ||
VERSION_PATCH: 1, | ||
VERSION_MINOR: 6, | ||
VERSION_PATCH: 0, | ||
VERSION_SUFFIX: '' | ||
}; |
{ | ||
"name": "oracledb", | ||
"version": "6.5.1", | ||
"version": "6.6.0", | ||
"description": "A Node.js module for Oracle Database access from JavaScript and TypeScript", | ||
@@ -5,0 +5,0 @@ "license": "(Apache-2.0 OR UPL-1.0)", |
@@ -1,2 +0,2 @@ | ||
# node-oracledb version 6.5.1 | ||
# node-oracledb version 6.6.0 | ||
@@ -7,3 +7,3 @@ The node-oracledb add-on for Node.js powers high performance Oracle Database | ||
Use node-oracledb 6.5.1 to connect Node.js 14.6, or later, to Oracle | ||
Use node-oracledb 6.6.0 to connect Node.js 14.6, or later, to Oracle | ||
Database. Older versions of node-oracledb may work with older versions of | ||
@@ -10,0 +10,0 @@ Node.js. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
4070326
248617
114
26603
5
18