Comparing version 6.7.2 to 6.8.0
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2016, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2016, 2025, Oracle and/or its affiliates. | ||
@@ -53,2 +53,44 @@ //----------------------------------------------------------------------------- | ||
// default closure for NUMBER type. | ||
const defaultNumberConverter = (v) => (v === null) ? null : parseFloat(v); | ||
//--------------------------------------------------------------------------- | ||
// _determineDbObjTypeConverter() | ||
// | ||
// Determines the converter associated with each DB type and its metadata. | ||
// This function is called once during metadata construction and the | ||
// converters are invoked when retriving DBObject values. | ||
//--------------------------------------------------------------------------- | ||
function _determineDbObjTypeConverter(metadata, options) { | ||
// clear any previous converter functions that may have been | ||
// retained | ||
delete metadata.converter; | ||
// If a DBfetch type handler is specified, update converter, | ||
// if available. | ||
if (options.dbObjectTypeHandler) { | ||
const result = options.dbObjectTypeHandler(metadata); | ||
if (result !== undefined) { | ||
errors.assert(typeof result === 'object', | ||
errors.ERR_DB_FETCH_TYPE_HANDLER_RETURN_VALUE); | ||
if (result.converter !== undefined) { | ||
errors.assert(typeof result.converter === 'function', | ||
errors.ERR_DB_FETCH_TYPE_HANDLER_CONVERTER); | ||
} | ||
if ([types.DB_TYPE_CLOB, types.DB_TYPE_NCLOB, types.DB_TYPE_BLOB, | ||
types.DB_TYPE_BFILE].includes(metadata.type)) { | ||
// converters for LOB's are not supported. | ||
return errors.throwErr(errors.ERR_NOT_IMPLEMENTED, | ||
'DbObjConverter for LOBs'); | ||
} | ||
metadata.converter = result.converter; | ||
} | ||
} | ||
if (metadata.type === types.DB_TYPE_NUMBER && !metadata.converter) { | ||
// set default converter for NUMBER type as they are returned as strings | ||
// from DB. | ||
metadata.converter = defaultNumberConverter; | ||
} | ||
} | ||
// define class | ||
@@ -110,5 +152,7 @@ class Connection extends EventEmitter { | ||
} | ||
const options = {dbObjectTypeHandler: settings.dbObjectTypeHandler}; | ||
if (objType.isCollection) { | ||
nodbUtil.addTypeProperties(objType, "elementType"); | ||
objType.elementTypeInfo.type = objType.elementType; | ||
_determineDbObjTypeConverter(objType.elementTypeInfo, options); | ||
} | ||
@@ -131,2 +175,6 @@ if (objType.attributes) { | ||
props[attr.name] = prop; | ||
// calculate for each attribute metadata as converters might change | ||
// based on precision, scale, maxSize,.. | ||
_determineDbObjTypeConverter(attr, options); | ||
} | ||
@@ -374,3 +422,5 @@ Object.defineProperties(DbObject.prototype, props); | ||
bindInfo.type !== types.DB_TYPE_TIMESTAMP_TZ && | ||
bindInfo.type !== types.DB_TYPE_RAW) { | ||
bindInfo.type !== types.DB_TYPE_RAW && | ||
bindInfo.type !== types.DB_TYPE_INTERVAL_YM && | ||
bindInfo.type !== types.DB_TYPE_INTERVAL_DS) { | ||
errors.throwErr(errors.ERR_INVALID_TYPE_FOR_ARRAY_BIND); | ||
@@ -1223,3 +1273,17 @@ } | ||
isCompressionEnabled() { | ||
return (this._impl && this._impl.isCompressionEnabled()); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// maxIdentifierLength | ||
// | ||
// Returns the maximum length of identifiers supported by the database to | ||
// which this connection has been established. | ||
//--------------------------------------------------------------------------- | ||
get maxIdentifierLength() { | ||
return this._impl && this._impl.getMaxIdentifierLength(); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// maxOpenCursors | ||
@@ -1226,0 +1290,0 @@ // |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2019, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2019, 2025, Oracle and/or its affiliates. | ||
@@ -89,3 +89,3 @@ //---------------------------------------------------------------------------- | ||
const value = this._impl.getAttrValue(attr); | ||
return this._transformValueOut(value, attr.typeClass); | ||
return this._transformValueOut(value, attr.typeClass, attr); | ||
} | ||
@@ -142,3 +142,3 @@ | ||
//--------------------------------------------------------------------------- | ||
_transformValueOut(value, cls) { | ||
_transformValueOut(value, cls, metaData) { | ||
let outValue = value; | ||
@@ -148,8 +148,13 @@ if (value instanceof impl.LobImpl) { | ||
outValue._setup(value, true); | ||
} else if (value instanceof impl.DbObjectImpl) { | ||
outValue = Object.create(cls.prototype); | ||
outValue._impl = value; | ||
if (outValue.isCollection) { | ||
outValue = new Proxy(outValue, BaseDbObject._collectionProxyHandler); | ||
} else { | ||
if (value instanceof impl.DbObjectImpl) { | ||
outValue = Object.create(cls.prototype); | ||
outValue._impl = value; | ||
if (outValue.isCollection) { | ||
outValue = new Proxy(outValue, BaseDbObject._collectionProxyHandler); | ||
} | ||
} | ||
if (metaData.converter) { | ||
outValue = metaData.converter(outValue); | ||
} | ||
} | ||
@@ -209,2 +214,17 @@ return outValue; | ||
//--------------------------------------------------------------------------- | ||
// copy | ||
// | ||
// Creates and returns a copy of the object. The copy is independent of | ||
// the original object that was copied. | ||
//--------------------------------------------------------------------------- | ||
copy() { | ||
errors.assertArgCount(arguments, 0, 0); | ||
const newObj = Object.create(this); | ||
newObj._impl = this._impl.copy(); | ||
if (this.isCollection) | ||
return new Proxy(newObj, BaseDbObject._collectionProxyHandler); | ||
return newObj; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// deleteElement() | ||
@@ -261,2 +281,13 @@ // | ||
//--------------------------------------------------------------------------- | ||
// length | ||
// | ||
// Length of the database object type, if it is a collection. Else it | ||
// returns undefined. | ||
//--------------------------------------------------------------------------- | ||
get length() { | ||
if (this.isCollection) | ||
return this._impl.getLength(); | ||
return undefined; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// getElement() | ||
@@ -270,3 +301,3 @@ // | ||
const value = this._impl.getElement(index); | ||
return this._transformValueOut(value, this.elementTypeClass); | ||
return this._transformValueOut(value, this.elementTypeClass, this._objType.elementTypeInfo); | ||
} | ||
@@ -335,3 +366,3 @@ | ||
for (let i = 0; i < values.length; i++) { | ||
values[i] = this._transformValueOut(values[i], this.elementTypeClass); | ||
values[i] = this._transformValueOut(values[i], this.elementTypeClass, this._objType.elementTypeInfo); | ||
} | ||
@@ -493,2 +524,3 @@ return values; | ||
"append", | ||
"copy", | ||
"deleteElement", | ||
@@ -495,0 +527,0 @@ "getElement", |
@@ -1,3 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
//----------------------------------------------------------------------------- | ||
@@ -167,2 +166,14 @@ // | ||
const ERR_EXECMANY_NOT_ALLOWED_ON_QUERIES = 157; | ||
const ERR_VECTOR_SPARSE_INDICES_IS_NOT_ARRAY = 158; | ||
const ERR_VECTOR_SPARSE_VALUES_IS_NOT_ARRAY = 159; | ||
const ERR_VECTOR_SPARSE_DIMS_IS_NOT_INTEGER = 160; | ||
const ERR_VECTOR_SPARSE_INDICES_VALUES_NOT_EQUAL = 161; | ||
const ERR_VECTOR_SPARSE_INVALID_JSON = 162; | ||
const ERR_VECTOR_SPARSE_INVALID_STRING = 163; | ||
const ERR_VECTOR_SPARSE_INVALID_INPUT = 164; | ||
const ERR_VECTOR_SPARSE_INDICES_ELEM_IS_NOT_VALID = 165; | ||
const ERR_DB_FETCH_TYPE_HANDLER_CONVERTER = 166; | ||
const ERR_DB_FETCH_TYPE_HANDLER_RETURN_VALUE = 167; | ||
const ERR_ACCESS_TOKEN = 168; | ||
const ERR_CALLOUT_FN = 169; | ||
@@ -200,2 +211,6 @@ // Oracle Net layer errors start from 500 | ||
const ERR_HOST_NOT_FOUND = 530; | ||
const ERR_ANO_PACKET = 531; | ||
const ERR_ANO_STATUS = 532; | ||
const ERR_ANO_NEGOTIATION = 533; | ||
const ERR_DATA_COMPRESSION = 534; | ||
@@ -421,3 +436,3 @@ // Oracle SUCCESS_WITH_INFO warning start from 700 | ||
messages.set(ERR_INVALID_COLL_INDEX_SET, // NJS-131 | ||
'given index %d must be in the range of %d to %d'); | ||
'given index [%d] must be in the range of [%d] to [%d]'); | ||
messages.set(ERR_INVALID_COLL_INDEX_GET, // NJS-132 | ||
@@ -473,2 +488,26 @@ 'element at index %d does not exist'); | ||
'executeMany() cannot be used with SELECT statement or WITH SQL clause'); | ||
messages.set(ERR_VECTOR_SPARSE_INDICES_IS_NOT_ARRAY, // NJS-158 | ||
'SPARSE VECTOR indices is not Uint32Array or an Array'); | ||
messages.set(ERR_VECTOR_SPARSE_VALUES_IS_NOT_ARRAY, // NJS-159 | ||
'SPARSE VECTOR values is not an Array'); | ||
messages.set(ERR_VECTOR_SPARSE_DIMS_IS_NOT_INTEGER, // NJS-160 | ||
'SPARSE VECTOR dimensions is not an Positive Integer'); | ||
messages.set(ERR_VECTOR_SPARSE_INDICES_VALUES_NOT_EQUAL, // NJS-161 | ||
'SPARSE VECTOR indices and values must be of same length'); | ||
messages.set(ERR_VECTOR_SPARSE_INVALID_JSON, // NJS-162 | ||
'SPARSE VECTOR string data is not valid JSON'); | ||
messages.set(ERR_VECTOR_SPARSE_INVALID_STRING, // NJS-163 | ||
'SPARSE VECTOR string data Array should have exactly 3 elements'); | ||
messages.set(ERR_VECTOR_SPARSE_INVALID_INPUT, // NJS-164 | ||
'SPARSE VECTOR Invalid Input Data'); | ||
messages.set(ERR_VECTOR_SPARSE_INDICES_ELEM_IS_NOT_VALID, // NJS-165 | ||
'SPARSE VECTOR indices element at index %d is not valid'); | ||
messages.set(ERR_DB_FETCH_TYPE_HANDLER_CONVERTER, // NJS-166 | ||
'DBFetchTypeHandler return value attribute "converter" must be a function'); | ||
messages.set(ERR_DB_FETCH_TYPE_HANDLER_RETURN_VALUE, // NJS-167 | ||
'DBFetchTypeHandler return value must be an object'); | ||
messages.set(ERR_ACCESS_TOKEN, // NJS-168 | ||
'access token function failed.'); | ||
messages.set(ERR_CALLOUT_FN, // NJS-169 | ||
'External function call failed.'); | ||
@@ -523,19 +562,25 @@ // Oracle Net layer errors | ||
'Failed to retrieve configuration from Centralized Configuration Provider:\n %s'); | ||
messages.set(ERR_CONFIG_PROVIDER_NOT_SUPPORTED, // NJS-524 | ||
messages.set(ERR_CONFIG_PROVIDER_NOT_SUPPORTED, // NJS-524 | ||
'Configuration Provider not supported: %s'); | ||
messages.set(ERR_CONFIG_PROVIDER_LOAD_FAILED, // NJS-525 | ||
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 | ||
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 | ||
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 | ||
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'); | ||
messages.set(ERR_WALLET_TYPE_NOT_SUPPORTED, // NJS-529 | ||
messages.set(ERR_WALLET_TYPE_NOT_SUPPORTED, // NJS-529 | ||
'Invalid wallet content format. Supported format is PEM'); | ||
messages.set(ERR_HOST_NOT_FOUND, // NJS-530 | ||
messages.set(ERR_HOST_NOT_FOUND, // NJS-530 | ||
'The host addresses or URLs provided by the connect string are incorrect or unresolvable in your network.'); | ||
messages.set(ERR_ANO_PACKET, // NJS-531 | ||
'Error in Advanced Networking Option packet received from the server'); | ||
messages.set(ERR_ANO_STATUS, // NJS-532 | ||
'%s service recieved status failure'); | ||
messages.set(ERR_ANO_NEGOTIATION, // NJS-533 | ||
'Advanced Networking Option service negotiation failed. Native Network Encryption and DataIntegrity only supported in node-oracledb thick mode.\nCause: ORA-%s'); | ||
messages.set(ERR_DATA_COMPRESSION, 'Error during data compression/decompression: %s\n'); //NJS-534 | ||
// Oracle SUCCESS_WITH_INFO warning | ||
messages.set(WRN_COMPILATION_CREATE, // NJS-700 | ||
messages.set(WRN_COMPILATION_CREATE, // NJS-700 | ||
'creation succeeded with compilation errors'); | ||
@@ -705,2 +750,10 @@ | ||
function throwErrWithORAError() { | ||
const err = (getErr(...arguments)); | ||
const pos = err.message.indexOf("ORA-"); | ||
const oraError = err.message.substring(pos + 4, pos + 9); | ||
err.message = err.message + '\nHelp: https://docs.oracle.com/error-help/db/ora-' + oraError; | ||
throw err; | ||
} | ||
//----------------------------------------------------------------------------- | ||
@@ -715,2 +768,3 @@ // throwNotImplemented() | ||
//----------------------------------------------------------------------------- | ||
@@ -764,2 +818,13 @@ // transformErr() | ||
//----------------------------------------------------------------------------- | ||
// throwWrapErr() | ||
// | ||
// Throws error by wrapping exceptions with a specific error. | ||
//----------------------------------------------------------------------------- | ||
function throwWrapErr(err, fnOpt) { | ||
const newErr = getErr(fnOpt); | ||
newErr.stack = err.stack; | ||
throw newErr; | ||
} | ||
// define exports | ||
@@ -857,4 +922,8 @@ module.exports = { | ||
ERR_CONFIG_PROVIDER_LOAD_FAILED, | ||
ERR_DATA_COMPRESSION, | ||
ERR_WALLET_TYPE_NOT_SUPPORTED, | ||
ERR_HOST_NOT_FOUND, | ||
ERR_ANO_PACKET, | ||
ERR_ANO_STATUS, | ||
ERR_ANO_NEGOTIATION, | ||
ERR_INVALID_BIND_NAME, | ||
@@ -921,2 +990,14 @@ ERR_WRONG_NUMBER_OF_BINDS, | ||
ERR_EXECMANY_NOT_ALLOWED_ON_QUERIES, | ||
ERR_VECTOR_SPARSE_INDICES_IS_NOT_ARRAY, | ||
ERR_VECTOR_SPARSE_VALUES_IS_NOT_ARRAY, | ||
ERR_VECTOR_SPARSE_DIMS_IS_NOT_INTEGER, | ||
ERR_VECTOR_SPARSE_INDICES_VALUES_NOT_EQUAL, | ||
ERR_VECTOR_SPARSE_INVALID_JSON, | ||
ERR_VECTOR_SPARSE_INVALID_STRING, | ||
ERR_VECTOR_SPARSE_INVALID_INPUT, | ||
ERR_VECTOR_SPARSE_INDICES_ELEM_IS_NOT_VALID, | ||
ERR_DB_FETCH_TYPE_HANDLER_CONVERTER, | ||
ERR_DB_FETCH_TYPE_HANDLER_RETURN_VALUE, | ||
ERR_ACCESS_TOKEN, | ||
ERR_CALLOUT_FN, | ||
WRN_COMPILATION_CREATE, | ||
@@ -936,4 +1017,6 @@ assert, | ||
throwErr, | ||
throwErrWithORAError, | ||
throwNotImplemented, | ||
transformErr | ||
transformErr, | ||
throwWrapErr | ||
}; |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -293,2 +293,12 @@ //----------------------------------------------------------------------------- | ||
//--------------------------------------------------------------------------- | ||
// getMaxIdentifierLength() | ||
// | ||
// Returns the maximum length of identifiers supported by the database to | ||
// which this connection has been established. | ||
//--------------------------------------------------------------------------- | ||
getMaxIdentifierLength() { | ||
errors.throwNotImplemented("getting the maximum identifier length"); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// getMaxOpenCursors() | ||
@@ -403,2 +413,6 @@ // | ||
isCompressionEnabled() { | ||
errors.throwNotImplemented("getting the data compression status on the connection"); | ||
} | ||
//--------------------------------------------------------------------------- | ||
@@ -405,0 +419,0 @@ // ping() |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -192,2 +192,32 @@ //----------------------------------------------------------------------------- | ||
//--------------------------------------------------------------------------- | ||
// parseOracleIntervalYM() | ||
// | ||
// Parses an Oracle interval year-to-month (YM) from the supplied buffer | ||
// and returns a corresponding IntervalYM object representing that value. | ||
// This object contains attributes for years and months. | ||
//--------------------------------------------------------------------------- | ||
parseOracleIntervalYM(buf) { | ||
const years = buf.readUInt32BE() - constants.TNS_DURATION_MID; | ||
const months = buf[4] - constants.TNS_DURATION_OFFSET; | ||
return new types.IntervalYM({ years: years, months: months }); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// parseOracleIntervalDS() | ||
// | ||
// Parses an Oracle interval day-to-second (DS) from the supplied buffer | ||
// and returns a corresponding IntervalDS object representing that value. | ||
// This object contains attributes for day and time units. | ||
//--------------------------------------------------------------------------- | ||
parseOracleIntervalDS(buf) { | ||
const days = buf.readUInt32BE() - constants.TNS_DURATION_MID; | ||
const fseconds = buf.readUInt32BE(7) - constants.TNS_DURATION_MID; | ||
const hours = buf[4] - constants.TNS_DURATION_OFFSET; | ||
const minutes = buf[5] - constants.TNS_DURATION_OFFSET; | ||
const seconds = buf[6] - constants.TNS_DURATION_OFFSET; | ||
return new types.IntervalDS({ days: days, hours: hours, minutes: minutes, | ||
seconds: seconds, fseconds: fseconds }); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// parseOracleNumber() | ||
@@ -435,2 +465,30 @@ // | ||
//--------------------------------------------------------------------------- | ||
// readOracleIntervalYM() | ||
// | ||
// Reads interval year to month value from the buffer and returns a | ||
// JavaScript object representing that value. | ||
//--------------------------------------------------------------------------- | ||
readOracleIntervalYM() { | ||
const buf = this.readBytesWithLength(); | ||
if (!buf) { | ||
return null; | ||
} | ||
return this.parseOracleIntervalYM(buf); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// readOracleIntervalDS() | ||
// | ||
// Reads interval day to second value from the buffer and returns a | ||
// JavaScript object representing that value. | ||
//--------------------------------------------------------------------------- | ||
readOracleIntervalDS() { | ||
const buf = this.readBytesWithLength(); | ||
if (!buf) { | ||
return null; | ||
} | ||
return this.parseOracleIntervalDS(buf); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// readOracleNumber() | ||
@@ -807,2 +865,35 @@ // | ||
//--------------------------------------------------------------------------- | ||
// writeOracleIntervalYM() | ||
// | ||
// Writes a time interval to the buffer in Oracle Interval Year To Month | ||
// format. It is assumed that the 'value' parameter is a valid IntervalYM | ||
// object at this stage. | ||
//--------------------------------------------------------------------------- | ||
writeOracleIntervalYM(value, writeLength = true) { | ||
if (writeLength) { | ||
this.writeUInt8(5); | ||
} | ||
this.writeUInt32BE(value.years + constants.TNS_DURATION_MID); | ||
this.writeUInt8(value.months + constants.TNS_DURATION_OFFSET); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// writeOracleIntervalDS() | ||
// | ||
// Writes a time interval to the buffer in Oracle Interval Day To Second | ||
// format. It is assumed that the 'value' parameter is a valid IntervalDS | ||
// object at this stage. | ||
//--------------------------------------------------------------------------- | ||
writeOracleIntervalDS(value, writeLength = true) { | ||
if (writeLength) { | ||
this.writeUInt8(11); | ||
} | ||
this.writeUInt32BE(value.days + constants.TNS_DURATION_MID); | ||
this.writeUInt8(value.hours + constants.TNS_DURATION_OFFSET); | ||
this.writeUInt8(value.minutes + constants.TNS_DURATION_OFFSET); | ||
this.writeUInt8(value.seconds + constants.TNS_DURATION_OFFSET); | ||
this.writeUInt32BE(value.fseconds + constants.TNS_DURATION_MID); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// writeOracleNumber() | ||
@@ -809,0 +900,0 @@ // |
@@ -37,2 +37,3 @@ // Copyright (c) 2024, Oracle and/or its affiliates. | ||
TNS_VECTOR_VERSION_WITH_BINARY: 1, | ||
TNS_VECTOR_VERSION_WITH_SPARSE: 2, | ||
@@ -42,2 +43,3 @@ // vector flags | ||
TNS_VECTOR_FLAG_NORM: 0x0002, | ||
TNS_VECTOR_FLAG_SPARSE: 0x0020, | ||
@@ -44,0 +46,0 @@ // base JSON constants |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2023, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2023, 2025, Oracle and/or its affiliates. | ||
@@ -141,2 +141,8 @@ //----------------------------------------------------------------------------- | ||
// handle interval datatypes | ||
} else if (nodeType === constants.TNS_JSON_TYPE_INTERVAL_YM) { | ||
return this.parseOracleIntervalYM(this.readBytes(5)); | ||
} else if (nodeType === constants.TNS_JSON_TYPE_INTERVAL_DS) { | ||
return this.parseOracleIntervalDS(this.readBytes(11)); | ||
// handle scalars with lengths stored outside the node itself | ||
@@ -577,2 +583,10 @@ } else if (nodeType === constants.TNS_JSON_TYPE_STRING_LENGTH_UINT8) { | ||
// handle interval data types | ||
} else if (value instanceof types.IntervalYM) { | ||
this.writeUInt8(constants.TNS_JSON_TYPE_INTERVAL_YM); | ||
this.writeOracleIntervalYM(value, false); | ||
} else if (value instanceof types.IntervalDS) { | ||
this.writeUInt8(constants.TNS_JSON_TYPE_INTERVAL_DS); | ||
this.writeOracleIntervalDS(value, false); | ||
// handle buffers | ||
@@ -579,0 +593,0 @@ } else if (Buffer.isBuffer(value)) { |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2024, 2025, Oracle and/or its affiliates. | ||
@@ -33,2 +33,3 @@ //----------------------------------------------------------------------------- | ||
const errors = require("../../errors.js"); | ||
const types = require("../../types.js"); | ||
@@ -54,3 +55,3 @@ /** | ||
const version = this.readUInt8(); | ||
if (version > constants.TNS_VECTOR_VERSION_WITH_BINARY) | ||
if (version > constants.TNS_VECTOR_VERSION_WITH_SPARSE) | ||
errors.throwErr(errors.ERR_VECTOR_VERSION_NOT_SUPPORTED, version); | ||
@@ -60,12 +61,30 @@ const flags = this.readUInt16BE(); | ||
let numElements = this.readUInt32BE(); | ||
let elementSize, result; | ||
let elementSize, value, sparseValue; | ||
// 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); | ||
let sparseFormat; | ||
if (flags & constants.TNS_VECTOR_FLAG_SPARSE) { | ||
sparseFormat = true; | ||
sparseValue = {}; | ||
sparseValue.numDimensions = numElements; // vector dimensions. | ||
numElements = this.readUInt16BE(); // actual elements. | ||
sparseValue.indices = new Uint32Array(numElements); | ||
for (let i = 0; i < numElements; i++) { | ||
sparseValue.indices[i] = this.readUInt32BE(); | ||
} | ||
} | ||
if (vectorFormat === constants.VECTOR_FORMAT_FLOAT32) { | ||
elementSize = 4; | ||
result = new Float32Array(numElements); | ||
value = new Float32Array(numElements); | ||
} else if (vectorFormat === constants.VECTOR_FORMAT_FLOAT64) { | ||
elementSize = 8; | ||
result = new Float64Array(numElements); | ||
value = new Float64Array(numElements); | ||
} else if (vectorFormat === constants.VECTOR_FORMAT_INT8) { | ||
elementSize = 1; | ||
result = new Int8Array(numElements); | ||
value = new Int8Array(numElements); | ||
} else if (vectorFormat === constants.VECTOR_FORMAT_BINARY) { | ||
@@ -75,3 +94,3 @@ elementSize = 1; | ||
numElements = numElements / 8; | ||
result = new Uint8Array(numElements); | ||
value = new Uint8Array(numElements); | ||
} else { | ||
@@ -81,20 +100,21 @@ errors.throwErr(errors.ERR_VECTOR_FORMAT_NOT_SUPPORTED, vectorFormat); | ||
// 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); | ||
if (sparseFormat) { | ||
sparseValue.values = value; | ||
} | ||
// parse data | ||
let res; | ||
for (let i = 0; i < numElements; i++) { | ||
const buf = this.readBytes(elementSize); | ||
if (vectorFormat === constants.VECTOR_FORMAT_FLOAT32) { | ||
result[i] = this.parseBinaryFloat(buf); | ||
res = this.parseBinaryFloat(buf); | ||
} else if (vectorFormat === constants.VECTOR_FORMAT_FLOAT64) { | ||
result[i] = this.parseBinaryDouble(buf); | ||
res = this.parseBinaryDouble(buf); | ||
} else { | ||
result[i] = buf[0]; | ||
res = buf[0]; | ||
} | ||
value[i] = res; | ||
} | ||
return result; | ||
return sparseFormat ? types.SparseVector.create(sparseValue) : value; | ||
} | ||
@@ -106,16 +126,12 @@ | ||
//--------------------------------------------------------------------------- | ||
// encode() | ||
// | ||
// Encodes the value as OSON and returns a buffer containing the OSON bytes. | ||
//--------------------------------------------------------------------------- | ||
encode(value) { | ||
// determine some basic information about the vector | ||
// Writes Header from value. | ||
// It returns function to serialize the value. | ||
// sparseVal is provided for SparseVector. | ||
_updateVectorHeader(value, sparseVal) { | ||
let flags = constants.TNS_VECTOR_FLAG_NORMSRC | ||
| constants.TNS_VECTOR_FLAG_NORM; // NORM is present and reserve space. | ||
let numElements = value.length; | ||
let vectorVersion = constants.TNS_VECTOR_VERSION_BASE; | ||
let vectorFormat = constants.VECTOR_FORMAT_FLOAT32; | ||
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. | ||
@@ -136,2 +152,7 @@ if (Array.isArray(value) || value instanceof Float64Array) { | ||
} | ||
if (sparseVal && sparseVal instanceof types.SparseVector) { | ||
vectorVersion = constants.TNS_VECTOR_VERSION_WITH_SPARSE; | ||
numElements = sparseVal.numDimensions; | ||
flags |= constants.TNS_VECTOR_FLAG_SPARSE; | ||
} | ||
@@ -145,3 +166,27 @@ // write header | ||
this.reserveBytes(8); | ||
return writeFn; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// encode() | ||
// | ||
// Encodes the value as OSON and returns a buffer containing the OSON bytes. | ||
//--------------------------------------------------------------------------- | ||
encode(value) { | ||
let writeFn; | ||
if (value instanceof types.SparseVector) { | ||
writeFn = this._updateVectorHeader(value.values, value); | ||
const numElements = value.indices.length; | ||
this.writeUInt16BE(numElements); | ||
// Write indices | ||
value.indices.forEach((element) => { | ||
this.writeUInt32BE(element); | ||
}); | ||
value = value.values; | ||
} else { | ||
writeFn = this._updateVectorHeader(value); | ||
} | ||
// write data | ||
@@ -148,0 +193,0 @@ value.forEach((element) => { |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2015, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2015, 2025, Oracle and/or its affiliates. | ||
@@ -70,2 +70,3 @@ //----------------------------------------------------------------------------- | ||
const defaultPoolAlias = 'default'; | ||
const registeredHooks = []; | ||
let configProviderCache; | ||
@@ -192,3 +193,15 @@ | ||
} | ||
if (options.networkCompression !== undefined) { | ||
errors.assertParamPropValue(typeof options.networkCompression === 'boolean', 1, | ||
"networkCompression"); | ||
outOptions.networkCompression = options.networkCompression; | ||
outOptions.networkCompressionLevels = []; | ||
outOptions.networkCompressionLevels.push('high'); | ||
} | ||
if (options.networkCompressionThreshold !== undefined) { | ||
errors.assertParamPropValue(Number.isInteger(options.networkCompressionThreshold), 1, "networkCompressionThreshold"); | ||
outOptions.networkCompressionThreshold = options.networkCompressionThreshold; | ||
} | ||
//wallet content must be a string | ||
@@ -367,2 +380,9 @@ if (options.walletContent !== undefined) { | ||
// useSNI must be a boolean | ||
if (options.useSNI !== undefined) { | ||
errors.assertParamPropValue(typeof options.useSNI === 'boolean', 1, | ||
"useSNI"); | ||
outOptions.useSNI = options.useSNI; | ||
} | ||
// check pool specific options | ||
@@ -519,5 +539,9 @@ if (inCreatePool) { | ||
outOptions.accessTokenConfig = options.accessTokenConfig; | ||
accessToken = await options.accessToken(false, options.accessTokenConfig); | ||
if (!nodbUtil.isTokenValid(accessToken)) { | ||
accessToken = await options.accessToken(true, options.accessTokenConfig); | ||
try { | ||
accessToken = await options.accessToken(false, outOptions.accessTokenConfig); | ||
if (!nodbUtil.isTokenValid(accessToken)) { | ||
accessToken = await options.accessToken(true, outOptions.accessTokenConfig); | ||
} | ||
} catch (error) { | ||
errors.throwWrapErr(error, errors.ERR_ACCESS_TOKEN); | ||
} | ||
@@ -575,2 +599,14 @@ } else { | ||
errors.assertParamValue(nodbUtil.isObject(options), 1); | ||
// this will invoke hookFn() written in application side. | ||
// for token based auth it will generate access token and save it in options. | ||
for (const hookFn of registeredHooks) { | ||
// eslint-disable-next-line no-useless-catch | ||
try { | ||
await hookFn(options); | ||
} catch (error) { | ||
errors.throwWrapErr(error, errors.ERR_CALLOUT_FN); | ||
} | ||
} | ||
options = await _verifyOptions(options, true); | ||
@@ -708,2 +744,13 @@ const sessionCallback = options.sessionCallback; | ||
// this will invoke hookFn() written in application side. | ||
// for token based auth it will generate access token and save it in options. | ||
for (const hookFn of registeredHooks) { | ||
// eslint-disable-next-line no-useless-catch | ||
try { | ||
await hookFn(options); | ||
} catch (error) { | ||
errors.throwWrapErr(error, errors.ERR_CALLOUT_FN); | ||
} | ||
} | ||
// create a standalone connection | ||
@@ -1007,2 +1054,14 @@ options = await _verifyOptions(options, false); | ||
//----------------------------------------------------------------------------- | ||
// registerProcessConfigurationHook() | ||
// | ||
// Registers extension modules and registered modules will be called and | ||
// executed during pool and standalone connection creation. | ||
//----------------------------------------------------------------------------- | ||
function registerProcessConfigurationHook(fn) { | ||
errors.assertArgCount(arguments, 1, 1); | ||
errors.assertParamValue(typeof fn === 'function', 1); | ||
registeredHooks.push(fn); | ||
} | ||
// module exports | ||
@@ -1028,2 +1087,5 @@ module.exports = { | ||
SodaOperation, | ||
SparseVector: types.SparseVector, | ||
IntervalYM: types.IntervalYM, | ||
IntervalDS: types.IntervalDS, | ||
@@ -1036,2 +1098,3 @@ // top-level functions | ||
initOracleClient, | ||
registerProcessConfigurationHook, | ||
shutdown: nodbUtil.callbackify(nodbUtil.wrapFn(shutdown)), | ||
@@ -1281,2 +1344,6 @@ startup: nodbUtil.callbackify(nodbUtil.wrapFn(startup)), | ||
get dbObjectTypeHandler() { | ||
return settings.dbObjectTypeHandler; | ||
}, | ||
get lobPrefetchSize() { | ||
@@ -1342,2 +1409,3 @@ return settings.lobPrefetchSize; | ||
get thin() { | ||
@@ -1427,2 +1495,9 @@ return settings.thin; | ||
set dbObjectTypeHandler(value) { | ||
if (value !== undefined) { | ||
errors.assertPropValue(typeof value === 'function', "dbObjectTypeHandler"); | ||
} | ||
settings.dbObjectTypeHandler = value; | ||
}, | ||
set lobPrefetchSize(value) { | ||
@@ -1524,2 +1599,3 @@ errors.assertPropValue(Number.isInteger(value) && value >= 0, | ||
}, | ||
set configProviderCacheTimeout(value) { | ||
@@ -1526,0 +1602,0 @@ errors.assertPropValue(Number.isInteger(value) && value >= 0, |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -67,3 +67,7 @@ //----------------------------------------------------------------------------- | ||
this.fetchTypeHandler = undefined; | ||
this.dbObjectTypeHandler = undefined; | ||
this._JsonId = types.JsonId; | ||
this._SparseVector = types.SparseVector; | ||
this._IntervalYM = types.IntervalYM; | ||
this._IntervalDS = types.IntervalDS; | ||
} | ||
@@ -70,0 +74,0 @@ |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -718,2 +718,5 @@ //----------------------------------------------------------------------------- | ||
isCompressionEnabled() { | ||
return this.nscon.compressionEnabled; | ||
} | ||
isHealthy() { | ||
@@ -843,3 +846,3 @@ try { | ||
} | ||
if (!params.token) { // non-token Authentication | ||
if (!params.externalAuth) { // non-token Authentication | ||
await this._protocol._processMessage(authMessage); // OAUTH | ||
@@ -1318,2 +1321,10 @@ } | ||
//--------------------------------------------------------------------------- | ||
// Returns the maximum length of identifiers supported by the database to | ||
// which this connection has been established. | ||
//--------------------------------------------------------------------------- | ||
getMaxIdentifierLength() { | ||
return this.maxIdentifierLength; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// Returns the Oracle Database service name associated with the connection. | ||
@@ -1320,0 +1331,0 @@ //--------------------------------------------------------------------------- |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2023, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2023, 2025, Oracle and/or its affiliates. | ||
@@ -371,6 +371,3 @@ //----------------------------------------------------------------------------- | ||
case types.DB_TYPE_NUMBER: | ||
value = buf.readOracleNumber(); | ||
if (value !== null) | ||
value = parseFloat(value); | ||
return value; | ||
return buf.readOracleNumber(); | ||
case types.DB_TYPE_BINARY_INTEGER: | ||
@@ -433,3 +430,3 @@ return buf.readBinaryInteger(); | ||
errors.throwErr(errors.ERR_INVALID_COLL_INDEX_SET, | ||
this.unpackedArray.length, 0, objType.maxNumElements); | ||
this.unpackedArray.length, 0, objType.maxNumElements - 1); | ||
} | ||
@@ -452,2 +449,22 @@ this.unpackedArray.push(value); | ||
//--------------------------------------------------------------------------- | ||
// copy | ||
// | ||
// Creates and returns a copy of the ThinDBObjectImpl object. The copy is | ||
// independent of the original object that was copied. | ||
//--------------------------------------------------------------------------- | ||
copy() { | ||
// We send in marshalled data of the original object to the constructor | ||
// when we create the object copy | ||
const newObjImpl = new ThinDbObjectImpl(this._objType, this._getPackedData()); | ||
// Set other properties | ||
newObjImpl.toid = this.toid; | ||
newObjImpl.flags = this.flags; | ||
newObjImpl.imageFlags = this.imageFlags; | ||
newObjImpl.imageVersion = this.imageVersion; | ||
return newObjImpl; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// deleteElement() | ||
@@ -465,3 +482,3 @@ // | ||
} else { | ||
this._unpackedAssocKeys = undefined; | ||
this.unpackedAssocKeys = undefined; | ||
this.unpackedAssocArray.delete(index); | ||
@@ -618,2 +635,16 @@ } | ||
//--------------------------------------------------------------------------- | ||
// getLength | ||
// | ||
// Gets the size of the database object if it is a collection. Else returns | ||
// undefined. | ||
//--------------------------------------------------------------------------- | ||
getLength() { | ||
this._ensureUnpacked(); | ||
if (this.unpackedArray) | ||
return this.unpackedArray.length; | ||
if (this.unpackedAssocArray) | ||
return this.unpackedAssocArray.size; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// hasElement() | ||
@@ -620,0 +651,0 @@ // |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -200,3 +200,7 @@ //----------------------------------------------------------------------------- | ||
if (typeof this._accessTokenFn === 'function') { | ||
accessToken = await this._accessTokenFn(true, this._accessTokenConfig); | ||
try { | ||
accessToken = await this._accessTokenFn(true, this._accessTokenConfig); | ||
} catch (error) { | ||
errors.throwWrapErr(error, errors.ERR_ACCESS_TOKEN); | ||
} | ||
if (typeof accessToken === 'string') { | ||
@@ -215,3 +219,3 @@ clonedAttrs.token = accessToken; | ||
clonedAttrs.token = accessToken.token; | ||
clonedAttrs.privateKey = accessToken.privateKey; | ||
clonedAttrs.privateKey = util.denormalizePrivateKey(accessToken.privateKey); | ||
if (util.isTokenExpired(clonedAttrs.token)) { | ||
@@ -218,0 +222,0 @@ // IAM token is expired |
@@ -122,3 +122,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
this.compileCaps[constants.TNS_CCAP_VECTOR_FEATURES] = | ||
constants.TNS_CCAP_VECTOR_FEATURE_BINARY; | ||
constants.TNS_CCAP_VECTOR_FEATURE_BINARY | constants.TNS_CCAP_VECTOR_FEATURE_SPARSE; | ||
} | ||
@@ -125,0 +125,0 @@ |
@@ -647,2 +647,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
TNS_CCAP_VECTOR_FEATURE_BINARY: 0x01, | ||
TNS_CCAP_VECTOR_FEATURE_SPARSE: 0x02, | ||
@@ -771,2 +772,3 @@ // runtime capability indices | ||
VECTOR_META_FLAG_FLEXIBLE_DIM: 1, | ||
VECTOR_META_FLAG_SPARSE: 2, | ||
@@ -773,0 +775,0 @@ // other constants |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -97,4 +97,6 @@ //----------------------------------------------------------------------------- | ||
this.token = config.token; | ||
if (this.token) | ||
if (config.externalAuth) { | ||
this.functionCode = constants.TNS_FUNC_AUTH_PHASE_TWO; | ||
this.externalAuth = true; | ||
} | ||
this.privateKey = config.privateKey; | ||
@@ -111,2 +113,7 @@ if (this.privateKey) { | ||
this.terminal = config.terminal; | ||
if (config.edition) { | ||
this.edition = config.edition; | ||
} else if (process.env.ORA_EDITION) { | ||
this.edition = process.env.ORA_EDITION; | ||
} | ||
this.setAuthMode(config); | ||
@@ -146,3 +153,3 @@ } | ||
} | ||
if (!this.token) { | ||
if (!config.externalAuth) { | ||
this.authMode |= constants.TNS_AUTH_MODE_WITH_PASSWORD; | ||
@@ -205,4 +212,6 @@ } | ||
numPairs = 4; | ||
if (this.token) { | ||
numPairs += 1; | ||
if (this.externalAuth) { | ||
numPairs += 5; | ||
if (this.token) | ||
numPairs += 1; | ||
} else { | ||
@@ -242,2 +251,5 @@ numPairs += 2; | ||
} | ||
if (this.edition) { | ||
numPairs += 1; | ||
} | ||
if (this.schemaUser.length !== 0) { | ||
@@ -254,6 +266,13 @@ numPairs += 1; | ||
buf.writeBytesWithLength(Buffer.from(this.username)); | ||
if (this.externalAuth) { | ||
buf.writeKeyValue("AUTH_TERMINAL", this.terminal ?? cInfo.terminal); | ||
buf.writeKeyValue("AUTH_PROGRAM_NM", this.program ?? cInfo.program); | ||
buf.writeKeyValue("AUTH_MACHINE", this.machine ?? cInfo.hostName); | ||
buf.writeKeyValue("AUTH_PID", cInfo.pid); | ||
buf.writeKeyValue("AUTH_SID", this.osUser ?? cInfo.userName); | ||
} | ||
if (this.token) { | ||
buf.writeKeyValue("AUTH_TOKEN", this.token); | ||
} else { | ||
if (!this.changePassword) { | ||
if (!this.changePassword && !this.externalAuth) { | ||
buf.writeKeyValue("AUTH_SESSKEY", this.sessionKey, 1); | ||
@@ -306,2 +325,5 @@ if (!verifier11G) { | ||
} | ||
if (this.edition) { | ||
buf.writeKeyValue("AUTH_ORA_EDITION", this.edition); | ||
} | ||
@@ -341,2 +363,3 @@ } | ||
this.conn.instanceName = this.sessionData['AUTH_INSTANCENAME']; | ||
this.conn.maxIdentifierLength = Number(this.sessionData['AUTH_MAX_IDEN_LENGTH'] || 30); | ||
const fullVersionNum = Number(this.sessionData['AUTH_VERSION_NO']); | ||
@@ -343,0 +366,0 @@ const versionNum = (fullVersionNum >> 24) & 0xFF; |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2023, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2023, 2025, Oracle and/or its affiliates. | ||
@@ -73,2 +73,7 @@ //----------------------------------------------------------------------------- | ||
this.endOfResponse = this.authMessage.endOfResponse; | ||
if (this.authMessage.errorOccurred) { | ||
// Capture the Error returned in TNS_MSG_TYPE_ERROR processing. | ||
this.errorOccurred = this.authMessage.errorOccurred; | ||
this.errorInfo = this.authMessage.errorInfo; | ||
} | ||
} | ||
@@ -75,0 +80,0 @@ } |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -283,2 +283,3 @@ //----------------------------------------------------------------------------- | ||
} | ||
fetchInfo.isSparseVector = Boolean(vectorFlags & constants.VECTOR_META_FLAG_SPARSE); | ||
if (vectorFormat !== constants.VECTOR_FORMAT_FLEX) { | ||
@@ -505,2 +506,6 @@ fetchInfo.vectorFormat = vectorFormat; | ||
colValue = buf.readBool(); | ||
} else if (oraTypeNum === constants.TNS_DATA_TYPE_INTERVAL_YM) { | ||
colValue = buf.readOracleIntervalYM(); | ||
} else if (oraTypeNum === constants.TNS_DATA_TYPE_INTERVAL_DS) { | ||
colValue = buf.readOracleIntervalDS(); | ||
} else if ( | ||
@@ -866,2 +871,6 @@ oraTypeNum === constants.TNS_DATA_TYPE_CLOB || | ||
} | ||
} else if (oraTypeNum === constants.TNS_DATA_TYPE_INTERVAL_YM) { | ||
buf.writeOracleIntervalYM(value); | ||
} else if (oraTypeNum === constants.TNS_DATA_TYPE_INTERVAL_DS) { | ||
buf.writeOracleIntervalDS(value); | ||
} else if ( | ||
@@ -868,0 +877,0 @@ oraTypeNum === constants.TNS_DATA_TYPE_CLOB || |
@@ -533,3 +533,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
} | ||
this.nsi.ntAdapter.send(buf); | ||
this.nsi.sendPacket(buf); | ||
} | ||
@@ -536,0 +536,0 @@ |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -158,2 +158,3 @@ //----------------------------------------------------------------------------- | ||
NSPDAFEOF: 0x40, // "end of file" | ||
NSPDAFCMP: 0x400, // "compressed data" | ||
@@ -205,4 +206,7 @@ /* Marker Packet */ | ||
/* Network Compression Algorithms */ | ||
NETWORK_COMPRESSION_ZLIB: 2, | ||
/* FLAGS */ | ||
NSNOBLOCK: 0x0001, // Do not block | ||
}; |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -60,3 +60,3 @@ //----------------------------------------------------------------------------- | ||
"SOURCE_ROUTE", "RETRY_COUNT", "RETRY_DELAY", | ||
"CONNECT_TIMEOUT", "TRANSPORT_CONNECT_TIMEOUT", "RECV_TIMEOUT"]; | ||
"CONNECT_TIMEOUT", "TRANSPORT_CONNECT_TIMEOUT", "RECV_TIMEOUT", "USE_SNI", "COMPRESSION"]; | ||
/* | ||
@@ -442,2 +442,3 @@ DESCRIPTION | ||
aliasMap.set("enable", "ENABLE"); | ||
aliasMap.set("compression", "COMPRESSION"); | ||
aliasMap.set("failover", "FAILOVER"); | ||
@@ -464,4 +465,5 @@ aliasMap.set("load_balance", "LOAD_BALANCE"); | ||
aliasMap.set("pool_boundary", "POOL_BOUNDARY"); | ||
aliasMap.set("use_sni", "USE_SNI"); | ||
return aliasMap; | ||
} | ||
}module.exports = EZConnectResolver; |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -249,2 +249,6 @@ //----------------------------------------------------------------------------- | ||
|| childnv.atom.toLowerCase() == "true"); | ||
} else if (childnv.name.toUpperCase() == "USE_SNI") { | ||
this.params.useSNI = (childnv.atom.toLowerCase() == "yes" | ||
|| childnv.atom.toLowerCase() == "on" | ||
|| childnv.atom.toLowerCase() == "true"); | ||
} else if (childnv.name.toUpperCase() == "ADDRESS_LIST") { | ||
@@ -294,2 +298,15 @@ child = new NavAddressList(); | ||
this.params.sdu = childnv.atom; | ||
} else if (childnv.name.toUpperCase() == "COMPRESSION") { | ||
this.params.networkCompression = (childnv.atom.toLowerCase() == "yes" | ||
|| childnv.atom.toLowerCase() == "on" | ||
|| childnv.atom.toLowerCase() == "true"); | ||
this.params.networkCompressionLevels = []; | ||
} else if (childnv.name.toUpperCase() == "COMPRESSION_LEVELS") { | ||
const listsize = childnv.getListSize(); | ||
for (let i = 0; i < listsize; i++) { | ||
const tmpnv = childnv.getListElement(i); | ||
if (tmpnv.name.toUpperCase() == "LEVEL") { | ||
this.params.networkCompressionLevels.push(tmpnv.atom.toLowerCase()); | ||
} | ||
} | ||
} else if (childnv.name.toUpperCase() == "EXPIRE_TIME") { | ||
@@ -701,3 +718,2 @@ if (childnv.atom > 0) | ||
desc.params = this.params; | ||
if ('connectTimeout' in this.params) { | ||
@@ -721,2 +737,5 @@ cs.sBuf.push("(CONNECT_TIMEOUT=" + this.params.connectTimeout + ")"); | ||
} | ||
if ('useSNI' in this.params) { | ||
cs.sBuf.push("(USE_SNI=" + this.params.useSNI + ")"); | ||
} | ||
if (('sslServerCertDN' in this.params) || ('sslServerDNMatch' in this.params) || ('walletLocation' in this.params) || ('sslAllowWeakDNMatch' in this.params)) { | ||
@@ -723,0 +742,0 @@ cs.sBuf.push("(SECURITY="); |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -28,3 +28,3 @@ //----------------------------------------------------------------------------- | ||
'use strict'; | ||
const zlib = require('zlib'); | ||
const Packet = require("./packet.js"); | ||
@@ -42,2 +42,3 @@ const NTTCP = require("./ntTcp.js"); | ||
const downHostInstance = require("./connStrategy.js").SOLE_INST_DHCACHE; | ||
const {ANO} = require("./ANO.js"); | ||
/** | ||
@@ -143,2 +144,3 @@ * | ||
this.breakPosted = false; | ||
this.compressionEnabled = false; | ||
} | ||
@@ -155,3 +157,3 @@ | ||
this.sAtts.setFrom(address.desc.params); /* Resolve attributes from Connect String */ | ||
await this.sAtts.prepare(address.protocol); | ||
await this.sAtts.prepare(address.protocol, userConfig); | ||
@@ -196,3 +198,3 @@ /* Insert Connection ID */ | ||
_sendConnect(connectPkt) { | ||
this._sendPacket(connectPkt.buf); | ||
this.sendPacket(connectPkt.buf); | ||
if (connectPkt.overflow) { | ||
@@ -303,8 +305,6 @@ this._send(connectPkt.connectData, 0, connectPkt.connectDataLen); | ||
/* Accepted */ | ||
this.connected = true; | ||
this.cData = null; | ||
this.sndDatapkt = new Packet.DataPacket(this.sAtts.largeSDU); | ||
this.sndDatapkt.createPacket(constants.NSPDADAT); //Currently only used for disconnect | ||
this.sndDatapkt.offset = this.sndDatapkt.dataPtr; | ||
this.sndDatapkt.len = this.sndDatapkt.bufLen; | ||
this.markerPkt = new Packet.MarkerPacket(this.sAtts.largeSDU); | ||
@@ -315,2 +315,15 @@ this.controlPkt = new Packet.ControlPacket(); | ||
this.sAtts.nt.walletPassword = null; | ||
if (!this.sAtts.noNA) { | ||
const NAContext = new ANO(this.sAtts); | ||
const buf = NAContext.sendPacket(); | ||
this._send(buf, 0, buf.length); | ||
this.flush(); | ||
const packet = await this._recvPacket(); | ||
NAContext.processPacket(packet.buf); | ||
} | ||
this.sndDatapkt.createPacket(constants.NSPDADAT); //Currently only used for disconnect | ||
this.sndDatapkt.offset = this.sndDatapkt.dataPtr; | ||
this.sndDatapkt.len = this.sndDatapkt.bufLen; | ||
return (true); | ||
@@ -363,5 +376,32 @@ } | ||
switch (packet.type) { | ||
case constants.NSPTDA: /* DATA packet */ | ||
case constants.NSPTDA: { /* DATA packet */ | ||
const size = packet.buf.length; | ||
const dataFlags = packet.buf.readUInt16BE(constants.NSPDAFLG); | ||
if ((dataFlags & constants.NSPDAFCMP) != 0) { // compression enabled | ||
const packetHeader = packet.buf.subarray(0, constants.NSPDADAT); | ||
const buffertoDeCompress = packet.buf.subarray(constants.NSPDADAT, size); | ||
let deCompressedDataBuffer; | ||
try { | ||
if (this.sAtts.firstCompressedPacket) { | ||
deCompressedDataBuffer = zlib.inflateSync(buffertoDeCompress, {finishFlush: zlib.constants.Z_SYNC_FLUSH}); | ||
this.sAtts.firstCompressedPacket = 0; | ||
} else { | ||
deCompressedDataBuffer = zlib.inflateRawSync(buffertoDeCompress, {finishFlush: zlib.constants.Z_SYNC_FLUSH}); | ||
} | ||
} catch (err) { | ||
errors.throwErr(errors.ERR_DATA_COMPRESSION, err.message); | ||
} | ||
const resultLength = deCompressedDataBuffer.length; | ||
//concatenate packet header with decompressed data | ||
packet.buf = Buffer.concat([packetHeader, deCompressedDataBuffer]); | ||
const length = resultLength + constants.NSPDADAT; | ||
if (this.sAtts.largeSDU) { | ||
packet.buf.writeUInt32BE(length, constants.NSPHDLEN); | ||
} else { | ||
packet.buf.writeUInt16BE(length, constants.NSPHDLEN); | ||
} | ||
} | ||
this.rcvDatapkt.fromPacket(packet); | ||
break; | ||
} | ||
case constants.NSPTMK: /* MARKER packet */ | ||
@@ -405,5 +445,7 @@ this.markerPkt.fromPacket(packet, this); | ||
break; | ||
this._processPacket(packet); | ||
if (packet.type !== constants.NSPTCNL) | ||
if (packet.type !== constants.NSPTCNL) { | ||
return packet; | ||
} | ||
} | ||
@@ -415,3 +457,33 @@ } | ||
*/ | ||
_sendPacket(buf) { | ||
sendPacket(buf) { | ||
const packetType = buf.readUInt8(constants.NSPHDTYP); | ||
// only data packets need to be compressed | ||
if (packetType == constants.NSPTDA) { | ||
const size = buf.length; | ||
let dataFlags = buf.readUInt16BE(constants.NSPDAFLG); | ||
if (this.sAtts.networkCompressionEnabled && size > this.sAtts.networkCompressionThreshold) { | ||
this.compressionEnabled = true; | ||
const buffertoCompress = buf.subarray(constants.NSPDADAT, size); | ||
const bufferHeader = buf.subarray(0, constants.NSPDADAT); | ||
let compressedDataBuffer; | ||
try { | ||
compressedDataBuffer = zlib.deflateSync(buffertoCompress, {finishFlush: zlib.constants.Z_SYNC_FLUSH}); | ||
} catch (err) { | ||
errors.throwErr(errors.ERR_DATA_COMPRESSION, err.message); | ||
} | ||
const resultLength = compressedDataBuffer.length; | ||
if (resultLength < size - constants.NSPDADAT) { | ||
dataFlags |= constants.NSPDAFCMP; | ||
// concatenate buffer header with the compressed data | ||
buf = Buffer.concat([bufferHeader, compressedDataBuffer]); | ||
buf.writeUInt16BE(dataFlags, constants.NSPDAFLG); | ||
const pktOffset = resultLength + constants.NSPDADAT; | ||
if (this.sAtts.largeSDU) { | ||
buf.writeUInt32BE(pktOffset, constants.NSPHDLEN); | ||
} else { | ||
buf.writeUInt16BE(pktOffset, constants.NSPHDLEN); | ||
} | ||
} | ||
} | ||
} | ||
this.ntAdapter.send(buf); | ||
@@ -435,3 +507,3 @@ } | ||
this.markerPkt.prepare(constants.NSPMKTD1, constants.NIQIMARK); | ||
this._sendPacket(this.markerPkt.buf); | ||
this.sendPacket(this.markerPkt.buf); | ||
} | ||
@@ -446,3 +518,3 @@ | ||
this.markerPkt.prepare(constants.NSPMKTD1, constants.NIQBMARK); | ||
this._sendPacket(this.markerPkt.buf); | ||
this.sendPacket(this.markerPkt.buf); | ||
this.breakPosted = false; | ||
@@ -452,3 +524,3 @@ } | ||
this.markerPkt.prepare(constants.NSPMKTD1, constants.NIQRMARK); | ||
this._sendPacket(this.markerPkt.buf); | ||
this.sendPacket(this.markerPkt.buf); | ||
@@ -507,3 +579,3 @@ /* Await Reset */ | ||
while (len) { | ||
this._sendPacket(this.sndDatapkt.dataBuf); | ||
this.sendPacket(this.sndDatapkt.dataBuf); | ||
@@ -533,3 +605,3 @@ /* If break throw error now */ | ||
this.sndDatapkt.prepare2Send(); | ||
this._sendPacket(Buffer.from(this.sndDatapkt.dataBuf)); | ||
this.sendPacket(Buffer.from(this.sndDatapkt.dataBuf)); | ||
this.sndDatapkt.dataLen = this.sndDatapkt.dataPtr; | ||
@@ -587,3 +659,3 @@ this.sndDatapkt.offset = this.sndDatapkt.dataPtr; | ||
this.sndDatapkt.prepare2Send(constants.NSPDAFEOF); | ||
this._sendPacket(this.sndDatapkt.dataBuf); | ||
this.sendPacket(this.sndDatapkt.dataBuf); | ||
} | ||
@@ -590,0 +662,0 @@ this.ntAdapter.disconnect(type); |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -37,3 +37,3 @@ //----------------------------------------------------------------------------- | ||
const errors = require("../../errors.js"); | ||
const { findValue } = require("./nvStrToNvPair.js"); | ||
const { findValue, findNVPair } = require("./nvStrToNvPair.js"); | ||
@@ -52,2 +52,8 @@ const PACKET_HEADER_SIZE = 8; | ||
const sniAllowedCDParams = ["SERVICE_NAME", "INSTANCE_NAME", "SERVER", "COLOCATION_TAG", "CONNECTION_ID", "POOL_BOUNDARY", | ||
"POOL_PURITY", "POOL_CONNECTION_CLASS", "POOL_NAME", "SERVICE_TAG", "CID"]; | ||
const sniParams = ["SERVICE_NAME", "INSTANCE_NAME", "SERVER", "COLOCATION_TAG"]; | ||
const sniMap = ['S', 'I', 'T', 'C']; | ||
const SNI_MAX_BYTES = 256; | ||
let streamNum = 1; | ||
@@ -118,6 +124,9 @@ | ||
this.stream.removeAllListeners(); | ||
let connectErrCause; | ||
let connectErrCause, sni = null; | ||
if (this.atts.useSNI) | ||
sni = this.generateSNI(); | ||
const tlsOptions = { | ||
host: this.host, | ||
socket: connStream, | ||
servername: sni, | ||
rejectUnauthorized: true, | ||
@@ -563,4 +572,42 @@ secureContext: secureContext, | ||
/** | ||
* Generate SNI data. | ||
*/ | ||
generateSNI() { | ||
/* No SNI if source route is set */ | ||
if ((findValue(this.atts.cDataNVPair, ["DESCRIPTION", "SOURCE_ROUTE"]) == "yes") || | ||
(findValue(this.atts.cDataNVPair, ["DESCRIPTION", "ADDRESS_LIST", "SOURCE_ROUTE"]) == "yes")) | ||
return null; | ||
const cdnvp = findNVPair(this.atts.cDataNVPair, "CONNECT_DATA"); | ||
/* Loop through the list of params */ | ||
for (let i = 0; i < cdnvp.getListSize(); i++) { | ||
const child = cdnvp.getListElement(i); | ||
if (!sniAllowedCDParams.includes(child.name.toUpperCase())) | ||
return null; /* No SNI for unsupported Connect Data params */ | ||
} | ||
/* Generate SNI */ | ||
let value, sni = ""; | ||
for (let i = 0; i < sniParams.length; i++) { | ||
if ((value = findValue(this.atts.cDataNVPair, ["DESCRIPTION", "CONNECT_DATA", sniParams[i]]))) { | ||
if (sniParams[i] == 'SERVER') /* For server type just pick the first letter */ | ||
sni += sniMap[i] + "1" + "." + value[0] + "."; | ||
else | ||
sni += sniMap[i] + value.length + "." + value + "."; | ||
} | ||
} | ||
sni += "V3." + constants.TNS_VERSION_DESIRED; /* Version */ | ||
const match_pattern = new RegExp("^[A-Za-z0-9._-]+$"); | ||
if (!(sni.match(match_pattern))) | ||
return null; /* No SNI if special characters are present */ | ||
if (sni.length > SNI_MAX_BYTES) | ||
return null; /* Max allowed length */ | ||
return sni; | ||
} | ||
} | ||
module.exports = NTTCP; |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -111,3 +111,3 @@ //----------------------------------------------------------------------------- | ||
this.buf.writeUInt8( | ||
constants.NSISUPSECRENEG | constants.NSINADISABLEDFORCONNECTION, | ||
sAtts.NAFlags, | ||
constants.NSPCNFL0 | ||
@@ -117,3 +117,3 @@ ); /* NA disabled */ | ||
this.buf.writeUInt8( | ||
constants.NSISUPSECRENEG | constants.NSINADISABLEDFORCONNECTION, | ||
sAtts.NAFlags, | ||
constants.NSPCNFL1 | ||
@@ -130,4 +130,18 @@ ); /* NA disabled * | ||
this.buf.writeUInt32BE(sAtts.tdu, constants.NSPCNLTD); /* TDU */ | ||
this.buf.writeUInt32BE(0, constants.NSPCNCFL); /* Compression not supported */ | ||
let compressionFieldBuilder = 0; // we will be using just the last 2 bytes | ||
/* | ||
* For the 2 byte field, the first bit represent ON/OFF , second is empty | ||
* After that every 4 bits represent a value in the user preference of sch | ||
eme | ||
* scheme values are 1 = LZO, 2 = ZLIB, 3 = GZIP ( only ZLIB supported in node-oracledb) */ | ||
if (sAtts.networkCompression) { | ||
compressionFieldBuilder = constants.NSPACCFON << 8 ; // set the ON bit | ||
const schemeShiftCounter = 10; // shifting by 10 puts the 4 bit field in the right place | ||
if (sAtts.networkCompressionLevels.includes('high')) | ||
compressionFieldBuilder |= constants.NETWORK_COMPRESSION_ZLIB << schemeShiftCounter; | ||
} | ||
this.buf.writeUInt16BE(compressionFieldBuilder, constants.NSPCNCFL); /* Compression field added */ | ||
this.buf.writeUInt32BE( | ||
@@ -246,2 +260,10 @@ 0, | ||
sAtts.largeSDU = true; | ||
this.cflag = packet.buf.readUInt8(constants.NSPACCFL); // 00001000 | ||
if ((this.cflag & constants.NSPACCFON) != 0) { // compression ON | ||
sAtts.negotiatedNetworkCompressionScheme = (this.cflag & 0x3c) >> 2; // 0x3c | ||
sAtts.networkCompressionEnabled = true; | ||
sAtts.firstCompressedPacket = true; | ||
} else { | ||
sAtts.networkCompressionEnabled = false; | ||
} | ||
} | ||
@@ -253,2 +275,7 @@ | ||
sAtts.noNA = ((this.flag1 & constants.NSINANOSERVICES) == constants.NSINANOSERVICES); | ||
if (!sAtts.noNA) | ||
sAtts.noNA = ((this.flag0 & constants.NSINADISABLEDFORCONNECTION) == constants.NSINADISABLEDFORCONNECTION); | ||
if (sAtts.version >= constants.TNS_VERSION_MIN_DATA_FLAGS) { | ||
@@ -255,0 +282,0 @@ packet.flags = packet.buf.readUInt32BE(constants.NSPACFL2); |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -33,2 +33,3 @@ //----------------------------------------------------------------------------- | ||
const fs = require("fs"); | ||
const {getFlags} = require("./ANO.js"); | ||
@@ -64,2 +65,3 @@ /** | ||
this.nt.sslAllowWeakDNMatch = false; | ||
this.nt.useSNI = false; | ||
} | ||
@@ -76,2 +78,18 @@ | ||
} | ||
if (typeof params.networkCompression == 'boolean') { | ||
this.networkCompression = params.networkCompression; | ||
this.networkCompressionLevels = []; | ||
if (params.networkCompressionLevels) { | ||
if (params.networkCompressionLevels.includes('high')) | ||
this.networkCompressionLevels.push('high'); | ||
if (params.networkCompressionLevels.length == 0) | ||
this.networkCompressionLevels.push('high'); | ||
} | ||
} | ||
if (params.networkCompressionThreshold >= 200) { | ||
this.networkCompressionThreshold = parseInt(params.networkCompressionThreshold); | ||
} else | ||
this.networkCompressionThreshold = 1024; | ||
if (typeof params.walletLocation === 'string') { | ||
@@ -125,2 +143,5 @@ this.nt.walletFile = path.join(params.walletLocation, constants.PEM_WALLET_FILE_NAME); | ||
} | ||
if (typeof params.useSNI === 'boolean') { | ||
this.nt.useSNI = params.useSNI; | ||
} | ||
} | ||
@@ -158,3 +179,3 @@ } | ||
*/ | ||
async prepare(protocol) { | ||
async prepare(protocol, userConfig) { | ||
if (!this.uuid) { | ||
@@ -177,2 +198,4 @@ this.uuid = await genuuid(); | ||
this.transportConnectTimeout = constants.DEFAULT_TRANSPORT_CONNECT_TIMEOUT; /* Default to 20 secs */ | ||
this.NAFlags = getFlags(protocol, userConfig); | ||
} | ||
@@ -179,0 +202,0 @@ |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -155,5 +155,3 @@ //----------------------------------------------------------------------------- | ||
if (proxyUser.length === 0) { | ||
return result; | ||
} else { | ||
if (proxyUser.length != 0) { | ||
result.proxyUser = proxyUser; | ||
@@ -233,6 +231,3 @@ } | ||
function checkCredentials(params) { | ||
if (params.token === undefined) { | ||
if (params.externalAuth === true) { | ||
errors.throwErr(errors.ERR_NOT_IMPLEMENTED, 'External Authentication'); | ||
} | ||
if (params.externalAuth === false) { | ||
if (params.password === undefined) { | ||
@@ -239,0 +234,0 @@ errors.throwErr(errors.ERR_MISSING_CREDENTIALS); |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2023, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2023, 2025, Oracle and/or its affiliates. | ||
@@ -92,3 +92,4 @@ //----------------------------------------------------------------------------- | ||
typeof value === 'boolean' || Buffer.isBuffer(value) || | ||
util.types.isDate(value) || nodbUtil.isVectorValue(value)) | ||
util.types.isDate(value) || nodbUtil.isVectorValue(value) || | ||
value instanceof types.IntervalYM || value instanceof types.IntervalDS) | ||
return value; | ||
@@ -201,2 +202,12 @@ | ||
// handle intervals | ||
} else if (value instanceof types.IntervalYM) { | ||
checkType(info, options, | ||
types.DB_TYPE_INTERVAL_YM); | ||
return value; | ||
} else if (value instanceof types.IntervalDS) { | ||
checkType(info, options, | ||
types.DB_TYPE_INTERVAL_DS); | ||
return value; | ||
// handle binding buffers | ||
@@ -203,0 +214,0 @@ } else if (Buffer.isBuffer(value)) { |
223
lib/types.js
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. | ||
@@ -36,2 +36,3 @@ //----------------------------------------------------------------------------- | ||
const dbTypeByColumnTypeName = new Map(); | ||
const MAX_UINT32 = Math.pow(2, 32) - 1; | ||
@@ -149,3 +150,3 @@ // define class used for database types | ||
"DB_TYPE_INTERVAL_YM", "INTERVAL YEAR TO MONTH", | ||
{ oraTypeNum: 182 }); | ||
{ oraTypeNum: 182, bufferSizeFactor: 5 }); | ||
const DB_TYPE_JSON = new DbType(2027, | ||
@@ -344,2 +345,215 @@ "DB_TYPE_JSON", "JSON", | ||
// Represents the SparseVector. | ||
// indices must be an regular Array | ||
// values can be regular or typedArray. | ||
class SparseVector { | ||
constructor(input) { | ||
this._indices = new Uint32Array(0); | ||
this._values = new Float64Array(0); | ||
this._numDimensions = 0; | ||
if (!input) { | ||
return; | ||
} | ||
if (typeof input === 'object' && | ||
"numDimensions" in input && | ||
"indices" in input && | ||
"values" in input | ||
) { | ||
// Object has valid properties for Sparse. | ||
this._fromObject(input); | ||
} else if (typeof input === 'string') { | ||
// initialize from string. | ||
this._fromString(input); | ||
} else if (this._validDenseArray(input)) { | ||
// dense array | ||
this._fromDense(input); | ||
} else { | ||
errors.throwErr(errors.ERR_VECTOR_SPARSE_INVALID_INPUT); | ||
} | ||
} | ||
_validDenseArray(value) { | ||
return (value instanceof Float32Array || | ||
value instanceof Float64Array || | ||
value instanceof Int8Array || (Object.getPrototypeOf(value) | ||
=== Uint8Array.prototype) || Array.isArray(value)); | ||
} | ||
// Check if indexArray and valuesArray have the same length | ||
static _validateLengths(indices, values) { | ||
if (indices.length !== values.length) { | ||
if (!(values instanceof Uint8Array)) { | ||
// Skip for binary vector format | ||
errors.throwErr(errors.ERR_VECTOR_SPARSE_INDICES_VALUES_NOT_EQUAL); | ||
} | ||
} | ||
} | ||
_updateProperties(dims, indices, values) { | ||
if (!this._validDenseArray(values)) { | ||
errors.throwErr(errors.ERR_VECTOR_SPARSE_VALUES_IS_NOT_ARRAY); | ||
} | ||
if (!(indices instanceof Uint32Array) && !Array.isArray(indices)) { | ||
errors.throwErr(errors.ERR_VECTOR_SPARSE_INDICES_IS_NOT_ARRAY); | ||
} | ||
SparseVector._validateLengths(indices, values); | ||
if (!(typeof dims === 'number' && Number.isInteger(dims) && dims > 0)) { | ||
errors.throwErr(errors.ERR_VECTOR_SPARSE_DIMS_IS_NOT_INTEGER); | ||
} | ||
this._numDimensions = dims; | ||
this._indices = indices; | ||
this._values = values; | ||
this._convertToTypedArrays(); | ||
} | ||
_fromObject(input) { | ||
this._updateProperties(input.numDimensions, input.indices, input.values); | ||
} | ||
_convertToTypedArrays() { | ||
// convert to typed arrays. | ||
if (!(this._indices instanceof Uint32Array)) { | ||
// validate elements are valid uint32 type. | ||
const indices = new Uint32Array(this._indices.map((x, index) => { | ||
if (typeof x !== 'number' || !Number.isInteger(x)) { | ||
errors.throwErr(errors.ERR_VECTOR_SPARSE_INDICES_ELEM_IS_NOT_VALID, index); | ||
} | ||
if (x < 0 || x > MAX_UINT32 || x > (this.numDimensions - 1)) { | ||
errors.throwErr(errors.ERR_VECTOR_SPARSE_INDICES_ELEM_IS_NOT_VALID, | ||
index); | ||
} | ||
return x; | ||
})); | ||
this._indices = indices; | ||
} | ||
this._values = Array.isArray(this._values) ? new Float64Array(this._values) | ||
: this._values; | ||
} | ||
// Initialize the state using the dense array. | ||
// The length of input is assumed to be same as | ||
// dimensions of sparse Vector column. | ||
// values will be an array even if input is a typedArray. | ||
_fromDense(input) { | ||
this._indices = []; | ||
this._values = []; | ||
for (let i = 0; i < input.length; i++) { | ||
if (input[i] !== 0) { | ||
this._indices.push(i); | ||
this._values.push(input[i]); | ||
} | ||
} | ||
this._numDimensions = input.length; | ||
this._convertToTypedArrays(); | ||
} | ||
// parse a string input into a sparse vector | ||
_fromString(str) { | ||
let data; | ||
// verify it is a valid JSON | ||
try { | ||
// use simple tokenizer? | ||
data = JSON.parse(str); | ||
} catch (e) { | ||
errors.throwErr(errors.ERR_VECTOR_SPARSE_INVALID_JSON); | ||
} | ||
// Check if data is an array with exactly 3 elements | ||
if (!Array.isArray(data) || data.length !== 3) { | ||
errors.throwErr(errors.ERR_VECTOR_SPARSE_INVALID_STRING); | ||
} | ||
const [dims, indices, values] = data; | ||
this._updateProperties(dims, indices, values); | ||
} | ||
// Internal method to create an instance | ||
static create(sparseValue) { | ||
SparseVector._validateLengths(sparseValue.indices, sparseValue.values); | ||
const instance = Object.create(this.prototype); | ||
instance._numDimensions = sparseValue.numDimensions; | ||
instance._indices = sparseValue.indices; | ||
instance._values = sparseValue.values; | ||
return instance; | ||
} | ||
get indices() { | ||
return this._indices; | ||
} | ||
get values() { | ||
return this._values; | ||
} | ||
get numDimensions() { | ||
return this._numDimensions; | ||
} | ||
toJSON() { | ||
return { | ||
numDimensions: this._numDimensions, | ||
indices: this._indices, | ||
values: this._values, | ||
}; | ||
} | ||
// It always constructs a typedArray. | ||
_createEmptyArray(input, len) { | ||
if (Array.isArray(input)) { | ||
return new Float64Array(len); | ||
} else { | ||
// same typedArray of input type. | ||
return new input.constructor(len); | ||
} | ||
} | ||
// Convert sparse vector to a dense vector | ||
// It returns typed array. | ||
dense() { | ||
if (this._numDimensions === 0) { | ||
return null; | ||
} | ||
const dense = this._createEmptyArray(this._values, this._numDimensions); | ||
this._indices.forEach((index, i) => { | ||
dense[index] = this._values[i]; | ||
}); | ||
return dense; | ||
} | ||
} | ||
// Interval Year-to-Month Class | ||
class IntervalYM { | ||
constructor(obj) { | ||
if (obj) { | ||
errors.assertParamPropInt(obj, 1, "years"); | ||
errors.assertParamPropInt(obj, 1, "months"); | ||
} | ||
this.years = obj?.years || 0; | ||
this.months = obj?.months || 0; | ||
} | ||
} | ||
// Interval Day-to-Second Class | ||
class IntervalDS { | ||
constructor(obj) { | ||
if (obj) { | ||
errors.assertParamPropInt(obj, 1, "days"); | ||
errors.assertParamPropInt(obj, 1, "hours"); | ||
errors.assertParamPropInt(obj, 1, "minutes"); | ||
errors.assertParamPropInt(obj, 1, "seconds"); | ||
errors.assertParamPropInt(obj, 1, "fseconds"); | ||
} | ||
this.days = obj?.days || 0; | ||
this.hours = obj?.hours || 0; | ||
this.minutes = obj?.minutes || 0; | ||
this.seconds = obj?.seconds || 0; | ||
this.fseconds = obj?.fseconds || 0; | ||
} | ||
} | ||
module.exports = { | ||
@@ -382,3 +596,6 @@ DbType, | ||
getTypeByOraTypeNum, | ||
JsonId | ||
JsonId, | ||
SparseVector, | ||
IntervalYM, | ||
IntervalDS | ||
}; |
@@ -504,3 +504,3 @@ // Copyright (c) 2016, 2023, Oracle and/or its affiliates. | ||
value instanceof Int8Array || (Object.getPrototypeOf(value) | ||
=== Uint8Array.prototype)); | ||
=== Uint8Array.prototype) || value instanceof types.SparseVector); | ||
} | ||
@@ -507,0 +507,0 @@ |
@@ -33,5 +33,5 @@ // Copyright (c) 2023, 2025, Oracle and/or its affiliates. | ||
VERSION_MAJOR: 6, | ||
VERSION_MINOR: 7, | ||
VERSION_PATCH: 2, | ||
VERSION_MINOR: 8, | ||
VERSION_PATCH: 0, | ||
VERSION_SUFFIX: '' | ||
}; |
@@ -1,2 +0,2 @@ | ||
Copyright (c) 2015, 2024 Oracle and/or its affiliates. | ||
Copyright (c) 2015, 2025 Oracle and/or its affiliates. | ||
@@ -3,0 +3,0 @@ This software is dual-licensed to you under the Universal Permissive License |
@@ -1,1 +0,1 @@ | ||
Copyright (c) 2015, 2024, Oracle and/or its affiliates. | ||
Copyright (c) 2015, 2025, Oracle and/or its affiliates. |
{ | ||
"name": "oracledb", | ||
"version": "6.7.2", | ||
"version": "6.8.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.7.2 | ||
# node-oracledb version 6.8.0 | ||
@@ -7,3 +7,3 @@ The node-oracledb add-on for Node.js powers high performance Oracle Database | ||
Use node-oracledb 6.7.2 to connect Node.js 14.6, or later, to Oracle | ||
Use node-oracledb 6.8.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. |
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
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
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
4266306
118
28800
21