mihaibudiu commented on code in PR #4942:
URL: https://github.com/apache/calcite/pull/4942#discussion_r3295460430
##########
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(
Review Comment:
This needs JavaDoc, particularly because it returns null on many paths.
You would not expect that result from the function name.
##########
core/src/main/java/org/apache/calcite/util/BuiltInMethod.java:
##########
@@ -784,8 +779,12 @@ public enum BuiltInMethod {
String.class, int.class),
UNIX_DATE_TO_STRING(DateTimeUtils.class, "unixDateToString", int.class),
UNIX_TIME_TO_STRING(DateTimeUtils.class, "unixTimeToString", int.class),
+ UNIX_TIME_TO_STRING_WITH_PRECISION(DateTimeUtils.class, "unixTimeToString",
Review Comment:
Both these methods assume that the actual data value is expressed as an
integer number of milliseconds, so they won't work for precisions higher than
3. Perhaps this is not worsening the problem, but it looks to me like it will
need to be fixed at some point again.
##########
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
Review Comment:
I don't see any cast in this function, so this comment is misleading.
##########
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:
can you document what this function is supposed to do?
--
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]