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 @@ -2126,6 +2126,9 @@ protected void inferUnknownTypes(
setValidatedNodeType(node, newInferredType);
} else if (node instanceof SqlNodeList) {
SqlNodeList nodeList = (SqlNodeList) node;
if (inferRowSqlNodeList(inferredType, scope, nodeList)) {
return;
}
if (inferredType.isStruct()) {
if (inferredType.getFieldCount() != nodeList.size()) {
// this can happen when we're validating an INSERT
Expand Down Expand Up @@ -2204,6 +2207,25 @@ protected void inferUnknownTypes(
}
}

private boolean inferRowSqlNodeList(final RelDataType inferredType,
final SqlValidatorScope scope, final SqlNodeList nodeList) {
if (!inferredType.isStruct()) {
return false;
}
boolean inferred = false;
for (SqlNode child : nodeList) {
if (child instanceof SqlBasicCall && SqlKind.ROW == child.getKind()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

There are expressions that evaluate to a ROW type that are not ROW expressions.
For example, a[1], where a is an array of ROW values.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for bringing this up, I might not have considered it before. Can you give a sql example? I will continue to analyze the possible problems in this scenario.

Copy link
Contributor

Choose a reason for hiding this comment

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

List<SqlNode> operands = ((SqlBasicCall) child).getOperandList();
for (int index = 0; index < operands.size(); index++) {
RelDataType type = inferredType.getFieldList().get(index).getType();
inferUnknownTypes(type, scope, operands.get(index));
}
inferred = true;
}
}
return inferred;
}

/**
* Adds an expression to a select list, ensuring that its alias does not
* clash with any existing expressions on the list.
Expand Down
25 changes: 25 additions & 0 deletions core/src/test/java/org/apache/calcite/test/JdbcTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9012,6 +9012,31 @@ void checkCalciteSchemaGetSubSchemaMap(boolean cache) {
});
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-7197">[CALCITE-7197]</a>
* UnsupportedOperationException when using dynamic parameters inside ROW expression. */
@Test void testSelectWithPlaceholdersInRowExpression() {
CalciteAssert.that()
.with(Lex.MYSQL)
.with(CalciteAssert.Config.SCOTT)
.query("select empno, ename from emp\n"
+ "where row(empno, ename) in ((?, ?))")
.consumesPreparedStatement(p -> {
p.setInt(1, 7782);
p.setString(2, "CLARK");
})
.returns(resultSet -> {
try {
assertTrue(resultSet.next());
assertThat(resultSet.getInt(1), is(7782));
assertThat(resultSet.getString(2), is("CLARK"));
assertFalse(resultSet.next());
} catch (SQLException e) {
throw new RuntimeException(e);
}
});
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-5414">[CALCITE-5414]</a>
* Convert between standard Gregorian and proleptic Gregorian calendars for
Expand Down
20 changes: 20 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 @@ -12405,6 +12405,26 @@ private void checkCustomColumnResolving(String table) {
.fails(maxError);
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-7197">[CALCITE-7197]</a>
* UnsupportedOperationException when using dynamic parameters inside ROW expression. */
@Test void testSelectWithRowExpressionPredicate() {
// test single row expression values
sql("select empno, ename from emp where row(empno, ename) in ((?, ?))")
.ok()
.assertBindType(is("RecordType(INTEGER ?0, VARCHAR(20) ?1)"));

// test multiple row expression values
sql("select empno, ename from emp where row(empno, ename) in ((?, ?), (7782, ?), (?, 'CLARK'))")
.ok()
.assertBindType(is("RecordType(INTEGER ?0, VARCHAR(20) ?1, VARCHAR(20) ?2, INTEGER ?3)"));

// test single row expression values with expression
sql("select empno, ename from emp where row(empno, ename) in ((? + 1, ?))")
.ok()
.assertBindType(is("RecordType(INTEGER ?0, VARCHAR(20) ?1)"));
}

@Test void testRolledUpColumnInWhere() {
final String error = "Rolled up column 'SLACKINGMIN' is not allowed in GREATER_THAN";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19698,16 +19698,7 @@ LogicalProject(A=[$0], Y=[$1])
LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 20 }, { null, 5 }]])
LogicalAggregate(group=[{0, 1}])
LogicalUnion(all=[true])
LogicalProject(EXPR$0=[3], EXPR$1=[null:INTEGER])
LogicalValues(tuples=[[{ 0 }]])
LogicalProject(EXPR$0=[7369], EXPR$1=[null:INTEGER])
LogicalValues(tuples=[[{ 0 }]])
LogicalProject(EXPR$0=[null:INTEGER], EXPR$1=[20])
LogicalValues(tuples=[[{ 0 }]])
LogicalProject(EXPR$0=[null:INTEGER], EXPR$1=[5])
LogicalValues(tuples=[[{ 0 }]])
LogicalValues(tuples=[[{ 1, 2 }, { 7499, 30 }]])
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 20 }, { null, 5 }]])
]]>
</Resource>
<Resource name="planAfter">
Expand All @@ -19716,7 +19707,7 @@ LogicalProject(A=[$0], Y=[$1])
LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 20 }, { null, 5 }]])
LogicalAggregate(group=[{0, 1}])
LogicalValues(tuples=[[{ 3, null }, { 7369, null }, { null, 20 }, { null, 5 }, { 1, 2 }, { 7499, 30 }]])
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 20 }, { null, 5 }]])
]]>
</Resource>
</TestCase>
Expand All @@ -19738,15 +19729,9 @@ LogicalProject(A=[$0], Y=[$1])
LogicalUnion(all=[true])
LogicalProject(EXPR$0=[1], EXPR$1=[2])
LogicalValues(tuples=[[{ 0 }]])
LogicalProject(EXPR$0=[3], EXPR$1=[null:INTEGER])
LogicalValues(tuples=[[{ 0 }]])
LogicalProject(EXPR$0=[7369], EXPR$1=[null:INTEGER])
LogicalValues(tuples=[[{ 0 }]])
LogicalProject(EXPR$0=[null:INTEGER], EXPR$1=[20])
LogicalValues(tuples=[[{ 0 }]])
LogicalProject(EXPR$0=[null:INTEGER], EXPR$1=[5])
LogicalValues(tuples=[[{ 0 }]])
LogicalValues(tuples=[[{ 7499, 30 }]])
LogicalValues(tuples=[[{ 3, null }, { 7369, null }, { 7499, 30 }, { null, 5 }]])
]]>
</Resource>
<Resource name="planAfter">
Expand All @@ -19755,7 +19740,7 @@ LogicalProject(A=[$0], Y=[$1])
LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 20 }, { null, 5 }]])
LogicalAggregate(group=[{0, 1}])
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { null, 20 }, { null, 5 }, { 7499, 30 }]])
LogicalValues(tuples=[[{ 1, 2 }, { null, 20 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 5 }]])
Copy link
Member

Choose a reason for hiding this comment

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

Maybe what I want to ask is this—why has the order changed here? Is this necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it's neccessay. This order is generated by the UnionToValuesRule rule based on planBefore. For details, see the corresponding relationship in the following figure.

image

]]>
</Resource>
</TestCase>
Expand Down
17 changes: 17 additions & 0 deletions core/src/test/resources/sql/conditions.iq
Original file line number Diff line number Diff line change
Expand Up @@ -547,4 +547,21 @@ where 5 < cast(deptno as integer) OR 5 >= cast(deptno as integer) OR deptno IS N
EnumerableTableScan(table=[[scott, EMP]])
!plan

!use scott

# Test case for [CALCITE-7197] UnsupportedOperationException when using dynamic parameters inside ROW expression
select *
from "scott".emp
where row(empno, ename) in ((7782, 'CLARK'), (7902, 'FORD'), (7839, 'KING'));
+-------+-------+-----------+------+------------+---------+------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+-------+-----------+------+------------+---------+------+--------+
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | | 10 |
| 7839 | KING | PRESIDENT | | 1981-11-17 | 5000.00 | | 10 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | | 20 |
+-------+-------+-----------+------+------------+---------+------+--------+
(3 rows)

!ok

# End conditions.iq
Loading