From 1b823b8f182e8f31b8c9db281311ef718299eda7 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Thu, 5 Oct 2017 18:52:37 +0200 Subject: [PATCH] Fixed #28596 -- Fixed QuerySet.bulk_create() and cascade deletion crash on Oracle when using more than 65535 parameters. Thanks Tim Graham for the review. --- django/db/backends/oracle/features.py | 1 + django/db/backends/oracle/operations.py | 6 ++++++ tests/backends/oracle/test_operations.py | 14 ++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/django/db/backends/oracle/features.py b/django/db/backends/oracle/features.py index a378372947..71421f0df8 100644 --- a/django/db/backends/oracle/features.py +++ b/django/db/backends/oracle/features.py @@ -55,3 +55,4 @@ class DatabaseFeatures(BaseDatabaseFeatures): """ supports_callproc_kwargs = True supports_over_clause = True + max_query_params = 2**16 - 1 diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py index 51df23aedb..5c0f6accae 100644 --- a/django/db/backends/oracle/operations.py +++ b/django/db/backends/oracle/operations.py @@ -556,3 +556,9 @@ END; rhs_sql, rhs_params = rhs return "NUMTODSINTERVAL(%s - %s, 'DAY')" % (lhs_sql, rhs_sql), lhs_params + rhs_params return super().subtract_temporals(internal_type, lhs, rhs) + + def bulk_batch_size(self, fields, objs): + """Oracle restricts the number of parameters in a query.""" + if fields: + return self.connection.features.max_query_params // len(fields) + return len(objs) diff --git a/tests/backends/oracle/test_operations.py b/tests/backends/oracle/test_operations.py index d73df9a05c..bcae17cec6 100644 --- a/tests/backends/oracle/test_operations.py +++ b/tests/backends/oracle/test_operations.py @@ -9,3 +9,17 @@ class OperationsTests(unittest.TestCase): def test_sequence_name_truncation(self): seq_name = connection.ops._get_no_autofield_sequence_name('schema_authorwithevenlongee869') self.assertEqual(seq_name, 'SCHEMA_AUTHORWITHEVENLOB0B8_SQ') + + def test_bulk_batch_size(self): + # Oracle restricts the number of parameters in a query. + objects = range(2**16) + self.assertEqual(connection.ops.bulk_batch_size([], objects), len(objects)) + # Each field is a parameter for each object. + self.assertEqual( + connection.ops.bulk_batch_size(['id'], objects), + connection.features.max_query_params, + ) + self.assertEqual( + connection.ops.bulk_batch_size(['id', 'other'], objects), + connection.features.max_query_params // 2, + )