2019-06-10 11:56:50 +00:00
|
|
|
import datetime
|
2017-02-11 20:37:49 +00:00
|
|
|
import unittest
|
|
|
|
|
|
|
|
from django.db import connection
|
2017-09-05 07:02:56 +00:00
|
|
|
from django.db.models.fields import BooleanField, NullBooleanField
|
2018-01-06 17:50:54 +00:00
|
|
|
from django.db.utils import DatabaseError
|
|
|
|
from django.test import TransactionTestCase
|
|
|
|
|
2019-06-10 11:56:50 +00:00
|
|
|
from ..models import NonIntegerAutoField, Square
|
2017-02-11 20:37:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipUnless(connection.vendor == 'oracle', 'Oracle tests')
|
|
|
|
class Tests(unittest.TestCase):
|
|
|
|
|
|
|
|
def test_quote_name(self):
|
|
|
|
"""'%' chars are escaped for query execution."""
|
|
|
|
name = '"SOME%NAME"'
|
|
|
|
quoted_name = connection.ops.quote_name(name)
|
|
|
|
self.assertEqual(quoted_name % (), name)
|
|
|
|
|
|
|
|
def test_dbms_session(self):
|
|
|
|
"""A stored procedure can be called through a cursor wrapper."""
|
|
|
|
with connection.cursor() as cursor:
|
|
|
|
cursor.callproc('DBMS_SESSION.SET_IDENTIFIER', ['_django_testing!'])
|
|
|
|
|
|
|
|
def test_cursor_var(self):
|
|
|
|
"""Cursor variables can be passed as query parameters."""
|
|
|
|
with connection.cursor() as cursor:
|
2019-02-12 19:10:02 +00:00
|
|
|
var = cursor.var(str)
|
2017-02-11 20:37:49 +00:00
|
|
|
cursor.execute("BEGIN %s := 'X'; END; ", [var])
|
|
|
|
self.assertEqual(var.getvalue(), 'X')
|
|
|
|
|
|
|
|
def test_client_encoding(self):
|
|
|
|
"""Client encoding is set correctly."""
|
|
|
|
connection.ensure_connection()
|
|
|
|
self.assertEqual(connection.connection.encoding, 'UTF-8')
|
|
|
|
self.assertEqual(connection.connection.nencoding, 'UTF-8')
|
|
|
|
|
|
|
|
def test_order_of_nls_parameters(self):
|
|
|
|
"""
|
|
|
|
An 'almost right' datetime works with configured NLS parameters
|
|
|
|
(#18465).
|
|
|
|
"""
|
|
|
|
with connection.cursor() as cursor:
|
|
|
|
query = "select 1 from dual where '1936-12-29 00:00' < sysdate"
|
|
|
|
# The query succeeds without errors - pre #18465 this
|
|
|
|
# wasn't the case.
|
|
|
|
cursor.execute(query)
|
|
|
|
self.assertEqual(cursor.fetchone()[0], 1)
|
2017-09-05 07:02:56 +00:00
|
|
|
|
|
|
|
def test_boolean_constraints(self):
|
|
|
|
"""Boolean fields have check constraints on their values."""
|
2017-05-06 14:56:28 +00:00
|
|
|
for field in (BooleanField(), NullBooleanField(), BooleanField(null=True)):
|
2017-09-05 07:02:56 +00:00
|
|
|
with self.subTest(field=field):
|
|
|
|
field.set_attributes_from_name('is_nice')
|
|
|
|
self.assertIn('"IS_NICE" IN (0,1)', field.db_check(connection))
|
2018-01-06 17:50:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipUnless(connection.vendor == 'oracle', 'Oracle tests')
|
2018-03-13 18:06:40 +00:00
|
|
|
class TransactionalTests(TransactionTestCase):
|
2018-01-06 17:50:54 +00:00
|
|
|
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"')
|
2018-03-13 18:06:40 +00:00
|
|
|
|
|
|
|
def test_password_with_at_sign(self):
|
|
|
|
old_password = connection.settings_dict['PASSWORD']
|
|
|
|
connection.settings_dict['PASSWORD'] = 'p@ssword'
|
|
|
|
try:
|
2019-04-01 23:34:11 +00:00
|
|
|
self.assertIn('/"p@ssword"@', connection._connect_string())
|
2018-03-13 18:06:40 +00:00
|
|
|
with self.assertRaises(DatabaseError) as context:
|
|
|
|
connection.cursor()
|
|
|
|
# Database exception: "ORA-01017: invalid username/password" is
|
|
|
|
# expected.
|
|
|
|
self.assertIn('ORA-01017', context.exception.args[0].message)
|
|
|
|
finally:
|
|
|
|
connection.settings_dict['PASSWORD'] = old_password
|
2019-06-10 11:56:50 +00:00
|
|
|
|
|
|
|
def test_non_integer_auto_field(self):
|
|
|
|
with connection.cursor() as cursor:
|
|
|
|
# Create trigger that fill non-integer auto field.
|
|
|
|
cursor.execute("""
|
|
|
|
CREATE OR REPLACE TRIGGER "TRG_FILL_CREATION_DATETIME"
|
|
|
|
BEFORE INSERT ON "BACKENDS_NONINTEGERAUTOFIELD"
|
|
|
|
FOR EACH ROW
|
|
|
|
BEGIN
|
|
|
|
:NEW.CREATION_DATETIME := SYSTIMESTAMP;
|
|
|
|
END;
|
|
|
|
""")
|
|
|
|
try:
|
|
|
|
NonIntegerAutoField._meta.auto_field = NonIntegerAutoField.creation_datetime
|
|
|
|
obj = NonIntegerAutoField.objects.create()
|
|
|
|
self.assertIsNotNone(obj.creation_datetime)
|
|
|
|
self.assertIsInstance(obj.creation_datetime, datetime.datetime)
|
|
|
|
finally:
|
|
|
|
with connection.cursor() as cursor:
|
|
|
|
cursor.execute('DROP TRIGGER "TRG_FILL_CREATION_DATETIME"')
|