Dwrite commented on code in PR #5108:
URL: https://github.com/apache/calcite/pull/5108#discussion_r3789578522
##########
core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java:
##########
@@ -1608,6 +1630,77 @@ public static SqlNode toSql(@Nullable RexProgram
program, RexLiteral literal) {
}
}
+ /** Converts a {@link RexLiteral} in the context of a {@link RexProgram}
+ * to a {@link SqlNode}, preserving the literal's type.
+ *
+ * <p>The SQL text of a literal does not always imply the literal's type:
+ * {@code 1} parses as INTEGER even if the literal's type is TINYINT, and
+ * {@code NULL} loses its type entirely. This method wraps such literals in
+ * a CAST that makes the type explicit; {@code dialect} supplies the SQL
+ * syntax of the CAST target type. */
+ public static SqlNode toSql(@Nullable RexProgram program, RexLiteral literal,
+ SqlDialect dialect) {
+ switch (literal.getTypeName()) {
+ case ROW:
+ // Cast the fields rather than the ROW call, because few dialects can
+ // parse a cast to a ROW type.
+ //noinspection unchecked
+ final List<RexLiteral> list =
castNonNull(literal.getValueAs(List.class));
+ return SqlStdOperatorTable.ROW.createCall(POS,
+ list.stream().map(e -> toSql(program, e, dialect))
+ .collect(toImmutableList()));
+
+ case SYMBOL:
+ case SARG:
+ return toSql(program, literal);
+
+ default:
+ final SqlNode node = toSql(program, literal);
+ // A result that is not a SqlLiteral is already a CAST; for example
+ // NaN becomes CAST('NaN' AS DOUBLE).
+ return node instanceof SqlLiteral
+ ? castIfTypeAmbiguous((SqlLiteral) node, literal.getType(), dialect)
+ : node;
+ }
+ }
+
+ /** Wraps a literal in a CAST to {@code type} if the type that the
+ * validator would infer for the literal's SQL text differs from
+ * {@code type}. */
+ private static SqlNode castIfTypeAmbiguous(SqlLiteral literal, RelDataType
type,
+ SqlDialect dialect) {
+ switch (type.getSqlTypeName()) {
+ case NULL:
+ case ANY:
+ case UNKNOWN:
+ // No valid SQL syntax for casts to these types
Review Comment:
for NULL/ANY/UNKNOWN we just return the literal as-is since there's no valid
CAST syntax. Are these types actually reachable for a RexLiteral here, or is
this purely defensive? Also, does the round-trip test suite cover a bare
top-level NULL literal (not nested in a ROW) to confirm we're not silently
losing type info on that path?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]