From e3fc9af4abd65262f2d3bdced96b687b65be618a Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Tue, 30 Jul 2019 16:21:05 +0200 Subject: [PATCH] Refs #30593 -- Fixed introspection of check constraints columns on MariaDB. --- django/db/backends/mysql/introspection.py | 11 ++++++++--- tests/backends/mysql/test_introspection.py | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/django/db/backends/mysql/introspection.py b/django/db/backends/mysql/introspection.py index 86133a254e..db1a387679 100644 --- a/django/db/backends/mysql/introspection.py +++ b/django/db/backends/mysql/introspection.py @@ -147,12 +147,16 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): return self.connection.features._mysql_storage_engine return result[0] - def _parse_constraint_columns(self, check_clause): + def _parse_constraint_columns(self, check_clause, columns): check_columns = OrderedSet() statement = sqlparse.parse(check_clause)[0] tokens = (token for token in statement.flatten() if not token.is_whitespace) for token in tokens: - if token.ttype in [sqlparse.tokens.Name, sqlparse.tokens.Literal.String.Single]: + if ( + token.ttype == sqlparse.tokens.Name and + self.connection.ops.quote_name(token.value) == token.value and + token.value[1:-1] in columns + ): check_columns.add(token.value[1:-1]) return check_columns @@ -201,6 +205,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): constraints[constraint]['unique'] = True # Add check constraints. if self.connection.features.can_introspect_check_constraints: + columns = {info.name for info in self.get_table_description(cursor, table_name)} type_query = """ SELECT c.constraint_name, c.check_clause FROM information_schema.check_constraints AS c @@ -211,7 +216,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): cursor.execute(type_query, [table_name]) for constraint, check_clause in cursor.fetchall(): constraints[constraint] = { - 'columns': self._parse_constraint_columns(check_clause), + 'columns': self._parse_constraint_columns(check_clause, columns), 'primary_key': False, 'unique': False, 'index': False, diff --git a/tests/backends/mysql/test_introspection.py b/tests/backends/mysql/test_introspection.py index 1b8fb94ed9..37fbcb1513 100644 --- a/tests/backends/mysql/test_introspection.py +++ b/tests/backends/mysql/test_introspection.py @@ -7,16 +7,23 @@ from django.test import TestCase @skipUnless(connection.vendor == 'mysql', 'MySQL tests') class ParsingTests(TestCase): def test_parse_constraint_columns(self): + _parse_constraint_columns = connection.introspection._parse_constraint_columns tests = ( - ('`height` >= 0', ['height']), - ('`cost` BETWEEN 1 AND 10', ['cost']), - ('`ref1` > `ref2`', ['ref1', 'ref2']), + ('`height` >= 0', ['height'], ['height']), + ('`cost` BETWEEN 1 AND 10', ['cost'], ['cost']), + ('`ref1` > `ref2`', ['id', 'ref1', 'ref2'], ['ref1', 'ref2']), ( '`start` IS NULL OR `end` IS NULL OR `start` < `end`', + ['id', 'start', 'end'], ['start', 'end'], ), + ('JSON_VALID(`json_field`)', ['json_field'], ['json_field']), + ('CHAR_LENGTH(`name`) > 2', ['name'], ['name']), + ("lower(`ref1`) != 'test'", ['id', 'owe', 'ref1'], ['ref1']), + ("lower(`ref1`) != 'test'", ['id', 'lower', 'ref1'], ['ref1']), + ("`name` LIKE 'test%'", ['name'], ['name']), ) - for check_clause, expected_columns in tests: + for check_clause, table_columns, expected_columns in tests: with self.subTest(check_clause): - check_columns = connection.introspection._parse_constraint_columns(check_clause) + check_columns = _parse_constraint_columns(check_clause, table_columns) self.assertEqual(list(check_columns), expected_columns)