Skip to content
Open
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 @@ -35,8 +35,6 @@
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlSyntax;
import org.apache.calcite.sql.SqlUtil;
import org.apache.calcite.sql.SqlWriter;
import org.apache.calcite.sql.fun.SqlLibraryOperators;
Expand All @@ -49,6 +47,7 @@
import org.checkerframework.checker.nullness.qual.Nullable;

import static org.apache.calcite.util.RelToSqlConverterUtil.unparseBoolLiteralToCondition;
import static org.apache.calcite.util.RelToSqlConverterUtil.unparseWithBinaryOperator;

import static java.util.Objects.requireNonNull;

Expand Down Expand Up @@ -222,8 +221,8 @@ private static SqlNode createDatetimeCastSpec(String typeAlias, RelDataType type
unparseFloor(writer, call);
break;
case MOD:
SqlOperator op = SqlStdOperatorTable.PERCENT_REMAINDER;
SqlSyntax.BINARY.unparse(writer, op, call, leftPrec, rightPrec);
unparseWithBinaryOperator(writer, SqlStdOperatorTable.PERCENT_REMAINDER, call,
leftPrec, rightPrec);
break;
case SAFE_CAST:
// MSSQL uses TRY_CAST instead of SAFE_CAST (BigQuery)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlMapTypeNameSpec;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlSpecialOperator;
import org.apache.calcite.sql.SqlSyntax;
import org.apache.calcite.sql.SqlTypeNameSpec;
import org.apache.calcite.sql.SqlWriter;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
Expand Down Expand Up @@ -339,6 +341,26 @@ public static void unparseBoolLiteralToCondition(SqlWriter writer, boolean value
writer.endList(frame);
}

/**
* Writes a two-operand call with an operator other than its own,
* parenthesized as that operator requires.
*
* <p>{@link SqlCall#unparse} chooses the parentheses from the call's own

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would shorten this comment to say that this will use parentheses when necessary.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I wonder what happens if not all SQL dialects have the same operation precedence...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Upon staring at it longer, I don't think dialects have any ability to hold per operator precedence, do they?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's frankly probably a good thing to add! If done, we'd pass getLeftPrec and getRightPrec through that I guess.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Actually. There are a bunch of special operators floating around for specific SQL languages. I guess if this got hit after those were substituted in, it would be fine, if those carried their own special precedence.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In calcite operators cannot change precedences, but I am saying is that the calcite unparse will decide whether to use parens based on the Calcite rules, which may not match the target dialect rules.

* operator before the dialect is consulted, so an operator that binds less
* tightly needs them added here.
*/
public static void unparseWithBinaryOperator(SqlWriter writer, SqlOperator operator,
SqlCall call, int leftPrec, int rightPrec) {
if (leftPrec > operator.getLeftPrec()
|| (operator.getRightPrec() <= rightPrec && rightPrec != 0)) {
final SqlWriter.Frame frame = writer.startList("(", ")");
SqlSyntax.BINARY.unparse(writer, operator, call, 0, 0);
writer.endList(frame);
} else {
SqlSyntax.BINARY.unparse(writer, operator, call, leftPrec, rightPrec);
}
}

/**
* Transformation Map type from {@code MAP<VARCHAR,VARCHAR>} to {@code Map(VARCHAR,VARCHAR)}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11820,6 +11820,22 @@ private void checkLiteral2(String expression, String expected) {
sql(query).dialect(MssqlSqlDialect.DEFAULT).ok(mssqlExpected);
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-7778">[CALCITE-7778]
* JDBC adapter for MSSQL generates % for MOD without preserving grouping,
* giving wrong results</a>. */
@Test void testModFunctionGroupingForMSSQL() {
final String from = "\nFROM (VALUES (0)) AS [t] ([ZERO])";
sql("select 100 / mod(11, 3)").dialect(MssqlSqlDialect.DEFAULT)
.ok("SELECT 100 / (11 % 3)" + from);
sql("select 100 * mod(11, 3)").dialect(MssqlSqlDialect.DEFAULT)
.ok("SELECT 100 * (11 % 3)" + from);
sql("select mod(100, mod(11, 3))").dialect(MssqlSqlDialect.DEFAULT)
.ok("SELECT 100 % (11 % 3)" + from);
// % already binds more tightly than -, so no parentheses are needed
sql("select 100 - mod(11, 3)").dialect(MssqlSqlDialect.DEFAULT)
.ok("SELECT 100 - 11 % 3" + from);
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-6655">[CALCITE-6655]
Expand Down
Loading