Opened 2 years ago

Closed 2 years ago

#20002 closed Bug (fixed)

Model inheritance depth may result in invalid SQL queries

Reported by: Keryn Knight <django@…> Owned by: nobody
Component: Database layer (models, ORM) Version: 1.5
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

This is an example pulled out of the test case I was writing as a baseline for something kind of crazy, and on 1.4 to boot.

Using

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': None,
    }
}

for settings (to get an in-memory database for tests), and the following models:

class A(Model):
    subcontent_type = models.ForeignKey(ContentType, null=True, related_name='+',
                                        editable=False)
    objects = Manager()

    def __unicode__(self):
        return unicode(self.pk)

    class Meta:
        ordering = ('pk',)

class B(A): pass
class C(B): pass
class D(C): pass

The following test case fails at evaluating D:

from django.test import TestCase as DjangoTestCase

class PolymorphTestCase(DjangoTestCase):
    def setUp(self):
        self.objects = [A.objects.create(), B.objects.create(),
                        C.objects.create(), D.objects.create(),
                        C.objects.create(), B.objects.create()]

    def test_default_manager(self):
        with self.assertNumQueries(4):
            all = list(A.objects.all())
            self.assertEqual(all, [
                A(pk=1), A(pk=2), A(pk=3), A(pk=4), A(pk=5), A(pk=6),
            ])
            all = list(B.objects.all())
            self.assertEqual(all, [
                B(pk=2), B(pk=3), B(pk=4), B(pk=5), B(pk=6),
            ])

            all = list(C.objects.all())
            self.assertEqual(all, [C(pk=3), C(pk=4), C(pk=5)])

            import pdb; pdb.set_trace()
            all = list(D.objects.all())
            self.assertEqual(all, [D(pk=4)])

The stack trace is:

Traceback (most recent call last):
  File "/path/to/tests.py", line 411, in test_default_manager
    all = list(D.objects.all())
  File "/path/python2.7/site-packages/Django-1.4.5-py2.7.egg/django/db/models/query.py", line 87, in __len__
    self._result_cache.extend(self._iter)
  File "/path/python2.7/site-packages/Django-1.4.5-py2.7.egg/django/db/models/query.py", line 291, in iterator
    for row in compiler.results_iter():
  File "/path/python2.7/site-packages/Django-1.4.5-py2.7.egg/django/db/models/sql/compiler.py", line 763, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/path/python2.7/site-packages/Django-1.4.5-py2.7.egg/django/db/models/sql/compiler.py", line 818, in execute_sql
    cursor.execute(sql, params)
  File "/path/python2.7/site-packages/Django-1.4.5-py2.7.egg/django/db/backends/util.py", line 40, in execute
    return self.cursor.execute(sql, params)
  File "/path/python2.7/site-packages/Django-1.4.5-py2.7.egg/django/db/backends/sqlite3/base.py", line 344, in execute
    return Database.Cursor.execute(self, query, params)
DatabaseError: no such column: T5.a_ptr_id

the query used for D.objects.all() is:

'SELECT "testmodel_a"."id", "testmodel_a"."subcontent_type_id", "testmodel_b"."a_ptr_id", "testmodel_c"."b_ptr_id", "testmodel_d"."c_ptr_id" FROM "testmodel_d" INNER JOIN "testmodel_a" ON ("testmodel_d"."c_ptr_id" = "testmodel_a"."id") INNER JOIN "testmodel_b" ON ("testmodel_d"."c_ptr_id" = "testmodel_b"."a_ptr_id") INNER JOIN "testmodel_c" ON ("testmodel_d"."c_ptr_id" = "testmodel_c"."b_ptr_id") INNER JOIN "testmodel_a" T6 ON (T5."a_ptr_id" = T6."id") ORDER BY "testmodel_d"."c_ptr_id" ASC'

I had a look at the model_inheritance tests, and couldn't see any that were testing to the depth I'm doing there, so either I'm doing something wrong, SQlite is (as always) being a pain, or the tests may not go far enough.

Change History (2)

comment:1 Changed 2 years ago by Keryn Knight <django@…>

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Version changed from 1.4 to 1.5

I've since tested this on 1.5 and 1.6 (master at 477d737e1e6bdf93950c8a381906925c594fac2f)

  • It still occurs in 1.5 (so I've bumped the version affected to reflect this)
  • It is fixed in 1.6

Looking around Trac, I'd guess tickets #16572 and #13781 were probably where the underlying problem got fixed.

I'm not sure if there are tests for the depth I've demonstrated in 1.6, so there might be value in doing so, but otherwise, I think this can be marked as invalid/duplicate/shutup-its-fixed.

comment:2 Changed 2 years ago by aaugustin

  • Resolution set to fixed
  • Status changed from new to closed

Thanks for attempting to reproduce with master. Indeed there's been some cleanup in this area.

Our policy is to close bugs that aren't reproducible on master, but of course feel free to re-open if you find a variant that isn't addressed yet!

Note: See TracTickets for help on using tickets.
Back to Top