Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 85 additions & 2 deletions core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.util.DateString;
import org.apache.calcite.util.NlsString;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.TimeString;
import org.apache.calcite.util.TimestampString;
import org.apache.calcite.util.trace.CalciteLogger;

import org.checkerframework.checker.nullness.qual.Nullable;
Expand All @@ -38,6 +41,8 @@
import java.math.BigDecimal;
import java.util.List;

import static java.util.Objects.requireNonNull;

/**
* DataContext for evaluating a RexExpression.
*/
Expand Down Expand Up @@ -107,7 +112,27 @@
return new VisitorDataContext(values);
}

/**
* Extracts a value from a RexLiteral for use in DataContext.
*
* <p>Returns a Pair of (column index, value) if extraction is successful,
* or null if the value cannot be extracted or is invalid.
*
* <p>Returns null when:
* <ul>
* <li>Arguments are not valid RexInputRef and RexLiteral</li>
* <li>Type conversion fails (e.g., invalid date/time format)</li>
* <li>Type combination is unsupported</li>
* </ul>
*
* <p>When null is returned, the containing optimization (e.g.,
* materialized view substitution) cannot be applied and is skipped.
*
* @param inputRef the input reference (column)
* @param literal the literal value to extract
* @return a Pair of (column index, value) or null
*/
public static @Nullable Pair<Integer, ? extends @Nullable Object> getValue(

Check failure on line 135 in core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 36 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=apache_calcite&issues=AZ5vPBSR_UxqA1b_DuCA&open=AZ5vPBSR_UxqA1b_DuCA&pullRequest=4974
@Nullable RexNode inputRef, @Nullable RexNode literal) {
inputRef = inputRef == null ? null : RexUtil.removeCast(inputRef);
literal = literal == null ? null : RexUtil.removeCast(literal);
Expand Down Expand Up @@ -140,10 +165,68 @@
case DECIMAL:
return Pair.of(index, rexLiteral.getValueAs(BigDecimal.class));
case DATE:
switch (rexLiteral.getType().getSqlTypeName()) {
case DATE:
return Pair.of(index, rexLiteral.getValueAs(Integer.class));
case CHAR:
case VARCHAR:
try {
return Pair.of(index,
new DateString(requireNonNull(rexLiteral.getValueAs(String.class)))
.getDaysSinceEpoch());
} catch (IllegalArgumentException e) {
LOGGER.warn(
"Cannot convert string literal '{}' to DATE type; "
+ "materialized view optimization will be skipped",

Check failure on line 180 in core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "materialized view optimization will be skipped" 3 times.

See more on https://sonarcloud.io/project/issues?id=apache_calcite&issues=AZ5yl3ji_3ELC_tVISQr&open=AZ5yl3ji_3ELC_tVISQr&pullRequest=4974
rexLiteral.getValueAs(String.class), e);
return null;
}
default:
break;
}
break;
case TIME:
return Pair.of(index, rexLiteral.getValueAs(Integer.class));
switch (rexLiteral.getType().getSqlTypeName()) {
case TIME:
return Pair.of(index, rexLiteral.getValueAs(Integer.class));
case CHAR:
case VARCHAR:
try {
return Pair.of(index,
new TimeString(requireNonNull(rexLiteral.getValueAs(String.class)))
.getMillisOfDay());
} catch (IllegalArgumentException e) {
LOGGER.debug(
"Cannot convert string literal '{}' to TIME type; "
+ "materialized view optimization will be skipped",
rexLiteral.getValueAs(String.class), e);
return null;
}
default:
break;
}
break;
case TIMESTAMP:
return Pair.of(index, rexLiteral.getValueAs(Long.class));
switch (rexLiteral.getType().getSqlTypeName()) {
case TIMESTAMP:
return Pair.of(index, rexLiteral.getValueAs(Long.class));
case CHAR:
case VARCHAR:
try {
return Pair.of(index,
new TimestampString(requireNonNull(rexLiteral.getValueAs(String.class)))
.getMillisSinceEpoch());
} catch (IllegalArgumentException e) {
LOGGER.debug(
"Cannot convert string literal '{}' to TIMESTAMP type; "
+ "materialized view optimization will be skipped",
rexLiteral.getValueAs(String.class), e);
return null;
}
default:
break;
}
break;
case CHAR:
return Pair.of(index, rexLiteral.getValueAs(Character.class));
case VARCHAR:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,21 @@ protected final MaterializedViewFixture sql(String materialize,
.ok();
}

/** Test case of
* <a href="https://issues.apache.org/jira/browse/CALCITE-6823">[CALCITE-6823]
* Cannot convert CHAR to Integer when applying SubstitutionVisitor</a>. */
@Test void testDateFilter() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the string is not a valid date literal?
You should get a decent error, not a crash.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense! I had fixed the issue and added a test about it.

sql("SELECT HIREDATE FROM EMP WHERE HIREDATE > '1990-10-01'",
"SELECT * FROM EMP WHERE HIREDATE > '1990-05-01'")
.withDefaultSchemaSpec(CalciteAssert.SchemaSpec.SCOTT)
.noMat();

sql("SELECT HIREDATE FROM EMP WHERE HIREDATE > '1990-10-01'",
"SELECT * FROM EMP WHERE HIREDATE > 'invalid-date'")
.withDefaultSchemaSpec(CalciteAssert.SchemaSpec.SCOTT)
.noMat();
}

@Test void testFilterToProject0() {
sql("select *, \"empid\" * 2 from \"emps\"",
"select * from \"emps\" where (\"empid\" * 2) > 3")
Expand Down
Loading