]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
fix(#10056): keep nullable as true for mariadb generated columns
authorindivar <indimishra@gmail.com>
Mon, 16 Oct 2023 18:53:04 +0000 (14:53 -0400)
committersqla-tester <sqla-tester@sqlalchemy.org>
Mon, 16 Oct 2023 18:53:04 +0000 (14:53 -0400)
mariaDB does not support setting NOT NULL for generated column
ref: https://mariadb.com/kb/en/generated-columns/#statement-support

added a check in `get_column_specification` for mariadb, checking
if user has not specified nullable set it as True for computed column,
but if user has explicitly set as False raise a compile error.

added testcase for same

<!-- Provide a general summary of your proposed changes in the Title field above -->

### Description
<!-- Describe your changes in detail -->

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [x] A short code fix
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.

**Have a nice day!**

Closes: #10354
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/10354
Pull-request-sha: 68035e0f77884f361bdcad0514ea731814cb1a34

Change-Id: I00188cf899c0a2efe759e06e510243fbdb1a6dcf

doc/build/changelog/unreleased_20/10056.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mysql/base.py
test/dialect/mysql/test_query.py

diff --git a/doc/build/changelog/unreleased_20/10056.rst b/doc/build/changelog/unreleased_20/10056.rst
new file mode 100644 (file)
index 0000000..d801e98
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, sql
+    :tickets: 10056
+
+    mariaDB does not support setting NOT NULL for generated column
+    ref: https://mariadb.com/kb/en/generated-columns/#statement-support
+    added a check in `get_column_specification` for mariadb, checking
+    if user has not specified nullable set it as True for computed column.
index d3f2a3ff87077d3efd79473b2eeb477ac51b8542..465f3597cbc368a415c2d3187f5de15564c4490e 100644 (file)
@@ -1063,6 +1063,7 @@ from ...sql import roles
 from ...sql import sqltypes
 from ...sql import util as sql_util
 from ...sql.compiler import InsertmanyvaluesSentinelOpts
+from ...sql.schema import SchemaConst
 from ...types import BINARY
 from ...types import BLOB
 from ...types import BOOLEAN
@@ -1071,6 +1072,7 @@ from ...types import UUID
 from ...types import VARBINARY
 from ...util import topological
 
+
 SET_RE = re.compile(
     r"\s*SET\s+(?:(?:GLOBAL|SESSION)\s+)?\w", re.I | re.UNICODE
 )
@@ -1766,7 +1768,12 @@ class MySQLCompiler(compiler.SQLCompiler):
 class MySQLDDLCompiler(compiler.DDLCompiler):
     def get_column_specification(self, column, **kw):
         """Builds column DDL."""
-
+        if (
+            self.dialect.is_mariadb is True
+            and column.computed is not None
+            and column._user_defined_nullable is SchemaConst.NULL_UNSPECIFIED
+        ):
+            column.nullable = True
         colspec = [
             self.preparer.format_column(column),
             self.dialect.type_compiler_instance.process(
index 921b5c52baa752f4d730197c36ae671ed1164f0b..9cbc38378fbfe23c660086e04635c080dfcc9e6d 100644 (file)
@@ -4,14 +4,20 @@ from sqlalchemy import any_
 from sqlalchemy import Boolean
 from sqlalchemy import cast
 from sqlalchemy import Column
+from sqlalchemy import Computed
+from sqlalchemy import exc
 from sqlalchemy import false
 from sqlalchemy import ForeignKey
 from sqlalchemy import Integer
+from sqlalchemy import MetaData
 from sqlalchemy import or_
+from sqlalchemy import schema
 from sqlalchemy import select
 from sqlalchemy import String
 from sqlalchemy import Table
 from sqlalchemy import true
+from sqlalchemy.testing import assert_raises
+from sqlalchemy.testing import combinations
 from sqlalchemy.testing import eq_
 from sqlalchemy.testing import expect_warnings
 from sqlalchemy.testing import fixtures
@@ -255,3 +261,47 @@ class AnyAllTest(fixtures.TablesTest):
         stmt = select(4 == any_(select(stuff.c.value).scalar_subquery()))
 
         is_(connection.execute(stmt).scalar(), True)
+
+
+class ComputedTest(fixtures.TestBase):
+    __only_on__ = "mysql >= 5.7", "mariadb"
+    __backend__ = True
+
+    @combinations(
+        (True),
+        (False),
+        (None),
+        ("unset"),
+        argnames="nullable",
+    )
+    def test_column_computed_for_nullable(self, connection, nullable):
+        """test #10056
+
+        we want to make sure that nullable is always set to True for computed
+        column as it is not supported for mariaDB
+        ref: https://mariadb.com/kb/en/generated-columns/#statement-support
+
+        """
+        m = MetaData()
+        kwargs = {"nullable": nullable} if nullable != "unset" else {}
+        t = Table(
+            "t",
+            m,
+            Column("x", Integer),
+            Column("y", Integer, Computed("x + 2"), **kwargs),
+        )
+        if connection.engine.dialect.name == "mariadb" and nullable in (
+            False,
+            None,
+        ):
+            assert_raises(
+                exc.ProgrammingError,
+                connection.execute,
+                schema.CreateTable(t),
+            )
+            # If assertion happens table won't be created so
+            #  return from test
+            return
+        # Create and then drop table
+        connection.execute(schema.CreateTable(t))
+        connection.execute(schema.DropTable(t))