summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/build/changelog/unreleased_14/9133.rst16
-rw-r--r--lib/sqlalchemy/dialects/mssql/base.py4
-rw-r--r--test/dialect/mssql/test_compiler.py41
-rw-r--r--test/dialect/mssql/test_reflection.py29
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(