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

Reply via email to