Skip to content

Commit e324648

Browse files
committed
[CALCITE-7197] UnsupportedOperationException when using dynamic parameters inside ROW expression
1 parent ebee26d commit e324648

File tree

5 files changed

+89
-19
lines changed

5 files changed

+89
-19
lines changed

core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,6 +2126,10 @@ protected void inferUnknownTypes(
21262126
setValidatedNodeType(node, newInferredType);
21272127
} else if (node instanceof SqlNodeList) {
21282128
SqlNodeList nodeList = (SqlNodeList) node;
2129+
if (isRowSqlNodeList(inferredType, nodeList)) {
2130+
inferRowSqlNodeList(inferredType, scope, nodeList);
2131+
return;
2132+
}
21292133
if (inferredType.isStruct()) {
21302134
if (inferredType.getFieldCount() != nodeList.size()) {
21312135
// this can happen when we're validating an INSERT
@@ -2204,6 +2208,25 @@ protected void inferUnknownTypes(
22042208
}
22052209
}
22062210

2211+
private boolean isRowSqlNodeList(final RelDataType inferredType, final SqlNodeList nodeList) {
2212+
return inferredType.isStruct() && !nodeList.isEmpty()
2213+
&& SqlKind.ROW == nodeList.get(0).getKind();
2214+
}
2215+
2216+
private void inferRowSqlNodeList(final RelDataType inferredType,
2217+
final SqlValidatorScope scope, final SqlNodeList nodeList) {
2218+
for (SqlNode child : nodeList) {
2219+
if (!(child instanceof SqlBasicCall)) {
2220+
continue;
2221+
}
2222+
List<SqlNode> operands = ((SqlBasicCall) child).getOperandList();
2223+
for (int index = 0; index < operands.size(); index++) {
2224+
RelDataType type = inferredType.getFieldList().get(index).getType();
2225+
inferUnknownTypes(type, scope, operands.get(index));
2226+
}
2227+
}
2228+
}
2229+
22072230
/**
22082231
* Adds an expression to a select list, ensuring that its alias does not
22092232
* clash with any existing expressions on the list.

core/src/test/java/org/apache/calcite/test/JdbcTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9012,6 +9012,31 @@ void checkCalciteSchemaGetSubSchemaMap(boolean cache) {
90129012
});
90139013
}
90149014

9015+
/** Test case for
9016+
* <a href="https://issues.apache.org/jira/browse/CALCITE-7197">[CALCITE-7197]</a>
9017+
* UnsupportedOperationException when using dynamic parameters inside ROW expression. */
9018+
@Test void testSelectWithPlaceholdersInRowExpression() {
9019+
CalciteAssert.that()
9020+
.with(Lex.MYSQL)
9021+
.with(CalciteAssert.Config.SCOTT)
9022+
.query("select empno, ename from emp\n"
9023+
+ "where row(empno, ename) in ((?, ?))")
9024+
.consumesPreparedStatement(p -> {
9025+
p.setInt(1, 7782);
9026+
p.setString(2, "CLARK");
9027+
})
9028+
.returns(resultSet -> {
9029+
try {
9030+
assertTrue(resultSet.next());
9031+
assertThat(resultSet.getInt(1), is(7782));
9032+
assertThat(resultSet.getString(2), is("CLARK"));
9033+
assertFalse(resultSet.next());
9034+
} catch (SQLException e) {
9035+
throw new RuntimeException(e);
9036+
}
9037+
});
9038+
}
9039+
90159040
/** Test case for
90169041
* <a href="https://issues.apache.org/jira/browse/CALCITE-5414">[CALCITE-5414]</a>
90179042
* Convert between standard Gregorian and proleptic Gregorian calendars for

core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12405,6 +12405,26 @@ private void checkCustomColumnResolving(String table) {
1240512405
.fails(maxError);
1240612406
}
1240712407

12408+
/** Test case for
12409+
* <a href="https://issues.apache.org/jira/browse/CALCITE-7197">[CALCITE-7197]</a>
12410+
* UnsupportedOperationException when using dynamic parameters inside ROW expression. */
12411+
@Test void testSelectWithRowExpressionPredicate() {
12412+
// test single row expression values
12413+
sql("select empno, ename from emp where row(empno, ename) in ((?, ?))")
12414+
.ok()
12415+
.assertBindType(is("RecordType(INTEGER ?0, VARCHAR(20) ?1)"));
12416+
12417+
// test multiple row expression values
12418+
sql("select empno, ename from emp where row(empno, ename) in ((?, ?), (7782, ?), (?, 'CLARK'))")
12419+
.ok()
12420+
.assertBindType(is("RecordType(INTEGER ?0, VARCHAR(20) ?1, VARCHAR(20) ?2, INTEGER ?3)"));
12421+
12422+
// test single row expression values with expression
12423+
sql("select empno, ename from emp where row(empno, ename) in ((? + 1, ?))")
12424+
.ok()
12425+
.assertBindType(is("RecordType(INTEGER ?0, VARCHAR(20) ?1)"));
12426+
}
12427+
1240812428
@Test void testRolledUpColumnInWhere() {
1240912429
final String error = "Rolled up column 'SLACKINGMIN' is not allowed in GREATER_THAN";
1241012430

core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19698,16 +19698,7 @@ LogicalProject(A=[$0], Y=[$1])
1969819698
LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
1969919699
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 20 }, { null, 5 }]])
1970019700
LogicalAggregate(group=[{0, 1}])
19701-
LogicalUnion(all=[true])
19702-
LogicalProject(EXPR$0=[3], EXPR$1=[null:INTEGER])
19703-
LogicalValues(tuples=[[{ 0 }]])
19704-
LogicalProject(EXPR$0=[7369], EXPR$1=[null:INTEGER])
19705-
LogicalValues(tuples=[[{ 0 }]])
19706-
LogicalProject(EXPR$0=[null:INTEGER], EXPR$1=[20])
19707-
LogicalValues(tuples=[[{ 0 }]])
19708-
LogicalProject(EXPR$0=[null:INTEGER], EXPR$1=[5])
19709-
LogicalValues(tuples=[[{ 0 }]])
19710-
LogicalValues(tuples=[[{ 1, 2 }, { 7499, 30 }]])
19701+
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 20 }, { null, 5 }]])
1971119702
]]>
1971219703
</Resource>
1971319704
<Resource name="planAfter">
@@ -19716,7 +19707,7 @@ LogicalProject(A=[$0], Y=[$1])
1971619707
LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])
1971719708
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 20 }, { null, 5 }]])
1971819709
LogicalAggregate(group=[{0, 1}])
19719-
LogicalValues(tuples=[[{ 3, null }, { 7369, null }, { null, 20 }, { null, 5 }, { 1, 2 }, { 7499, 30 }]])
19710+
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 20 }, { null, 5 }]])
1972019711
]]>
1972119712
</Resource>
1972219713
</TestCase>
@@ -19738,15 +19729,9 @@ LogicalProject(A=[$0], Y=[$1])
1973819729
LogicalUnion(all=[true])
1973919730
LogicalProject(EXPR$0=[1], EXPR$1=[2])
1974019731
LogicalValues(tuples=[[{ 0 }]])
19741-
LogicalProject(EXPR$0=[3], EXPR$1=[null:INTEGER])
19742-
LogicalValues(tuples=[[{ 0 }]])
19743-
LogicalProject(EXPR$0=[7369], EXPR$1=[null:INTEGER])
19744-
LogicalValues(tuples=[[{ 0 }]])
1974519732
LogicalProject(EXPR$0=[null:INTEGER], EXPR$1=[20])
1974619733
LogicalValues(tuples=[[{ 0 }]])
19747-
LogicalProject(EXPR$0=[null:INTEGER], EXPR$1=[5])
19748-
LogicalValues(tuples=[[{ 0 }]])
19749-
LogicalValues(tuples=[[{ 7499, 30 }]])
19734+
LogicalValues(tuples=[[{ 3, null }, { 7369, null }, { 7499, 30 }, { null, 5 }]])
1975019735
]]>
1975119736
</Resource>
1975219737
<Resource name="planAfter">
@@ -19755,7 +19740,7 @@ LogicalProject(A=[$0], Y=[$1])
1975519740
LogicalJoin(condition=[AND(=($0, $2), =($1, $3))], joinType=[inner])
1975619741
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 20 }, { null, 5 }]])
1975719742
LogicalAggregate(group=[{0, 1}])
19758-
LogicalValues(tuples=[[{ 1, 2 }, { 3, null }, { 7369, null }, { null, 20 }, { null, 5 }, { 7499, 30 }]])
19743+
LogicalValues(tuples=[[{ 1, 2 }, { null, 20 }, { 3, null }, { 7369, null }, { 7499, 30 }, { null, 5 }]])
1975919744
]]>
1976019745
</Resource>
1976119746
</TestCase>

core/src/test/resources/sql/conditions.iq

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,4 +547,21 @@ where 5 < cast(deptno as integer) OR 5 >= cast(deptno as integer) OR deptno IS N
547547
EnumerableTableScan(table=[[scott, EMP]])
548548
!plan
549549

550+
!use scott
551+
552+
# Test case for [CALCITE-7197] UnsupportedOperationException when using dynamic parameters inside ROW expression
553+
select *
554+
from "scott".emp
555+
where row(empno, ename) in ((7782, 'CLARK'), (7902, 'FORD'), (7839, 'KING'));
556+
+-------+-------+-----------+------+------------+---------+------+--------+
557+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
558+
+-------+-------+-----------+------+------------+---------+------+--------+
559+
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | | 10 |
560+
| 7839 | KING | PRESIDENT | | 1981-11-17 | 5000.00 | | 10 |
561+
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | | 20 |
562+
+-------+-------+-----------+------+------------+---------+------+--------+
563+
(3 rows)
564+
565+
!ok
566+
550567
# End conditions.iq

0 commit comments

Comments
 (0)