Hi all,

I found an issue in the Java client's handling of the tree-model time
column. The fix is open as:

- Master: https://github.com/apache/iotdb/pull/17408

Bug description
---------------

In the tree model, a result set's time pseudo-column is addressed by a
negative TsBlock column index. getLong, getString and getObject handle
that and return the timestamp. getBoolean, getInt, getFloat, getDouble
and getBinary do not: they reach TsBlock.getColumn(-1) and throw

java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 3

getDate is affected as well, since it delegates to getInt.

Root cause
----------

- isNull(index, rowNum) is "index >= 0 && ...", so it returns false
for the time column. Execution therefore enters the value branch
rather than the null branch.
- The five strictly-typed ByTsBlockColumnIndex getters have no
tsBlockColumnIndex < 0 guard before that point, unlike getLong and
getString, which handle the negative index explicitly.

Why this matters beyond the exception type
------------------------------------------

java.sql.ResultSet.getInt and its siblings declare "throws SQLException",
and IoTDBJDBCResultSet only catches StatementExecutionException. The
ArrayIndexOutOfBoundsException is unchecked, so it crosses the JDBC
boundary uncaught and a caller writing the documented
"catch (SQLException)" cannot handle it.

The Session API is affected the same way: SessionDataSet.DataIterator
returns ioTDBRpcDataSet.getInt(columnIndex) directly, so the exception
propagates unwrapped there too.

The fix
-------

- A tsBlockColumnIndex < 0 guard in the five strictly-typed getters,
throwing StatementExecutionException, placed after checkRecord() and
before isNull(...).
- Messages routed through RpcMessages in both en and zh rather than
string literals.
- A regression test in IoTDBJDBCResultSetTest. Against master
(219332dacb8) it fails with the exception above; it asserts that the
time column surfaces as SQLException rather than merely that something
was thrown.

Relation to the C++ client
--------------------------

The same defect in the C++ client was fixed in #17400, approved by
@jt2594838 and merged on 2026-04-01. This change uses the same five
getters, the same guard position, and the same five message texts, so a
user meeting this through either client sees the same message.

I would rather state one thing than let it be assumed: that review does
not settle the Java side. @CritasWang wrote there that a fast-fail
exception "aligns perfectly with our Java client which typically throws
IndexOutOfBoundsException or ClassCastException for mismatched types on
the Time column" -- that is, the current Java behaviour was cited as the
model for the C++ change, and it was described accurately. So the
argument above has to stand on the JDBC contract on its own. It is a new
argument rather than a decision already taken, and an objection to it is
welcome.

Status
------

The PR was opened on 2026-03-31 and has had no review since. @HTHou
suggested the list back in April for exactly this reason and I did not
follow up, which was my mistake. At the time of writing the branch also
has twelve workflow runs sitting at action_required and no CI has ever
run on it, so an approval there would help.

Thanks,
Zihan Dai

Reply via email to