class NameScopeStack extends SQLConfHelper
The NameScopeStack is a stack of NameScopes managed by the Resolver. Usually the current scope is used for name resolution, but in case of correlated subqueries we can lookup names in the parent scopes. Low-level scope creation is managed internally, and only high-level api like pushScope and popScope is available to the resolvers. Freshly-created NameScopeStack contains an empty root NameScope, which in the context of Resolver corresponds to the query output.
- Alphabetic
- By Inheritance
- NameScopeStack
- SQLConfHelper
- AnyRef
- Any
- Hide All
- Show All
- Public
- Protected
Instance Constructors
- new NameScopeStack(planLogger: PlanLogger = new PlanLogger)
Value Members
- final def !=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def ##: Int
- Definition Classes
- AnyRef → Any
- final def ==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def asInstanceOf[T0]: T0
- Definition Classes
- Any
- def clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.CloneNotSupportedException]) @IntrinsicCandidate() @native()
- def conf: SQLConf
The active config object within the current scope.
The active config object within the current scope. See SQLConf.get for more information.
- Definition Classes
- SQLConfHelper
- def current: NameScope
Get the current scope, which is a default choice for name resolution.
- final def eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- def equals(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef → Any
- final def getClass(): Class[_ <: AnyRef]
- Definition Classes
- AnyRef → Any
- Annotations
- @IntrinsicCandidate() @native()
- def hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @IntrinsicCandidate() @native()
- final def isInstanceOf[T0]: Boolean
- Definition Classes
- Any
- final def ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- final def notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @IntrinsicCandidate() @native()
- final def notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @IntrinsicCandidate() @native()
- def overwriteCurrent(output: Option[Seq[Attribute]] = None, hiddenOutput: Option[Seq[Attribute]] = None, availableAliases: Option[HashSet[ExprId]] = None, aggregateListAliases: Seq[Alias] = Seq.empty, baseAggregate: Option[Aggregate] = None): Unit
Completely overwrite the current scope state with operator
output,hiddenOutput,availableAliases,aggregateListAliasesandbaseAggregate.Completely overwrite the current scope state with operator
output,hiddenOutput,availableAliases,aggregateListAliasesandbaseAggregate. IfhiddenOutput,availableAliasesorbaseAggregateare not provided, preserve the previous values. Additionally, update nullabilities of attributes in hidden output from new output, so that if attribute was nullable in either old hidden output or new output, it must stay nullable in new hidden output as well.This method is called by the Resolver when we've calculated the output of an operator that is being resolved. The new output is calculated based on the outputs of operator's children.
Example for SubqueryAlias, here we rewrite the current NameScope's attributes to prepend subquery qualifier to their names:
val qualifier = sa.identifier.qualifier :+ sa.alias scopes.overwriteCurrent(scope.output.map(attribute => attribute.withQualifier(qualifier)))
Trivially, we would call this method for every operator in the query plan, however some operators just propagate the output of their children without any changes, so we can omit this call for them (e.g. Filter).
This method should be preferred over pushScope.
- def overwriteOutputAndExtendHiddenOutput(output: Seq[Attribute], groupingAttributeIds: Option[HashSet[ExprId]] = None, aggregateListAliases: Seq[Alias] = Seq.empty, baseAggregate: Option[Aggregate] = None): Unit
Overwrites
output,groupingAttributeIds,aggregateListAliasesandbaseAggregateof the current NameScope entry and:Overwrites
output,groupingAttributeIds,aggregateListAliasesandbaseAggregateof the current NameScope entry and:- extends hidden output with the provided output (only attributes that are not in the hidden output are added). This is done because resolution of arguments can be done through certain operators by hidden output. This use case is specific to Dataframe programs. Example:
val df = (1 to 100).map { i => (i, i % 10, i % 2 == 0) }.toDF("a", "b", "c") df.select($"a", $"b").filter($"c")
Unresolved tree would be:
Filter 'c +- 'Project ['a, 'b] +- Project [_1 AS a, _2 AS b, _3 AS c] +- LocalRelation [_1, _2, _3]
As it can be seen in the example above,
cfrom the Filter condition should be resolved using thehiddenOutput(because its child output doesn't containc). That's why in hidden output we have to have both hidden output from the previous scope and the provided output. This is done for Project and Aggregate operators.2. updates properties of attributes in hidden output. This includes nullabilities and access modes. See updateHiddenOutputProperties for more details.
- def popScope(): Unit
After finishing the resolution after pushScope, the caller needs to call popScope to clear the stack.
After finishing the resolution after pushScope, the caller needs to call popScope to clear the stack. We propagate
hiddenOutput,availableAliasesupwards because of name resolution by overwriting their current values with the popped ones. This is not done in case pushScope and popScope were called in the context of subquery resolution (which is indicated byisSubqueryRootflag), because we don't want to overwrite the existinghiddenOutputof the main plan. - def pushScope(isSubqueryRoot: Boolean = false): Unit
Push a fresh scope to the stack.
Push a fresh scope to the stack.
This method is called by the Resolver before recursing into the operator's child resolution _only_ in cases where a fresh scope is required.
For example, Project or Aggregate introduce their own scopes semantically, so that a lower resolution can lookup correlated names:
CREATE TABLE IF NOT EXISTS t1 (col1 INT, col2 STRING); CREATE TABLE IF NOT EXISTS t2 (col1 INT, col2 STRING); -- Here we need a scope for the upper [[Project]], and a separate scope for the correlated -- subquery, because its [[Filter]] need to lookup `t1.col1` from the upper scope. -- Those scopes have to be independent to avoid polluting each other's attributes. SELECT col1, (SELECT col2 FROM t2 WHERE t2.col1 == t1.col1 LIMIT 1) FROM t1;
Also, we need separate scopes for the operators with multiple children, so that the next child's resolution wouldn't try to work with the data from it's sibling's scope, to avoid all kinds of undefined behavior:
pushScope() val resolvedLeftChild = try { resolve(unresolvedExcept.left) } finally { popScope() } // Right child should not see the left child's resolution data to avoid subtle bugs, so we // create a fresh scope here. pushScope() val resolvedRightChild = try { resolve(unresolvedExcept.right) } finally { popScope() }
- isSubqueryRoot
Indicates that the current scope is a root of a subquery. This is used by NameScopeStack.resolveMultipartName to detect the nearest outer scope.
- def resolveMultipartName(multipartName: Seq[String], canLaterallyReferenceColumn: Boolean = false, canReferenceAggregateExpressionAliases: Boolean = false, canResolveNameByHiddenOutput: Boolean = false, canResolveNameByHiddenOutputInSubquery: Boolean = false, shouldPreferTableColumnsOverAliases: Boolean = false, shouldPreferHiddenOutput: Boolean = false, canReferenceAggregatedAccessOnlyAttributes: Boolean = false): NameTarget
Resolve multipart name into a NameTarget from current or outer scopes.
Resolve multipart name into a NameTarget from current or outer scopes. Currently we only support one level of correlation, so we look up
multipartNamein current scope, and if the name was not found, we look it up in the nearest outer scope:-- 'a' is a simple lookup from the current scope. SELECT a FROM (SELECT col1 AS a FROM VALUES (1));
-- `a` in `(SELECT a + 1)` will be wrapped in [[OuterReference]]. SELECT a, (SELECT a + 1) AS b FROM (SELECT col1 AS a FROM VALUES (1));
The ambiguity between local and outer references is resolved in favour of current:
-- There's no correlation here, subquery references its column from the current scope. -- This returns [1, 2]. SELECT col1, (SELECT col1 FROM VALUES (2)) AS b FROM VALUES (1)
Correlations beyond one level are not supported:
-- 3 levels, fails with `UNRESOLVED_COLUMN`. SELECT ( SELECT ( SELECT t1.col1 FROM VALUES (3) AS t3 ) FROM VALUES (2) AS t2 ) FROM VALUES (1) AS t1;
Correlated references are accessible from lower subquery operators:
-- Returns [1, 1] SELECT col1, (SELECT * FROM (SELECT t1.col1 FROM VALUES (2) AS t2)) FROM VALUES (1) AS t1;
We cannot reference LCA or aggregate expression by alias in the outer scope:
-- These examples fail with `UNRESOLVED_COLUMN`. -- LCA in outer scope. SELECT col1 AS a, (SELECT a + 1) AS b FROM VALUES (1); -- Aliased aggerate expression in outer scope. SELECT col1 AS a FROM VALUES (1) GROUP BY a, (SELECT a + 1);
Only Attributes are wrapped in OuterReference:
-- The subquery's [[Project]] list will contain outer(col1#0).f1.f2. SELECT col1, (SELECT col1.f1.f2 + 1) AS b FROM VALUES (named_struct('f1', named_struct('f2', 1)));
- final def synchronized[T0](arg0: => T0): T0
- Definition Classes
- AnyRef
- def toString(): String
- Definition Classes
- AnyRef → Any
- final def wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- final def wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException]) @native()
- final def wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- def withSQLConf[T](pairs: (String, String)*)(f: => T): T
Sets all SQL configurations specified in
pairs, callsf, and then restores all SQL configurations.Sets all SQL configurations specified in
pairs, callsf, and then restores all SQL configurations.- Attributes
- protected
- Definition Classes
- SQLConfHelper
Deprecated Value Members
- def finalize(): Unit
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.Throwable]) @Deprecated
- Deprecated
(Since version 9)