ganeshashree commented on code in PR #58450:
URL: https://github.com/apache/spark/pull/58450#discussion_r3930726238


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionResolution.scala:
##########
@@ -404,6 +388,87 @@ class FunctionResolution(
     }
   }
 
+  /**
+   * Returns whether an unqualified function name reaches `system.builtin` 
before any temp or
+   * persistent function in the effective SQL PATH. When a temp or persistent 
function shadows the
+   * builtin, special-syntax rewrites (e.g. `count(*) -> count(1)`) must not 
fire, since the name no
+   * longer refers to Spark's builtin.
+   */
+  def unqualifiedFunctionResolvesToBuiltinBeforeAnyShadow(functionName: 
String): Boolean = {
+    // Walk the PATH in order and stop at the first entry that owns the name. 
The default order puts
+    // system.builtin first, so the common case returns on the first entry 
with no catalog lookup;
+    // only a custom PATH that lists a persistent catalog ahead of 
system.builtin reaches the probe
+    // below (one lookup per such preceding entry, recomputed on each call -- 
not cached).
+    sqlResolutionPathEntriesForAnalysis.foreach { pathEntry =>
+      val candidate = pathEntry :+ functionName
+      FunctionResolution.sessionNamespaceKind(candidate) match {
+        case 
Some(org.apache.spark.sql.catalyst.catalog.SessionCatalog.Builtin) =>
+          return true
+        case Some(org.apache.spark.sql.catalyst.catalog.SessionCatalog.Temp) =>
+          if 
(v1SessionCatalog.isTemporaryFunction(FunctionIdentifier(functionName))) {
+            return false
+          }
+        case None =>
+          if (persistentFunctionExists(candidate)) {
+            return false
+          }
+      }
+    }
+    false
+  }
+
+  /**
+   * Returns true when a function reference resolves to the system built-in 
with the requested name.
+   * This mirrors [[resolveFunction]] for special parser/analyzer rewrites 
that must run only for
+   * Spark's built-ins. In particular, two-part `builtin.name` is not always a 
system built-in:
+   * with `spark.sql.legacy.persistentCatalogFirst=true`, an existing 
persistent
+   * `current_catalog.builtin.name` takes precedence.
+   */
+  def functionNameResolvesToBuiltin(nameParts: Seq[String], expectedName: 
String): Boolean = {
+    if (!FunctionRegistry.functionSet.contains(
+          FunctionRegistry.builtinFunctionIdentifier(expectedName)) ||
+        !FunctionResolution.isUnqualifiedOrBuiltinFunctionName(nameParts, 
expectedName)) {
+      return false
+    }
+    nameParts.length match {
+      case 1 =>
+        unqualifiedFunctionResolvesToBuiltinBeforeAnyShadow(nameParts.head)
+      case 2 =>
+        conf.prioritizeSystemCatalog || !persistentFunctionExists(nameParts)
+      case 3 =>
+        true
+      case _ =>
+        false
+    }
+  }
+
+  private val starDisallowedJsonConstructors =
+    Set("json_array", "json_exists", "json_query", "json_value")

Review Comment:
   Done. Extracted `FunctionRegistry.routedJsonConstructorNames` as the single 
source of truth; the star-guard set now derives from it, so a newly routed 
constructon automatically. The `expressionBuilder(...)` registrations can't be 
generated from it (each needs its concrete builder's ClassTag for 
ExpressionInfo), so I documented the two lists that still need a mgrammar).
   



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