summaryrefslogtreecommitdiff
path: root/django/db/backends/sqlite3
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2018-08-05 21:06:52 -0400
committerTim Graham <timograham@gmail.com>2018-11-13 15:25:44 -0500
commitdba4a634ba999bf376caee193b3378bc0b730bd4 (patch)
treedcf309133def892bc314e69f423e926f6e4dcc73 /django/db/backends/sqlite3
parent2f120ac51722a257219a7577759702605cefddf4 (diff)
Refs #29641 -- Refactored database schema constraint creation.
Added a test for constraint names in the database. Updated SQLite introspection to use sqlparse to allow reading the constraint name for table check and unique constraints. Co-authored-by: Ian Foote <python@ian.feete.org>
Diffstat (limited to 'django/db/backends/sqlite3')
-rw-r--r--django/db/backends/sqlite3/introspection.py50
-rw-r--r--django/db/backends/sqlite3/schema.py2
2 files changed, 36 insertions, 16 deletions
diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py
index 0c82ea8844..47ca25a78a 100644
--- a/django/db/backends/sqlite3/introspection.py
+++ b/django/db/backends/sqlite3/introspection.py
@@ -1,5 +1,7 @@
import re
+import sqlparse
+
from django.db.backends.base.introspection import (
BaseDatabaseIntrospection, FieldInfo, TableInfo,
)
@@ -242,21 +244,39 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
# table_name is a view.
pass
else:
- fields_with_check_constraints = [
- schema_row.strip().split(' ')[0][1:-1]
- for schema_row in table_schema.split(',')
- if schema_row.find('CHECK') >= 0
- ]
- for field_name in fields_with_check_constraints:
- # An arbitrary made up name.
- constraints['__check__%s' % field_name] = {
- 'columns': [field_name],
- 'primary_key': False,
- 'unique': False,
- 'foreign_key': False,
- 'check': True,
- 'index': False,
- }
+ # Check constraint parsing is based of SQLite syntax diagram.
+ # https://www.sqlite.org/syntaxdiagrams.html#table-constraint
+ def next_ttype(ttype):
+ for token in tokens:
+ if token.ttype == ttype:
+ return token
+
+ statement = sqlparse.parse(table_schema)[0]
+ tokens = statement.flatten()
+ for token in tokens:
+ name = None
+ if token.match(sqlparse.tokens.Keyword, 'CONSTRAINT'):
+ # Table constraint
+ name_token = next_ttype(sqlparse.tokens.Literal.String.Symbol)
+ name = name_token.value[1:-1]
+ token = next_ttype(sqlparse.tokens.Keyword)
+ if token.match(sqlparse.tokens.Keyword, 'CHECK'):
+ # Column check constraint
+ if name is None:
+ column_token = next_ttype(sqlparse.tokens.Literal.String.Symbol)
+ column = column_token.value[1:-1]
+ name = '__check__%s' % column
+ columns = [column]
+ else:
+ columns = []
+ constraints[name] = {
+ 'check': True,
+ 'columns': columns,
+ 'primary_key': False,
+ 'unique': False,
+ 'foreign_key': False,
+ 'index': False,
+ }
# Get the index info
cursor.execute("PRAGMA index_list(%s)" % self.connection.ops.quote_name(table_name))
for row in cursor.fetchall():
diff --git a/django/db/backends/sqlite3/schema.py b/django/db/backends/sqlite3/schema.py
index 7aa1f28f53..ad22d03763 100644
--- a/django/db/backends/sqlite3/schema.py
+++ b/django/db/backends/sqlite3/schema.py
@@ -12,10 +12,10 @@ from django.db.utils import NotSupportedError
class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
sql_delete_table = "DROP TABLE %(table)s"
- sql_create_fk = None
sql_create_inline_fk = "REFERENCES %(to_table)s (%(to_column)s) DEFERRABLE INITIALLY DEFERRED"
sql_create_unique = "CREATE UNIQUE INDEX %(name)s ON %(table)s (%(columns)s)"
sql_delete_unique = "DROP INDEX %(name)s"
+ sql_foreign_key_constraint = None
def __enter__(self):
# Some SQLite schema alterations need foreign key constraints to be