This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 12d7179c21b fix(hive): select schema via USE prequery instead of
rewriting the URI database (#36603)
12d7179c21b is described below
commit 12d7179c21b2016daf3b0ee493451e0a539a189c
Author: jobbywl <[email protected]>
AuthorDate: Mon Jul 27 23:54:16 2026 +0200
fix(hive): select schema via USE prequery instead of rewriting the URI
database (#36603)
Co-authored-by: Job <[email protected]>
Co-authored-by: Evan Rusackas <[email protected]>
Co-authored-by: Claude Fable 5 <[email protected]>
---
superset/db_engine_specs/hive.py | 33 +++++++++++--
tests/unit_tests/db_engine_specs/test_hive.py | 68 +++++++++++++++++++++++++++
2 files changed, 98 insertions(+), 3 deletions(-)
diff --git a/superset/db_engine_specs/hive.py b/superset/db_engine_specs/hive.py
index efd5a970bcd..a806155b0a4 100644
--- a/superset/db_engine_specs/hive.py
+++ b/superset/db_engine_specs/hive.py
@@ -308,11 +308,38 @@ class HiveEngineSpec(PrestoEngineSpec):
catalog: str | None = None,
schema: str | None = None,
) -> tuple[URL, dict[str, Any]]:
- if schema:
- uri = uri.set(database=parse.quote(schema, safe=""))
-
+ """
+ Return the URI and connection arguments unchanged.
+
+ This overrides the Presto implementation, whose ``catalog/schema`` URI
+ convention doesn't apply to PyHive URLs. The URI must also not be
+ rewritten to point at the selected schema: PyHive issues ``USE`` on the
+ URI database at connect time, so on backends where the URI database
+ selects a catalog (e.g. Spark Thrift Server) rewriting it would be seen
+ as a catalog change and break table resolution. Schema selection is
+ handled by :meth:`get_prequeries` instead.
+ """
return uri, connect_args
+ @classmethod
+ def get_prequeries(
+ cls,
+ database: Database,
+ catalog: str | None = None,
+ schema: str | None = None,
+ ) -> list[str]:
+ """
+ Return a ``USE`` statement to select the schema for new connections.
+
+ A plain single-identifier ``USE`` is valid on both HiveServer2 and
+ Spark Thrift Server, and on the latter it resolves within the current
+ catalog rather than replacing it.
+ """
+ if schema:
+ escaped_schema = schema.replace("`", "``")
+ return [f"USE `{escaped_schema}`"]
+ return []
+
@classmethod
def get_schema_from_engine_params(
cls,
diff --git a/tests/unit_tests/db_engine_specs/test_hive.py
b/tests/unit_tests/db_engine_specs/test_hive.py
index f070b805a33..56b059b3ead 100644
--- a/tests/unit_tests/db_engine_specs/test_hive.py
+++ b/tests/unit_tests/db_engine_specs/test_hive.py
@@ -64,6 +64,74 @@ def test_get_schema_from_engine_params() -> None:
)
[email protected](
+ "catalog,schema",
+ [
+ (None, None),
+ (None, "new_schema"),
+ ("catalog", None),
+ ("catalog", "new_schema"),
+ ],
+)
+def test_adjust_engine_params(catalog: Optional[str], schema: Optional[str])
-> None:
+ """
+ Test that ``adjust_engine_params`` leaves the URI untouched.
+
+ The URI database must not be rewritten to the selected schema: PyHive runs
+ ``USE`` on it at connect time, and on Spark Thrift Server it can select a
+ catalog, so overwriting it with the schema breaks table resolution (see
+ issue #30208). Schema selection happens via ``get_prequeries`` instead.
+ """
+ from superset.db_engine_specs.hive import HiveEngineSpec
+
+ uri = make_url("hive://localhost:10000/default")
+ connect_args = {"foo": "bar"}
+
+ adjusted_uri, adjusted_connect_args = HiveEngineSpec.adjust_engine_params(
+ uri,
+ connect_args,
+ catalog=catalog,
+ schema=schema,
+ )
+ assert adjusted_uri is uri
+ assert adjusted_connect_args is connect_args
+ assert connect_args == {"foo": "bar"}
+
+
[email protected](
+ "catalog,schema,expected",
+ [
+ (None, None, []),
+ ("catalog", None, []),
+ (None, "new_schema", ["USE `new_schema`"]),
+ ("catalog", "new_schema", ["USE `new_schema`"]),
+ (None, "evil`schema", ["USE `evil``schema`"]),
+ ],
+)
+def test_get_prequeries(
+ mocker: MockerFixture,
+ catalog: Optional[str],
+ schema: Optional[str],
+ expected: list[str],
+) -> None:
+ """
+ Test that ``get_prequeries`` selects the schema with a ``USE`` statement.
+
+ Together with ``supports_dynamic_schema`` this implements per-query schema
+ selection, so unqualified table names resolve in the schema Superset
+ attributes the query to.
+ """
+ from superset.db_engine_specs.hive import HiveEngineSpec
+
+ assert HiveEngineSpec.supports_dynamic_schema
+
+ database = mocker.MagicMock()
+ assert (
+ HiveEngineSpec.get_prequeries(database, catalog=catalog, schema=schema)
+ == expected
+ )
+
+
def test_select_star(mocker: MockerFixture) -> None:
"""
Test the ``select_star`` method.