Packages

class CteScope extends AnyRef

The CteScope is responsible for keeping track of visible and known CTE definitions at a given stage of a SQL query/DataFrame program resolution. These scopes are stacked and the stack is managed by the CteRegistry. The scope is created per single WITH clause.

The CTE operators are:

  • UnresolvedWith. This is a host operator that contains a list of unresolved CTE definitions from the WITH clause and a single child operator, which is the actual unresolved SELECT query.
  • UnresolvedRelation. This is a generic unresolved relation operator that will sometimes be resolved to a CTE definition and later replaced with a CTERelationRef. The CTE takes precedence over a regular table or a view when resolving this identifier.
  • CTERelationDef. This is a reusable logical plan, which will later be referenced by the lower CTE definitions and UnresolvedWith child.
  • CTERelationRef. This is a leaf node similar to a relation operator that references a certain CTERelationDef by its ID. It has a name (unique locally for a WITH clause list) and an ID (unique for all the CTEs in a query).
  • WithCTE. This is a host operator that contains a list of resolved CTE definitions from the WITH clause and a single child operator, which is the actual resolved SELECT query.

The task of the Resolver is to correctly place WithCTE with CTERelationDefs inside and make sure that CTERelationRefs correctly reference CTERelationDefs with their IDs. The decision whether to inline those CTE subtrees or not is made by the Optimizer, unlike what Spark does for the Views (always inline during the analysis).

There are some caveats in how Spark places those operators and resolves their names:

  • Ambiguous CTE definition names are disallowed only within a single WITH clause, and this is validated by the Parser in AstBuilder using QueryParsingErrors.duplicateCteDefinitionNamesError:
-- This is disallowed.
WITH cte AS (SELECT 1),
cte AS (SELECT 2)
SELECT * FROM cte;
  • When UnresolvedRelation identifier is resolved to a CTERelationDef and there is a name conflict on several layers of CTE definitions, the lower definitions take precedence:
-- The result is `3`, lower [[CTERelationDef]] takes precedence.
WITH cte AS (
  SELECT 1
)
SELECT * FROM (
  WITH cte AS (
    SELECT 2
  )
  SELECT * FROM (
    WITH cte AS (
      SELECT 3
    )
    SELECT * FROM cte
  )
)
  • Any subquery can contain UnresolvedWith on top of it, but WithCTE is not gonna be 1 to 1 to its unresolved counterpart. For example, if we are dealing with simple subqueries, CTERelationDefs will be merged together under a single WithCTE. The previous example would produce the following resolved plan:
WithCTE
:- CTERelationDef 18, false
:  +- ...
:- CTERelationDef 19, false
:  +- ...
:- CTERelationDef 20, false
:  +- ...
+- Project [3#1203]
:  +- ...
  • However, if we have any expression subquery (scalar/IN/EXISTS...), the top CTERelationDefs and subquery's CTERelationDef won't be merged together (as they are separated by an expression tree):
WITH cte AS (
  SELECT 1 AS col1
)
SELECT * FROM cte WHERE col1 IN (
  WITH cte AS (
    SELECT 2
  )
  SELECT * FROM cte
)

->

WithCTE
:- CTERelationDef 21, false
:  +- ...
+- Project [col1#1223]
   +- Filter col1#1223 IN (list#1222 [])
      :  +- WithCTE
      :     :- CTERelationDef 22, false
      :     :  +- ...
      :     +- Project [2#1241]
      :        +- ...
      +- ...
  • Upper CTEs are visible through subqueries and can be referenced by lower operators, but not through the View boundary:
CREATE VIEW v1 AS SELECT 1;
CREATE VIEW v2 AS SELECT * FROM v1;

-- The result is 1.
-- The `v2` body will be inlined in the main query tree during the analysis, but upper `v1`
-- CTE definition _won't_ take precedence over the lower `v1` view.
WITH v1 AS (
  SELECT 2
)
SELECT * FROM v2;
Linear Supertypes
AnyRef, Any
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. CteScope
  2. AnyRef
  3. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Instance Constructors

  1. new CteScope(isRoot: Boolean, isOpaque: Boolean)

    isRoot

    This marks the place where WithCTE has to be placed with all the merged CTERelationDef that were collected under it. It will be true for root query, Views and expression subqueries.

    isOpaque

    This flag makes this CteScope opaque for CTERelationDef lookups. It will be true for root query and Views.

Value Members

  1. final def !=(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  2. final def ##: Int
    Definition Classes
    AnyRef → Any
  3. final def ==(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  4. final def asInstanceOf[T0]: T0
    Definition Classes
    Any
  5. def clone(): AnyRef
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.CloneNotSupportedException]) @IntrinsicCandidate() @native()
  6. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  7. def equals(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef → Any
  8. final def getClass(): Class[_ <: AnyRef]
    Definition Classes
    AnyRef → Any
    Annotations
    @IntrinsicCandidate() @native()
  9. def getCte(name: String): Option[CTERelationDef]

    Get a visible CTE definition by its name.

  10. def getKnownCtes: Seq[CTERelationDef]

    Get all known (from this and child scopes) CTERelationDefs.

    Get all known (from this and child scopes) CTERelationDefs. This is used to construct WithCTE from a root scope.

  11. def hashCode(): Int
    Definition Classes
    AnyRef → Any
    Annotations
    @IntrinsicCandidate() @native()
  12. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  13. val isOpaque: Boolean
  14. val isRoot: Boolean
  15. def mergeChildScope(childScope: CteScope): Unit

    Merge the state from a child scope.

    Merge the state from a child scope. We transfer all the known CTE definitions to later merge them in one WithCTE. Root scopes terminate this chain, since they have their own WithCTE.

  16. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  17. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @IntrinsicCandidate() @native()
  18. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @IntrinsicCandidate() @native()
  19. def registerCte(name: String, cteDef: CTERelationDef): Unit

    Register a new CTE definition in this scope.

    Register a new CTE definition in this scope. Since the scope is created per single WITH clause, there can be no name conflicts, but this is validated by the Parser in AstBuilder using QueryParsingErrors.duplicateCteDefinitionNamesError. This definition will be both known and visible.

  20. final def synchronized[T0](arg0: => T0): T0
    Definition Classes
    AnyRef
  21. def toString(): String
    Definition Classes
    AnyRef → Any
  22. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  23. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException]) @native()
  24. final def wait(): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])

Deprecated Value Members

  1. def finalize(): Unit
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.Throwable]) @Deprecated
    Deprecated

    (Since version 9)

Inherited from AnyRef

Inherited from Any

Ungrouped