]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Run bracket interpretation for reflection
authorShan <shan224@gmail.com>
Sun, 22 Jan 2023 16:19:11 +0000 (11:19 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 23 Jan 2023 15:49:28 +0000 (10:49 -0500)
Fixed bug where a schema name given with brackets, but no dots inside the
name, for parameters such as :paramref:`_schema.Table.schema` would not be
interpreted within the context of the SQL Server dialect's documented
behavior of interpreting explicit brackets as token delimiters, first added
in 1.2 for #2626, when referring to the schema name in reflection
operations. The original assumption for #2626's behavior was that the
special interpretation of brackets was only significant if dots were
present, however in practice, the brackets are not included as part of the
identifier name for all SQL rendering operations since these are not valid
characters within regular or delimited identifiers.  Pull request courtesy
Shan.

Fixes: #9133
Closes: #9134
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/9134
Pull-request-sha: 5dac87c82cd3063dd8e50f0075c7c00330be6439

Change-Id: I7a507bc38d75a04ffcb7e920298775baae22c6d1
(cherry picked from commit aa50375a9aa72be896a7cf3afbbbec161c7111bd)

doc/build/changelog/unreleased_14/9133.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mssql/base.py
test/dialect/mssql/test_compiler.py
test/dialect/mssql/test_reflection.py

diff --git a/doc/build/changelog/unreleased_14/9133.rst b/doc/build/changelog/unreleased_14/9133.rst
new file mode 100644 (file)
index 0000000..29e05f5
--- /dev/null
@@ -0,0 +1,16 @@
+.. change::
+    :tags: bug, mssql
+    :tickets: 9133
+
+    Fixed bug where a schema name given with brackets, but no dots inside the
+    name, for parameters such as :paramref:`_schema.Table.schema` would not be
+    interpreted within the context of the SQL Server dialect's documented
+    behavior of interpreting explicit brackets as token delimiters, first added
+    in 1.2 for #2626, when referring to the schema name in reflection
+    operations. The original assumption for #2626's behavior was that the
+    special interpretation of brackets was only significant if dots were
+    present, however in practice, the brackets are not included as part of the
+    identifier name for all SQL rendering operations since these are not valid
+    characters within regular or delimited identifiers.  Pull request courtesy
+    Shan.
+
index 948d3afb0632433de3aeca30784c095d108a08a0..db741d84aafc32b78a5f018fb4698b8290a87488 100644 (file)
@@ -2664,10 +2664,8 @@ def _switch_db(dbname, connection, fn, *arg, **kw):
 def _owner_plus_db(dialect, schema):
     if not schema:
         return None, dialect.default_schema_name
-    elif "." in schema:
-        return _schema_elements(schema)
     else:
-        return None, schema
+        return _schema_elements(schema)
 
 
 _memoized_schema = util.LRUCache()
index d54295b3062eb03505495856fef75eabb9bdc9e4..a385ad120836034c9bc8d33ac5c43857cf0dcb6a 100644 (file)
@@ -585,6 +585,47 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
             checkpositional=("bar",),
         )
 
+    @testing.variation("use_schema_translate", [True, False])
+    @testing.combinations(
+        "abc", "has spaces", "[abc]", "[has spaces]", argnames="schemaname"
+    )
+    def test_schema_single_token_bracketed(
+        self, use_schema_translate, schemaname
+    ):
+        """test for #9133.
+
+        this is not the actual regression case for #9133, which is instead
+        within the reflection process.  However, when we implemented
+        #2626, we never considered the case of ``[schema]`` without any
+        dots in it.
+
+        """
+
+        schema_no_brackets = schemaname.strip("[]")
+
+        if " " in schemaname:
+            rendered_schema = "[%s]" % (schema_no_brackets,)
+        else:
+            rendered_schema = schema_no_brackets
+
+        metadata = MetaData()
+        tbl = Table(
+            "test",
+            metadata,
+            Column("id", Integer, primary_key=True),
+            schema=schemaname if not use_schema_translate else None,
+        )
+
+        self.assert_compile(
+            select(tbl),
+            "SELECT %(name)s.test.id FROM %(name)s.test"
+            % {"name": rendered_schema},
+            schema_translate_map={None: schemaname}
+            if use_schema_translate
+            else None,
+            render_schema_translate=True if use_schema_translate else False,
+        )
+
     def test_schema_many_tokens_one(self):
         metadata = MetaData()
         tbl = Table(
index 4c5a5398164ae46357ff104499a4d0c2a53be437..d24ee4adb9a3f12567e57cfba1223fb49a382348 100644 (file)
@@ -411,6 +411,35 @@ class ReflectionTest(fixtures.TestBase, ComparesTables, AssertsCompiledSQL):
             )
             Table(tname, MetaData(), autoload_with=conn)
 
+    @testing.combinations(
+        ("test_schema"),
+        ("[test_schema]"),
+        argnames="schema_value",
+    )
+    @testing.variation(
+        "reflection_operation", ["has_table", "reflect_table", "get_columns"]
+    )
+    def test_has_table_with_single_token_schema(
+        self, metadata, connection, schema_value, reflection_operation
+    ):
+        """test for #9133"""
+        tt = Table(
+            "test", metadata, Column("id", Integer), schema=schema_value
+        )
+        tt.create(connection)
+
+        if reflection_operation.has_table:
+            is_true(inspect(connection).has_table("test", schema=schema_value))
+        elif reflection_operation.reflect_table:
+            m2 = MetaData()
+            Table("test", m2, autoload_with=connection, schema=schema_value)
+        elif reflection_operation.get_columns:
+            is_true(
+                inspect(connection).get_columns("test", schema=schema_value)
+            )
+        else:
+            reflection_operation.fail()
+
     def test_db_qualified_items(self, metadata, connection):
         Table("foo", metadata, Column("id", Integer, primary_key=True))
         Table(