Skip to content

Commit

Permalink
[CALCITE-6620] VALUES created by RelBuilder do not have a homogeneous…
Browse files Browse the repository at this point in the history
… type

Signed-off-by: Mihai Budiu <[email protected]>
  • Loading branch information
mihaibudiu authored and julianhyde committed Oct 10, 2024
1 parent 243c3ad commit a7c3d16
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 76 deletions.
31 changes: 30 additions & 1 deletion core/src/main/java/org/apache/calcite/tools/RelBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -2886,6 +2886,31 @@ private static boolean isGroupId(AggCall c) {
return ((AggCallPlus) c).op().kind == SqlKind.GROUP_ID;
}

/** Given a list of literals and a target row type, make the literals
* respectively match the fields types of the row.
*
* @param rowType Type expected for values
* @param values A list of literals that should match the rowType */
private List<RexLiteral> convertLiteralTypes(
RelDataType rowType, List<RexLiteral> values) {
assert values.size() == rowType.getFieldCount()
: "List of literals of size " + values.size() + " does not match expected type " + rowType;

List<RelDataTypeField> fields = rowType.getFieldList();
List<RexLiteral> constants = new ArrayList<>();

for (int i = 0; i < values.size(); i++) {
RexLiteral vi = values.get(i);
RelDataType type = fields.get(i).getType();
RexNode e = cluster.getRexBuilder().makeAbstractCast(type, vi, false);
RexNode simplified = simplifier.simplify(e);
assert simplified instanceof RexLiteral
: "Could not simplify expression to literal" + simplified;
constants.add((RexLiteral) simplified);
}
return ImmutableList.copyOf(constants);
}

