Skip to content

QueryBinder.bindIdSet throws on undefined/null entries in the id array #9530

Description

@anmolshres98

Summary

QueryBinder.bindIdSet throws when the id array contains undefined/null entries, e.g. bindIdSet(1, ["0x1", undefined, "0x2"]). the legacy ECSqlStatement.bindIdSet (native binder) silently drops such entries instead, so code migrating from withPreparedStatement/ECSqlStatement to withQueryReader/QueryBinder (see #9463) can crash on inputs that used to work fine.

Repro

const qb = new QueryBinder();
qb.bindIdSet(1, ["0x1", undefined, "0x2"]);

throws:

TypeError: Cannot read properties of undefined (reading 'length')
    at Object.isId64 (core/bentley/.../Id.js)
    at Object.isValidId64 (core/bentley/.../Id.js)
    at compressIds (core/bentley/.../CompressedId64Set.js)
    at compressArray
    at sortAndCompress
    at QueryBinder.bindIdSet (core/common/.../ConcurrentQuery.js)

Same crash reachable via withQueryReader/InVirtualSet using an id array bound through QueryBinder.

Root cause

QueryBinder.bindIdSet (core/common/src/ConcurrentQuery.ts) passes the raw array directly to CompressedId64Set.sortAndCompress, which calls Id64.isValidId64 on every entry. isValidId64 reads .length on the value, which throws for undefined/null instead of returning false.

Verified against the native implementation (iTwin/imodel-native, iModelJsNodeAddon/IModelJsNative.cpp, NativeECSqlBinder::BindIdSet): it uses the REQUIRE_ARGUMENT_STRING_ARRAY macro, which silently skips any non-string array entry before building the native IdSet. That's why the same input works through ECSqlStatement.bindIdSet but crashes through QueryBinder.bindIdSet.

-- created w/ help from AnmolDroid 🤖

Metadata

Metadata

Assignees

Labels

ecdbECDb and ECSQL related issues

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions