I am not sure this is only a problem with dynamic parameters; I haven't noticed 
any code that enforces CHAR(N) limits at runtime, but maybe I haven't looked 
carefully enough. There are certainly known problems related to CHAR(N): 
https://issues.apache.org/jira/browse/CALCITE-4493

Mihai

________________________________
From: Chris Dennis <[email protected]>
Sent: Tuesday, July 29, 2025 12:07 PM
To: [email protected] <[email protected]>
Subject: Dynamic parameter typing & code generation

I’m trying to figure out if the following test represents an error in the rel 
graph generation, the enumerable code generation, or just a grey area in the 
SQL spec/Calcite implementation:

  @Test void bindCharParameter() {
    final String sql = "select * from (values ('a'), ('b')) as tab (foo) where 
foo = ?";
    CalciteAssert.that()
        .query(sql)
        .convertMatches(root -> {
          RelNodes.findRex(root, RexUtil.find(SqlKind.EQUALS), null, (rel, rex) 
-> {
            ((RexCall) ((Filter) rel).getCondition()).getOperands().forEach(o 
-> {
              assertThat(o.getType().getPrecision(), is(1));
            });
          });
        })
        .consumesPreparedStatement(p -> {
          p.setString(1, "a");
        })
        .returnsUnordered("FOO=a")
        .consumesPreparedStatement(p -> {
          p.setString(1, "aa");
        })
        .returnsUnordered("");
  }

In the test above the Rel graph generated from the query types both the column 
‘foo’ and the RelDynamicParam as CHAR(1). The code generated by Calcite however 
treats the values passed through the prepared statement as simple Java Strings 
of arbitrary length. This means the second invocation returns no rows. Is this 
correct? Would it also be correct for an implementation of the query to 
truncate the value of the dynamic parameter to one character before performing 
the comparison, and thereby return a non-empty result set?

Thanks,

Chris


Reply via email to