Author: mtredinnick
Date: 2007-11-04 00:05:24 -0500 (Sun, 04 Nov 2007)
New Revision: 6650

Modified:
   django/trunk/django/core/management/sql.py
   django/trunk/django/db/backends/__init__.py
   django/trunk/django/db/backends/mysql/base.py
   django/trunk/django/db/backends/mysql_old/base.py
Log:
Fixed #5729 -- For MySQL (only), always delay the creation of foreign key
references, for all tables, until after the table has been created. This means
that when using the InnoDB storage engine, true foreign key constraints are
created (inline "REFERENCES" are ignored by InnoDB, unfortunately).

Fully backwards compatible.


Modified: django/trunk/django/core/management/sql.py
===================================================================
--- django/trunk/django/core/management/sql.py  2007-11-04 03:37:04 UTC (rev 
6649)
+++ django/trunk/django/core/management/sql.py  2007-11-04 05:05:24 UTC (rev 
6650)
@@ -252,6 +252,7 @@
     table_output = []
     pending_references = {}
     qn = connection.ops.quote_name
+    inline_references = connection.features.inline_fk_references
     for f in opts.fields:
         col_type = f.db_type()
         tablespace = f.db_tablespace or opts.db_tablespace
@@ -272,7 +273,7 @@
             # won't be generating a CREATE INDEX statement for this field.
             field_output.append(connection.ops.tablespace_sql(tablespace, 
inline=True))
         if f.rel:
-            if f.rel.to in known_models:
+            if inline_references and f.rel.to in known_models:
                 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
                     style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \
                     
style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
@@ -341,10 +342,12 @@
 def many_to_many_sql_for_model(model, style):
     from django.db import connection, models
     from django.contrib.contenttypes import generic
+    from django.db.backends.util import truncate_name
 
     opts = model._meta
     final_output = []
     qn = connection.ops.quote_name
+    inline_references = connection.features.inline_fk_references
     for f in opts.many_to_many:
         if not isinstance(f.rel, generic.GenericRel):
             tablespace = f.db_tablespace or opts.db_tablespace
@@ -354,26 +357,43 @@
                 tablespace_sql = ''
             table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
                 style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
-            table_output.append('    %s %s %s%s,' % \
+            table_output.append('    %s %s %s%s,' %
                 (style.SQL_FIELD(qn('id')),
                 
style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
                 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
                 tablespace_sql))
-            table_output.append('    %s %s %s %s (%s)%s,' % \
-                (style.SQL_FIELD(qn(f.m2m_column_name())),
-                style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
-                style.SQL_KEYWORD('NOT NULL REFERENCES'),
-                style.SQL_TABLE(qn(opts.db_table)),
-                style.SQL_FIELD(qn(opts.pk.column)),
-                connection.ops.deferrable_sql()))
-            table_output.append('    %s %s %s %s (%s)%s,' % \
-                (style.SQL_FIELD(qn(f.m2m_reverse_name())),
-                style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
-                style.SQL_KEYWORD('NOT NULL REFERENCES'),
-                style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
-                style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
-                connection.ops.deferrable_sql()))
-            table_output.append('    %s (%s, %s)%s' % \
+            if inline_references:
+                deferred = []
+                table_output.append('    %s %s %s %s (%s)%s,' %
+                    (style.SQL_FIELD(qn(f.m2m_column_name())),
+                    style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
+                    style.SQL_KEYWORD('NOT NULL REFERENCES'),
+                    style.SQL_TABLE(qn(opts.db_table)),
+                    style.SQL_FIELD(qn(opts.pk.column)),
+                    connection.ops.deferrable_sql()))
+                table_output.append('    %s %s %s %s (%s)%s,' %
+                    (style.SQL_FIELD(qn(f.m2m_reverse_name())),
+                    style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
+                    style.SQL_KEYWORD('NOT NULL REFERENCES'),
+                    style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
+                    style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
+                    connection.ops.deferrable_sql()))
+            else:
+                table_output.append('    %s %s %s,' %
+                    (style.SQL_FIELD(qn(f.m2m_column_name())),
+                    style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
+                    style.SQL_KEYWORD('NOT NULL')))
+                table_output.append('    %s %s %s,' %
+                    (style.SQL_FIELD(qn(f.m2m_reverse_name())),
+                    style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
+                    style.SQL_KEYWORD('NOT NULL')))
+                deferred = [
+                    (f.m2m_db_table(), f.m2m_column_name(), opts.db_table,
+                        opts.pk.column),
+                    ( f.m2m_db_table(), f.m2m_reverse_name(),
+                        f.rel.to._meta.db_table, f.rel.to._meta.pk.column)
+                    ]
+            table_output.append('    %s (%s, %s)%s' %
                 (style.SQL_KEYWORD('UNIQUE'),
                 style.SQL_FIELD(qn(f.m2m_column_name())),
                 style.SQL_FIELD(qn(f.m2m_reverse_name())),
@@ -385,6 +405,15 @@
             table_output.append(';')
             final_output.append('\n'.join(table_output))
 
+            for r_table, r_col, table, col in deferred:
+                r_name = '%s_refs_%s_%x' % (r_col, col,
+                        abs(hash((r_table, table))))
+                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s 
ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 
+                (qn(r_table),
+                truncate_name(r_name, connection.ops.max_name_length()),
+                qn(r_col), qn(table), qn(col),
+                connection.ops.deferrable_sql()))
+
             # Add any extra SQL needed to support auto-incrementing PKs
             autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table(), 'id')
             if autoinc_sql:

Modified: django/trunk/django/db/backends/__init__.py
===================================================================
--- django/trunk/django/db/backends/__init__.py 2007-11-04 03:37:04 UTC (rev 
6649)
+++ django/trunk/django/db/backends/__init__.py 2007-11-04 05:05:24 UTC (rev 
6650)
@@ -43,6 +43,7 @@
     allows_group_by_ordinal = True
     allows_unique_and_pk = True
     autoindexes_primary_keys = True
+    inline_fk_references = True
     needs_datetime_string_cast = True
     needs_upper_for_iops = False
     supports_constraints = True

Modified: django/trunk/django/db/backends/mysql/base.py
===================================================================
--- django/trunk/django/db/backends/mysql/base.py       2007-11-04 03:37:04 UTC 
(rev 6649)
+++ django/trunk/django/db/backends/mysql/base.py       2007-11-04 05:05:24 UTC 
(rev 6650)
@@ -61,6 +61,7 @@
 
 class DatabaseFeatures(BaseDatabaseFeatures):
     autoindexes_primary_keys = False
+    inline_fk_references = False
 
 class DatabaseOperations(BaseDatabaseOperations):
     def date_extract_sql(self, lookup_type, field_name):

Modified: django/trunk/django/db/backends/mysql_old/base.py
===================================================================
--- django/trunk/django/db/backends/mysql_old/base.py   2007-11-04 03:37:04 UTC 
(rev 6649)
+++ django/trunk/django/db/backends/mysql_old/base.py   2007-11-04 05:05:24 UTC 
(rev 6650)
@@ -65,6 +65,7 @@
 
 class DatabaseFeatures(BaseDatabaseFeatures):
     autoindexes_primary_keys = False
+    inline_fk_references = False
 
 class DatabaseOperations(BaseDatabaseOperations):
     def date_extract_sql(self, lookup_type, field_name):


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to