Skip to content

Commit 08d4b6b

Browse files
committed
Validate sparse index array values
1 parent 29def58 commit 08d4b6b

File tree

4 files changed

+37
-17
lines changed

4 files changed

+37
-17
lines changed

examples/vectorSparse.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ async function run() {
166166
/ORA-51803:/
167167
);
168168

169-
const sparseQueryVec = new oracledb.SparseVector({ values: queryVector, indices: [2, 4], numDimensions: 4 });
169+
const sparseQueryVec = new oracledb.SparseVector({ values: queryVector, indices: [2, 3], numDimensions: 4 });
170170
console.log('vector distance with Query ', queryVector);
171171
console.log(await connection.execute(`select vector_distance (sparseF64, :1) from ${tableName}`, [sparseQueryVec]));
172172

lib/errors.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ const ERR_VECTOR_SPARSE_INDICES_VALUES_NOT_EQUAL = 161;
171171
const ERR_VECTOR_SPARSE_INVALID_JSON = 162;
172172
const ERR_VECTOR_SPARSE_INVALID_STRING = 163;
173173
const ERR_VECTOR_SPARSE_INVALID_INPUT = 164;
174+
const ERR_VECTOR_SPARSE_INDICES_ELEM_IS_NOT_VALID = 165;
174175

175176
// Oracle Net layer errors start from 500
176177
const ERR_CONNECTION_CLOSED = 500;
@@ -475,7 +476,7 @@ messages.set(ERR_OPERATION_ONLY_SUPPORTED_ON_BFILE, // NJS-156
475476
messages.set(ERR_EXECMANY_NOT_ALLOWED_ON_QUERIES, // NJS-157
476477
'executeMany() cannot be used with SELECT statement or WITH SQL clause');
477478
messages.set(ERR_VECTOR_SPARSE_INDICES_IS_NOT_ARRAY, // NJS-158
478-
'SPARSE VECTOR indices is not an Array');
479+
'SPARSE VECTOR indices is not Uint32Array or an Array');
479480
messages.set(ERR_VECTOR_SPARSE_VALUES_IS_NOT_ARRAY, // NJS-159
480481
'SPARSE VECTOR values is not an Array');
481482
messages.set(ERR_VECTOR_SPARSE_DIMS_IS_NOT_INTEGER, // NJS-160
@@ -488,6 +489,8 @@ messages.set(ERR_VECTOR_SPARSE_INVALID_STRING, // NJS-163
488489
'SPARSE VECTOR string data Array should have exactly 3 elements');
489490
messages.set(ERR_VECTOR_SPARSE_INVALID_INPUT, // NJS-164
490491
'SPARSE VECTOR Invalid Input Data');
492+
messages.set(ERR_VECTOR_SPARSE_INDICES_ELEM_IS_NOT_VALID, // NJS-165
493+
'SPARSE VECTOR indices element at index %d is not valid');
491494

492495
// Oracle Net layer errors
493496

@@ -937,6 +940,7 @@ module.exports = {
937940
ERR_VECTOR_SPARSE_INVALID_JSON,
938941
ERR_VECTOR_SPARSE_INVALID_STRING,
939942
ERR_VECTOR_SPARSE_INVALID_INPUT,
943+
ERR_VECTOR_SPARSE_INDICES_ELEM_IS_NOT_VALID,
940944
WRN_COMPILATION_CREATE,
941945
assert,
942946
assertArgCount,

lib/types.js

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const util = require('util');
3333
const dbTypeByNum = new Map();
3434
const dbTypeByOraTypeNum = new Map();
3535
const dbTypeByColumnTypeName = new Map();
36+
const MAX_UINT32 = Math.pow(2, 32) - 1;
3637

3738
// define class used for database types
3839
class DbType {
@@ -343,8 +344,6 @@ class JsonId extends Uint8Array {
343344
// indices must be an regular Array
344345
// values can be regular or typedArray.
345346
class SparseVector {
346-
// It also takes skipChecks which is made true for avoiding checks if
347-
// the SparseVector is constructed internally.
348347
constructor(input) {
349348
this._indices = new Uint32Array(0);
350349
this._values = new Float64Array(0);
@@ -353,25 +352,29 @@ class SparseVector {
353352
if (!input) {
354353
return;
355354
}
356-
if (typeof input === 'string') {
355+
if (typeof input === 'object' &&
356+
"numDimensions" in input &&
357+
"indices" in input &&
358+
"values" in input
359+
) {
360+
// Object has valid properties for Sparse.
361+
this._fromObject(input);
362+
} else if (typeof input === 'string') {
357363
// initialize from string.
358364
this._fromString(input);
359365
} else if (this._validDenseArray(input)) {
360366
// dense array
361367
this._fromDense(input);
362-
} else if (typeof input === 'object') {
363-
this._fromObject(input);
364368
} else {
365369
errors.throwErr(errors.ERR_VECTOR_SPARSE_INVALID_INPUT);
366370
}
367371
}
368372

369-
_validDenseArray(value, isIndices = false) {
370-
const valid = (value instanceof Float32Array ||
373+
_validDenseArray(value) {
374+
return (value instanceof Float32Array ||
371375
value instanceof Float64Array ||
372376
value instanceof Int8Array || (Object.getPrototypeOf(value)
373377
=== Uint8Array.prototype) || Array.isArray(value));
374-
return !isIndices ? valid : valid || value instanceof Uint32Array;
375378
}
376379

377380
// Check if indexArray and valuesArray have the same length
@@ -388,7 +391,7 @@ class SparseVector {
388391
if (!this._validDenseArray(values)) {
389392
errors.throwErr(errors.ERR_VECTOR_SPARSE_VALUES_IS_NOT_ARRAY);
390393
}
391-
if (!(this._validDenseArray(indices, true))) {
394+
if (!(indices instanceof Uint32Array) && !Array.isArray(indices)) {
392395
errors.throwErr(errors.ERR_VECTOR_SPARSE_INDICES_IS_NOT_ARRAY);
393396
}
394397
SparseVector._validateLengths(indices, values);
@@ -402,14 +405,27 @@ class SparseVector {
402405
this._convertToTypedArrays();
403406
}
404407

405-
_fromObject(input, skipChecks = false) {
406-
this._updateProperties(input.numDimensions, input.indices, input.values, skipChecks);
408+
_fromObject(input) {
409+
this._updateProperties(input.numDimensions, input.indices, input.values);
407410
}
408411

409412
_convertToTypedArrays() {
410413
// convert to typed arrays.
411-
this._indices = this._indices instanceof Uint32Array ? this._indices :
412-
new Uint32Array(this._indices);
414+
if (!(this._indices instanceof Uint32Array)) {
415+
// validate elements are valid uint32 type.
416+
const indices = new Uint32Array(this._indices.map((x, index) => {
417+
if (typeof x !== 'number' || !Number.isInteger(x)) {
418+
errors.throwErr(errors.ERR_VECTOR_SPARSE_INDICES_ELEM_IS_NOT_VALID, index);
419+
}
420+
if (x < 0 || x > MAX_UINT32 || x > (this.numDimensions - 1)) {
421+
errors.throwErr(errors.ERR_VECTOR_SPARSE_INDICES_ELEM_IS_NOT_VALID,
422+
index);
423+
}
424+
return x;
425+
}));
426+
this._indices = indices;
427+
}
428+
413429
this._values = Array.isArray(this._values) ? new Float64Array(this._values)
414430
: this._values;
415431
}
@@ -428,8 +444,8 @@ class SparseVector {
428444
this._values.push(input[i]);
429445
}
430446
}
431-
this._convertToTypedArrays();
432447
this._numDimensions = input.length;
448+
this._convertToTypedArrays();
433449
}
434450

435451
// parse a string input into a sparse vector

test/dataTypeJson.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ describe('244.dataTypeJson.js', function() {
217217
"key23": [new oracledb.SparseVector(
218218
{
219219
values: new Float64Array([-992.1, 994.3]),
220-
indices: new Uint8Array([0, 2]),
220+
indices: new Uint32Array([0, 2]),
221221
numDimensions: 4
222222
})]
223223
};

0 commit comments

Comments
 (0)