Skip to content

Commit 473fa49

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

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
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: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9012,6 +9012,28 @@ void checkCalciteSchemaGetSubSchemaMap(boolean cache) {
90129012
});
90139013
}
90149014

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

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

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

12408+
@Test void testSelectWithRowExpressionPredicate() {
12409+
// test single row expression values
12410+
sql("select empno, ename from emp where row(empno, ename) in ((?, ?))")
12411+
.ok()
12412+
.assertBindType(is("RecordType(INTEGER ?0, VARCHAR(20) ?1)"));
12413+
12414+
// test multiple row expression values
12415+
sql("select empno, ename from emp where row(empno, ename) in ((?, ?), (7782, ?), (?, 'CLARK'))")
12416+
.ok()
12417+
.assertBindType(is("RecordType(INTEGER ?0, VARCHAR(20) ?1, VARCHAR(20) ?2, INTEGER ?3)"));
12418+
12419+
// test single row expression values with expression
12420+
sql("select empno, ename from emp where row(empno, ename) in ((? + 1, ?))")
12421+
.ok()
12422+
.assertBindType(is("RecordType(INTEGER ?0, VARCHAR(20) ?1)"));
12423+
}
12424+
1240812425
@Test void testRolledUpColumnInWhere() {
1240912426
final String error = "Rolled up column 'SLACKINGMIN' is not allowed in GREATER_THAN";
1241012427

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,4 +547,20 @@ 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+
select *
553+
from "scott".emp
554+
where row(empno, ename) in ((7782, 'CLARK'), (7902, 'FORD'), (7839, 'KING'));
555+
+-------+-------+-----------+------+------------+---------+------+--------+
556+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
557+
+-------+-------+-----------+------+------------+---------+------+--------+
558+
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | | 10 |
559+
| 7839 | KING | PRESIDENT | | 1981-11-17 | 5000.00 | | 10 |
560+
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | | 20 |
561+
+-------+-------+-----------+------+------------+---------+------+--------+
562+
(3 rows)
563+
564+
!ok
565+
550566
# End conditions.iq

0 commit comments

Comments
 (0)