diff options
| -rw-r--r-- | doc/build/changelog/unreleased_14/9133.rst | 16 | ||||
| -rw-r--r-- | lib/sqlalchemy/dialects/mssql/base.py | 4 | ||||
| -rw-r--r-- | test/dialect/mssql/test_compiler.py | 41 | ||||
| -rw-r--r-- | test/dialect/mssql/test_reflection.py | 29 |
4 files changed, 87 insertions, 3 deletions
diff --git a/doc/build/changelog/unreleased_14/9133.rst b/doc/build/changelog/unreleased_14/9133.rst new file mode 100644 index 000000000..29e05f5fe --- /dev/null +++ b/doc/build/changelog/unreleased_14/9133.rst @@ -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. + diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index b1f30d577..eabea88db 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -2871,10 +2871,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() diff --git a/test/dialect/mssql/test_compiler.py b/test/dialect/mssql/test_compiler.py index 00bbc2af4..0076c76fd 100644 --- a/test/dialect/mssql/test_compiler.py +++ b/test/dialect/mssql/test_compiler.py @@ -599,6 +599,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( diff --git a/test/dialect/mssql/test_reflection.py b/test/dialect/mssql/test_reflection.py index 1716d68e3..59b88c6ef 100644 --- a/test/dialect/mssql/test_reflection.py +++ b/test/dialect/mssql/test_reflection.py @@ -410,6 +410,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( |
