gianm commented on code in PR #5349:
URL: https://github.com/apache/calcite/pull/5349#discussion_r4406884207
##########
core/src/main/codegen/templates/Parser.jj:
##########
@@ -915,6 +923,138 @@ SqlNode LeafQuery(ExprContext exprContext) :
e = TableConstructor() { return e; }
|
e = ExplicitTable(getPos()) { return e; }
+|
+ e = FromQuery() { return e; }
+}
+
+/**
+ * Parses a standalone FROM clause. Only valid under conformance levels
+ * that allow pipe syntax.
+ */
+SqlNode FromQuery() :
+{
+ final SqlNode fromClause;
+ final Span s;
+}
+{
+ <FROM> {
+ s = span();
+ if (!this.conformance.isPipeSyntaxAllowed()) {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.pipeSyntaxNotAllowed());
+ }
+ }
+ fromClause = FromClause()
+ // Report helpful error messages for common mistakes. (Generally, FROM
+ // must be followed by pipe operators.)
+ [
+ LOOKAHEAD(1)
+ (
+ <WHERE> {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.pipeClauseNotAllowed("WHERE", "|> WHERE"));
+ }
+ |
+ <ORDER> {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.fromQueryClauseNotAllowed("ORDER BY"));
+ }
+ |
+ <LIMIT> {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.fromQueryClauseNotAllowed("LIMIT"));
+ }
+ |
+ <OFFSET> {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.fromQueryClauseNotAllowed("OFFSET"));
+ }
+ |
+ <FETCH> {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.fromQueryClauseNotAllowed("FETCH"));
+ }
+ |
+ ( <UNION> | <INTERSECT> | <EXCEPT> | <SET_MINUS> ) {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.fromQueryInSetOpNotAllowed());
+ }
+ )
+ ]
+ { return new SqlFromQuery(s.end(this), fromClause); }
+}
+
+/**
+ * Reads optional pipe operators and applies them to the query {@code e}.
+ *
+ * <p>If {@code with}, {@code e} is a WITH, or an ORDER BY of a WITH, that is
+ * not in parentheses. Then the operators go inside the WITH, so that they can
+ * see its CTEs.
+ */
+SqlNode PipeOpt(SqlNode e, boolean with) :
+{
+ SqlWith w = null;
+}
+{
+ {
+ if (with && getToken(1).kind == PIPE) {
+ if (e instanceof SqlOrderBy) {
+ final SqlOrderBy orderBy = (SqlOrderBy) e;
+ w = (SqlWith) orderBy.query;
+ orderBy.setOperand(0, w.body);
+ } else {
+ w = (SqlWith) e;
+ e = w.body;
+ }
+ }
+ }
+ ( e = PipeOperator(e) )*
+ {
+ if (w != null) {
+ w.setOperand(1, e);
+ return w;
+ }
+ return e;
+ }
+}
+
+/**
+ * Reads a single pipe operator and applies it to the query {@code e}.
+ */
+SqlNode PipeOperator(SqlNode e) :
+{
+ final Span s;
+}
+{
+ <PIPE> {
+ s = span();
+ if (!this.conformance.isPipeSyntaxAllowed()) {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.pipeSyntaxNotAllowed());
+ }
+ if (!e.isA(SqlKind.QUERY)) {
+ // A pipe operator applies only to a query.
+ checkNonQueryExpression(ExprContext.ACCEPT_QUERY);
+ }
+ }
+ (
+ e = PipeWhere(s, e)
+ )
+ { return e; }
+}
+
+/**
+ * Parses a pipe WHERE operator, and applies it to the query {@code e}.
Review Comment:
It just means it returns a call whose input is `e`. Reworded it to be
clearer:
```
/**
* Parses a pipe WHERE operator, and returns a SqlPipeWhere whose input
* is the query {@code e}.
*/
```
##########
core/src/main/codegen/templates/Parser.jj:
##########
@@ -3977,6 +4117,18 @@ void AddSetOpQuery(List<Object> list, ExprContext
exprContext) :
pos = getPos();
checkQueryExpression(exprContext);
}
+ [
+ // A FROM query must be in parentheses to follow a set operator.
+ LOOKAHEAD(1)
+ <FROM> {
+ if (!this.conformance.isPipeSyntaxAllowed()) {
+ throw SqlUtil.newContextException(getPos(),
+ RESOURCE.pipeSyntaxNotAllowed());
+ }
+ throw SqlUtil.newContextException(getPos(),
Review Comment:
Ah, this is intentional, the behavior is taken from GoogleSQL. It requires
parentheses in such situations. I added a comment.
##########
core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java:
##########
@@ -667,7 +680,10 @@ private boolean coalesceCoercion(SqlCallBinding
callBinding) {
int colCount = type1.isStruct() ? type1.getFieldCount() : 1;
RelDataType[] argTypes = new RelDataType[2];
argTypes[0] = type1;
- final boolean isSubQuery = node2 instanceof SqlSelect;
+ // Not isA(SqlKind.QUERY): coercing a WITH as a sub-query gives it a type
Review Comment:
I just removed the comment. It was trying to say that we need to use
`PIPE_QUERY` here rather than `QUERY`. I don't think it was adding much, the
line of code stands on its own.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]