Comparing version 6.4.0 to 6.5.0
@@ -184,3 +184,3 @@ // Copyright (c) 2019, 2024, Oracle and/or its affiliates. | ||
const msgImpls = await this._impl.deq(1); | ||
if (msgImpls) | ||
if (msgImpls.length > 0) | ||
return this._makeMessage(msgImpls[0]); | ||
@@ -187,0 +187,0 @@ } |
@@ -203,2 +203,3 @@ // Copyright (c) 2016, 2024, Oracle and/or its affiliates. | ||
typeof value === 'boolean' || | ||
typeof value === 'bigint' || | ||
Array.isArray(value) || | ||
@@ -209,3 +210,3 @@ value instanceof Float32Array || | ||
Buffer.isBuffer(value) || | ||
util.isDate(value) || | ||
util.types.isDate(value) || | ||
value instanceof Lob || | ||
@@ -575,7 +576,4 @@ value instanceof ResultSet || | ||
// fetchArraySize must be a positive integer | ||
if (options.fetchArraySize !== undefined) { | ||
errors.assertParamPropValue(Number.isInteger(options.fetchArraySize) && | ||
options.fetchArraySize > 0, 3, "fetchArraySize"); | ||
outOptions.fetchArraySize = options.fetchArraySize; | ||
} | ||
errors.assertParamPropUnsignedIntNonZero(options, 3, "fetchArraySize"); | ||
outOptions.fetchArraySize = options.fetchArraySize; | ||
@@ -866,3 +864,3 @@ // fetchInfo must be an object with keys containing an object with a | ||
const encoder = new oson.OsonEncoder(); | ||
return encoder.encode(transformer.transformJsonValue(value)); | ||
return encoder.encode(transformer.transformJsonValue(value), this._impl._osonMaxFieldNameSize); | ||
} | ||
@@ -934,4 +932,4 @@ | ||
if (result.outBinds !== undefined) { | ||
for (const key in result.outBinds) { | ||
const val = this._transformOutBind(result.outBinds[key], options); | ||
for (const [key, value] of Object.entries(result.outBinds)) { | ||
const val = this._transformOutBind(value, options); | ||
result.outBinds[key] = val; | ||
@@ -945,6 +943,5 @@ } | ||
if (result.implicitResults) { | ||
for (const key in result.implicitResults) { | ||
const resultSetImpl = result.implicitResults[key]; | ||
for (const [key, impl] of Object.entries(result.implicitResults)) { | ||
const resultSet = new ResultSet(); | ||
resultSet._setup(this, resultSetImpl); | ||
resultSet._setup(this, impl); | ||
if (options.resultSet) { | ||
@@ -1005,4 +1002,4 @@ result.implicitResults[key] = resultSet; | ||
const outBind = result.outBinds[i]; | ||
for (const key in outBind) { | ||
outBind[key] = this._transformOutBind(outBind[key], options); | ||
for (const [key, value] of Object.entries(outBind)) { | ||
outBind[key] = this._transformOutBind(value, options); | ||
} | ||
@@ -1009,0 +1006,0 @@ } |
@@ -146,2 +146,4 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
const ERR_OBJECT_IS_NOT_A_COLLECTION = 146; | ||
const ERR_CURSOR_HAS_BEEN_CLOSED = 147; | ||
const ERR_DML_RETURNING_DUP_BINDS = 149; | ||
@@ -360,3 +362,3 @@ // Oracle Net layer errors start from 500 | ||
messages.set(ERR_OSON_FIELD_NAME_LIMITATION, // NJS-114 | ||
'OSON field names may not exceed 255 UTF-8 encoded bytes'); | ||
'OSON field names may not exceed %d UTF-8 encoded bytes'); | ||
messages.set(ERR_ORACLE_NUMBER_NO_REPR, // NJS-115 | ||
@@ -422,2 +424,6 @@ 'value cannot be represented as an Oracle Database number'); | ||
'object %s is not a collection'); | ||
messages.set(ERR_CURSOR_HAS_BEEN_CLOSED, // NJS-147 | ||
'cursor has been closed by the database'); | ||
messages.set(ERR_DML_RETURNING_DUP_BINDS, // NJS-149 | ||
'the bind variable placeholder "%s" cannot be used both before and after the RETURNING clause in a DML RETURNING statement'); | ||
@@ -550,2 +556,15 @@ // Oracle Net layer errors | ||
//----------------------------------------------------------------------------- | ||
// assertParamPropUnsignedIntNonZero() | ||
// | ||
// Asserts that the property value of a parameter is a positive integer value | ||
// (or undefined). | ||
//----------------------------------------------------------------------------- | ||
function assertParamPropUnsignedIntNonZero(obj, parameterNum, propName) { | ||
if (obj[propName] !== undefined) { | ||
assertParamPropValue(Number.isInteger(obj[propName]) && obj[propName] > 0, | ||
parameterNum, propName); | ||
} | ||
} | ||
//----------------------------------------------------------------------------- | ||
// assertParamPropString() | ||
@@ -646,3 +665,3 @@ // | ||
messages, but only in thin mode since this is done | ||
automatically in thick mode with Oracle Client 23c and higher | ||
automatically in thick mode with Oracle Client 23ai and higher | ||
*/ | ||
@@ -816,2 +835,4 @@ const settings = require('./settings.js'); | ||
ERR_OBJECT_IS_NOT_A_COLLECTION, | ||
ERR_CURSOR_HAS_BEEN_CLOSED, | ||
ERR_DML_RETURNING_DUP_BINDS, | ||
ERR_CONNECTION_CLOSED_CODE: `${ERR_PREFIX}-${ERR_CONNECTION_CLOSED}`, | ||
@@ -826,2 +847,3 @@ WRN_COMPILATION_CREATE, | ||
assertParamPropUnsignedInt, | ||
assertParamPropUnsignedIntNonZero, | ||
assertParamPropValue, | ||
@@ -828,0 +850,0 @@ assertParamValue, |
@@ -40,2 +40,3 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
this._requestQueue = []; | ||
this._osonMaxFieldNameSize = 255; | ||
} | ||
@@ -114,3 +115,3 @@ | ||
_isDate(val) { | ||
return (util.isDate(val)); | ||
return (util.types.isDate(val)); | ||
} | ||
@@ -117,0 +118,0 @@ |
@@ -38,6 +38,4 @@ // Copyright (c) 2024, Oracle and/or its affiliates. | ||
// vector flags | ||
TNS_VECTOR_FLAG_DIM_UINT8: 0x0001, | ||
TNS_VECTOR_FLAG_DIM_UINT32: 0x0002, | ||
TNS_VECTOR_FLAG_NORMSRC: 0x0040, | ||
TNS_VECTOR_FLAG_NORM: 0x0008, | ||
TNS_VECTOR_FLAG_NORMSRC: 0x0010, | ||
TNS_VECTOR_FLAG_NORM: 0x0002, | ||
@@ -48,3 +46,4 @@ // base JSON constants | ||
TNS_JSON_MAGIC_BYTE_3: 0x5a, // 'Z' | ||
TNS_JSON_VERSION: 1, | ||
TNS_JSON_VERSION_MAX_FNAME_255: 1, | ||
TNS_JSON_VERSION_MAX_FNAME_65535: 3, | ||
TNS_JSON_FLAG_HASH_ID_UINT8: 0x0100, | ||
@@ -61,2 +60,3 @@ TNS_JSON_FLAG_HASH_ID_UINT16: 0x0200, | ||
TNS_JSON_FLAG_IS_SCALAR: 0x10, | ||
TNS_JSON_FLAG_SEC_FNAMES_SEG_UINT16: 0x100, | ||
@@ -85,2 +85,3 @@ // JSON data types | ||
TNS_JSON_TYPE_VECTOR: 0x01, | ||
TNS_JSON_TYPE_ID: 0x7e, | ||
@@ -87,0 +88,0 @@ // timezone offsets |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2023, Oracle and/or its affiliates. | ||
// Copyright (c) 2023, 2024, Oracle and/or its affiliates. | ||
@@ -39,3 +39,3 @@ //----------------------------------------------------------------------------- | ||
/** | ||
* Class used for decodeing | ||
* Class used for decoding | ||
*/ | ||
@@ -56,2 +56,3 @@ class OsonDecoder extends BaseBuffer { | ||
let container, offsetsPos, fieldIdsPos; | ||
const containerOffset = this.pos - this.treeSegPos - 1; | ||
let numChildren = this._getNumChildren(nodeType); | ||
@@ -91,3 +92,6 @@ const isObject = ((nodeType & 0x40) === 0); | ||
this.pos = offsetsPos; | ||
const offset = this._getOffset(nodeType); | ||
let offset = this._getOffset(nodeType); | ||
if (this.relativeOffsets) { | ||
offset += containerOffset; | ||
} | ||
offsetsPos = this.pos; | ||
@@ -149,2 +153,7 @@ this.pos = this.treeSegPos + offset; | ||
return parseFloat(this.readOracleNumber()); | ||
} else if (nodeType === constants.TNS_JSON_TYPE_ID) { | ||
const buf = this.readBytes(this.readUInt8()); | ||
const jsonId = new types.JsonId(buf.length); | ||
buf.copy(jsonId); | ||
return jsonId; | ||
} else if (nodeType === constants.TNS_JSON_TYPE_BINARY_LENGTH_UINT16) { | ||
@@ -224,2 +233,42 @@ return Buffer.from(this.readBytes(this.readUInt16BE())); | ||
//--------------------------------------------------------------------------- | ||
// _getFieldNames | ||
// | ||
// Reads the field names from the buffer. | ||
//--------------------------------------------------------------------------- | ||
_getFieldNames(arrStartPos, numFields, offsetsSize, fieldNamesSegSize, fieldNamesSize) { | ||
// skip the hash id array (1 byte * fieldNamesSize for each field) | ||
this.skipBytes(numFields * fieldNamesSize); | ||
// skip the field name offsets array for now | ||
const offsetsPos = this.pos; | ||
this.skipBytes(numFields * offsetsSize); | ||
const ptr = this.readBytes(fieldNamesSegSize); | ||
const finalPos = this.pos; | ||
// determine the names of the fields | ||
this.pos = offsetsPos; | ||
let offset; | ||
for (let i = arrStartPos; i < arrStartPos + numFields; i++) { | ||
if (offsetsSize === 2) { | ||
offset = this.readUInt16BE(); | ||
} else { | ||
offset = this.readUInt32BE(); | ||
} | ||
// get the field name object | ||
let temp; | ||
if (fieldNamesSize === 1) { | ||
// Short Field Name | ||
temp = ptr.readUInt8(offset); | ||
} else { | ||
// Long Field Name | ||
temp = ptr.readUInt16BE(offset); | ||
} | ||
this.fieldNames[i] = ptr.subarray(offset + fieldNamesSize, offset + temp + fieldNamesSize).toString(); | ||
} | ||
this.pos = finalPos; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// decode() | ||
@@ -240,10 +289,12 @@ // | ||
const version = this.readUInt8(); | ||
if (version !== constants.TNS_JSON_VERSION) { | ||
if (version !== constants.TNS_JSON_VERSION_MAX_FNAME_255 && | ||
version !== constants.TNS_JSON_VERSION_MAX_FNAME_65535) { | ||
errors.throwErr(errors.ERR_OSON_VERSION_NOT_SUPPORTED, version); | ||
} | ||
const flags = this.readUInt16BE(); | ||
const primaryFlags = this.readUInt16BE(); | ||
this.relativeOffsets = primaryFlags & constants.TNS_JSON_FLAG_REL_OFFSET_MODE; | ||
// scalar values are much simpler | ||
if (flags & constants.TNS_JSON_FLAG_IS_SCALAR) { | ||
if (flags & constants.TNS_JSON_FLAG_TREE_SEG_UINT32) { | ||
if (primaryFlags & constants.TNS_JSON_FLAG_IS_SCALAR) { | ||
if (primaryFlags & constants.TNS_JSON_FLAG_TREE_SEG_UINT32) { | ||
this.skipBytes(4); | ||
@@ -256,27 +307,42 @@ } else { | ||
// determine the number of field names | ||
let numFieldNames; | ||
if (flags & constants.TNS_JSON_FLAG_NUM_FNAMES_UINT32) { | ||
numFieldNames = this.readUInt32BE(); | ||
// determine the number of short field names | ||
let numShortFieldNames; | ||
if (primaryFlags & constants.TNS_JSON_FLAG_NUM_FNAMES_UINT32) { | ||
numShortFieldNames = this.readUInt32BE(); | ||
this.fieldIdLength = 4; | ||
} else if (flags & constants.TNS_JSON_FLAG_NUM_FNAMES_UINT16) { | ||
numFieldNames = this.readUInt16BE(); | ||
} else if (primaryFlags & constants.TNS_JSON_FLAG_NUM_FNAMES_UINT16) { | ||
numShortFieldNames = this.readUInt16BE(); | ||
this.fieldIdLength = 2; | ||
} else { | ||
numFieldNames = this.readUInt8(); | ||
numShortFieldNames = this.readUInt8(); | ||
this.fieldIdLength = 1; | ||
} | ||
// determine the size of the field names segment | ||
let fieldNameOffsetsSize, fieldNamesSegSize; | ||
if (flags & constants.TNS_JSON_FLAG_FNAMES_SEG_UINT32) { | ||
fieldNameOffsetsSize = 4; | ||
fieldNamesSegSize = this.readUInt32BE(); | ||
// determine the size of the short field names segment | ||
let shortFieldNameOffsetsSize, shortFieldNamesSegSize; | ||
if (primaryFlags & constants.TNS_JSON_FLAG_FNAMES_SEG_UINT32) { | ||
shortFieldNameOffsetsSize = 4; | ||
shortFieldNamesSegSize = this.readUInt32BE(); | ||
} else { | ||
fieldNameOffsetsSize = 2; | ||
fieldNamesSegSize = this.readUInt16BE(); | ||
shortFieldNameOffsetsSize = 2; | ||
shortFieldNamesSegSize = this.readUInt16BE(); | ||
} | ||
// if the version indicates that field names > 255 bytes exist, parse | ||
// the information about that segment | ||
let longFieldNameOffsetsSize, longFieldNamesSegSize; | ||
let numLongFieldNames = 0; | ||
if (version === constants.TNS_JSON_VERSION_MAX_FNAME_65535) { | ||
const secondaryFlags = this.readUInt16BE(); | ||
if (secondaryFlags & constants.TNS_JSON_FLAG_SEC_FNAMES_SEG_UINT16) { | ||
longFieldNameOffsetsSize = 2; | ||
} else { | ||
longFieldNameOffsetsSize = 4; | ||
} | ||
numLongFieldNames = this.readUInt32BE(); | ||
longFieldNamesSegSize = this.readUInt32BE(); | ||
} | ||
// skip the size of the tree segment | ||
if (flags & constants.TNS_JSON_FLAG_TREE_SEG_UINT32) { | ||
if (primaryFlags & constants.TNS_JSON_FLAG_TREE_SEG_UINT32) { | ||
this.skipBytes(4); | ||
@@ -290,33 +356,14 @@ } else { | ||
// skip the hash id array | ||
let hashIdSize; | ||
if (flags & constants.TNS_JSON_FLAG_HASH_ID_UINT8) { | ||
hashIdSize = 1; | ||
} else if (flags & constants.TNS_JSON_FLAG_HASH_ID_UINT16) { | ||
hashIdSize = 2; | ||
} else { | ||
hashIdSize = 4; | ||
this.fieldNames = new Array(numShortFieldNames + numLongFieldNames); | ||
// if there are any short names, read them now | ||
if (numShortFieldNames > 0) { | ||
this._getFieldNames(0, numShortFieldNames, | ||
shortFieldNameOffsetsSize, shortFieldNamesSegSize, 1); | ||
} | ||
this.skipBytes(numFieldNames * hashIdSize); | ||
// skip over the field name offsets and field names | ||
let fieldNameOffsetsPos = this.pos; | ||
this.skipBytes(numFieldNames * fieldNameOffsetsSize); | ||
const fieldNamesPos = this.pos; | ||
this.skipBytes(fieldNamesSegSize); | ||
// determine the names of the fields | ||
this.fieldNames = new Array(numFieldNames); | ||
for (let i = 0; i < numFieldNames; i++) { | ||
let offset = fieldNamesPos; | ||
if (flags & constants.TNS_JSON_FLAG_FNAMES_SEG_UINT32) { | ||
offset += this.buf.readUInt32BE(fieldNameOffsetsPos); | ||
fieldNameOffsetsPos += 4; | ||
} else { | ||
offset += this.buf.readUInt16BE(fieldNameOffsetsPos); | ||
fieldNameOffsetsPos += 2; | ||
} | ||
const len = this.buf[offset]; | ||
const name = this.buf.subarray(offset + 1, offset + len + 1).toString(); | ||
this.fieldNames[i] = name; | ||
// if there are any long names, read them now | ||
if (numLongFieldNames > 0) { | ||
this._getFieldNames(numShortFieldNames, numLongFieldNames, | ||
longFieldNameOffsetsSize, longFieldNamesSegSize, 2); | ||
} | ||
@@ -335,14 +382,18 @@ | ||
constructor(name) { | ||
constructor(name, maxFieldNameSize) { | ||
this.name = name; | ||
this.nameBytes = Buffer.from(name); | ||
if (this.nameBytes.length > 255) { | ||
errors.throwErr(errors.ERR_OSON_FIELD_NAME_LIMITATION); | ||
if (this.nameBytes.length > maxFieldNameSize) { | ||
errors.throwErr(errors.ERR_OSON_FIELD_NAME_LIMITATION, maxFieldNameSize); | ||
} | ||
this.hashId = BigInt(0x811C9DC5); | ||
const multiplier = BigInt(16777619); | ||
const mask = BigInt(0xffffffff); | ||
// BigInt constants for calculating Hash ID for the OSON Field Name | ||
const INITIAL_HASHID = 0x811C9DC5n; | ||
const HASH_MULTIPLIER = 16777619n; | ||
const HASH_MASK = 0xffffffffn; | ||
this.hashId = INITIAL_HASHID; | ||
for (let i = 0; i < this.nameBytes.length; i++) { | ||
const c = BigInt(this.nameBytes[i]); | ||
this.hashId = ((this.hashId ^ c) * multiplier) & mask; | ||
this.hashId = ((this.hashId ^ c) * HASH_MULTIPLIER) & HASH_MASK; | ||
} | ||
@@ -356,37 +407,21 @@ this.hashId = Number(this.hashId) & 0xff; | ||
constructor(value) { | ||
constructor() { | ||
super(); | ||
this.fieldNamesMap = new Map(); | ||
this.fieldNames = []; | ||
this._examineNode(value); | ||
this._processFieldNames(); | ||
} | ||
//--------------------------------------------------------------------------- | ||
// _exmaineNode() | ||
// addName() | ||
// | ||
// Examines the value. If it contains fields, unique names are retained. The | ||
// values are then examined to see if they also contain fields. Arrays are | ||
// examined to determine they contain elements that contain fields. | ||
// Adds a name to the field names segment. | ||
//--------------------------------------------------------------------------- | ||
_examineNode(value) { | ||
if (Array.isArray(value)) { | ||
for (const element of value) { | ||
this._examineNode(element); | ||
} | ||
} else if (value && Array.isArray(value.fields)) { | ||
for (let i = 0; i < value.fields.length; i++) { | ||
const name = value.fields[i]; | ||
const element = value.values[i]; | ||
if (!this.fieldNamesMap.has(name)) { | ||
const fieldName = new OsonFieldName(name); | ||
this.fieldNamesMap.set(name, fieldName); | ||
this.fieldNames.push(fieldName); | ||
fieldName.offset = this.pos; | ||
this.writeUInt8(fieldName.nameBytes.length); | ||
this.writeBytes(fieldName.nameBytes); | ||
} | ||
this._examineNode(element); | ||
} | ||
addName(fieldName) { | ||
fieldName.offset = this.pos; | ||
if (fieldName.nameBytes.length <= 255) { | ||
this.writeUInt8(fieldName.nameBytes.length); | ||
} else { | ||
this.writeUInt16BE(fieldName.nameBytes.length); | ||
} | ||
this.writeBytes(fieldName.nameBytes); | ||
this.fieldNames.push(fieldName); | ||
} | ||
@@ -399,3 +434,3 @@ | ||
//--------------------------------------------------------------------------- | ||
_processFieldNames() { | ||
_processFieldNames(fieldIdOffset) { | ||
this.fieldNames.sort((a, b) => { | ||
@@ -417,3 +452,3 @@ if (a.hashId < b.hashId) | ||
for (let i = 0; i < this.fieldNames.length; i++) { | ||
this.fieldNames[i].fieldId = i + 1; | ||
this.fieldNames[i].fieldId = fieldIdOffset + i + 1; | ||
} | ||
@@ -438,3 +473,3 @@ if (this.fieldNames.length < 256) { | ||
//--------------------------------------------------------------------------- | ||
_encodeArray(value, fnamesSeg) { | ||
_encodeArray(value, encoder) { | ||
this._encodeContainer(constants.TNS_JSON_TYPE_ARRAY, value.length); | ||
@@ -447,3 +482,3 @@ const len = value.length * 4; | ||
offsetsBufPos += 4; | ||
this.encodeNode(element, fnamesSeg); | ||
this.encodeNode(element, encoder); | ||
} | ||
@@ -480,15 +515,15 @@ } | ||
//--------------------------------------------------------------------------- | ||
_encodeObject(value, fnamesSeg) { | ||
_encodeObject(value, encoder) { | ||
const numChildren = value.values.length; | ||
this._encodeContainer(constants.TNS_JSON_TYPE_OBJECT, numChildren); | ||
const len = numChildren * (fnamesSeg.fieldIdSize + 4); | ||
const pos = this.reserveBytes(len); | ||
let fieldIdOffset = pos; | ||
let valueOffset = pos + (numChildren * fnamesSeg.fieldIdSize); | ||
let fieldIdOffset = this.pos; | ||
let valueOffset = this.pos + (numChildren * encoder.fieldIdSize); | ||
const finalOffset = valueOffset + numChildren * 4; | ||
this.reserveBytes(finalOffset - this.pos); | ||
for (let i = 0; i < value.fields.length; i++) { | ||
const fieldName = fnamesSeg.fieldNamesMap.get(value.fields[i]); | ||
if (fnamesSeg.fieldIdSize == 1) { | ||
const fieldName = encoder.fieldNamesMap.get(value.fields[i]); | ||
if (encoder.fieldIdSize == 1) { | ||
this.buf[fieldIdOffset] = fieldName.fieldId; | ||
} else if (fnamesSeg.fieldIdSize == 2) { | ||
} else if (encoder.fieldIdSize == 2) { | ||
this.buf.writeUInt16BE(fieldName.fieldId, fieldIdOffset); | ||
@@ -499,5 +534,5 @@ } else { | ||
this.buf.writeUInt32BE(this.pos, valueOffset); | ||
fieldIdOffset += fnamesSeg.fieldIdSize; | ||
fieldIdOffset += encoder.fieldIdSize; | ||
valueOffset += 4; | ||
this.encodeNode(value.values[i], fnamesSeg); | ||
this.encodeNode(value.values[i], encoder); | ||
} | ||
@@ -511,3 +546,3 @@ } | ||
//--------------------------------------------------------------------------- | ||
encodeNode(value, fnamesSeg) { | ||
encodeNode(value, encoder) { | ||
@@ -549,3 +584,3 @@ // handle null | ||
// handle dates | ||
} else if (util.isDate(value)) { | ||
} else if (util.types.isDate(value)) { | ||
if (value.getUTCMilliseconds() === 0) { | ||
@@ -572,3 +607,3 @@ this.writeUInt8(constants.TNS_JSON_TYPE_TIMESTAMP7); | ||
} else if (Array.isArray(value)) { | ||
this._encodeArray(value, fnamesSeg); | ||
this._encodeArray(value, encoder); | ||
@@ -584,5 +619,10 @@ // handle vectors | ||
} else if (value instanceof types.JsonId) { | ||
this.writeUInt8(constants.TNS_JSON_TYPE_ID); | ||
this.writeUInt8(value.length); | ||
this.writeBytes(Buffer.from(value.buffer)); | ||
// handle objects | ||
} else { | ||
this._encodeObject(value, fnamesSeg); | ||
this._encodeObject(value, encoder); | ||
} | ||
@@ -594,5 +634,117 @@ | ||
/** | ||
* Class used for encoding | ||
*/ | ||
class OsonEncoder extends GrowableBuffer { | ||
//--------------------------------------------------------------------------- | ||
// _addFieldName() | ||
// | ||
// Add a field with the given name. | ||
//--------------------------------------------------------------------------- | ||
_addFieldName(name) { | ||
const fieldName = new OsonFieldName(name, this.maxFieldNameSize); | ||
this.fieldNamesMap.set(name, fieldName); | ||
if (fieldName.nameBytes.length <= 255) { | ||
this.shortFieldNamesSeg.addName(fieldName); | ||
} else { | ||
if (!this.longFieldNamesSeg) { | ||
this.longFieldNamesSeg = new OsonFieldNamesSegment(); | ||
} | ||
this.longFieldNamesSeg.addName(fieldName); | ||
} | ||
} | ||
//--------------------------------------------------------------------------- | ||
// _examineNode() | ||
// | ||
// Examines the value. If it contains fields, unique names are retained. The | ||
// values are then examined to see if they also contain fields. Arrays are | ||
// examined to determine they contain elements that contain fields. | ||
//--------------------------------------------------------------------------- | ||
_examineNode(value) { | ||
if (Array.isArray(value)) { | ||
for (const element of value) { | ||
this._examineNode(element); | ||
} | ||
} else if (value && Array.isArray(value.fields)) { | ||
for (let i = 0; i < value.fields.length; i++) { | ||
const name = value.fields[i]; | ||
const element = value.values[i]; | ||
if (!this.fieldNamesMap.has(name)) { | ||
this._addFieldName(name); | ||
} | ||
this._examineNode(element); | ||
} | ||
} | ||
} | ||
//--------------------------------------------------------------------------- | ||
// _writeExtendedHeader() | ||
// | ||
// Write the extended header containing information about the short and long | ||
// field name segments. | ||
//--------------------------------------------------------------------------- | ||
_writeExtendedHeader() { | ||
// write number of short field names | ||
if (this.fieldIdSize === 1) { | ||
this.writeUInt8(this.shortFieldNamesSeg.fieldNames.length); | ||
} else if (this.fieldIdSize === 2) { | ||
this.writeUInt16BE(this.shortFieldNamesSeg.fieldNames.length); | ||
} else { | ||
this.writeUInt32BE(this.shortFieldNamesSeg.fieldNames.length); | ||
} | ||
// write size of short field names segment | ||
if (this.shortFieldNamesSeg.pos < 65536) { | ||
this.writeUInt16BE(this.shortFieldNamesSeg.pos); | ||
} else { | ||
this.writeUInt32BE(this.shortFieldNamesSeg.pos); | ||
} | ||
// write fields for long field names segment, if applicable | ||
if (this.longFieldNamesSeg) { | ||
let secondaryFlags = 0; | ||
if (this.longFieldNamesSeg.pos < 65536) { | ||
secondaryFlags = constants.TNS_JSON_FLAG_SEC_FNAMES_SEG_UINT16; | ||
} | ||
this.writeUInt16BE(secondaryFlags); | ||
this.writeUInt32BE(this.longFieldNamesSeg.fieldNames.length); | ||
this.writeUInt32BE(this.longFieldNamesSeg.pos); | ||
} | ||
} | ||
//--------------------------------------------------------------------------- | ||
// _writeFieldNamesSeg() | ||
// | ||
// Write the contents of the field names segment to the buffer. | ||
//--------------------------------------------------------------------------- | ||
_writeFieldNamesSeg(fieldNamesSeg) { | ||
// write array of hash ids | ||
for (const fieldName of fieldNamesSeg.fieldNames) { | ||
if (fieldName.nameBytes.length <= 255) { | ||
this.writeUInt8(fieldName.hashId); | ||
} else { | ||
this.writeUInt16BE(fieldName.hashId); | ||
} | ||
} | ||
// write array of field name offsets for the short field names | ||
for (const fieldName of fieldNamesSeg.fieldNames) { | ||
if (fieldNamesSeg.pos < 65536) { | ||
this.writeUInt16BE(fieldName.offset); | ||
} else { | ||
this.writeUInt32BE(fieldName.offset); | ||
} | ||
} | ||
// write field names | ||
if (fieldNamesSeg.pos > 0) { | ||
this.writeBytes(fieldNamesSeg.buf.subarray(0, fieldNamesSeg.pos)); | ||
} | ||
} | ||
//--------------------------------------------------------------------------- | ||
// encode() | ||
@@ -602,26 +754,51 @@ // | ||
//--------------------------------------------------------------------------- | ||
encode(value) { | ||
encode(value, maxFieldNameSize) { | ||
// determine flags to use | ||
let fnamesSeg; | ||
this.maxFieldNameSize = maxFieldNameSize; | ||
// determine the flags to use | ||
let flags = constants.TNS_JSON_FLAG_INLINE_LEAF; | ||
if (Array.isArray(value) || (value && Array.isArray(value.fields))) { | ||
// examine all values recursively to determine the unique set of field | ||
// names and whether they need to be added to the long field names | ||
// segment (> 255 bytes) or short field names segment (<= 255 bytes) | ||
this.fieldNamesMap = new Map(); | ||
this.shortFieldNamesSeg = new OsonFieldNamesSegment(); | ||
this._examineNode(value); | ||
// perform processing of field names segments and determine the total | ||
// number of unique field names in the value | ||
let totalNumFieldNames = 0; | ||
if (this.shortFieldNamesSeg) { | ||
this.shortFieldNamesSeg._processFieldNames(0); | ||
totalNumFieldNames += this.shortFieldNamesSeg.fieldNames.length; | ||
} | ||
if (this.longFieldNamesSeg) { | ||
this.longFieldNamesSeg._processFieldNames(totalNumFieldNames); | ||
totalNumFieldNames += this.longFieldNamesSeg.fieldNames.length; | ||
} | ||
// determine remaining flags and field id size | ||
flags |= constants.TNS_JSON_FLAG_HASH_ID_UINT8 | | ||
constants.TNS_JSON_FLAG_TINY_NODES_STAT; | ||
fnamesSeg = new OsonFieldNamesSegment(value); | ||
if (fnamesSeg.fieldNames.length > 65535) { | ||
if (totalNumFieldNames > 65535) { | ||
flags |= constants.TNS_JSON_FLAG_NUM_FNAMES_UINT32; | ||
} else if (fnamesSeg.fieldNames.length > 255) { | ||
this.fieldIdSize = 4; | ||
} else if (totalNumFieldNames > 255) { | ||
flags |= constants.TNS_JSON_FLAG_NUM_FNAMES_UINT16; | ||
this.fieldIdSize = 2; | ||
} else { | ||
this.fieldIdSize = 1; | ||
} | ||
if (fnamesSeg.pos > 65535) { | ||
if (this.shortFieldNamesSeg.pos > 65535) { | ||
flags |= constants.TNS_JSON_FLAG_FNAMES_SEG_UINT32; | ||
} | ||
} else { | ||
// if the value is a simple scalar | ||
flags |= constants.TNS_JSON_FLAG_IS_SCALAR; | ||
} | ||
// encode values into the tree segment | ||
// encode values into the OSON tree segment | ||
const treeSeg = new OsonTreeSegment(); | ||
treeSeg.encodeNode(value, fnamesSeg); | ||
treeSeg.encodeNode(value, this); | ||
if (treeSeg.pos > 65535) { | ||
@@ -635,24 +812,12 @@ flags |= constants.TNS_JSON_FLAG_TREE_SEG_UINT32; | ||
this.writeUInt8(constants.TNS_JSON_MAGIC_BYTE_3); | ||
this.writeUInt8(constants.TNS_JSON_VERSION); | ||
if (this.longFieldNamesSeg) { | ||
this.writeUInt8(constants.TNS_JSON_VERSION_MAX_FNAME_65535); | ||
} else { | ||
this.writeUInt8(constants.TNS_JSON_VERSION_MAX_FNAME_255); | ||
} | ||
this.writeUInt16BE(flags); | ||
// write extended header (when value is not scalar) | ||
if (fnamesSeg) { | ||
// write number of field names | ||
if (fnamesSeg.fieldNames.length < 256) { | ||
this.writeUInt8(fnamesSeg.fieldNames.length); | ||
} else if (fnamesSeg.fieldNames.length < 65536) { | ||
this.writeUInt16BE(fnamesSeg.fieldNames.length); | ||
} else { | ||
this.writeUInt32BE(fnamesSeg.fieldNames.length); | ||
} | ||
// write size of field names segment | ||
if (fnamesSeg.pos < 65536) { | ||
this.writeUInt16BE(fnamesSeg.pos); | ||
} else { | ||
this.writeUInt32BE(fnamesSeg.pos); | ||
} | ||
if (this.shortFieldNamesSeg) { | ||
this._writeExtendedHeader(); | ||
} | ||
@@ -668,3 +833,3 @@ | ||
// write remainder of header and any data (when value is not scalar) | ||
if (fnamesSeg) { | ||
if (this.shortFieldNamesSeg) { | ||
@@ -674,21 +839,7 @@ // write number of "tiny" nodes (always zero) | ||
// write array of hash ids | ||
for (const fieldName of fnamesSeg.fieldNames) { | ||
this.writeUInt8(fieldName.hashId); | ||
// write the field names segments | ||
this._writeFieldNamesSeg(this.shortFieldNamesSeg); | ||
if (this.longFieldNamesSeg) { | ||
this._writeFieldNamesSeg(this.longFieldNamesSeg); | ||
} | ||
// write array of field name offsets | ||
for (const fieldName of fnamesSeg.fieldNames) { | ||
if (fnamesSeg.pos < 65536) { | ||
this.writeUInt16BE(fieldName.offset); | ||
} else { | ||
this.writeUInt32BE(fieldName.offset); | ||
} | ||
} | ||
// write field names | ||
if (fnamesSeg.pos > 0) { | ||
this.writeBytes(fnamesSeg.buf.subarray(0, fnamesSeg.pos)); | ||
} | ||
} | ||
@@ -695,0 +846,0 @@ |
@@ -57,10 +57,3 @@ // Copyright (c) 2024, Oracle and/or its affiliates. | ||
const vectorFormat = this.readUInt8(); | ||
let numElements; | ||
if (flags & constants.TNS_VECTOR_FLAG_DIM_UINT8) { | ||
numElements = this.readUInt8(); | ||
} else if (flags & constants.TNS_VECTOR_FLAG_DIM_UINT32) { | ||
numElements = this.readUInt32BE(); | ||
} else { | ||
numElements = this.readUInt16BE(); | ||
} | ||
const numElements = this.readUInt32BE(); | ||
let elementSize, result; | ||
@@ -121,10 +114,4 @@ if (vectorFormat === constants.VECTOR_FORMAT_FLOAT32) { | ||
// Let server generate the norm (TNS_VECTOR_FLAG_NORMSRC) | ||
let flags = constants.TNS_VECTOR_FLAG_NORM | ||
const flags = constants.TNS_VECTOR_FLAG_NORM | ||
| constants.TNS_VECTOR_FLAG_NORMSRC; | ||
const numElements = value.length; | ||
if (numElements < 256) { | ||
flags |= constants.TNS_VECTOR_FLAG_DIM_UINT8; | ||
} else if (numElements > 65535) { | ||
flags |= constants.TNS_VECTOR_FLAG_DIM_UINT32; | ||
} | ||
@@ -136,9 +123,3 @@ // write header | ||
this.writeUInt8(vectorFormat); | ||
if (numElements < 256) { | ||
this.writeUInt8(numElements); | ||
} else if (numElements < 65536) { | ||
this.writeUInt16BE(numElements); | ||
} else { | ||
this.writeUInt32BE(numElements); | ||
} | ||
this.writeUInt32BE(value.length); | ||
this.reserveBytes(8); | ||
@@ -145,0 +126,0 @@ |
@@ -127,2 +127,12 @@ // Copyright (c) 2015, 2023, Oracle and/or its affiliates. | ||
function _isPrivilege(value) { | ||
// Privileges are mutually exclusive and cannot be specified together | ||
// except SYSPRELIM, which cannot be specified alone, it is specified in a | ||
// combo with SYSOPER or SYSDBA. SYSPRELIM is used only for | ||
// startup/shutdown | ||
// If SYSPRELIM specified, clear the bit | ||
if (value & constants.SYSPRELIM) { | ||
value = value ^ constants.SYSPRELIM; | ||
} | ||
return ( | ||
@@ -135,3 +145,2 @@ value === constants.SYSASM || | ||
value === constants.SYSOPER || | ||
value === constants.SYSPRELIM || | ||
value === constants.SYSRAC | ||
@@ -837,2 +846,3 @@ ); | ||
Connection, | ||
JsonId: types.JsonId, | ||
Lob, | ||
@@ -839,0 +849,0 @@ Pool, |
@@ -684,3 +684,3 @@ // Copyright (c) 2016, 2024, Oracle and/or its affiliates. | ||
errors.assertParamPropUnsignedInt(options, 1, "poolMin"); | ||
errors.assertParamPropUnsignedInt(options, 1, "poolMax"); | ||
errors.assertParamPropUnsignedIntNonZero(options, 1, "poolMax"); | ||
errors.assertParamPropUnsignedInt(options, 1, "poolMaxPerShard"); | ||
@@ -693,2 +693,8 @@ errors.assertParamPropUnsignedInt(options, 1, "poolIncrement"); | ||
// poolMax must be greater than or equal to poolMin | ||
if (options.poolMin > options.poolMax) { | ||
errors.throwErr(errors.ERR_INVALID_NUMBER_OF_CONNECTIONS, options.poolMax, | ||
options.poolMin); | ||
} | ||
// reconfiguration can happen only when status is OPEN | ||
@@ -695,0 +701,0 @@ this._checkPoolOpen(false); |
@@ -66,2 +66,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
this.fetchTypeHandler = undefined; | ||
this._JsonId = types.JsonId; | ||
} | ||
@@ -68,0 +69,0 @@ |
@@ -53,4 +53,2 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
const connectionCookies = new Map(); | ||
class ThinConnectionImpl extends ConnectionImpl { | ||
@@ -187,4 +185,11 @@ | ||
message.batchErrors = options.batchErrors; | ||
if (statement.isPlSql && statement.requiresFullExecute) { | ||
// if a PL/SQL statement requires a full execute, perform only a single | ||
// iteration in order to allow the determination of input/output binds | ||
// to be completed; after that, an execution of the remaining iterations | ||
// can be performed. | ||
if (statement.isPlSql && (statement.cursorId === 0 || | ||
statement.requiresFullExecute)) { | ||
message.numExecs = 1; | ||
message.noImplicitRelease = true; | ||
await this._protocol._processMessage(message); | ||
@@ -194,2 +199,3 @@ statement.requiresFullExecute = false; | ||
message.offset = 1; | ||
message.noImplicitRelease = false; | ||
} | ||
@@ -594,22 +600,2 @@ if (message.numExecs > 0) { | ||
//--------------------------------------------------------------------------- | ||
// getConnectionCookieByUUID() | ||
// | ||
// It fetches from map which keeps keyname as UUID+ServiceName. | ||
// UUID identifies the CDB instance and ServiceName identifies the | ||
// entity within a PDB which uniquely identifies a pdb instance. | ||
//--------------------------------------------------------------------------- | ||
getConnectionCookieByUUID(uuid) { | ||
let cookie; | ||
if (uuid) { | ||
const key = uuid + ((this.serviceName) ? this.serviceName : this.sid); | ||
cookie = connectionCookies.get(key); | ||
if (!cookie) { | ||
cookie = {}; | ||
connectionCookies.set(key, cookie); | ||
} | ||
} | ||
return cookie; | ||
} | ||
/** | ||
@@ -699,33 +685,20 @@ * | ||
try { | ||
const cookie = this.getConnectionCookieByUUID(this.nscon.dbUUID); | ||
this.nscon.dbUUID = null; | ||
const protocolMessage = new messages.ProtocolMessage(this); | ||
const dataTypeMessage = new messages.DataTypeMessage(this); | ||
const authMessage = new messages.AuthMessage(this, params); | ||
let sentCookie = false; | ||
if (cookie && cookie.populated) { | ||
const cookieMessage = new messages.ConnectionCookieMessage(this); | ||
cookieMessage.cookie = cookie; | ||
cookieMessage.protocolMessage = protocolMessage; | ||
cookieMessage.dataTypeMessage = dataTypeMessage; | ||
cookieMessage.authMessage = authMessage; | ||
await this._protocol._processMessage(cookieMessage); | ||
sentCookie = true; | ||
if (this.nscon.supportsFastAuth) { | ||
const fastAuthMessage = new messages.FastAuthMessage(this); | ||
fastAuthMessage.protocolMessage = protocolMessage; | ||
fastAuthMessage.dataTypeMessage = dataTypeMessage; | ||
fastAuthMessage.authMessage = authMessage; | ||
await this._protocol._processMessage(fastAuthMessage); | ||
if (fastAuthMessage.reNegotiate) { | ||
// Fast Authentication failed. | ||
await this._protocol._processMessage(dataTypeMessage); | ||
await this._protocol._processMessage(authMessage); | ||
} | ||
} else { | ||
await this._protocol._processMessage(protocolMessage); | ||
} | ||
if (!sentCookie || !cookie.populated) { | ||
await this._protocol._processMessage(dataTypeMessage); | ||
// Does OSESSKEY for non-token Authentication else OAUTH | ||
await this._protocol._processMessage(authMessage); | ||
if (cookie && !cookie.populated) { | ||
cookie.protocolVersion = protocolMessage.serverVersion; | ||
cookie.serverBanner = protocolMessage.serverBanner; | ||
cookie.charsetID = this._protocol.caps.charSetID; | ||
cookie.ncharsetID = this._protocol.caps.nCharsetId; | ||
cookie.flags = protocolMessage.serverFlags; | ||
cookie.compileCaps = Buffer.from(protocolMessage.serverCompileCaps); | ||
cookie.runtimeCaps = Buffer.from(protocolMessage.serverRunTimeCaps); | ||
cookie.populated = true; | ||
} | ||
} | ||
@@ -930,6 +903,4 @@ if (!params.token) { // non-token Authentication | ||
_getStatement(sql, cacheStatement = false) { | ||
if (this._drcpEstablishSession) { | ||
cacheStatement = false; | ||
} | ||
return this.statementCache.getStatement(sql, cacheStatement); | ||
return this.statementCache.getStatement(sql, cacheStatement, | ||
this._drcpEstablishSession); | ||
} | ||
@@ -1086,3 +1057,3 @@ | ||
getTransactionInProgress() { | ||
return this._protocol.txnInProgress === constants.TNS_TXN_IN_PROGRESS; | ||
return this._protocol.txnInProgress; | ||
} | ||
@@ -1089,0 +1060,0 @@ |
@@ -108,2 +108,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
this._isDRCPEnabled = false; | ||
this._implicitPool = null; | ||
this.eventEmitter = new EventEmitter(); | ||
@@ -389,7 +390,7 @@ // listener to remove dead or idle connections | ||
//--------------------------------------------------------------------------- | ||
// _getNumConns() | ||
// _getNumConnsToCreate() | ||
// | ||
// get number of connections need to be created | ||
//--------------------------------------------------------------------------- | ||
_getNumConns() { | ||
_getNumConnsToCreate() { | ||
const usedConns = this._freeConnectionList.length + this._usedConnectionList.size; | ||
@@ -420,7 +421,15 @@ // less connections in the pool than poolMin? restore to poolMin | ||
while (!this._poolCloseWaiter) { | ||
// get count for connections to be created | ||
const numConns = this._getNumConns(); | ||
// eliminate connections that exceed the poolMax (this should only happen | ||
// after a reconfiguration has taken place where the maximum number of | ||
// connections is reduced) | ||
let numToDestroy = this._poolMax - this.getConnectionsOpen(); | ||
while (numToDestroy > 0 && this._freeConnectionList.length > 0) { | ||
const connToBeRemoved = this._freeConnectionList.shift(); | ||
this.eventEmitter.emit('_removePoolConnection', connToBeRemoved); | ||
numToDestroy--; | ||
} | ||
const numToCreate = this._getNumConnsToCreate(); | ||
// connection creation is going on serially and not concurrently | ||
for (let i = 0; i < numConns; i++) { | ||
for (let i = 0; i < numToCreate; i++) { | ||
try { | ||
@@ -570,4 +579,10 @@ // get deobfuscated value | ||
conn._newSession = false; | ||
this._freeConnectionList.push(conn); | ||
if ((this._freeConnectionList.length + this._usedConnectionList.size) | ||
< this._poolMax) { | ||
this._freeConnectionList.push(conn); | ||
} else { | ||
this.eventEmitter.emit('_removePoolConnection', conn); | ||
} | ||
} | ||
this._setScheduler(); | ||
@@ -585,4 +600,45 @@ } | ||
} | ||
//--------------------------------------------------------------------------- | ||
// reconfigure() | ||
// | ||
// Reconfigures the pool with new parameters | ||
//--------------------------------------------------------------------------- | ||
reconfigure(params) { | ||
if (params.poolIncrement !== undefined) { | ||
this._poolIncrement = params.poolIncrement; | ||
} | ||
if (params.poolTimeout !== undefined && | ||
this._poolTimeout !== params.poolTimeout) { | ||
this._poolTimeout = params.poolTimeout; | ||
// clear scheduled job | ||
if (this._schedulerJob) { | ||
clearTimeout(this._schedulerJob); | ||
this._schedulerJob = null; | ||
} | ||
} | ||
if (params.poolPingInterval !== undefined) { | ||
this._poolPingInterval = params.poolPingInterval; | ||
} | ||
if (params.stmtCacheSize !== undefined) { | ||
this._stmtCacheSize = params.stmtCacheSize; | ||
} | ||
if (params.poolMax !== undefined) { | ||
this._poolMax = params.poolMax; | ||
} | ||
if (params.poolMin !== undefined) { | ||
this._poolMin = params.poolMin; | ||
} | ||
if (this.bgWaiter) { | ||
this.bgWaiter(); | ||
} | ||
} | ||
} | ||
module.exports = ThinPoolImpl; |
@@ -39,4 +39,4 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
constructor(protocolVersion) { | ||
this.protocolVersion = protocolVersion; | ||
constructor(nscon) { | ||
this.protocolVersion = nscon.sAtts.version; | ||
this.ttcFieldVersion = constants.TNS_CCAP_FIELD_VERSION_MAX; | ||
@@ -48,3 +48,3 @@ this.supports12cLogon = true; | ||
this.runtimeCaps = Buffer.alloc(constants.TNS_RCAP_MAX); | ||
this.initCompileCaps(); | ||
this.initCompileCaps(nscon); | ||
this.initRuntimeCaps(); | ||
@@ -54,3 +54,3 @@ this.maxStringSize = 0; | ||
adjustForServerCompileCaps(serverCaps) { | ||
adjustForServerCompileCaps(serverCaps, nscon) { | ||
if (serverCaps[constants.TNS_CCAP_FIELD_VERSION] < this.ttcFieldVersion) { | ||
@@ -61,2 +61,9 @@ this.ttcFieldVersion = serverCaps[constants.TNS_CCAP_FIELD_VERSION]; | ||
} | ||
if ((this.ttcFieldVersion < constants.TNS_CCAP_FIELD_VERSION_23_4 | ||
&& nscon.endOfRequestSupport)) { | ||
// endOfRequestSupport used only from 23.4 onwards and not for 23.3 | ||
this.compileCaps[constants.TNS_CCAP_TTC4] | ||
^= constants.TNS_CCAP_END_OF_REQUEST; | ||
nscon.endOfRequestSupport = false; | ||
} | ||
} | ||
@@ -72,3 +79,3 @@ | ||
initCompileCaps() { | ||
initCompileCaps(nscon) { | ||
this.compileCaps[constants.TNS_CCAP_SQL_VERSION] = | ||
@@ -112,2 +119,7 @@ constants.TNS_CCAP_SQL_VERSION_MAX; | ||
constants.TNS_CCAP_INBAND_NOTIFICATION; | ||
if (nscon.endOfRequestSupport) { | ||
this.compileCaps[constants.TNS_CCAP_TTC4] |= constants.TNS_CCAP_END_OF_REQUEST; | ||
} | ||
this.compileCaps[constants.TNS_CCAP_CTB_FEATURE_BACKPORT] = | ||
constants.TNS_CCAP_CTB_IMPLICIT_POOL; | ||
this.compileCaps[constants.TNS_CCAP_TTC5] = | ||
@@ -114,0 +126,0 @@ constants.TNS_CCAP_VECTOR_SUPPORT; |
@@ -436,3 +436,4 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
TNS_MSG_TYPE_RENEGOTIATE: 28, | ||
TNS_MSG_TYPE_COOKIE: 30, | ||
TNS_MSG_TYPE_END_OF_REQUEST: 29, | ||
TNS_MSG_TYPE_FAST_AUTH: 34, | ||
@@ -468,2 +469,3 @@ // parameter keyword numbers, | ||
TNS_EXEC_OPTION_BATCH_ERRORS: 0x80000, | ||
TNS_EXEC_OPTION_NO_IMPL_REL: 0x200000, | ||
@@ -563,2 +565,3 @@ // server side piggyback op codes | ||
TNS_CCAP_LOGON_TYPES: 4, | ||
TNS_CCAP_CTB_FEATURE_BACKPORT: 5, | ||
TNS_CCAP_FIELD_VERSION: 7, | ||
@@ -631,5 +634,7 @@ TNS_CCAP_SERVER_DEFINE_CONV: 8, | ||
TNS_CCAP_INBAND_NOTIFICATION: 0x04, | ||
TNS_CCAP_END_OF_REQUEST: 0x20, | ||
TNS_CCAP_CLIENT_FN_MAX: 12, | ||
TNS_CCAP_LOB2_QUASI: 0x01, | ||
TNS_CCAP_LOB2_2GB_PREFETCH: 0x04, | ||
TNS_CCAP_CTB_IMPLICIT_POOL: 0x08, | ||
TNS_CCAP_VECTOR_SUPPORT: 0x08, | ||
@@ -658,2 +663,6 @@ | ||
// end of call status flags | ||
TNS_EOCS_FLAGS_TXN_IN_PROGRESS: 0x00000002, | ||
TNS_EOCS_FLAGS_SESS_RELEASE: 0x00008000, | ||
// other constants | ||
@@ -668,5 +677,5 @@ TNS_ESCAPE_CHAR: 253, | ||
TNS_TDU: 65535, | ||
TNS_TXN_IN_PROGRESS: 0x00000002, | ||
TNS_MAX_CONNECT_DATA: 230, | ||
TNS_MAX_UROWID_LENGTH: 3950, | ||
TNS_SERVER_CONVERTS_CHARS: 0x01, // server does charset conversion | ||
@@ -744,4 +753,7 @@ // drcp release mode | ||
// Network Header flags for Data packet | ||
TNS_DATA_FLAGS_END_OF_REQUEST: 0x2000, | ||
TNS_BASE64_ALPHABET_ARRAY: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'), | ||
TNS_EXTENT_OID: Buffer.from('00000000000000000000000000010001', 'hex') | ||
}; |
@@ -184,3 +184,3 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
} | ||
buf.writeKeyValue("AUTH_TERMINAL", "unknown"); | ||
buf.writeKeyValue("AUTH_TERMINAL", cInfo.terminal); | ||
buf.writeKeyValue("AUTH_PROGRAM_NM", cInfo.program); | ||
@@ -187,0 +187,0 @@ buf.writeKeyValue("AUTH_MACHINE", cInfo.hostName); |
@@ -45,6 +45,5 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
this.flushOutBinds = false; | ||
this.endOfResponse = false; | ||
this.endToEndSeqNum = 0; | ||
this.errorOccurred = false; | ||
this.flushOutBinds = false; | ||
this.processedError = false; | ||
this.warning = undefined; | ||
@@ -165,3 +164,3 @@ } | ||
} | ||
this.processedError = true; | ||
this.endOfResponse = !this.connection.nscon.endOfRequestSupport; | ||
} | ||
@@ -183,6 +182,2 @@ | ||
hasMoreData(buf) { | ||
return buf.numBytesLeft() > 0 && !this.flushOutBinds; | ||
} | ||
decode(buf) { | ||
@@ -193,4 +188,4 @@ this.process(buf); | ||
process(buf) { | ||
this.endOfResponse = false; | ||
this.flushOutBinds = false; | ||
this.processedError = false; | ||
do { | ||
@@ -200,3 +195,3 @@ this.savePoint(buf); | ||
this.processMessage(buf, messageType); | ||
} while (this.hasMoreData(buf)); | ||
} while (!this.endOfResponse); | ||
} | ||
@@ -216,2 +211,3 @@ | ||
this.endToEndSeqNum = buf.readUB2(); | ||
this.endOfResponse = !this.connection.nscon.endOfRequestSupport; | ||
} else if (messageType === constants.TNS_MSG_TYPE_PARAMETER) { | ||
@@ -221,2 +217,4 @@ this.processReturnParameter(buf); | ||
this.processServerSidePiggyBack(buf); | ||
} else if (messageType === constants.TNS_MSG_TYPE_END_OF_REQUEST) { | ||
this.endOfResponse = true; | ||
} else { | ||
@@ -292,3 +290,3 @@ errors.throwErr(errors.ERR_UNEXPECTED_MESSAGE_TYPE, messageType, buf.pos, buf.packetNum); | ||
if (this.connection._drcpEstablishSession) { | ||
this.connection.statementCache.clearOpenCursors(); | ||
this.connection.statementCache.clearCursors(); | ||
} | ||
@@ -295,0 +293,0 @@ } |
@@ -51,2 +51,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
} | ||
this.endOfResponse = !this.connection.nscon.endOfRequestSupport; | ||
} else { | ||
@@ -53,0 +54,0 @@ super.processMessage(buf, messageType); |
@@ -71,2 +71,6 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
if (this.noImplicitRelease) { | ||
dmlOptions |= constants.TNS_EXEC_OPTION_NO_IMPL_REL; | ||
} | ||
if (!stmt.requiresDefine && !this.parseOnly && params) { | ||
@@ -78,3 +82,3 @@ numParams = params.length; | ||
} else if (!this.parseOnly && stmt.sql) { | ||
dmlOptions = constants.TNS_EXEC_OPTION_IMPLICIT_RESULTSET; | ||
dmlOptions |= constants.TNS_EXEC_OPTION_IMPLICIT_RESULTSET; | ||
options |= constants.TNS_EXEC_OPTION_EXECUTE; | ||
@@ -81,0 +85,0 @@ } |
@@ -31,2 +31,3 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
const MessageWithData = require("./withData.js"); | ||
const errors = require("../../../errors.js"); | ||
@@ -55,2 +56,5 @@ /** | ||
this.writeFunctionHeader(buf); | ||
if (this.statement.cursorId === 0) { | ||
errors.throwErr(errors.ERR_CURSOR_HAS_BEEN_CLOSED); | ||
} | ||
buf.writeUB4(this.statement.cursorId); | ||
@@ -57,0 +61,0 @@ buf.writeUB4(this.options.fetchArraySize); |
@@ -40,3 +40,3 @@ // Copyright (c) 2023, Oracle and/or its affiliates. | ||
const SessionReleaseMessage = require('./sessionRelease.js'); | ||
const ConnectionCookieMessage = require('./connectionCookie.js'); | ||
const FastAuthMessage = require('./fastAuth.js'); | ||
@@ -46,3 +46,3 @@ module.exports = { | ||
CommitMessage, | ||
ConnectionCookieMessage, | ||
FastAuthMessage, | ||
DataTypeMessage, | ||
@@ -49,0 +49,0 @@ ExecuteMessage, |
@@ -56,2 +56,3 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
this.processProtocolInfo(buf); | ||
this.endOfResponse = !this.connection.nscon.endOfRequestSupport; | ||
} else { | ||
@@ -79,3 +80,10 @@ super.processMessage(buf, messageType); | ||
this.serverCompileCaps = Buffer.from(serverCompileCaps); | ||
buf.caps.adjustForServerCompileCaps(this.serverCompileCaps); | ||
buf.caps.adjustForServerCompileCaps(this.serverCompileCaps, this.connection.nscon); | ||
// Set the maximum OSON field name size | ||
if (buf.caps.ttcFieldVersion >= constants.TNS_CCAP_FIELD_VERSION_23_1) { | ||
this.connection._osonMaxFieldNameSize = 65535; | ||
} else { | ||
this.connection._osonMaxFieldNameSize = 255; | ||
} | ||
} | ||
@@ -82,0 +90,0 @@ const serverRunTimeCaps = buf.readBytesWithLength(); |
@@ -88,2 +88,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
this.flushOutBinds = true; | ||
this.endOfResponse = true; | ||
} else if (messageType === constants.TNS_MSG_TYPE_ERROR) { | ||
@@ -96,6 +97,2 @@ this.processErrorInfo(buf); | ||
hasMoreData() { | ||
return !this.processedError && !this.flushOutBinds; | ||
} | ||
processErrorInfo(buf) { | ||
@@ -857,3 +854,3 @@ super.processErrorInfo(buf); | ||
} else if (oraTypeNum === constants.TNS_DATA_TYPE_JSON) { | ||
buf.writeOson(value); | ||
buf.writeOson(value, this.connection._osonMaxFieldNameSize); | ||
} else if (oraTypeNum === constants.TNS_DATA_TYPE_VECTOR) { | ||
@@ -860,0 +857,0 @@ buf.writeVector(value); |
@@ -38,2 +38,5 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
const TNS_BASE64_ALPHABET_ARRAY = Buffer.from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 'utf8'); | ||
const FAST_AUTH_END_OF_RPC_VALUE = 0x800; | ||
const FAST_AUTH_END_OF_RPC_OFFSET = 0x8; | ||
const MSG_TYPE_OFFSET = 11; | ||
@@ -294,4 +297,10 @@ /** | ||
async waitForPackets() { | ||
const packet = await this.nsi.recvPacket(); | ||
/** | ||
* Read packets from network. | ||
* If checkRequestBoundary is passed as true, it | ||
* would read all packets until end of request | ||
* boundary is seen in nwk header. | ||
*/ | ||
async waitForPackets(checkRequestBoundary = false) { | ||
let packet = await this.nsi.recvPacket(); | ||
if (!this.savedPackets) { | ||
@@ -303,2 +312,20 @@ this.savedPackets = [packet]; | ||
} | ||
if (checkRequestBoundary && this.nsi.endOfRequestSupport) { | ||
while (packet.type === constants.TNS_PACKET_TYPE_DATA) { | ||
// End Marker | ||
if ((packet.buf.readUInt16BE(8) & | ||
constants.TNS_DATA_FLAGS_END_OF_REQUEST)) { | ||
break; | ||
} | ||
// Single Byte 1D packet | ||
if (packet.buf.length === MSG_TYPE_OFFSET && | ||
packet.buf[MSG_TYPE_OFFSET - 1] === | ||
constants.TNS_MSG_TYPE_END_OF_REQUEST) { | ||
break; | ||
} | ||
packet = await this.nsi.recvPacket(); | ||
this.savedPackets.push(packet); | ||
} | ||
} | ||
this.startPacket(this.savedPackets[this.savedPacketPos++]); | ||
@@ -501,2 +528,6 @@ } | ||
this.startPacket(); | ||
} else { | ||
// Write End of RPC bit in last packet used only for fastAuth Message. | ||
this.buf.writeUInt16BE(FAST_AUTH_END_OF_RPC_VALUE, | ||
FAST_AUTH_END_OF_RPC_OFFSET); | ||
} | ||
@@ -552,5 +583,5 @@ if (!this.nsi.ntAdapter) { | ||
*/ | ||
writeOson(value) { | ||
writeOson(value, osonMaxFieldSize) { | ||
const encoder = new oson.OsonEncoder(); | ||
const buf = encoder.encode(value); | ||
const buf = encoder.encode(value, osonMaxFieldSize); | ||
this.writeQLocator(buf.length); | ||
@@ -557,0 +588,0 @@ this.writeBytesWithLength(buf); |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
@@ -52,3 +52,3 @@ //----------------------------------------------------------------------------- | ||
*/ | ||
this.caps = new Capabilities(conn.nscon.sAtts.version); | ||
this.caps = new Capabilities(conn.nscon); | ||
this.writeBuf = new WritePacket(conn.nscon, this.caps, this); | ||
@@ -71,7 +71,7 @@ this.readBuf = new ReadPacket(conn.nscon, this.caps); | ||
message.preProcess(); | ||
await this.readBuf.waitForPackets(); | ||
await this.readBuf.waitForPackets(true); | ||
while (true) { // eslint-disable-line | ||
if (this.nsi.isBreak) { | ||
await this.resetMessage(); | ||
delete this.readBuf.savedBuffers; | ||
delete this.readBuf.savedPackets; | ||
await this.readBuf.waitForPackets(); | ||
@@ -169,3 +169,8 @@ } | ||
} | ||
this.txnInProgress = message.callStatus & constants.TNS_TXN_IN_PROGRESS; | ||
this.txnInProgress = Boolean(message.callStatus & constants.TNS_EOCS_FLAGS_TXN_IN_PROGRESS); | ||
// processes the call status flags returned by the server. | ||
if (message.callStatus & constants.TNS_EOCS_FLAGS_SESS_RELEASE) { | ||
message.connection.statementCache.clearCursors(); | ||
} | ||
if (message.errorOccurred) { | ||
@@ -172,0 +177,0 @@ if (callTimeoutExpired) { |
@@ -55,26 +55,19 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
// obfuscate value and clear memory for Buffers as they are from Buffer pool | ||
// and are possible to stay longer | ||
// obfuscate value | ||
function setObfuscatedValue(value) { | ||
const buf = crypto.randomBytes(Buffer.byteLength(value)); | ||
const bytes = Buffer.from(value, 'utf8'); | ||
const len = Buffer.byteLength(value); | ||
const arr = []; | ||
for (let i = 0; i < len; i++) { | ||
arr.push(buf[i] ^ bytes[i]); | ||
const valueBytes = Buffer.from(value); | ||
const obfuscatedBytes = crypto.randomBytes(valueBytes.length); | ||
for (let i = 0; i < valueBytes.length; i++) { | ||
valueBytes[i] = obfuscatedBytes[i] ^ valueBytes[i]; | ||
} | ||
bytes.fill(0); | ||
return {obfuscatedValue: buf, value: arr}; | ||
return {obfuscatedValue: obfuscatedBytes, value: valueBytes}; | ||
} | ||
// returns the Deobfuscated value, after removing the obfuscation | ||
// returns the deobfuscated value, after removing the obfuscation | ||
// and clear memory of temporary Buffers coming from Buffer pool | ||
function getDeobfuscatedValue(value, obfuscatedValue) { | ||
const arr = []; | ||
for (let i = 0; i < value.length; i++) { | ||
arr.push(value[i] ^ obfuscatedValue[i]); | ||
function getDeobfuscatedValue(valueBytes, obfuscatedBytes) { | ||
const buf = Buffer.from(valueBytes); | ||
for (let i = 0; i < valueBytes.length; i++) { | ||
buf[i] = valueBytes[i] ^ obfuscatedBytes[i]; | ||
} | ||
const buf = Buffer.from(arr); | ||
arr.fill(0); | ||
const retVal = buf.toString(); | ||
@@ -81,0 +74,0 @@ buf.fill(0); |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
@@ -110,3 +110,4 @@ //----------------------------------------------------------------------------- | ||
TNS_VERSION_MINIMUM: 300, | ||
TNS_VERSION_MIN_UUID: 319, | ||
TNS_VERSION_MIN_DATA_FLAGS: 318, | ||
TNS_VERSION_MIN_END_OF_RESPONSE: 319, | ||
TNS_UUID_OFFSET: 45, | ||
@@ -147,2 +148,4 @@ | ||
NSGPCHKSCMD: 0x01000000, // Support for Poll and Check logic | ||
TNS_ACCEPT_FLAG_HAS_END_OF_REQUEST: 0x02000000, | ||
TNS_ACCEPT_FLAG_FAST_AUTH: 0x10000000, // Support Fast Auth | ||
@@ -149,0 +152,0 @@ /* Redirect packet */ |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
@@ -167,2 +167,3 @@ //----------------------------------------------------------------------------- | ||
const serviceTag = this.urlProps.get("SERVICE_TAG"); | ||
const poolBoundary = this.urlProps.get("POOL_BOUNDARY"); | ||
@@ -186,2 +187,4 @@ const parts = []; | ||
parts.push(`(CONNECTION_ID_PREFIX=${connectionIdPrefix})`); | ||
if (poolBoundary) | ||
parts.push(`(POOL_BOUNDARY=${poolBoundary})`); | ||
return `(CONNECT_DATA=${parts.join("")})`; | ||
@@ -216,6 +219,6 @@ } | ||
const addressLists = hostInfo.split(";"); | ||
for (const addressList in addressLists) { | ||
for (const addressList of addressLists) { | ||
let addressNodeCount = 0; | ||
const addressListBuilder = new Array(); | ||
for (const match of addressLists[addressList].matchAll(HOSTNAMES_PATTERN)) { | ||
for (const match of addressList.matchAll(HOSTNAMES_PATTERN)) { | ||
const hostnames = (match.groups.hostnames).split(','); | ||
@@ -226,4 +229,4 @@ let port = match.groups.port; | ||
} | ||
for (const hname in hostnames) { | ||
addressListBuilder.push(this.getAddrStr(hostnames[hname], port, protocol, proxyInfo)); | ||
for (const hname of hostnames) { | ||
addressListBuilder.push(this.getAddrStr(hname, port, protocol, proxyInfo)); | ||
addressNodeCount++; | ||
@@ -462,4 +465,5 @@ } | ||
aliasMap.set("connection_id_prefix", "CONNECTION_ID_PREFIX"); | ||
aliasMap.set("pool_boundary", "POOL_BOUNDARY"); | ||
return aliasMap; | ||
} | ||
}module.exports = EZConnectResolver; |
@@ -489,3 +489,3 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
addresses = await dnsPromises.lookup(this.host, options); | ||
for (const addr in addresses) { | ||
for (const addr of addresses) { | ||
const co = new ConnOption(); | ||
@@ -503,3 +503,3 @@ co.hostname = this.host; | ||
co.CNdata.push(this.toString()); | ||
co.host = addresses[addr].address; | ||
co.host = addr.address; | ||
co.addr = this.addr; | ||
@@ -782,3 +782,4 @@ cs.getcurrentDescription().addConnectOption(co); | ||
} | ||
const cid = `(CID=(PROGRAM=${cInfo.program})(HOST=${cInfo.hostName})(USER=${cInfo.userName}))`; | ||
const pgmName = "\"'" + cInfo.program + "'\""; | ||
const cid = `(CID=(PROGRAM=${pgmName})(HOST=${cInfo.hostName})(USER=${cInfo.userName}))`; | ||
cOpts[i].CNdata.push(NavSchemaObject.CD); | ||
@@ -785,0 +786,0 @@ cOpts[i].CNdata.push(this.connectData); |
@@ -62,3 +62,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
return [serverVal, connClass, svcname, poolPurity, sid, addressNode ]; | ||
return [serverVal, connClass, svcname, poolPurity, sid, addressNode]; | ||
} | ||
@@ -87,2 +87,8 @@ | ||
errors.throwErr(errors.ERR_TNS_ENTRY_NOT_FOUND, connStr, configDir ? configDir + '/tnsnames.ora' : process.env.TNS_ADMIN + '/tnsnames.ora'); | ||
if (resolvedVal.rhsType == 1) { | ||
const rString = resolvedVal.atom; | ||
if ((rString.indexOf(':') != -1) || (rString.indexOf('/') != -1)) { | ||
return new EzConnect(rString).getResolvedUrl(); | ||
} | ||
} | ||
resolvedVal = resolvedVal.getListElement(0); | ||
@@ -359,4 +365,9 @@ } | ||
Packet.AcceptPacket(packet, this.sAtts); | ||
this.dbUUID = packet.dbUUID; | ||
packet.dbUUID = null; | ||
if (this.sAtts.version >= constants.TNS_VERSION_MIN_END_OF_RESPONSE | ||
&& (packet.flags & constants.TNS_ACCEPT_FLAG_HAS_END_OF_REQUEST)) { | ||
this.endOfRequestSupport = true; | ||
} | ||
if (packet.flags & constants.TNS_ACCEPT_FLAG_FAST_AUTH) { | ||
this.supportsFastAuth = true; | ||
} | ||
break; | ||
@@ -363,0 +374,0 @@ case constants.NSPTRF: /* REFUSE */ |
@@ -249,7 +249,4 @@ // Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
/* UUID - CDB Instance ID */ | ||
if (sAtts.version >= constants.TNS_VERSION_MIN_UUID) { | ||
packet.dbUUID = packet.buf.subarray(constants.TNS_UUID_OFFSET, | ||
constants.TNS_UUID_OFFSET + 16); | ||
packet.dbUUID = packet.dbUUID.toString('base64'); | ||
if (sAtts.version >= constants.TNS_VERSION_MIN_DATA_FLAGS) { | ||
packet.flags = packet.buf.readUInt32BE(constants.NSPACFL2); | ||
} | ||
@@ -256,0 +253,0 @@ } |
@@ -31,2 +31,3 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
const constants = require('../constants'); | ||
const errors = require('../errors'); | ||
@@ -363,2 +364,3 @@ /** | ||
this.bufferRowCount = 0; | ||
this.pendingClear = false; | ||
this.statementType = constants.STMT_TYPE_UNKNOWN; | ||
@@ -500,2 +502,8 @@ } | ||
if (this.bindInfoDict.has(info.bindName)) { | ||
if (this.isReturning) { | ||
const origInfo = this.bindInfoDict.get(info.bindName)[0]; | ||
if (!origInfo.isReturnBind) { | ||
errors.throwErr(errors.ERR_DML_RETURNING_DUP_BINDS, name); | ||
} | ||
} | ||
this.bindInfoDict.get(info.bindName).push(info); | ||
@@ -534,4 +542,32 @@ } else { | ||
} | ||
//--------------------------------------------------------------------------- | ||
// _clearAllState | ||
// | ||
// clear all state associated with the cursor | ||
//--------------------------------------------------------------------------- | ||
_clearAllState() { | ||
this.cursorId = 0; | ||
this.requiresDefine = false; | ||
this.noPrefetch = false; | ||
this.requiresFullExecute = false; | ||
this.queryVars = []; | ||
this.numQueryVars = 0; | ||
this.bufferRowCount = 0; | ||
this.bufferRowIndex = 0; | ||
} | ||
//--------------------------------------------------------------------------- | ||
// _clearState | ||
// | ||
// clear some state associated with the cursor | ||
//--------------------------------------------------------------------------- | ||
_clearState() { | ||
this.cursorId = 0; | ||
this.requiresDefine = false; | ||
this.noPrefetch = false; | ||
this.requiresFullExecute = false; | ||
} | ||
} | ||
module.exports.Statement = Statement; |
@@ -74,3 +74,3 @@ // Copyright (c) 2024, Oracle and/or its affiliates. | ||
//--------------------------------------------------------------------------- | ||
//clearOpenCursors() { | ||
//clearCursors() { | ||
// Clears the list of open cursors and removes the list of cursors that | ||
@@ -80,14 +80,31 @@ // need to be closed. This is required when a DRCP session change has | ||
//--------------------------------------------------------------------------- | ||
clearOpenCursors() { | ||
clearCursors() { | ||
const newOpenCursors = new Set(); | ||
for (const stmt of this._openCursors) { | ||
stmt.cursorId = 0; | ||
if (stmt.inUse) { | ||
if (stmt.inUse || stmt.returnToCache) { | ||
stmt.pendingClear = true; | ||
newOpenCursors.add(stmt); | ||
} | ||
stmt._clearState(); | ||
} | ||
this._openCursors = newOpenCursors; | ||
this._cursorsToClose.clear(); | ||
} | ||
//--------------------------------------------------------------------------- | ||
//clearPendingState() { | ||
// Clears state for statment with pending clear flag set and not in use. | ||
// This will clear all state for open cursors. | ||
// Called after rows processing is completed. | ||
//--------------------------------------------------------------------------- | ||
clearPendingStatus() { | ||
for (const stmt of this._openCursors) { | ||
if (stmt.pendingClear && !stmt.inUse) { | ||
stmt._clearAllState(); | ||
stmt.pendingClear = false; | ||
} | ||
} | ||
} | ||
//--------------------------------------------------------------------------- | ||
// get_statement() | ||
@@ -99,10 +116,6 @@ // Get a statement from the statement cache, or prepare a new statement | ||
//--------------------------------------------------------------------------- | ||
getStatement(sql, cacheStatement = false) { | ||
getStatement(sql, cacheStatement = false, forceNew = false) { | ||
let stmt = null; | ||
if (sql) { | ||
stmt = this._cachedStatements.get(sql); | ||
if (!cacheStatement) { | ||
this._openCursors.add(stmt); | ||
this._cachedStatements.delete(sql); | ||
} | ||
} | ||
@@ -120,5 +133,12 @@ if (!stmt) { | ||
this._openCursors.add(stmt); | ||
} else if (stmt.inUse || !cacheStatement) { | ||
} else if (forceNew || stmt.inUse) { | ||
if (!cacheStatement) { | ||
this._addCursorToClose(stmt); | ||
this._cachedStatements.delete(sql); | ||
} | ||
stmt = stmt._copy(); | ||
this._openCursors.add(stmt); | ||
} else if (!cacheStatement) { | ||
this._cachedStatements.delete(sql); | ||
stmt.returnToCache = false; | ||
} else { | ||
@@ -128,2 +148,3 @@ this._cachedStatements.delete(sql); | ||
} | ||
this._openCursors.add(stmt); | ||
stmt.inUse = true; | ||
@@ -154,5 +175,7 @@ return stmt; | ||
statement.inUse = false; | ||
} else if (statement.cursorId !== 0) { | ||
} else { | ||
this._addCursorToClose(statement); | ||
} | ||
// clear all state for statement which is having flag set and not in use | ||
this.clearPendingStatus(); | ||
} | ||
@@ -159,0 +182,0 @@ |
@@ -1,2 +0,2 @@ | ||
// Copyright (c) 2022, 2023, Oracle and/or its affiliates. | ||
// Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
@@ -257,3 +257,3 @@ //----------------------------------------------------------------------------- | ||
checkCredentials, | ||
normalizePrivateKey | ||
normalizePrivateKey, | ||
}; |
@@ -92,3 +92,3 @@ // Copyright (c) 2023, 2024, Oracle and/or its affiliates. | ||
typeof value === 'boolean' || Buffer.isBuffer(value) || | ||
util.isDate(value) || nodbUtil.isVectorValue(value)) | ||
util.types.isDate(value) || nodbUtil.isVectorValue(value)) | ||
return value; | ||
@@ -109,2 +109,8 @@ | ||
// JsonId is a special type to represent autogenerated id | ||
// for SODA documents. | ||
if (value instanceof types.JsonId) { | ||
return value; | ||
} | ||
// all other objects are transformed to an object with two arrays (fields | ||
@@ -171,3 +177,3 @@ // and values) | ||
// handle numbers | ||
} else if (typeof value === 'number') { | ||
} else if (typeof value === 'number' || typeof value === 'bigint') { | ||
checkType(info, options, | ||
@@ -189,3 +195,3 @@ types.DB_TYPE_NUMBER, | ||
// handle dates | ||
} else if (util.isDate(value)) { | ||
} else if (util.types.isDate(value)) { | ||
checkType(info, options, | ||
@@ -192,0 +198,0 @@ types.DB_TYPE_TIMESTAMP, |
@@ -335,2 +335,9 @@ // Copyright (c) 2022, 2024, Oracle and/or its affiliates. | ||
// It abstracts the autogenerated SODA Document key. | ||
class JsonId extends Uint8Array { | ||
toJSON() { | ||
return (Buffer.from(this.buffer).toString('hex')); | ||
} | ||
} | ||
module.exports = { | ||
@@ -372,3 +379,4 @@ DbType, | ||
getTypeByNum, | ||
getTypeByOraTypeNum | ||
getTypeByOraTypeNum, | ||
JsonId | ||
}; |
@@ -234,3 +234,3 @@ // Copyright (c) 2016, 2023, Oracle and/or its affiliates. | ||
typeof element === 'number' || Buffer.isBuffer(element) || | ||
util.isDate(element); | ||
util.types.isDate(element); | ||
if (!ok) | ||
@@ -237,0 +237,0 @@ return false; |
@@ -33,5 +33,5 @@ // Copyright (c) 2023, 2024, Oracle and/or its affiliates. | ||
VERSION_MAJOR: 6, | ||
VERSION_MINOR: 4, | ||
VERSION_MINOR: 5, | ||
VERSION_PATCH: 0, | ||
VERSION_SUFFIX: '' | ||
}; |
{ | ||
"name": "oracledb", | ||
"version": "6.4.0", | ||
"version": "6.5.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.4.0 | ||
# node-oracledb version 6.5.0 | ||
@@ -7,3 +7,3 @@ The node-oracledb add-on for Node.js powers high performance Oracle Database | ||
Use node-oracledb 6.4.0 to connect Node.js 14.6, or later, to Oracle | ||
Use node-oracledb 6.5.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
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 4 instances 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
25125
3359856
9