private RelBuilder setOp(boolean all, SqlKind kind, int n) {
List<RelNode> inputs = new ArrayList<>();
for (int i = 0; i < n; i++) {
Expand Down Expand Up @@ -2917,7 +2942,11 @@ private RelBuilder setOp(boolean all, SqlKind kind, int n) {
requireNonNull(rowType, () -> "leastRestrictive(" + inputTypes + ")");
final List<List<RexLiteral>> tuples = new ArrayList<>();
for (RelNode input : inputs) {
tuples.addAll(((Values) input).tuples);
ImmutableList<ImmutableList<RexLiteral>> literals = ((Values) input).tuples;
for (ImmutableList<RexLiteral> l : literals) {
List<RexLiteral> converted = convertLiteralTypes(rowType, l);
tuples.add(converted);
}
}
final List<List<RexLiteral>> tuples2 =
all ? tuples : Util.distinctList(tuples);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7765,7 +7765,7 @@ private void checkLiteral2(String expression, String expected) {
final String expectedDefault = "INSERT INTO \"SCOTT\".\"DEPT\""
+ " (\"DEPTNO\", \"DNAME\", \"LOC\")\n"
+ "VALUES (1, 'Fred', 'San Francisco'),\n"
+ "(2, 'Eric', 'Washington')";
+ "(2, 'Eric', 'Washington ')";
final String expectedDefaultX = "INSERT INTO \"SCOTT\".\"DEPT\""
+ " (\"DEPTNO\", \"DNAME\", \"LOC\")\n"
+ "SELECT 1, 'Fred', 'San Francisco'\n"
Expand All @@ -7775,15 +7775,15 @@ private void checkLiteral2(String expression, String expected) {
+ "FROM (VALUES (0)) AS \"t\" (\"ZERO\")";
final String expectedHive = "INSERT INTO `SCOTT`.`DEPT` (`DEPTNO`, `DNAME`, `LOC`)\n"
+ "VALUES (1, 'Fred', 'San Francisco'),\n"
+ "(2, 'Eric', 'Washington')";
+ "(2, 'Eric', 'Washington ')";
final String expectedHiveX = "INSERT INTO `SCOTT`.`DEPT` (`DEPTNO`, `DNAME`, `LOC`)\n"
+ "SELECT 1, 'Fred', 'San Francisco'\n"
+ "UNION ALL\n"
+ "SELECT 2, 'Eric', 'Washington'";
final String expectedMysql = "INSERT INTO `SCOTT`.`DEPT`"
+ " (`DEPTNO`, `DNAME`, `LOC`)\n"
+ "VALUES (1, 'Fred', 'San Francisco'),\n"
+ "(2, 'Eric', 'Washington')";
+ "(2, 'Eric', 'Washington ')";
final String expectedMysqlX = "INSERT INTO `SCOTT`.`DEPT`"
+ " (`DEPTNO`, `DNAME`, `LOC`)\n"
+ "SELECT 1, 'Fred', 'San Francisco'\n"
Expand All @@ -7792,7 +7792,7 @@ private void checkLiteral2(String expression, String expected) {
final String expectedOracle = "INSERT INTO \"SCOTT\".\"DEPT\""
+ " (\"DEPTNO\", \"DNAME\", \"LOC\")\n"
+ "VALUES (1, 'Fred', 'San Francisco'),\n"
+ "(2, 'Eric', 'Washington')";
+ "(2, 'Eric', 'Washington ')";
final String expectedOracleX = "INSERT INTO \"SCOTT\".\"DEPT\""
+ " (\"DEPTNO\", \"DNAME\", \"LOC\")\n"
+ "SELECT 1, 'Fred', 'San Francisco'\n"
Expand All @@ -7803,7 +7803,7 @@ private void checkLiteral2(String expression, String expected) {
final String expectedMssql = "INSERT INTO [SCOTT].[DEPT]"
+ " ([DEPTNO], [DNAME], [LOC])\n"
+ "VALUES (1, 'Fred', 'San Francisco'),\n"
+ "(2, 'Eric', 'Washington')";
+ "(2, 'Eric', 'Washington ')";
final String expectedMssqlX = "INSERT INTO [SCOTT].[DEPT]"
+ " ([DEPTNO], [DNAME], [LOC])\n"
+ "SELECT 1, 'Fred', 'San Francisco'\n"
Expand All @@ -7814,7 +7814,7 @@ private void checkLiteral2(String expression, String expected) {
final String expectedCalcite = "INSERT INTO \"SCOTT\".\"DEPT\""
+ " (\"DEPTNO\", \"DNAME\", \"LOC\")\n"
+ "VALUES (1, 'Fred', 'San Francisco'),\n"
+ "(2, 'Eric', 'Washington')";
+ "(2, 'Eric', 'Washington ')";
final String expectedCalciteX = "INSERT INTO \"SCOTT\".\"DEPT\""
+ " (\"DEPTNO\", \"DNAME\", \"LOC\")\n"
+ "SELECT 1, 'Fred', 'San Francisco'\n"
Expand Down
16 changes: 16 additions & 0 deletions core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import org.apache.calcite.adapter.enumerable.EnumerableConvention;
import org.apache.calcite.adapter.enumerable.EnumerableRules;
import org.apache.calcite.adapter.java.ReflectiveSchema;
import org.apache.calcite.config.CalciteConnectionProperty;
import org.apache.calcite.config.Lex;
import org.apache.calcite.jdbc.CalciteConnection;
import org.apache.calcite.plan.Contexts;
import org.apache.calcite.plan.Convention;
Expand Down Expand Up @@ -231,6 +233,20 @@ static RelBuilder createBuilder(UnaryOperator<RelBuilder.Config> transform) {
hasTree("LogicalTableScan(table=[[scott, EMP]])\n"));
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-6620">[CALCITE-6620]
* VALUES created by RelBuilder do not have a homogeneous type</a>. */
@Test void differentTypeValues() {
CalciteAssert.that()
.with(CalciteConnectionProperty.LEX, Lex.JAVA)
.with(CalciteConnectionProperty.FORCE_DECORRELATE, false)
.withSchema("s", new ReflectiveSchema(new HrSchema()))
.query("SELECT * FROM (VALUES (1, 2, 3), (CAST(5E0 AS REAL), 5E0, NULL))")
.explainContains("PLAN=EnumerableValues(tuples=[[{ 1.0E0, 2.0E0, 3 }, "
+ "{ 5.0E0, 5.0E0, null }]])")
.returnsOrdered("EXPR$0=1.0; EXPR$1=2.0; EXPR$2=3", "EXPR$0=5.0; EXPR$1=5.0; EXPR$2=null");
}

@Test void testScanQualifiedTable() {
// Equivalent SQL:
// SELECT *
Expand Down
Loading

0 comments on commit a7c3d16

Please sign in to comment.