Skip to content

Commit

Permalink
[CALCITE-6355] Improve subquery check to consider chained ORDER BY calls
Browse files Browse the repository at this point in the history
  • Loading branch information
bvolpato committed Apr 7, 2024
1 parent 4c69588 commit 1ec65f4
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,7 @@ private boolean needNewSubQuery(
if (rel instanceof Project
&& clauses.contains(Clause.ORDER_BY)
&& dialect.getConformance().isSortByOrdinal()
&& hasSortByOrdinal()) {
&& hasSortByOrdinal(node)) {
// Cannot merge a Project that contains sort by ordinal under it.
return true;
}
Expand Down Expand Up @@ -1932,25 +1932,32 @@ && hasSortByOrdinal()) {
}

/**
* Return whether the current {@link SqlNode} in {@link Result} contains sort by column
* in ordinal format.
* Return whether the given {@link SqlNode} contains a sort by using an ordinal / numeric
* literal. Checks recursively if the node is a {@link SqlSelect} or a {@link SqlBasicCall}.
*
* @param sqlNode SqlNode to check
*/
private boolean hasSortByOrdinal(@UnknownInitialization Result this) {
if (node instanceof SqlSelect) {
final SqlNodeList orderList = ((SqlSelect) node).getOrderList();
private boolean hasSortByOrdinal(@UnknownInitialization Result this, @Nullable SqlNode sqlNode) {
if (sqlNode == null) {
return false;
}
if (sqlNode instanceof SqlNumericLiteral) {
return true;
}
if (sqlNode instanceof SqlSelect) {
final SqlNodeList orderList = ((SqlSelect) sqlNode).getOrderList();
if (orderList == null) {
return false;
}
for (SqlNode sqlNode : orderList) {
if (sqlNode instanceof SqlNumericLiteral) {
for (SqlNode child : orderList) {
if (hasSortByOrdinal(child)) {
return true;
}
if (sqlNode instanceof SqlBasicCall) {
for (SqlNode operand : ((SqlBasicCall) sqlNode).getOperandList()) {
if (operand instanceof SqlNumericLiteral) {
return true;
}
}
}
} else if (sqlNode instanceof SqlBasicCall) {
for (SqlNode operand : ((SqlBasicCall) sqlNode).getOperandList()) {
if (hasSortByOrdinal(operand)) {
return true;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2162,6 +2162,48 @@ private SqlDialect nonOrdinalDialect() {
.ok(prestoExpected);
}

/**
* Test case for the base case of
* <a href="https://issues.apache.org/jira/browse/CALCITE-6355">[CALCITE-6355]
* RelToSqlConverter[ORDER BY] generates an incorrect order by when NULLS LAST is used in
* non-projected</a>.
*/
@Test void testOrderByOrdinalDesc() {
String query = "select \"product_id\"\n"
+ "from \"product\"\n"
+ "where \"net_weight\" is not null\n"
+ "group by \"product_id\""
+ "order by MAX(\"net_weight\") desc";
final String expected = "SELECT \"product_id\"\n"
+ "FROM (SELECT \"product_id\", MAX(\"net_weight\") AS \"EXPR$1\"\n"
+ "FROM \"foodmart\".\"product\"\n"
+ "WHERE \"net_weight\" IS NOT NULL\n"
+ "GROUP BY \"product_id\"\n"
+ "ORDER BY 2 DESC) AS \"t3\"";
sql(query).ok(expected);
}

/**
* Test case for the problematic case of
* <a href="https://issues.apache.org/jira/browse/CALCITE-6355">[CALCITE-6355]
* RelToSqlConverter[ORDER BY] generates an incorrect order by when NULLS LAST is used in
* non-projected</a>.
*/
@Test void testOrderByOrdinalDescNullsLast() {
String query = "select \"product_id\"\n"
+ "from \"product\"\n"
+ "where \"net_weight\" is not null\n"
+ "group by \"product_id\""
+ "order by MAX(\"net_weight\") desc nulls last";
final String expected = "SELECT \"product_id\"\n"
+ "FROM (SELECT \"product_id\", MAX(\"net_weight\") AS \"EXPR$1\"\n"
+ "FROM \"foodmart\".\"product\"\n"
+ "WHERE \"net_weight\" IS NOT NULL\n"
+ "GROUP BY \"product_id\"\n"
+ "ORDER BY 2 DESC NULLS LAST) AS \"t3\"";
sql(query).ok(expected);
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-3440">[CALCITE-3440]
* RelToSqlConverter does not properly alias ambiguous ORDER BY</a>. */
Expand Down

0 comments on commit 1ec65f4

Please sign in to comment.