]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
adjust MySQL view reflection for non-standard MySQL variants
authorJohn Bodley <4567245+john-bodley@users.noreply.github.com>
Fri, 30 Sep 2022 01:58:58 +0000 (21:58 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 3 Oct 2022 22:08:08 +0000 (18:08 -0400)
Adjusted the regular expression used to match "CREATE VIEW" when
testing for views to work more flexibly, no longer requiring the
special keyword "ALGORITHM" in the middle, which was intended to be
optional but was not working correctly.  The change allows view reflection
to work more completely on MySQL-compatible variants such as StarRocks.
Pull request courtesy John Bodley.

Fixes: #8588
Closes: #8589
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/8589
Pull-request-sha: d85b2c5b51e45cec543c9ae9d62d6d659b063354

Change-Id: I173137f0bf68639cad0d5c329055475b40ddb5e4

doc/build/changelog/unreleased_14/8588.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mysql/base.py
lib/sqlalchemy/dialects/mysql/reflection.py
test/dialect/mysql/test_reflection.py

diff --git a/doc/build/changelog/unreleased_14/8588.rst b/doc/build/changelog/unreleased_14/8588.rst
new file mode 100644 (file)
index 0000000..879b8b2
--- /dev/null
@@ -0,0 +1,10 @@
+.. change::
+    :tags: bug, mysql
+    :tickets: 8588
+
+    Adjusted the regular expression used to match "CREATE VIEW" when
+    testing for views to work more flexibly, no longer requiring the
+    special keyword "ALGORITHM" in the middle, which was intended to be
+    optional but was not working correctly.  The change allows view reflection
+    to work more completely on MySQL-compatible variants such as StarRocks.
+    Pull request courtesy John Bodley.
\ No newline at end of file
index a3e99514bc55b2bd4a7a0f319c21bfb3406499ec..e8ddb6d1e9e76435287decbd52d080a792c27277 100644 (file)
@@ -3162,7 +3162,7 @@ class MySQLDialect(default.DefaultDialect):
         sql = self._show_create_table(
             connection, None, charset, full_name=full_name
         )
-        if re.match(r"^CREATE (?:ALGORITHM)?.* VIEW", sql):
+        if parser._check_view(sql):
             # Adapt views to something table-like.
             columns = self._describe_table(
                 connection, None, charset, full_name=full_name
index e7a6b157fcacd4d3f7cc9baba3153c4d6f973f0b..44bc62179d7ecb79703f0621d04975a855762175 100644 (file)
@@ -74,6 +74,9 @@ class MySQLTableDefinitionParser:
                     pass
         return state
 
+    def _check_view(self, sql: str) -> bool:
+        return bool(self._re_is_view.match(sql))
+
     def _parse_constraints(self, line):
         """Parse a KEY or CONSTRAINT line.
 
@@ -409,6 +412,8 @@ class MySQLTableDefinitionParser:
             self.preparer._unescape_identifier,
         )
 
+        self._re_is_view = _re_compile(r"^CREATE(?! TABLE)(\s.*)?\sVIEW")
+
         # `col`,`col2`(32),`col3`(15) DESC
         #
         self._re_keyexprs = _re_compile(
index f815a7b3c919fe021bc45ffacfad11ab75bd3b10..8f093f13448159dedb846041173482459dd28ed3 100644 (file)
@@ -1285,8 +1285,6 @@ class ReflectionTest(fixtures.TestBase, AssertsCompiledSQL):
 
 
 class RawReflectionTest(fixtures.TestBase):
-    __backend__ = True
-
     def setup_test(self):
         dialect = mysql.dialect()
         self.parser = _reflection.MySQLTableDefinitionParser(
@@ -1412,3 +1410,18 @@ class RawReflectionTest(fixtures.TestBase):
                 "SET NULL",
             ),
         )
+
+    @testing.combinations(
+        (
+            "CREATE ALGORITHM=UNDEFINED DEFINER=`scott`@`%` "
+            "SQL SECURITY DEFINER VIEW `v1` AS SELECT",
+            True,
+        ),
+        ("CREATE VIEW `v1` AS SELECT", True),
+        ("CREATE TABLE `v1`", False),
+        ("CREATE TABLE `VIEW`", False),
+        ("CREATE TABLE `VIEW_THINGS`", False),
+        ("CREATE TABLE `A VIEW`", False),
+    )
+    def test_is_view(self, sql: str, expected: bool) -> None:
+        is_(self.parser._check_view(sql), expected)