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
13 changes: 13 additions & 0 deletions common/utils/src/main/resources/error/error-conditions.json
Original file line number Diff line number Diff line change
Expand Up @@ -3642,6 +3642,19 @@
},
"sqlState" : "42601"
},
"NOT_ALLOWED_IN_PIPE_OPERATOR_WHERE" : {
"message" : [
"Not allowed in the pipe WHERE clause:"
],
"subClass" : {
"WINDOW_CLAUSE" : {
"message" : [
"WINDOW clause."
]
}
},
"sqlState" : "42601"
},
"NOT_A_CONSTANT_STRING" : {
"message" : [
"The expression <expr> used for the routine or clause <name> must be a constant STRING which is NOT NULL."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1502,8 +1502,11 @@ version
;

operatorPipeRightSide
: selectClause
| whereClause
: selectClause windowClause?
// Note that the WINDOW clause is not allowed in the WHERE pipe operator, but we add it here in
// the grammar simply for purposes of catching this invalid syntax and throwing a specific
// dedicated error message.
| whereClause windowClause?
// The following two cases match the PIVOT or UNPIVOT clause, respectively.
// For each one, we add the other clause as an option in order to return high-quality error
// messages in the event that both are present (this is not allowed).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ private[sql] object QueryParsingErrors extends DataTypeErrorsBase {
ctx)
}

def windowClauseInPipeOperatorWhereClauseNotAllowedError(ctx: ParserRuleContext): Throwable = {
new ParseException(errorClass = "NOT_ALLOWED_IN_PIPE_OPERATOR_WHERE.WINDOW_CLAUSE", ctx)
}

