]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Ensure SQL Server default schema name not interpreted as dot-separated tokens
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 18 Oct 2019 01:29:51 +0000 (21:29 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 18 Oct 2019 02:13:58 +0000 (22:13 -0400)
Fixed an issue in the :meth:`.Engine.table_names` method where it would
feed the dialect's default schema name back into the dialect level table
function, which in the case of SQL Server would interpret it as a
dot-tokenized schema name as viewed by the mssql dialect, which would
cause the method to fail in the case where the database username actually
had a dot inside of it.  In 1.3, this method is still used by the
:meth:`.MetaData.reflect` function so is a prominent codepath. In 1.4,
which is the current master development branch, this issue doesn't exist,
both because :meth:`.MetaData.reflect` isn't using this method nor does the
method pass the default schema name explicitly.  The fix nonetheless
guards against the default server name value returned by the dialect from
being interpreted as dot-tokenized name under any circumstances by
wrapping it in quoted_name().

Fixes: #4923
Change-Id: I821bd38ed89b767eaca0bdffee7f8ba3baf82560
(cherry picked from commit f50c6a04067acf2cd2fc5e42d5acaa9206d9a078)

doc/build/changelog/unreleased_13/4923.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mssql/base.py
lib/sqlalchemy/engine/base.py
test/dialect/mssql/test_reflection.py

diff --git a/doc/build/changelog/unreleased_13/4923.rst b/doc/build/changelog/unreleased_13/4923.rst
new file mode 100644 (file)
index 0000000..e5318f5
--- /dev/null
@@ -0,0 +1,17 @@
+.. change::
+    :tags: bug, mssql
+    :tickets: 4923
+
+    Fixed an issue in the :meth:`.Engine.table_names` method where it would
+    feed the dialect's default schema name back into the dialect level table
+    function, which in the case of SQL Server would interpret it as a
+    dot-tokenized schema name as viewed by the mssql dialect, which would
+    cause the method to fail in the case where the database username actually
+    had a dot inside of it.  In 1.3, this method is still used by the
+    :meth:`.MetaData.reflect` function so is a prominent codepath. In 1.4,
+    which is the current master development branch, this issue doesn't exist,
+    both because :meth:`.MetaData.reflect` isn't using this method nor does the
+    method pass the default schema name explicitly.  The fix nonetheless
+    guards against the default server name value returned by the dialect from
+    being interpreted as dot-tokenized name under any circumstances by
+    wrapping it in quoted_name().
index d01acab1258a78f892ef0f0ccdabaf3df4ddcd8a..e4f1d205d131e8b73b418fc150105b3a919acb8c 100644 (file)
@@ -2399,7 +2399,9 @@ class MSDialect(default.DefaultDialect):
             query = sql.text("SELECT schema_name()")
             default_schema_name = connection.scalar(query)
             if default_schema_name is not None:
-                return util.text_type(default_schema_name)
+                # guard against the case where the default_schema_name is being
+                # fed back into a table reflection function.
+                return quoted_name(default_schema_name, quote=True)
             else:
                 return self.schema_name
 
index 7d2715fd117b1f1d2f1cb017393b43c2a4e7bc31..53bb1857c4dc9b085a1f844f4bdbeba58b4377f4 100644 (file)
@@ -2254,8 +2254,6 @@ class Engine(Connectable, log.Identified):
         """
 
         with self._optional_conn_ctx_manager(connection) as conn:
-            if not schema:
-                schema = self.dialect.default_schema_name
             return self.dialect.get_table_names(conn, schema)
 
     def has_table(self, table_name, schema=None):
index 789fe6526a3c3707a86a037c214337eb7ee64652..347adbbd6f3f105d9a11cdb638b401c00c91c6db 100644 (file)
@@ -421,6 +421,18 @@ class ReflectHugeViewTest(fixtures.TestBase):
 
 
 class OwnerPlusDBTest(fixtures.TestBase):
+    def test_default_schema_name_not_interpreted_as_tokenized(self):
+        dialect = mssql.dialect()
+        dialect.server_version_info = base.MS_2014_VERSION
+
+        mock_connection = mock.Mock(scalar=lambda sql: "Jonah.The.Whale")
+        schema_name = dialect._get_default_schema_name(mock_connection)
+        eq_(schema_name, "Jonah.The.Whale")
+        eq_(
+            base._owner_plus_db(dialect, schema_name),
+            (None, "Jonah.The.Whale"),
+        )
+
     def test_owner_database_pairs_dont_use_for_same_db(self):
         dialect = mssql.dialect()