You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by dt...@apache.org on 2026/06/18 00:31:33 UTC
(spark) branch master updated: [SPARK-57328][SQL] Extract matchedIdentifier into a static, resolver-parameterized helper
This is an automated email from the ASF dual-hosted git repository.
dtenedor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new d31cf1921c18 [SPARK-57328][SQL] Extract matchedIdentifier into a static, resolver-parameterized helper
d31cf1921c18 is described below
commit d31cf1921c18ee87f385cd670d495c994b26a354
Author: Daniel Tenedorio <da...@databricks.com>
AuthorDate: Wed Jun 17 17:31:20 2026 -0700
[SPARK-57328][SQL] Extract matchedIdentifier into a static, resolver-parameterized helper
## What changes were proposed in this pull request?
This PR refactors the relation-identifier suffix-match logic (`matchedIdentifier`) out of the
`ResolveHints.ResolveJoinStrategyHints` rule and into a static, resolver-parameterized helper,
so the logic can be shared without depending on fixed-point rule state.
- Added a static `ResolveHints.matchedIdentifier(identInHint, identInQuery, resolver)` helper that
takes the `resolver: Resolver` (i.e. `(String, String) => Boolean`) as an explicit parameter.
- Moved the explanatory doc comment (describing the tail-match semantics and the catalog-independent
comparison) onto the static helper.
- `ResolveJoinStrategyHints` now keeps a thin private `matchedIdentifier` that delegates to the
static helper, passing its `resolver`.
Passing the `resolver` in explicitly gives both the fixed-point analyzer and the single-pass
resolver one source of truth for hint-to-relation matching, without either having to depend on the
other's rule state.
No behavior change: the helper body is identical to the original.
## How was this patch tested?
Existing join-hint resolution test coverage (e.g. join hint suites) pins the behavior; this is a
pure extraction with no functional change.
## Was this patch authored or co-authored using generative AI tooling?
No
Closes #56478 from dtenedor/refactor-matched-identifier.
Authored-by: Daniel Tenedorio <da...@databricks.com>
Signed-off-by: Daniel Tenedorio <da...@databricks.com>
---
.../spark/sql/catalyst/analysis/ResolveHints.scala | 55 +++++++++++++---------
1 file changed, 34 insertions(+), 21 deletions(-)
diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveHints.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveHints.scala
index f6d20dd71b1f..c352f0552339 100644
--- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveHints.scala
+++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveHints.scala
@@ -38,6 +38,38 @@ import org.apache.spark.sql.internal.SQLConf
*/
object ResolveHints {
+ /**
+ * Checks if the given multi-part identifiers are matched with each other.
+ *
+ * The [[ResolveJoinStrategyHints]] rule is applied before the resolution batch in the analyzer
+ * and we cannot semantically compare them at this stage. Therefore, we follow a simple rule;
+ * they match if an identifier in a hint is a tail of an identifier in a relation. This process
+ * is independent of a session catalog (`currentDb` in [[SessionCatalog]]) and it just compares
+ * them literally.
+ *
+ * For example,
+ * - in a query `SELECT /*+ BROADCAST(t) */ * FROM db1.t JOIN t`,
+ * the broadcast hint will match both tables, `db1.t` and `t`,
+ * even when the current db is `db2`.
+ * - in a query `SELECT /*+ BROADCAST(default.t) */ * FROM default.t JOIN t`,
+ * the broadcast hint will match the left-side table only, `default.t`.
+ *
+ * The `resolver` is passed in explicitly so that this logic can be shared by both the
+ * fixed-point analyzer and the single-pass resolver, neither of which has to depend on the
+ * other's rule state.
+ */
+ def matchedIdentifier(
+ identInHint: Seq[String],
+ identInQuery: Seq[String],
+ resolver: Resolver): Boolean = {
+ if (identInHint.length <= identInQuery.length) {
+ identInHint.zip(identInQuery.takeRight(identInHint.length))
+ .forall { case (i1, i2) => resolver(i1, i2) }
+ } else {
+ false
+ }
+ }
+
/**
* The list of allowed join strategy hints is defined in [[JoinStrategyHint.strategies]], and a
* sequence of relation aliases can be specified with a join strategy hint, e.g., "MERGE(a, c)",
@@ -65,27 +97,8 @@ object ResolveHints {
_.toUpperCase(Locale.ROOT)).contains(hintName.toUpperCase(Locale.ROOT))))
}
- // This method checks if given multi-part identifiers are matched with each other.
- // The [[ResolveJoinStrategyHints]] rule is applied before the resolution batch
- // in the analyzer and we cannot semantically compare them at this stage.
- // Therefore, we follow a simple rule; they match if an identifier in a hint
- // is a tail of an identifier in a relation. This process is independent of a session
- // catalog (`currentDb` in [[SessionCatalog]]) and it just compares them literally.
- //
- // For example,
- // * in a query `SELECT /*+ BROADCAST(t) */ * FROM db1.t JOIN t`,
- // the broadcast hint will match both tables, `db1.t` and `t`,
- // even when the current db is `db2`.
- // * in a query `SELECT /*+ BROADCAST(default.t) */ * FROM default.t JOIN t`,
- // the broadcast hint will match the left-side table only, `default.t`.
- private def matchedIdentifier(identInHint: Seq[String], identInQuery: Seq[String]): Boolean = {
- if (identInHint.length <= identInQuery.length) {
- identInHint.zip(identInQuery.takeRight(identInHint.length))
- .forall { case (i1, i2) => resolver(i1, i2) }
- } else {
- false
- }
- }
+ private def matchedIdentifier(identInHint: Seq[String], identInQuery: Seq[String]): Boolean =
+ ResolveHints.matchedIdentifier(identInHint, identInQuery, resolver)
private def extractIdentifier(r: SubqueryAlias): Seq[String] = {
r.identifier.qualifier :+ r.identifier.name
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org