def distributeByUnsupportedError(ctx: QueryOrganizationContext): Throwable = {
new ParseException(errorClass = "_LEGACY_ERROR_TEMP_0012", ctx)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,12 +428,18 @@ class Analyzer(override val catalogManager: CatalogManager) extends RuleExecutor
def apply(plan: LogicalPlan): LogicalPlan = plan.resolveOperatorsUpWithPruning(
_.containsAnyPattern(WITH_WINDOW_DEFINITION, UNRESOLVED_WINDOW_EXPRESSION), ruleId) {
// Lookup WindowSpecDefinitions. This rule works with unresolved children.
case WithWindowDefinition(windowDefinitions, child) => child.resolveExpressions {
case UnresolvedWindowExpression(c, WindowSpecReference(windowName)) =>
val windowSpecDefinition = windowDefinitions.getOrElse(windowName,
throw QueryCompilationErrors.windowSpecificationNotDefinedError(windowName))
WindowExpression(c, windowSpecDefinition)
}
case WithWindowDefinition(windowDefinitions, child, forPipeSQL) =>
val resolveWindowExpression: PartialFunction[Expression, Expression] = {
case UnresolvedWindowExpression(c, WindowSpecReference(windowName)) =>
val windowSpecDefinition = windowDefinitions.getOrElse(windowName,
throw QueryCompilationErrors.windowSpecificationNotDefinedError(windowName))
WindowExpression(c, windowSpecDefinition)
}
if (forPipeSQL) {
child.transformExpressions(resolveWindowExpression)
} else {
child.resolveExpressions(resolveWindowExpression)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -979,9 +979,10 @@ class AstBuilder extends DataTypeAstBuilder
* Add ORDER BY/SORT BY/CLUSTER BY/DISTRIBUTE BY/LIMIT/WINDOWS clauses to the logical plan. These
* clauses determine the shape (ordering/partitioning/rows) of the query result.
*
* If 'forPipeOperators' is true, throws an error if the WINDOW clause is present (since this is
* not currently supported) or if more than one clause is present (this can be useful when parsing
* clauses used with pipe operations which only allow one instance of these clauses each).
* If 'forPipeOperators' is true, throws an error if the WINDOW clause is present (since it breaks
* the composability of the pipe operators) or if more than one clause is present (this can be
* useful when parsing clauses used with pipe operations which only allow one instance of these
* clauses each).
*/
private def withQueryResultClauses(
ctx: QueryOrganizationContext,
Expand Down Expand Up @@ -1023,7 +1024,7 @@ class AstBuilder extends DataTypeAstBuilder

// WINDOWS
val withWindow = withOrder.optionalMap(windowClause) {
withWindowClause
withWindowClause(_, _, forPipeOperators)
}
if (forPipeOperators && windowClause != null) {
throw QueryParsingErrors.clausesWithPipeOperatorsUnsupportedError(
Expand Down Expand Up @@ -1306,7 +1307,9 @@ class AstBuilder extends DataTypeAstBuilder
}

// Window
val withWindow = withDistinct.optionalMap(windowClause)(withWindowClause)
val withWindow = withDistinct.optionalMap(windowClause) {
withWindowClause(_, _, isPipeOperatorSelect)
}

withWindow
}
Expand Down Expand Up @@ -1463,7 +1466,8 @@ class AstBuilder extends DataTypeAstBuilder
*/
private def withWindowClause(
ctx: WindowClauseContext,
query: LogicalPlan): LogicalPlan = withOrigin(ctx) {
query: LogicalPlan,
forPipeSQL: Boolean): LogicalPlan = withOrigin(ctx) {
// Collect all window specifications defined in the WINDOW clause.
val baseWindowTuples = ctx.namedWindow.asScala.map {
wCtx =>
Expand Down Expand Up @@ -1495,7 +1499,7 @@ class AstBuilder extends DataTypeAstBuilder

// Note that mapValues creates a view instead of materialized map. We force materialization by
// mapping over identity.
WithWindowDefinition(windowMapView.map(identity), query)
WithWindowDefinition(windowMapView.map(identity), query, forPipeSQL)
}

/**
Expand Down Expand Up @@ -5894,10 +5898,13 @@ class AstBuilder extends DataTypeAstBuilder
whereClause = null,
aggregationClause = null,
havingClause = null,
windowClause = null,
windowClause = ctx.windowClause,
relation = left,
isPipeOperatorSelect = true)
}.getOrElse(Option(ctx.whereClause).map { c =>
if (ctx.windowClause() != null) {
throw QueryParsingErrors.windowClauseInPipeOperatorWhereClauseNotAllowedError(ctx)
}
withWhereClause(c, withSubqueryAlias())
}.getOrElse(Option(ctx.pivotClause()).map { c =>
if (ctx.unpivotClause() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,8 @@ trait CTEInChildren extends LogicalPlan {

case class WithWindowDefinition(
windowDefinitions: Map[String, WindowSpecDefinition],
child: LogicalPlan) extends UnaryNode {
child: LogicalPlan,
forPipeSQL: Boolean) extends UnaryNode {
override def output: Seq[Attribute] = child.output
final override val nodePatterns: Seq[TreePattern] = Seq(WITH_WINDOW_DEFINITION)
override protected def withNewChildInternal(newChild: LogicalPlan): WithWindowDefinition =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,9 @@ class PlanParserSuite extends AnalysisTest {
val limitWindowClauses = Seq(
("", (p: LogicalPlan) => p),
(" limit 10", (p: LogicalPlan) => p.limit(10)),
(" window w1 as ()", (p: LogicalPlan) => WithWindowDefinition(ws, p)),
(" window w1 as () limit 10", (p: LogicalPlan) => WithWindowDefinition(ws, p).limit(10))
(" window w1 as ()", (p: LogicalPlan) => WithWindowDefinition(ws, p, forPipeSQL = false)),
(" window w1 as () limit 10", (p: LogicalPlan) =>
WithWindowDefinition(ws, p, forPipeSQL = false).limit(10))
)

val orderSortDistrClusterClauses = Seq(
Expand Down Expand Up @@ -524,7 +525,7 @@ class PlanParserSuite extends AnalysisTest {
|window w1 as (partition by a, b order by c rows between 1 preceding and 1 following),
| w2 as w1,
| w3 as w1""".stripMargin,
WithWindowDefinition(ws1, plan))
WithWindowDefinition(ws1, plan, forPipeSQL = false))
}

test("lateral view") {
Expand Down
Loading