@@ -222,7 +222,38 @@ trait ColumnResolutionHelper extends Logging with DataTypeErrorsBase {
222
222
val outerPlan = AnalysisContext .get.outerPlan
223
223
if (outerPlan.isEmpty) return e
224
224
225
- def resolve (nameParts : Seq [String ]): Option [Expression ] = try {
225
+ def findNestedSubqueryPlans (p : LogicalPlan ): Seq [LogicalPlan ] = {
226
+ if (! p.containsPattern(PLAN_EXPRESSION )) {
227
+ // There are no nested subquery plans in the current plan,
228
+ // stop searching for its children plan
229
+ return Seq .empty
230
+ }
231
+
232
+ val subqueriesInThisNode : Seq [SubqueryExpression ] =
233
+ p.expressions.flatMap(_.collect {
234
+ case in : InSubquery => in.query
235
+ case s : SubqueryExpression => s
236
+ })
237
+
238
+ val subqueryPlansFromExpressions : Seq [LogicalPlan ] =
239
+ subqueriesInThisNode.flatMap(s => findNestedSubqueryPlans(s.plan) :+ s.plan)
240
+
241
+ val subqueryPlansFromChildren : Seq [LogicalPlan ] =
242
+ p.children.flatMap(findNestedSubqueryPlans)
243
+
244
+ // Subquery plan in more inner position gets collected first
245
+ // As it is more near the position of the outer reference, it is more likely to have
246
+ // the original attributes.
247
+ // Though as there are no conflicts, the order does not affect correctness.
248
+ subqueryPlansFromChildren ++ subqueryPlansFromExpressions
249
+ }
250
+
251
+ // The passed in `outerPlan` is the outermost plan
252
+ // Outer references can be from the `outerPlan` or any of its nested subquery plans
253
+ // So we need to try resolving the outer references by using all the plans
254
+ val outerPlans = Seq (outerPlan.get) ++ findNestedSubqueryPlans(outerPlan.get)
255
+
256
+ def resolve (nameParts : Seq [String ], outerPlan : Option [LogicalPlan ]): Option [Expression ] = try {
226
257
outerPlan.get match {
227
258
// Subqueries in UnresolvedHaving can host grouping expressions and aggregate functions.
228
259
// We should resolve columns with `agg.output` and the rule `ResolveAggregateFunctions` will
@@ -240,14 +271,21 @@ trait ColumnResolutionHelper extends Logging with DataTypeErrorsBase {
240
271
None
241
272
}
242
273
243
- e.transformWithPruning(
244
- _.containsAnyPattern(UNRESOLVED_ATTRIBUTE , TEMP_RESOLVED_COLUMN )) {
274
+ e.transformWithPruning(_.containsAnyPattern(UNRESOLVED_ATTRIBUTE , TEMP_RESOLVED_COLUMN )) {
245
275
case u : UnresolvedAttribute =>
246
- resolve(u.nameParts).getOrElse(u)
276
+ val maybeResolved = outerPlans.foldLeft(Option .empty[Expression ]) { (acc, plan) =>
277
+ // If we've already resolved, keep that; otherwise try this plan
278
+ acc.orElse(resolve(u.nameParts, Some (plan)))
279
+ }
280
+ maybeResolved.getOrElse(u)
247
281
// Re-resolves `TempResolvedColumn` as outer references if it has tried to be resolved with
248
282
// Aggregate but failed.
249
283
case t : TempResolvedColumn if t.hasTried =>
250
- resolve(t.nameParts).getOrElse(t)
284
+ val maybeResolved = outerPlans.foldLeft(Option .empty[Expression ]) { (acc, plan) =>
285
+ // If we've already resolved, keep that; otherwise try this plan
286
+ acc.orElse(resolve(t.nameParts, Some (plan)))
287
+ }
288
+ maybeResolved.getOrElse(t)
251
289
}
252
290
}
253
291
0 commit comments