diff --unified -r a/django/db/backends/postgresql/operations.py b/django/db/backends/postgresql/operations.py
|
a
|
b
|
|
| 54 | 54 | return '%s' |
| 55 | 55 | |
| 56 | 56 | def last_insert_id(self, cursor, table_name, pk_name): |
| 57 | | cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name)) |
| | 57 | # Use pg_get_serial_sequence to get the underlying sequence name from the table name and column name (available since postgres 8) |
| | 58 | cursor.execute("SELECT CURRVAL(pg_get_serial_sequence('%s','%s'))" % (table_name, pk_name)) |
| 58 | 59 | return cursor.fetchone()[0] |
| 59 | 60 | |
| 60 | 61 | def no_limit_value(self): |
| … |
… |
|
| 90 | 91 | for sequence_info in sequences: |
| 91 | 92 | table_name = sequence_info['table'] |
| 92 | 93 | column_name = sequence_info['column'] |
| 93 | | if column_name and len(column_name) > 0: |
| 94 | | sequence_name = '%s_%s_seq' % (table_name, column_name) |
| 95 | | else: |
| 96 | | sequence_name = '%s_id_seq' % table_name |
| 97 | | sql.append("%s setval('%s', 1, false);" % \ |
| | 94 | if not (column_name and len(column_name) > 0): |
| | 95 | # This will be the case if it's an m2m using an intermediate table (see BaseDatabaseIntrospection.sequence_list) |
| | 96 | # - that function claims we don't need to reset the sequence if that's the case, although the code prior to the #8901 |
| | 97 | # fix did reset it so I'm retaining resetting it - the pk will be id in those cases. (Note that sequence_reset_sql below also |
| | 98 | # seems to include resetting sequences of m2m with in intermediate table) |
| | 99 | column_name = 'id' |
| | 100 | # Use pg_get_serial_sequence to get the underlying sequence name from the table name and column name (available since postgres 8) |
| | 101 | sql.append("%s setval(pg_get_serial_sequence('%s','%s'), 1, false);" % \ |
| 98 | 102 | (style.SQL_KEYWORD('SELECT'), |
| 99 | | style.SQL_FIELD(self.quote_name(sequence_name))) |
| | 103 | style.SQL_TABLE(table_name), |
| | 104 | style.SQL_FIELD(column_name)) |
| 100 | 105 | ) |
| 101 | 106 | return sql |
| 102 | 107 | else: |
| … |
… |
|
| 109 | 114 | for model in model_list: |
| 110 | 115 | # Use `coalesce` to set the sequence for each model to the max pk value if there are records, |
| 111 | 116 | # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true |
| 112 | | # if there are records (as the max pk value is already in use), otherwise set it to false. |
| | 117 | # if there are records (as the max pk value is already in use), otherwise set it to false. |
| | 118 | # Use pg_get_serial_sequence to get the underlying sequence name from the table name and column name (available since postgres 8) |
| | 119 | |
| 113 | 120 | for f in model._meta.local_fields: |
| 114 | 121 | if isinstance(f, models.AutoField): |
| 115 | | output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ |
| | 122 | output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ |
| 116 | 123 | (style.SQL_KEYWORD('SELECT'), |
| 117 | | style.SQL_FIELD(qn('%s_%s_seq' % (model._meta.db_table, f.column))), |
| | 124 | style.SQL_TABLE(model._meta.db_table), |
| | 125 | style.SQL_FIELD(f.column), |
| 118 | 126 | style.SQL_FIELD(qn(f.column)), |
| 119 | 127 | style.SQL_FIELD(qn(f.column)), |
| 120 | 128 | style.SQL_KEYWORD('IS NOT'), |
| … |
… |
|
| 123 | 131 | break # Only one AutoField is allowed per model, so don't bother continuing. |
| 124 | 132 | for f in model._meta.many_to_many: |
| 125 | 133 | if not f.rel.through: |
| 126 | | output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ |
| | 134 | output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ |
| 127 | 135 | (style.SQL_KEYWORD('SELECT'), |
| 128 | | style.SQL_FIELD(qn('%s_id_seq' % f.m2m_db_table())), |
| | 136 | style.SQL_TABLE(model._meta.db_table), |
| | 137 | style.SQL_FIELD('id'), |
| 129 | 138 | style.SQL_FIELD(qn('id')), |
| 130 | 139 | style.SQL_FIELD(qn('id')), |
| 131 | 140 | style.SQL_KEYWORD('IS NOT'), |
diff --unified -r a/tests/regressiontests/backends/models.py b/tests/regressiontests/backends/models.py
|
a
|
b
|
|
| 19 | 19 | year = models.PositiveIntegerField() |
| 20 | 20 | day = models.CharField(max_length=9, blank=True) |
| 21 | 21 | last_updated = models.DateTimeField() |
| | 22 | |
| | 23 | class OtherRelatedThingTestBug8901(models.Model): |
| | 24 | pass |
| | 25 | |
| | 26 | class VeryLongModelNameToTestBug8901ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ(models.Model): |
| | 27 | class Meta: |
| | 28 | verbose_name = 'TestBug8901' # Short verbose name or we hit issue in #8548 which we're not testing! |
| | 29 | primary_key_is_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz = models.AutoField(primary_key=True) |
| | 30 | m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz = models.ManyToManyField(OtherRelatedThingTestBug8901,blank=True) |
| 22 | 31 | |
| 23 | 32 | qn = connection.ops.quote_name |
| 24 | 33 | |
diff --unified -r a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
|
a
|
b
|
|
| 7 | 7 | from django.db.backends.signals import connection_created |
| 8 | 8 | from django.conf import settings |
| 9 | 9 | from django.test import TestCase |
| | 10 | from django.core import management |
| 10 | 11 | |
| 11 | 12 | class Callproc(unittest.TestCase): |
| 12 | 13 | |
| … |
… |
|
| 88 | 89 | self.assertRaises(Exception, cursor.executemany, query, [(1,2,3),]) |
| 89 | 90 | self.assertRaises(Exception, cursor.executemany, query, [(1,),]) |
| 90 | 91 | |
| | 92 | class PostgresqlSequenceNameLimitsTest(TestCase): |
| | 93 | """Long primary keys and model names can result in a sequence name that's longer than |
| | 94 | postgresql's limit of 63 characters so it truncates them. The backend needs to use the correct |
| | 95 | sequence name in last_insert_id and other places, so check it is. Ref #8901.""" |
| | 96 | |
| | 97 | def test_sequence_name_length_limits_create(self): |
| | 98 | """Test creation of model with long name and long pk name doesn't error. Ref #8901""" |
| | 99 | #import time |
| | 100 | #time.sleep(1000) |
| | 101 | models.VeryLongModelNameToTestBug8901ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create() |
| | 102 | |
| | 103 | def test_sequence_name_length_limits_m2m(self): |
| | 104 | """Test an m2m save of a model with a long name and a long m2m field name doesn't error as on Django >=1.2 this now uses object saves. Ref #8901""" |
| | 105 | obj = models.VeryLongModelNameToTestBug8901ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create() |
| | 106 | rel_obj = models.OtherRelatedThingTestBug8901.objects.create() |
| | 107 | obj.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.add(rel_obj) |
| | 108 | |
| | 109 | def test_sequence_name_length_limits_flush(self): |
| | 110 | """Test management flush command with model with long name and long pk name doesn't error. Ref #8901""" |
| | 111 | management.call_command('flush', verbosity=0, interactive=False) |
| 91 | 112 | |
| 92 | 113 | def connection_created_test(sender, **kwargs): |
| 93 | 114 | print 'connection_created signal' |