diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py index 1b0c6e9ed85..bea03e355e4 100644 --- a/django/db/backends/oracle/operations.py +++ b/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'): diff --git a/tests/backends/oracle/tests.py b/tests/backends/oracle/tests.py index fd2435e5bb6..02bcceabb4a 100644 --- a/tests/backends/oracle/tests.py +++ b/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"')