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 defcd639107 fix(mongodb): route dataset FROM clauses through 
quote_table so chart queries return rows (#44583)
defcd639107 is described below

commit defcd639107946734c068bc33c3c32ce71ee2e5d
Author: akashchamp <[email protected]>
AuthorDate: Fri Sep 25 02:46:12 2026 +0530

    fix(mongodb): route dataset FROM clauses through quote_table so chart 
queries return rows (#44583)
    
    Co-authored-by: Claude Sonnet 5 <[email protected]>
---
 superset/connectors/sqla/models.py               | 14 ++++-
 superset/db_engine_specs/base.py                 | 10 ++++
 superset/db_engine_specs/mongodb.py              |  9 ++++
 tests/unit_tests/connectors/sqla/models_test.py  | 68 ++++++++++++++++++++++++
 tests/unit_tests/db_engine_specs/test_mongodb.py | 36 +++++++++++++
 5 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/superset/connectors/sqla/models.py 
b/superset/connectors/sqla/models.py
index 7bb0b48855a..548a5403660 100644
--- a/superset/connectors/sqla/models.py
+++ b/superset/connectors/sqla/models.py
@@ -1985,7 +1985,19 @@ class SqlaTable(
             return table(quoted_name(full_name, quote=False))
 
         if self.schema:
-            return table(self.table_name, schema=self.schema)
+            if self.database.db_engine_spec.quote_table_includes_schema:
+                return table(self.table_name, schema=self.schema)
+
+            # This engine's `quote_table` doesn't qualify the identifier with 
the
+            # schema (e.g. MongoDB/PyMongoSQL, which takes the whole FROM 
reference
+            # as a literal collection name). Build the FROM-clause identifier 
the
+            # same way `select_star` does for SQL Lab, and rely on
+            # `adjust_engine_params` to select the schema at the connection 
level.
+            full_table_name = self.database.db_engine_spec.quote_table(
+                Table(self.table_name, self.schema),
+                self.database.get_dialect(),
+            )
+            return table(quoted_name(full_table_name, quote=False))
 
         return table(self.table_name)
 
diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py
index a32aeb9f34d..3989fbc42e8 100644
--- a/superset/db_engine_specs/base.py
+++ b/superset/db_engine_specs/base.py
@@ -682,6 +682,16 @@ class BaseEngineSpec:  # pylint: 
disable=too-many-public-methods
     # a custom `adjust_engine_params` method.
     supports_dynamic_schema = False
 
+    # Does the qualified identifier built by `quote_table` include the schema 
(and
+    # catalog, if any)? True for virtually every engine. A driver that treats 
the
+    # whole FROM reference as a single opaque name (e.g. PyMongoSQL, which 
resolves
+    # `schema.table` as a literal collection name instead of parsing it) sets 
this to
+    # False and overrides `quote_table` to emit only the table, relying on
+    # `adjust_engine_params`/`supports_dynamic_schema` to select the schema at 
the
+    # connection level instead. `SqlaTable.get_sqla_table` consults this flag 
so
+    # datasets build the same FROM-clause identifier as `select_star` (SQL 
Lab).
+    quote_table_includes_schema = True
+
     # Does the DB support catalogs? A catalog here is a group of schemas, and 
has
     # different names depending on the DB: BigQuery calles it a "project", 
Postgres calls  # noqa: E501
     # it a "database", Trino calls it a "catalog", etc.
diff --git a/superset/db_engine_specs/mongodb.py 
b/superset/db_engine_specs/mongodb.py
index 28c41759525..51013918e3e 100644
--- a/superset/db_engine_specs/mongodb.py
+++ b/superset/db_engine_specs/mongodb.py
@@ -52,6 +52,15 @@ class MongoDBEngineSpec(BaseEngineSpec):
     # the default ``authSource``.
     supports_dynamic_schema = True
 
+    # `quote_table` below emits only the bare, quoted collection name -- 
PyMongoSQL
+    # resolves the whole FROM reference as a literal collection name, so a
+    # schema-qualified identifier would never match. `SqlaTable.get_sqla_table`
+    # (charts) consults this flag; `select_star` (SQL Lab) reaches the same
+    # unqualified FROM clause through the `quote_table` override above. Both
+    # rely on `adjust_engine_params` to select the schema at the connection
+    # level instead.
+    quote_table_includes_schema = False
+
     metadata = {
         "description": ("MongoDB is a document-oriented, operational NoSQL 
database."),
         "logo": "mongodb.png",
diff --git a/tests/unit_tests/connectors/sqla/models_test.py 
b/tests/unit_tests/connectors/sqla/models_test.py
index 41212930f9e..ee05de12a3d 100644
--- a/tests/unit_tests/connectors/sqla/models_test.py
+++ b/tests/unit_tests/connectors/sqla/models_test.py
@@ -1408,6 +1408,74 @@ def test_quoted_name_prevents_double_quoting(mocker: 
MockerFixture) -> None:
     assert '"MY_DB"."MY_SCHEMA"."MY_TABLE"' in compiled
 
 
+def test_get_sqla_table_schema_not_qualified_when_engine_opts_out(
+    mocker: MockerFixture,
+) -> None:
+    """
+    Engines that set ``quote_table_includes_schema = False`` (e.g. MongoDB, 
whose
+    PyMongoSQL driver resolves ``schema.collection`` as a literal collection 
name
+    instead of parsing it) must get an unqualified FROM-clause identifier from
+    ``get_sqla_table``, built through the engine spec's own ``quote_table``, 
the
+    same way ``select_star`` builds it for SQL Lab's Data Preview. Regression 
test
+    for datasets on such engines returning no rows once a schema is set.
+    """
+    from sqlalchemy import create_engine, select
+
+    engine = create_engine("sqlite://")
+
+    database = mocker.MagicMock()
+    database.db_engine_spec.supports_cross_catalog_queries = False
+    database.db_engine_spec.quote_table_includes_schema = False
+    database.db_engine_spec.quote_table.side_effect = (
+        lambda table, dialect: dialect.identifier_preparer.quote(table.table)
+    )
+    database.get_dialect.return_value = engine.dialect
+
+    table = SqlaTable(
+        table_name="orders",
+        database=database,
+        schema="testdb",
+    )
+
+    sqla_table = table.get_sqla_table()
+    compiled = str(
+        select(sqla_table).compile(engine, compile_kwargs={"literal_binds": 
True})
+    )
+
+    assert "FROM orders" in compiled
+    assert "testdb" not in compiled
+    database.db_engine_spec.quote_table.assert_called_once()
+
+
+def test_get_sqla_table_schema_qualified_by_default(mocker: MockerFixture) -> 
None:
+    """
+    Engines that don't override ``quote_table_includes_schema`` (the default,
+    ``True``) keep qualifying the FROM clause with the schema, unaffected by 
the
+    opt-out path above.
+    """
+    from sqlalchemy import create_engine, select
+
+    engine = create_engine("postgresql://user:pass@host/db")
+
+    database = mocker.MagicMock()
+    database.db_engine_spec.supports_cross_catalog_queries = False
+    database.db_engine_spec.quote_table_includes_schema = True
+
+    table = SqlaTable(
+        table_name="My-Table",
+        database=database,
+        schema="My-Schema",
+    )
+
+    sqla_table = table.get_sqla_table()
+    compiled = str(
+        select(sqla_table).compile(engine, compile_kwargs={"literal_binds": 
True})
+    )
+
+    assert '"My-Schema"."My-Table"' in compiled
+    database.db_engine_spec.quote_table.assert_not_called()
+
+
 def test_sqla_table_currency_code_column_property() -> None:
     """
     Test currency_code_column property on SqlaTable.
diff --git a/tests/unit_tests/db_engine_specs/test_mongodb.py 
b/tests/unit_tests/db_engine_specs/test_mongodb.py
index 8a481daa082..c8cb94d463e 100644
--- a/tests/unit_tests/db_engine_specs/test_mongodb.py
+++ b/tests/unit_tests/db_engine_specs/test_mongodb.py
@@ -326,3 +326,39 @@ def test_get_sqla_engine_applies_selected_schema() -> None:
             assert credentials.source == "dbone"
         finally:
             raw_connection.close()
+
+
+def test_get_sqla_table_does_not_qualify_collection() -> None:
+    """
+    Charts built on a MongoDB dataset with a schema hit the same PyMongoSQL
+    ``schema.collection`` resolution bug SQL Lab's Data Preview had before 
#44141:
+    ``SqlaTable.get_sqla_table`` must build an unqualified FROM clause too, not
+    just ``select_star``. Regression test for #44576.
+    """
+    from sqlalchemy import create_engine, select
+
+    from superset.connectors.sqla.models import SqlaTable
+    from superset.db_engine_specs.mongodb import MongoDBEngineSpec
+    from superset.models.core import Database
+
+    pytest.importorskip("pymongosql")
+
+    assert MongoDBEngineSpec.quote_table_includes_schema is False
+
+    database = Database(
+        database_name="mongo",
+        sqlalchemy_uri="mongodb://user:pass@host:27017/dbone?mode=superset",
+    )
+    dataset = SqlaTable(table_name="orders", database=database, 
schema="testdb")
+
+    sqla_table = dataset.get_sqla_table()
+
+    # Compile with the engine's own dialect -- the one `get_sqla_table` already
+    # quoted the identifier with -- so the assertion covers the real path.
+    engine = create_engine(database.sqlalchemy_uri)
+    compiled = str(
+        select(sqla_table).compile(engine, compile_kwargs={"literal_binds": 
True})
+    )
+
+    assert "FROM orders" in compiled
+    assert "testdb" not in compiled

Reply via email to