Fixed #31301 -- Fixed crash of QuerySet.bulk_create() with mixed empty and set ForeignKeys to AutoFields on Oracle.

This commit is contained in:
Hans Aarne Liblik 2020-02-28 08:50:24 +02:00 committed by Mariusz Felisiak
parent 8b30360322
commit a21f7b91db
3 changed files with 24 additions and 4 deletions

View File

@ -62,6 +62,8 @@ class BulkInsertMapper:
TIMESTAMP = 'TO_TIMESTAMP(%s)' TIMESTAMP = 'TO_TIMESTAMP(%s)'
types = { types = {
'AutoField': NUMBER,
'BigAutoField': NUMBER,
'BigIntegerField': NUMBER, 'BigIntegerField': NUMBER,
'BinaryField': BLOB, 'BinaryField': BLOB,
'BooleanField': NUMBER, 'BooleanField': NUMBER,
@ -75,6 +77,7 @@ class BulkInsertMapper:
'PositiveBigIntegerField': NUMBER, 'PositiveBigIntegerField': NUMBER,
'PositiveIntegerField': NUMBER, 'PositiveIntegerField': NUMBER,
'PositiveSmallIntegerField': NUMBER, 'PositiveSmallIntegerField': NUMBER,
'SmallAutoField': NUMBER,
'SmallIntegerField': NUMBER, 'SmallIntegerField': NUMBER,
'TextField': CLOB, 'TextField': CLOB,
'TimeField': TIMESTAMP, 'TimeField': TIMESTAMP,

View File

@ -64,6 +64,14 @@ class NoFields(models.Model):
pass pass
class SmallAutoFieldModel(models.Model):
id = models.SmallAutoField(primary_key=True)
class BigAutoFieldModel(models.Model):
id = models.BigAutoField(primary_key=True)
class NullableFields(models.Model): class NullableFields(models.Model):
# Fields in db.backends.oracle.BulkInsertMapper # Fields in db.backends.oracle.BulkInsertMapper
big_int_filed = models.BigIntegerField(null=True, default=1) big_int_filed = models.BigIntegerField(null=True, default=1)
@ -81,6 +89,9 @@ class NullableFields(models.Model):
positive_small_integer_field = models.PositiveSmallIntegerField(null=True, default=4) positive_small_integer_field = models.PositiveSmallIntegerField(null=True, default=4)
small_integer_field = models.SmallIntegerField(null=True, default=5) small_integer_field = models.SmallIntegerField(null=True, default=5)
time_field = models.TimeField(null=True, default=timezone.now) time_field = models.TimeField(null=True, default=timezone.now)
auto_field = models.ForeignKey(NoFields, on_delete=models.CASCADE, null=True)
small_auto_field = models.ForeignKey(SmallAutoFieldModel, on_delete=models.CASCADE, null=True)
big_auto_field = models.ForeignKey(BigAutoFieldModel, on_delete=models.CASCADE, null=True)
# Fields not required in BulkInsertMapper # Fields not required in BulkInsertMapper
char_field = models.CharField(null=True, max_length=4, default='char') char_field = models.CharField(null=True, max_length=4, default='char')
email_field = models.EmailField(null=True, default='user@example.com') email_field = models.EmailField(null=True, default='user@example.com')

View File

@ -9,9 +9,9 @@ from django.test import (
) )
from .models import ( from .models import (
Country, NoFields, NullableFields, Pizzeria, ProxyCountry, BigAutoFieldModel, Country, NoFields, NullableFields, Pizzeria,
ProxyMultiCountry, ProxyMultiProxyCountry, ProxyProxyCountry, Restaurant, ProxyCountry, ProxyMultiCountry, ProxyMultiProxyCountry, ProxyProxyCountry,
State, TwoFields, Restaurant, SmallAutoFieldModel, State, TwoFields,
) )
@ -234,10 +234,16 @@ class BulkCreateTests(TestCase):
@skipUnlessDBFeature('has_bulk_insert') @skipUnlessDBFeature('has_bulk_insert')
def test_bulk_insert_nullable_fields(self): def test_bulk_insert_nullable_fields(self):
fk_to_auto_fields = {
'auto_field': NoFields.objects.create(),
'small_auto_field': SmallAutoFieldModel.objects.create(),
'big_auto_field': BigAutoFieldModel.objects.create(),
}
# NULL can be mixed with other values in nullable fields # NULL can be mixed with other values in nullable fields
nullable_fields = [field for field in NullableFields._meta.get_fields() if field.name != 'id'] nullable_fields = [field for field in NullableFields._meta.get_fields() if field.name != 'id']
NullableFields.objects.bulk_create([ NullableFields.objects.bulk_create([
NullableFields(**{field.name: None}) for field in nullable_fields NullableFields(**{**fk_to_auto_fields, field.name: None})
for field in nullable_fields
]) ])
self.assertEqual(NullableFields.objects.count(), len(nullable_fields)) self.assertEqual(NullableFields.objects.count(), len(nullable_fields))
for field in nullable_fields: for field in nullable_fields: