gengliangwang commented on code in PR #53570:
URL: https://github.com/apache/spark/pull/53570#discussion_r2850348516


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/catalog/SessionCatalog.scala:
##########
@@ -2101,85 +2437,335 @@ class SessionCatalog(
   }
 
   /**
-   * Look up the `ExpressionInfo` of the given function by name if it's a 
built-in or temp function.
+   * Handles view resolution context for temporary functions (both scalar and 
table-valued).
+   * When resolving a view, only returns the result if the function is 
explicitly referred
+   * by that view. Otherwise, tracks the function reference for future view 
creation.
+   *
+   * This generic helper works for both scalar functions (FunctionRegistry) 
and table-valued
+   * functions (TableFunctionRegistry) due to the type parameter T.
+   *
+   * @param name The function name (unqualified)
+   * @param result The result to wrap with view context handling
+   * @tparam T The result type (ExpressionInfo, Expression, or LogicalPlan)
+   * @return The result if visible in current context, None otherwise
+   */
+  private def handleViewContext[T](name: String, result: Option[T]): Option[T] 
=
+    result.filter { _ =>
+      val isResolvingView = AnalysisContext.get.catalogAndNamespace.nonEmpty
+      val referredTempFunctionNames = 
AnalysisContext.get.referredTempFunctionNames
+
+      if (isResolvingView) {
+        // When resolving a view, only return a temp function if it's referred 
by this view.
+        referredTempFunctionNames.contains(name)
+      } else {
+        // We are not resolving a view and the function is a temp one, add it 
to
+        // AnalysisContext so if a view is being created, it can be checked.
+        AnalysisContext.get.referredTempFunctionNames.add(name)
+        true
+      }
+    }
+
+  /**
+   * Generic helper for looking up functions with temp/builtin shadowing and 
view context.
+   * Checks temp function first (with TEMP_FUNCTION_DB database qualifier), 
then built-in
+   * (without database qualifier). For temp functions, applies view resolution 
context.
+   *
+   * @param name The function name (unqualified)
+   * @param registry The registry to search (FunctionRegistry or 
TableFunctionRegistry)
+   * @param checkBuiltinOperators Whether to check built-in operators first 
(scalar functions only)
+   * @tparam T The registry's type parameter (Expression for FunctionRegistry,
+   *           LogicalPlan for TableFunctionRegistry)
+   * @return ExpressionInfo if function found, None otherwise
+   */
+  /**
+   * Looks up functions using PATH-based resolution.
+   * Searches through the resolution path (session then builtin) with view 
context handling.
+   *
+   * @param name The function name (unqualified).
+   * @param registry The registry to search (FunctionRegistry or 
TableFunctionRegistry).
+   * @param checkBuiltinOperators Whether to check built-in operators first 
(scalar functions only).
+   * @tparam T The registry's type parameter (Expression for FunctionRegistry,
+   *           LogicalPlan for TableFunctionRegistry).
+   * @return ExpressionInfo if function found, None otherwise.
+   */
+  private def lookupFunctionWithShadowing[T](
+      name: String,
+      registry: FunctionRegistryBase[T],
+      checkBuiltinOperators: Boolean): Option[ExpressionInfo] = {
+
+    // Check built-in operators first (only for scalar functions).
+    val operatorResult = if (checkBuiltinOperators) {
+      FunctionRegistry.builtinOperators.get(name.toLowerCase(Locale.ROOT))
+    } else {
+      None
+    }
+
+    operatorResult.orElse {
+      // Use PATH-based resolution: iterate through namespaces until a match 
is found.
+      val path = resolutionPath()
+
+      // Use iterator for short-circuit evaluation (stops at first match).
+      path.iterator.flatMap { namespace =>
+        lookupInNamespace(namespace, name, registry)
+      }.nextOption()
+    }
+  }
+
+  /**
+   * Look up the `ExpressionInfo` of the given function by name.
+   * Resolution order follows the configured path (e.g. builtin then session);
+   * extension functions are stored in the builtin namespace.
    * This only supports scalar functions.
    */
   def lookupBuiltinOrTempFunction(name: String): Option[ExpressionInfo] = {
-    
FunctionRegistry.builtinOperators.get(name.toLowerCase(Locale.ROOT)).orElse {
-      synchronized(lookupTempFuncWithViewContext(
-        name, FunctionRegistry.builtin.functionExists, 
functionRegistry.lookupFunction))
+    lookupFunctionWithShadowing(name, functionRegistry, checkBuiltinOperators 
= true)
+  }
+
+  /**
+   * Look up the `ExpressionInfo` of the given function by name.
+   * Resolution order follows the configured path (e.g. builtin then session);
+   * extension functions are stored in the builtin namespace.
+   */
+  def lookupBuiltinOrTempTableFunction(name: String): Option[ExpressionInfo] = 
{
+    lookupFunctionWithShadowing(name, tableFunctionRegistry, 
checkBuiltinOperators = false)
+  }
+
+  /**
+   * Look up only builtin function (no temp).
+   */
+  def lookupBuiltinFunction(name: String): Option[ExpressionInfo] = {
+    val builtinIdentifier = FunctionIdentifier(format(name))
+    functionRegistry.lookupFunction(builtinIdentifier)
+  }
+
+  /**
+   * Look up only builtin table function (no temp).
+   */
+  def lookupBuiltinTableFunction(name: String): Option[ExpressionInfo] = {
+    val builtinIdentifier = FunctionIdentifier(format(name))
+    tableFunctionRegistry.lookupFunction(builtinIdentifier)
+  }
+
+  /**
+   * Look up only temp function (no builtin).
+   */
+  def lookupTempFunction(name: String): Option[ExpressionInfo] = {
+    val tempIdentifier = tempFunctionIdentifier(name)
+    synchronized(lookupTempFuncWithViewContext(
+      name,
+      // Return false if temp exists (not builtin)
+      ident => !functionRegistry.functionExists(tempIdentifier),
+      _ => functionRegistry.lookupFunction(tempIdentifier)))
+  }
+
+  /**
+   * Look up only temp table function (no builtin).
+   */
+  def lookupTempTableFunction(name: String): Option[ExpressionInfo] = {
+    val tempIdentifier = tempFunctionIdentifier(name)
+    if (tableFunctionRegistry.functionExists(tempIdentifier)) {
+      tableFunctionRegistry.lookupFunction(tempIdentifier)
+    } else {
+      None
     }
   }
 
   /**
-   * Look up the `ExpressionInfo` of the given function by name if it's a 
built-in or
-   * temp table function.
+   * Look up only extension function (no builtin or temp).
    */
-  def lookupBuiltinOrTempTableFunction(name: String): Option[ExpressionInfo] = 
synchronized {

Review Comment:
   shall we keep the `synchronized` keyword for thread safety?



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