vladimirg-db commented on code in PR #53570:
URL: https://github.com/apache/spark/pull/53570#discussion_r2873212123


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/resolver/ResolverGuard.scala:
##########
@@ -345,14 +347,46 @@ class ResolverGuard(catalogManager: CatalogManager) 
extends SQLConfHelper {
     createNamedStruct.children.forall(checkExpression)
   }
 
-  private def checkUnresolvedFunction(unresolvedFunction: UnresolvedFunction) =
-    unresolvedFunction.nameParts.size == 1 &&
-    
!ResolverGuard.UNSUPPORTED_FUNCTION_NAMES.contains(unresolvedFunction.nameParts.head)
 &&
-    // UDFs are not supported
-    FunctionRegistry.functionSet.contains(
-      
FunctionIdentifier(unresolvedFunction.nameParts.head.toLowerCase(Locale.ROOT))
-    ) &&
-    unresolvedFunction.children.forall(checkExpression)
+  /**
+   * Checks if an unresolved function is supported by the single-pass analyzer.
+   *
+   * The single-pass analyzer supports built-in functions. For qualified 
function names,
+   * we allow them to pass through to the resolver, which will handle them 
appropriately.
+   * This includes:
+   * - Built-in functions: `builtin.count`, `system.builtin.count`, 
unqualified `count`
+   * - Session/temp functions: `session.my_func`, `system.session.my_func` 
(may or may not work)
+   * - Persistent functions: `catalog.db.func` (not currently supported, but 
not actively blocked)
+   *
+   * We only explicitly reject certain built-in functions that require special 
handling
+   * (lambdas, generators, etc.) via the UNSUPPORTED_FUNCTION_NAMES list.
+   *
+   * @param unresolvedFunction the unresolved function to check
+   * @return true if the function should be allowed to attempt resolution, 
false otherwise
+   */
+  private def checkUnresolvedFunction(unresolvedFunction: UnresolvedFunction) 
= {
+    val nameParts = unresolvedFunction.nameParts
+    val functionName = nameParts.last
+
+    // Reject only when we know it's the builtin: unqualified or explicitly 
builtin-qualified
+    // (system.builtin.func or builtin.func). Any other qualification 
(session, catalog.db) we let
+    // through since it's not a forbidden builtin.
+    val shouldReject = if (nameParts.length == 1) {
+      // Unqualified: only allow if it's a known builtin (excluding 
unsupported ones)
+      ResolverGuard.UNSUPPORTED_FUNCTION_NAMES.contains(functionName) ||
+      !FunctionRegistry.functionSet.contains(
+        FunctionIdentifier(functionName.toLowerCase(Locale.ROOT))
+      )
+    } else if (FunctionResolution.sessionNamespaceKind(nameParts)
+        .contains(SessionCatalog.Builtin)) {
+      // Explicitly builtin-qualified (builtin.func, system.builtin.func): 
reject if unsupported
+      ResolverGuard.UNSUPPORTED_FUNCTION_NAMES.contains(functionName)
+    } else {
+      // Other qualification (session, catalog.db, etc.): allow through
+      false

Review Comment:
   Let's make sure we have a test for this in ResolverGuardSuite



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