srielau commented on code in PR #55647:
URL: https://github.com/apache/spark/pull/55647#discussion_r3177635417


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveFetchCursor.scala:
##########
@@ -64,7 +64,8 @@ class ResolveFetchCursor(val catalogManager: CatalogManager) 
extends Rule[Logica
           nameParts = u.nameParts
         ) match {
           case Some(variable) => variable.copy(canFold = false)
-          case _ => throw unresolvedVariableError(u.nameParts, Seq("SYSTEM", 
"SESSION"))
+          case _ => throw unresolvedVariableError(
+            u.nameParts, Seq(Seq("SYSTEM", "SESSION")), u.origin)

Review Comment:
   Good catch -- this was a real miss. Fixed in c2f8f642c45: `FETCH ... INTO` 
now routes through `variableResolution.searchPathEntriesForError` and reports 
the full SQL path consistently with `SET VAR`.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/VariableResolution.scala:
##########
@@ -43,10 +43,25 @@ class VariableResolution(
    * (PATH enabled and explicitly set).
    */
   private def allowUnqualifiedSessionTempVariableLookup(nameParts: 
Seq[String]): Boolean = {
-    if (nameParts.length != 1) return true
-    catalogManager.sessionScopeUnqualifiedAllowed(
-      catalogManager.currentCatalog.name(),
-      catalogManager.currentNamespace.toSeq)
+    nameParts.length != 1 || catalogManager.isSystemSessionOnPath
+  }
+
+  /**
+   * Search-path entries to report in `UNRESOLVED_VARIABLE` for DML lookups 
(`SET VAR`,
+   * `FETCH ... INTO`). The full SQL path is reported regardless of how the 
name was
+   * qualified, matching the convention used by `TABLE_OR_VIEW_NOT_FOUND` and
+   * `UNRESOLVED_ROUTINE`. Keeping the rendering qualification-independent 
also avoids
+   * re-shaping the error if Spark ever grows struct-field assignment, where 
2-part forms
+   * become genuinely ambiguous.
+   *
+   * DDL paths (`DECLARE` / `DROP` name validation in
+   * [[org.apache.spark.sql.catalyst.analysis.ResolveCatalogs]]) do not 
consult the SQL path
+   * and report `[system.session]` directly at their throw site.
+   */
+  def searchPathEntriesForError: Seq[Seq[String]] = {

Review Comment:
   Yes, deliberate. Two reasons:
   
   1. **Consistency with the other `*_NOT_FOUND` errors.** 
`TABLE_OR_VIEW_NOT_FOUND` keeps `system.builtin` in its rendered `searchPath` 
even though no tables can ever live there, and `UNRESOLVED_ROUTINE` likewise 
reports the full path regardless of qualification. The reported `searchPath` is 
"the path the resolver would consult", not "the path that could possibly hold 
this object kind". Filtering for variables would make `UNRESOLVED_VARIABLE` the 
third inconsistent variant in this family.
   
   2. **Future-proofing against struct-field assignment.** If `SET VAR 
session.foo = ...` ever gains a struct-field-assignment interpretation, 2-part 
forms become genuinely ambiguous between qualified-variable and field-access. 
The resolver would then try multiple interpretations through PATH-gated lookup, 
and the error format wouldn't have to change.
   
   `isSystemSessionOnPath` keeps the *resolution-time* check cheap and accurate 
(no spurious lookups in non-session namespaces), so resolution and reporting 
are decoupled: optimization in the gate, full faithful path in the error. The 
added doc on `searchPathEntriesForError` calls this out.



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to