浏览代码

Fixed #28859 -- Made Oracle backend raise DatabaseError if "no data found" exception is hidden by the Oracle OCI library.

Thanks Tim Graham for the review and Jani Tiainen for the report.
Mariusz Felisiak 7 年之前
父节点
当前提交
8f8a93a9ae
共有 2 个文件被更改,包括 42 次插入1 次删除
  1. 9 1
      django/db/backends/oracle/operations.py
  2. 33 0
      tests/backends/oracle/tests.py

+ 9 - 1
django/db/backends/oracle/operations.py

@@ -5,6 +5,7 @@ import uuid
 from django.conf import settings
 from django.db.backends.base.operations import BaseDatabaseOperations
 from django.db.backends.utils import strip_quotes, truncate_name
+from django.db.utils import DatabaseError
 from django.utils import timezone
 from django.utils.encoding import force_bytes
 
@@ -217,7 +218,14 @@ END;
         return " DEFERRABLE INITIALLY DEFERRED"
 
     def fetch_returned_insert_id(self, cursor):
-        return int(cursor._insert_id_var.getvalue())
+        try:
+            return int(cursor._insert_id_var.getvalue())
+        except TypeError:
+            raise DatabaseError(
+                'The database did not return a new row id. Probably "ORA-1403: '
+                'no data found" was raised internally but was hidden by the '
+                'Oracle OCI library (see https://code.djangoproject.com/ticket/28859).'
+            )
 
     def field_cast_sql(self, db_type, internal_type):
         if db_type and db_type.endswith('LOB'):

+ 33 - 0
tests/backends/oracle/tests.py

@@ -2,6 +2,10 @@ import unittest
 
 from django.db import connection
 from django.db.models.fields import BooleanField, NullBooleanField
+from django.db.utils import DatabaseError
+from django.test import TransactionTestCase
+
+from ..models import Square
 
 
 @unittest.skipUnless(connection.vendor == 'oracle', 'Oracle tests')
@@ -61,3 +65,32 @@ class Tests(unittest.TestCase):
             with self.subTest(field=field):
                 field.set_attributes_from_name('is_nice')
                 self.assertIn('"IS_NICE" IN (0,1)', field.db_check(connection))
+
+
+@unittest.skipUnless(connection.vendor == 'oracle', 'Oracle tests')
+class HiddenNoDataFoundExceptionTest(TransactionTestCase):
+    available_apps = ['backends']
+
+    def test_hidden_no_data_found_exception(self):
+        # "ORA-1403: no data found" exception is hidden by Oracle OCI library
+        # when an INSERT statement is used with a RETURNING clause (see #28859).
+        with connection.cursor() as cursor:
+            # Create trigger that raises "ORA-1403: no data found".
+            cursor.execute("""
+                CREATE OR REPLACE TRIGGER "TRG_NO_DATA_FOUND"
+                AFTER INSERT ON "BACKENDS_SQUARE"
+                FOR EACH ROW
+                BEGIN
+                    RAISE NO_DATA_FOUND;
+                END;
+            """)
+        try:
+            with self.assertRaisesMessage(DatabaseError, (
+                'The database did not return a new row id. Probably "ORA-1403: '
+                'no data found" was raised internally but was hidden by the '
+                'Oracle OCI library (see https://code.djangoproject.com/ticket/28859).'
+            )):
+                Square.objects.create(root=2, square=4)
+        finally:
+            with connection.cursor() as cursor:
+                cursor.execute('DROP TRIGGER "TRG_NO_DATA_FOUND"')