Fixed #7783 -- Made introspection of nullable columns more robust with Postgres.

Thanks bthomas AT ncorcle DOT com for the report and initial patch, and
Claude Paroz for the final, complete patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17508 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Ramiro Morales 2012-02-11 20:05:50 +00:00
parent 4b81d790a8
commit ccc0e122d4
3 changed files with 18 additions and 2 deletions

View File

@ -34,8 +34,16 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
def get_table_description(self, cursor, table_name): def get_table_description(self, cursor, table_name):
"Returns a description of the table, with the DB-API cursor.description interface." "Returns a description of the table, with the DB-API cursor.description interface."
# As cursor.description does not return reliably the nullable property,
# we have to query the information_schema (#7783)
cursor.execute("""
SELECT column_name, is_nullable
FROM information_schema.columns
WHERE table_name = %s""", [table_name])
null_map = dict(cursor.fetchall())
cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
return cursor.description return [tuple([item for item in line[:6]] + [null_map[line[0]]==u'YES'])
for line in cursor.description]
def get_relations(self, cursor, table_name): def get_relations(self, cursor, table_name):
""" """

View File

@ -5,7 +5,7 @@ class Reporter(models.Model):
first_name = models.CharField(max_length=30) first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
email = models.EmailField() email = models.EmailField()
facebook_user_id = models.BigIntegerField() facebook_user_id = models.BigIntegerField(null=True)
def __unicode__(self): def __unicode__(self):
return u"%s %s" % (self.first_name, self.last_name) return u"%s %s" % (self.first_name, self.last_name)

View File

@ -78,6 +78,14 @@ class IntrospectionTests(TestCase):
['IntegerField', 'CharField', 'CharField', 'CharField', 'BigIntegerField'] ['IntegerField', 'CharField', 'CharField', 'CharField', 'BigIntegerField']
) )
def test_get_table_description_nullable(self):
cursor = connection.cursor()
desc = connection.introspection.get_table_description(cursor, Reporter._meta.db_table)
self.assertEqual(
[r[6] for r in desc],
[False, False, False, False, True]
)
# Regression test for #9991 - 'real' types in postgres # Regression test for #9991 - 'real' types in postgres
@skipUnlessDBFeature('has_real_datatype') @skipUnlessDBFeature('has_real_datatype')
def test_postgresql_real_type(self): def test_postgresql_real_type(self):