Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -1560,7 +1560,12 @@ private static void adjustTypeForMultisetConstructor(
if (adjustedOperands == null) {
adjustedOperands = new ArrayList<>(operands);
}
adjustedOperands.set(i, castTo(operands.get(i), elementType));
SqlCall cast = (SqlCall) castTo(operands.get(i), elementType);
// This CAST was generated with the built-in operator; validate its
// operands directly instead of resolving the function again by name.
cast.getOperator().validateOperands(

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.

You seem to do strictly more work than before.
This looks correct, but does not seem more efficient.

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.

That's fare. the intention here is to keep the type in the cache for cast expression. let me take a look at if there's a better way to make it

sqlCallBinding.getValidator(), sqlCallBinding.getScope(), cast);
adjustedOperands.set(i, cast);
}
}
if (adjustedOperands != null) {
Expand Down
37 changes: 37 additions & 0 deletions core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.apache.calcite.sql.SqlOperatorTable;
import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.sql.SqlSpecialOperator;
import org.apache.calcite.sql.SqlSyntax;
import org.apache.calcite.sql.fun.SqlCase;
import org.apache.calcite.sql.fun.SqlLibrary;
import org.apache.calcite.sql.fun.SqlLibraryOperatorTableFactory;
Expand All @@ -62,6 +63,7 @@
import org.apache.calcite.sql.validate.SqlConformanceEnum;
import org.apache.calcite.sql.validate.SqlDelegatingConformance;
import org.apache.calcite.sql.validate.SqlMonotonicity;
import org.apache.calcite.sql.validate.SqlNameMatcher;
import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.sql.validate.SqlValidatorCatalogReader;
import org.apache.calcite.sql.validate.SqlValidatorImpl;
Expand Down Expand Up @@ -9756,6 +9758,41 @@ void testGroupExpressionEquivalenceParams() {
.columnType("CHAR(3) ARRAY NOT NULL");
}

@Test void testValidateOperandsCachesGeneratedCastType()
throws SqlParseException {
final int[] castLookups = {0};
final SqlValidator validator = fixture()
.withFactory(
factory -> factory.withOperatorTable(operatorTable ->
new SqlOperatorTable() {
@Override public void lookupOperatorOverloads(SqlIdentifier opName,
SqlFunctionCategory category, SqlSyntax syntax,
List<SqlOperator> operatorList, SqlNameMatcher nameMatcher) {
if (opName.isSimple() && opName.getSimple().equals("CAST")) {
castLookups[0]++;
}
operatorTable.lookupOperatorOverloads(
opName, category, syntax, operatorList, nameMatcher);
}

@Override public List<SqlOperator> getOperatorList() {
return operatorTable.getOperatorList();
}
}))
.factory.createValidator();
final SqlCall cast = (SqlCall) SqlParser
.create("cast('a' as varchar(2))", SqlParser.config())
.parseExpression();
final SqlValidatorScope scope = validator.getEmptyScope();
validator.deriveType(scope, cast.getOperandList().get(0));
// SqlValidatorUtil relies on validateOperands caching the generated CAST
// type so a later deriveType call does not resolve the operator by name.
cast.getOperator().validateOperands(validator, scope, cast);

validator.deriveType(scope, cast);
assertThat(castLookups[0], is(0));
}

/**
* Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-4999">[CALCITE-4999]
Expand Down
Loading