mihaibudiu commented on code in PR #5108:
URL: https://github.com/apache/calcite/pull/5108#discussion_r3791043113


##########
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:
   I would expect the NULL case is reachable, e.g., in a query like `SELECT 
NULL`, which is legal.
   There are actually about 500+ round-trip tests added: the subclass 
`RelToSqlConverterRoundTripTest` runs almost every test from 
`RelToSqlConverterTest`. There are several tests that contain a `SELECT NULL` 
pattern.



-- 
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]

Reply via email to