gabotorresruiz commented on code in PR #43974:
URL: https://github.com/apache/superset/pull/43974#discussion_r4020329977


##########
superset/db_engine_specs/mssql.py:
##########
@@ -194,6 +195,82 @@ def fetch_data(
         # Lists of `pyodbc.Row` need to be unpacked further
         return cls.pyodbc_rows_to_tuples(data)
 
+    @classmethod
+    def get_catalog_from_engine_params(
+        cls,
+        sqlalchemy_uri: URL,
+        connect_args: dict[str, Any],
+    ) -> str | None:
+        """
+        Resolve the database from genuine, statically-configured connection
+        settings only: an explicit ``connect_args["database"]``, a
+        ``Database=``/``Initial Catalog=`` entry embedded in the documented
+        ``odbc_connect`` connection-string query parameter, or the URL's own
+        database segment.
+
+        The check order mirrors ``MSDialect_pyodbc.create_connect_args``'s
+        actual precedence, not just plausibility:
+
+        - ``connect_args`` is always appended, as extra keyword arguments, to
+          whatever connection string SQLAlchemy hands to ``pyodbc.connect()``
+          -- regardless of whether that string came from the URL or from
+          ``odbc_connect`` -- so a duplicate key there wins over both.
+        - When ``odbc_connect`` is present, SQLAlchemy uses it as the *entire*
+          connection string and never looks at the URL's host/database
+          segments at all, so it must be checked before falling back to
+          ``sqlalchemy_uri.database``.
+
+        Returns None when none of these statically state a database -- e.g. a
+        host/DSN-only URI that relies on the SQL login's server-side default
+        database. That default is only known to SQL Server itself, at connect
+        time; resolving it would require a live query, which this method
+        deliberately does not perform.
+        """
+        if isinstance(database := connect_args.get("database"), str) and 
database:

Review Comment:
   Thanks @Ujjwaljain16 for pinning this down against the real driver, that 
settles it far better than my spec reading did. My approval stands.
   
   I verified the delta independently on this branch:
   
   * The reordered hook matches how the positional connection string is really 
built. I checked `PyODBCConnector.create_connect_args` on SQLAlchemy 2.0.52, 
which is exactly what `requirements/base.txt` pins: `odbc_connect` becomes the 
entire string, a host URL with a database bakes `Database=<db>` in 
positionally, and a host-only URL becomes a `dsn=` string with no `Database=` 
at all, so the `connect_args` fallback really is what the driver connects to in 
that last case.
   * All three affected suites pass at `d2a2327` (283 tests). Running the 
updated test files against the previous commit `723e6b2` fails exactly the six 
precedence tests, including the new `raise_for_access` level conflict test, so 
the coverage genuinely pins this fix.
   * Adversarial probes all keep the pre-existing denial: repeated 
`odbc_connect` query params, non-string `connect_args["database"]` values, a 
bare `Database` token without `=`, an empty `Database=` alongside a conflicting 
`connect_args`, and an unclosed brace value all resolve to `None` or to a value 
that can never match a parsed catalog.
   
   Good catch on `Initial Catalog=` being an OLEDB/ADO.NET keyword. Dropping it 
also closes a subtle over-grant in the version I approved: had the driver 
silently ignored it and connected to the login's default database, the old 
parser reported a database the connection never used, and the normalization 
could have fired on it.
   
   One tiny leftover in the same contradictory-config family, not a blocker and 
fine as a follow-up or a wontfix: SQLAlchemy also accepts the database as a URL 
query parameter. On 2.0.52, 
`mssql+pyodbc://u:p@host?database=realdb&driver=...` builds `Database=realdb` 
into the positional string while `URL.database` stays `None`, so with a 
conflicting `connect_args["database"]` the hook falls through and reports the 
`connect_args` value the driver never uses. Superset only documents the path 
form, so I would not hold the PR on it; if you want cheap insurance, checking 
`sqlalchemy_uri.query.get("database")` before the `connect_args` fallback would 
cover it.



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