Skip to content
Closed
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 @@ -41,6 +41,7 @@
import org.apache.calcite.rel.logical.LogicalProject;
import org.apache.calcite.rel.logical.LogicalSort;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexCall;
import org.apache.calcite.rex.RexInputRef;
Expand All @@ -64,6 +65,7 @@
import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.sql.SqlUpdate;
import org.apache.calcite.sql.SqlUtil;
import org.apache.calcite.sql.fun.SqlRowOperator;
import org.apache.calcite.sql.fun.SqlSingleValueAggFunction;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
Expand Down Expand Up @@ -199,13 +201,27 @@ public Result visit(Project e) {
final List<SqlNode> selectList = new ArrayList<>();
for (RexNode ref : e.getChildExps()) {
SqlNode sqlExpr = builder.context.toSql(null, ref);
if (SqlUtil.isNullLiteral(sqlExpr, false)) {
sqlExpr = castNullType(sqlExpr, e.getRowType().getFieldList().get(selectList.size()));
}
addSelect(selectList, sqlExpr, e.getRowType());
}

builder.setSelect(new SqlNodeList(selectList, POS));
return builder.result();
}

/**
* Wrap the {@code sqlNodeNull} in a CAST operator with target type as {@code field}.
* @param sqlNodeNull null literal
* @param field field description of sqlNodeNull
* @return null literal wrapped in CAST call.
*/
private SqlNode castNullType(SqlNode sqlNodeNull, RelDataTypeField field) {
return SqlStdOperatorTable.CAST.createCall(POS,
sqlNodeNull, dialect.getCastSpec(field.getType()));
}

/** @see #dispatch */
public Result visit(Aggregate e) {
return visitAggregate(e, e.getGroupSet().toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3694,6 +3694,96 @@ private void checkLiteral2(String expression, String expected) {
assertTrue(postgresqlDialect.supportsDataType(integerDataType));
}

@Test public void testSelectNull() {
String query = "SELECT CAST(NULL AS INT)";
final String expected = "SELECT CAST(NULL AS INTEGER)\n"
+ "FROM (VALUES (0)) AS \"t\" (\"ZERO\")";
sql(query).ok(expected);
// validate
sql(expected).exec();
}

@Test public void testSelectNullWithCount() {
String query = "SELECT COUNT(CAST(NULL AS INT))";
final String expected = "SELECT COUNT(CAST(NULL AS INTEGER))\n"
+ "FROM (VALUES (0)) AS \"t\" (\"ZERO\")";
sql(query).ok(expected);
// validate
sql(expected).exec();
}

@Test public void testSelectNullWithGroupByNull() {
String query = "SELECT COUNT(CAST(NULL AS INT)) FROM (VALUES (0)) "
+ "AS \"t\" GROUP BY CAST(NULL AS VARCHAR CHARACTER SET \"ISO-8859-1\")";
final String expected = "SELECT COUNT(CAST(NULL AS INTEGER))\n"
+ "FROM (VALUES (0)) AS \"t\" (\"EXPR$0\")\nGROUP BY CAST(NULL "
+ "AS VARCHAR CHARACTER SET \"ISO-8859-1\")";
sql(query).ok(expected);
// validate
sql(expected).exec();
}

@Test public void testSelectNullWithGroupByVar() {
String query = "SELECT COUNT(CAST(NULL AS INT)) FROM \"account\" "
+ "AS \"t\" GROUP BY \"account_type\"";
final String expected = "SELECT COUNT(CAST(NULL AS INTEGER))\n"
+ "FROM \"foodmart\".\"account\"\n"
+ "GROUP BY \"account_type\"";
sql(query).ok(expected);
// validate
sql(expected).exec();
}

@Test public void testSelectNullWithInsert() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, can we also give a test case for Join relational expression ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, see testSelectNullWithInsertFromJoin.

String query = "insert into "
+ "\"account\"(\"account_id\",\"account_parent\",\"account_type\",\"account_rollup\")"
+ " select 1, cast(NULL AS INT), cast(123 as varchar), cast(123 as varchar)";
final String expected = "INSERT INTO \"foodmart\".\"account\" ("
+ "\"account_id\", \"account_parent\", \"account_description\", "
+ "\"account_type\", \"account_rollup\", \"Custom_Members\")\n"
+ "(SELECT 1 AS \"account_id\", CAST(NULL AS INTEGER) AS \"account_parent\","
+ " CAST(NULL AS VARCHAR(30) CHARACTER SET "
+ "\"ISO-8859-1\") AS \"account_description\", '123' AS \"account_type\", "
+ ""
+ "'123' AS \"account_rollup\", CAST(NULL AS VARCHAR"
+ "(255) CHARACTER SET \"ISO-8859-1\") AS \"Custom_Members\"\n"
+ "FROM (VALUES (0)) AS \"t\" (\"ZERO\"))";
sql(query).ok(expected);
// validate
sql(expected).exec();
}

@Test public void testSelectNullWithInsertFromJoin() {
String query = "insert into \n"
+ "\"account\"(\"account_id\",\"account_parent\",\n"
+ "\"account_type\",\"account_rollup\")\n"
+ "select \"product\".\"product_id\", \n"
+ "cast(NULL AS INT), \n"
+ "cast(\"product\".\"product_id\" as varchar), \n"
+ "cast(\"sales_fact_1997\".\"store_id\" as varchar)\n"
+ "from \"product\"\n"
+ "inner join \"sales_fact_1997\"\n"
+ "on \"product\".\"product_id\" = \"sales_fact_1997\".\"product_id\"";
final String expected = "INSERT INTO \"foodmart\".\"account\" "
+ "(\"account_id\", \"account_parent\", \"account_description\", "
+ "\"account_type\", \"account_rollup\", \"Custom_Members\")\n"
+ "(SELECT \"product\".\"product_id\" AS \"account_id\", "
+ "CAST(NULL AS INTEGER) AS \"account_parent\", CAST(NULL AS VARCHAR"
+ "(30) CHARACTER SET \"ISO-8859-1\") AS \"account_description\", "
+ "CAST(\"product\".\"product_id\" AS VARCHAR CHARACTER SET "
+ "\"ISO-8859-1\") AS \"account_type\", "
+ "CAST(\"sales_fact_1997\".\"store_id\" AS VARCHAR CHARACTER SET \"ISO-8859-1\") AS "
+ "\"account_rollup\", "
+ "CAST(NULL AS VARCHAR(255) CHARACTER SET \"ISO-8859-1\") AS \"Custom_Members\"\n"
+ "FROM \"foodmart\".\"product\"\n"
+ "INNER JOIN \"foodmart\".\"sales_fact_1997\" "
+ "ON \"product\".\"product_id\" = \"sales_fact_1997\".\"product_id\")";
sql(query).ok(expected);
// validate
sql(expected).exec();
}


@Test public void testDialectQuoteStringLiteral() {
dialects().forEach((dialect, databaseProduct) -> {
assertThat(dialect.quoteStringLiteral(""), is("''"));
Expand Down