Hi all, I've opened PR #18962 [1]. It fixes a set of defects in the JDBC driver when it is used with the table model (sql_dialect=table). They came up while evaluating a Trino connector for IoTDB built on Trino's generic JDBC client (trino-base-jdbc), and most of them also affect generic tools such as DBeaver and DataGrip.
The changes are planned for 2.0.13. Several of them change behavior that existing applications may rely on, so I'd like to give everyone a heads-up before the PR is merged. 1. Incompatible changes DatabaseMetaData (table dialect only) - getTables() now returns TABLE_CAT as its first column, as the JDBC spec requires. Columns read by position shift by one; columns read by name are unaffected. - getTables() returns an empty ResultSet instead of null when nothing matches. - getTables() and getColumns() now honor tableNamePattern, columnNamePattern and types, which they used to ignore. A null pattern now means "no filter", as JDBC defines it; it used to become LIKE 'null' and match nothing. - TABLE_SCHEM and TABLE_NAME in getTables(), getColumns() and getPrimaryKeys() now hold the real database and table names. They used to echo the arguments, escape characters included (e.g. "sensor\_data"). - TABLE_CAT is NULL in all three results. It used to be "" in getColumns() and the schema argument in getPrimaryKeys(). - getColumns(): ORDINAL_POSITION restarts at 1 for each table (it kept counting across tables), and NULLABLE / IS_NULLABLE now depend on the TIME category instead of on a column being named "time". - getPrimaryKeys() matches the given names exactly instead of as LIKE patterns, and KEY_SEQ restarts for each table. - getColumns() reports OBJECT columns with DATA_TYPE java.sql.Types.OTHER (it was 0). Connection - getAutoCommit() returns true for new connections in both dialects; it used to return false. IoTDB has no transactions, so commit() and rollback() remain no-ops. - setReadOnly(true) no longer throws in either dialect. It records the hint, and isReadOnly() returns it; the connection is not actually made read-only. - getCatalog() returns null in the table dialect instead of "Apache IoTDB", and setCatalog(null) is ignored instead of throwing a NullPointerException. The tree dialect is unchanged. PreparedStatement (table dialect only) - setTimestamp() converts the value to the server's timestamp precision (ms/us/ns); it always sent milliseconds before. A value the precision cannot represent (e.g. nanoseconds after the year 2262) is rejected with an SQLException. - For non-query statements, whose parameters are substituted on the client: a "?" inside a quoted identifier or a comment is no longer treated as a parameter marker, and a backslash no longer escapes the next character (only a doubled quote does, as in the SQL grammar). NaN is written as 'NaN', which the server stores as NaN. +/-Infinity is rejected with an SQLException, because the server accepts no SQL form of it. - cancel() now sends the cancel request to the server. The server does not implement cancelOperation yet, so the call fails with an SQLException, as cancel() on a plain Statement already did. It used to be a silent no-op. ResultSet (both dialects) - getTimestamp() returns null for SQL NULL instead of 1970-01-01, and getTimestamp(String) now honors the timestamp precision. - ResultSetMetaData reports OBJECT columns with type name "OBJECT" and java.sql.Types.OTHER (it returned null and 0). 2. New features (compatible) - ResultSet.getObject(int, Class) and getObject(String, Class), for String, Boolean, Integer, Long, Float, Double, byte[], Timestamp and LocalDate. - PreparedStatement.setObject() in the table dialect accepts java.time.LocalDate. - Prepared executions send the statement's fetch size. - When information_schema cannot be queried (e.g. missing privileges), the SHOW/DESC fallback of getTables(), getColumns() and getPrimaryKeys() applies the same patterns. 3. Known limitation Statement.cancel() still cannot stop a running query. The server's cancelOperation RPC is not implemented, and the client serializes the RPCs of a connection, so a cancel from another thread waits for the running execute call. Fixing this needs server-side changes and will be handled separately. 4. Feedback wanted In the table dialect, table names have at most two parts (database.table), so the driver maps an IoTDB database to a JDBC schema and leaves the catalog empty. A few older APIs (getCatalogs(), setCatalog(), getCatalogTerm()) still treat a database as a catalog, and I'd like to align them with the schema mapping in a follow-up. If your tools or applications depend on the current behavior of any API above, please reply here or comment on the PR. [1] https://github.com/apache/iotdb/pull/18962 Best regards, ---------------- Yuan Tian
