zzwqqq commented on code in PR #4942:
URL: https://github.com/apache/calcite/pull/4942#discussion_r3295979604
##########
core/src/main/java/org/apache/calcite/rex/RexBuilder.java:
##########
@@ -877,6 +887,116 @@ public RexNode makeCast(
return makeAbstractCast(pos, type, exp, safe, format);
}
+ private @Nullable RexNode makeCastForTemporalLiteral(
+ SqlParserPos pos,
+ RelDataType type,
+ RexLiteral literal,
+ boolean matchNullability,
+ boolean safe,
+ RexLiteral format) {
+ if (!format.isNull()) {
+ return null;
+ }
+ if (SqlTypeUtil.isCharacter(literal.getType())) {
+ return makeCastFromCharacterLiteralToTemporal(
+ pos, type, literal, matchNullability, safe, format);
+ }
+ if (SqlTypeUtil.isCharacter(type)) {
+ return makeCastFromTemporalLiteralToCharacter(type, literal);
+ }
+ return null;
+ }
+
+ private @Nullable RexNode makeCastFromCharacterLiteralToTemporal(
+ SqlParserPos pos,
+ RelDataType type,
+ RexLiteral literal,
+ boolean matchNullability,
+ boolean safe,
+ RexLiteral format) {
+ final NlsString nlsString = literal.getValueAs(NlsString.class);
+ if (nlsString == null) {
+ return null;
+ }
+ final String value = nlsString.getValue().trim();
+ final RexNode temporalLiteral;
+ try {
+ switch (type.getSqlTypeName()) {
+ case TIME:
+ final SqlTimeLiteral timeLiteral =
+ SqlParserUtil.parseTimeLiteral(value, pos);
+ if (!isExactFractionalSecondLiteral(timeLiteral, value)) {
+ return null;
+ }
+ final TimeString time =
+ requireNonNull(timeLiteral.getValueAs(TimeString.class),
+ "timeLiteral.getValueAs(TimeString.class)");
+ temporalLiteral = makeTimeLiteral(time, type.getPrecision());
+ break;
+ case TIMESTAMP:
+ final SqlTimestampLiteral timestampLiteral =
+ SqlParserUtil.parseTimestampLiteral(value, pos);
+ if (!isExactFractionalSecondLiteral(timestampLiteral, value)) {
+ return null;
+ }
+ final TimestampString timestamp =
+ requireNonNull(timestampLiteral.getValueAs(TimestampString.class),
+ "timestampLiteral.getValueAs(TimestampString.class)");
+ temporalLiteral = makeTimestampLiteral(timestamp, type.getPrecision());
+ break;
+ default:
+ return null;
+ }
+ } catch (RuntimeException e) {
+ return safe ? makeNullLiteral(type) : null;
+ }
+ if (type.isNullable()
+ && !temporalLiteral.getType().isNullable()
+ && matchNullability) {
+ return makeAbstractCast(pos, type, temporalLiteral, safe, format);
+ }
+ return temporalLiteral;
+ }
+
+ private @Nullable RexNode makeCastFromTemporalLiteralToCharacter(
+ RelDataType type,
+ RexLiteral literal) {
+ // Format temporal literals directly so they do not go through generated
+ // code, whose TIME/TIMESTAMP runtime values have millisecond precision.
+ final String value;
+ final int precision = literal.getType().getPrecision();
+ switch (literal.getType().getSqlTypeName()) {
+ case TIME:
+ final TimeString time = literal.getValueAs(TimeString.class);
+ if (time == null) {
+ return null;
+ }
+ value = time.toString(precision);
+ break;
+ case TIMESTAMP:
+ final TimestampString timestamp =
literal.getValueAs(TimestampString.class);
+ if (timestamp == null) {
+ return null;
+ }
+ value = timestamp.toString(precision);
+ break;
+ default:
+ return null;
+ }
+ // Replace the CAST with a character literal only if the formatted temporal
+ // value fits in the target type; otherwise leave the CAST unchanged.
+ return SqlTypeUtil.comparePrecision(type.getPrecision(), value.length())
>= 0
+ ? makeLiteral(value, type, true)
+ : null;
+ }
+
+ private static boolean isExactFractionalSecondLiteral(
Review Comment:
Added a short JavaDoc. This checks that the parsed literal has explicit
fractional-second precision and still formats back to the original string.
--
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]