def test_include_views(self): """inspectdb --include-views creates models for database views.""" with connection.cursor() as cursor: cursor.execute('CREATE VIEW inspectdb_people_view AS ' 'SELECT id, name FROM inspectdb_people') out = StringIO() view_model = 'class InspectdbPeopleView(models.Model):' view_managed = 'managed = False # Created from a view.' try: call_command('inspectdb', table_name_filter=inspectdb_tables_only, stdout=out) no_views_output = out.getvalue() self.assertNotIn(view_model, no_views_output) self.assertNotIn(view_managed, no_views_output) call_command('inspectdb', table_name_filter=inspectdb_tables_only, include_views=True, stdout=out) with_views_output = out.getvalue() self.assertIn(view_model, with_views_output) self.assertIn(view_managed, with_views_output) finally: with connection.cursor() as cursor: cursor.execute('DROP VIEW inspectdb_people_view')
def test_adding_arrayfield_with_index(self): """ ArrayField shouldn't have varchar_patterns_ops or text_patterns_ops indexes. """ table_name = 'postgres_tests_chartextarrayindexmodel' call_command('migrate', 'postgres_tests', verbosity=0) with connection.cursor() as cursor: like_constraint_columns_list = [ v['columns'] for k, v in list(connection.introspection.get_constraints(cursor, table_name).items()) if k.endswith('_like') ] # Only the CharField should have a LIKE index. self.assertEqual(like_constraint_columns_list, [['char2']]) # All fields should have regular indexes. with connection.cursor() as cursor: indexes = [ c['columns'][0] for c in connection.introspection.get_constraints(cursor, table_name).values() if c['index'] and len(c['columns']) == 1 ] self.assertIn('char', indexes) self.assertIn('char2', indexes) self.assertIn('text', indexes) call_command('migrate', 'postgres_tests', 'zero', verbosity=0) with connection.cursor() as cursor: self.assertNotIn(table_name, connection.introspection.table_names(cursor))
def test_default_connection_thread_local(self): """ The default connection (i.e. djmodels.db.connection) is different for each thread (#17258). """ # Map connections by id because connections with identical aliases # have the same hash. connections_dict = {} connection.cursor() connections_dict[id(connection)] = connection def runner(): # Passing djmodels.db.connection between threads doesn't work while # connections[DEFAULT_DB_ALIAS] does. from djmodels.db import connections connection = connections[DEFAULT_DB_ALIAS] # Allow thread sharing so the connection can be closed by the # main thread. connection.allow_thread_sharing = True connection.cursor() connections_dict[id(connection)] = connection for x in range(2): t = threading.Thread(target=runner) t.start() t.join() # Each created connection got different inner connection. self.assertEqual(len({conn.connection for conn in connections_dict.values()}), 3) # Finish by closing the connections opened by the other threads (the # connection opened in the main thread will automatically be closed on # teardown). for conn in connections_dict.values(): if conn is not connection: conn.close()
def test_parameter_quoting(self): # The implementation of last_executed_queries isn't optimal. It's # worth testing that parameters are quoted (#14091). query = "SELECT %s" params = ["\"'\\"] connection.cursor().execute(query, params) # Note that the single quote is repeated substituted = "SELECT '\"''\\'" self.assertEqual(connection.queries[-1]['sql'], substituted)
def _test_procedure(self, procedure_sql, params, param_types, kparams=None): with connection.cursor() as cursor: cursor.execute(procedure_sql) # Use a new cursor because in MySQL a procedure can't be used in the # same cursor in which it was created. with connection.cursor() as cursor: cursor.callproc('test_procedure', params, kparams) with connection.schema_editor() as editor: editor.remove_procedure('test_procedure', param_types)
def runner(): # Passing djmodels.db.connection between threads doesn't work while # connections[DEFAULT_DB_ALIAS] does. from djmodels.db import connections connection = connections[DEFAULT_DB_ALIAS] # Allow thread sharing so the connection can be closed by the # main thread. connection.allow_thread_sharing = True connection.cursor() connections_dict[id(connection)] = connection
def test_adding_field_with_default(self): # See #22962 table_name = 'postgres_tests_integerarraydefaultmodel' with connection.cursor() as cursor: self.assertNotIn(table_name, connection.introspection.table_names(cursor)) call_command('migrate', 'postgres_tests', verbosity=0) with connection.cursor() as cursor: self.assertIn(table_name, connection.introspection.table_names(cursor)) call_command('migrate', 'postgres_tests', 'zero', verbosity=0) with connection.cursor() as cursor: self.assertNotIn(table_name, connection.introspection.table_names(cursor))
def test_password_with_at_sign(self): old_password = connection.settings_dict['PASSWORD'] connection.settings_dict['PASSWORD'] = '******' try: self.assertIn('/\\"p@ssword\\"@', connection._connect_string()) 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
def test_unicode_password(self): old_password = connection.settings_dict['PASSWORD'] connection.settings_dict['PASSWORD'] = "******" try: connection.cursor() except DatabaseError: # As password is probably wrong, a database exception is expected pass except Exception as e: self.fail("Unexpected error raised with unicode password: %s" % e) finally: connection.settings_dict['PASSWORD'] = old_password
def test_loaddata_error_message(self): """ Loading a fixture which contains an invalid object outputs an error message which contains the pk of the object that triggered the error. """ # MySQL needs a little prodding to reject invalid data. # This won't affect other tests because the database connection # is closed at the end of each test. if connection.vendor == 'mysql': connection.cursor().execute("SET sql_mode = 'TRADITIONAL'") with self.assertRaises(IntegrityError) as cm: management.call_command('loaddata', 'invalid.json', verbosity=0) self.assertIn("Could not load fixtures.Article(pk=1):", cm.exception.args[0])
def test_signal(self): data = {} def receiver(sender, connection, **kwargs): data["connection"] = connection connection_created.connect(receiver) connection.close() connection.cursor() self.assertIs(data["connection"].connection, connection.connection) connection_created.disconnect(receiver) data.clear() connection.cursor() self.assertEqual(data, {})
def test_wrapper_gets_sql(self): wrapper = self.mock_wrapper() sql = "SELECT 'aloha'" + connection.features.bare_select_suffix with connection.execute_wrapper(wrapper), connection.cursor() as cursor: cursor.execute(sql) (_, reported_sql, _, _, _), _ = wrapper.call_args self.assertEqual(reported_sql, sql)
def test_get_table_description_col_lengths(self): with connection.cursor() as cursor: desc = connection.introspection.get_table_description( cursor, Reporter._meta.db_table) self.assertEqual( [r[3] for r in desc if datatype(r[1], r) == 'CharField'], [30, 30, 254])
def test_no_index_for_foreignkey(self): """ MySQL on InnoDB already creates indexes automatically for foreign keys. (#14180). An index should be created if db_constraint=False (#26171). """ storage = connection.introspection.get_storage_engine( connection.cursor(), ArticleTranslation._meta.db_table ) if storage != "InnoDB": self.skip("This test only applies to the InnoDB storage engine") index_sql = [str(statement) for statement in connection.schema_editor()._model_indexes_sql(ArticleTranslation)] self.assertEqual(index_sql, [ 'CREATE INDEX `indexes_articletranslation_article_no_constraint_id_d6c0806b` ' 'ON `indexes_articletranslation` (`article_no_constraint_id`)' ]) # The index also shouldn't be created if the ForeignKey is added after # the model was created. field_created = False try: with connection.schema_editor() as editor: new_field = ForeignKey(Article, CASCADE) new_field.set_attributes_from_name('new_foreign_key') editor.add_field(ArticleTranslation, new_field) field_created = True self.assertEqual([str(statement) for statement in editor.deferred_sql], [ 'ALTER TABLE `indexes_articletranslation` ' 'ADD CONSTRAINT `indexes_articletrans_new_foreign_key_id_d27a9146_fk_indexes_a` ' 'FOREIGN KEY (`new_foreign_key_id`) REFERENCES `indexes_article` (`id`)' ]) finally: if field_created: with connection.schema_editor() as editor: editor.remove_field(ArticleTranslation, new_field)
def test_last_executed_query(self): """ last_executed_query should not raise an exception even if no previous query has been run. """ with connection.cursor() as cursor: connection.ops.last_executed_query(cursor, '', ())
def test_sequence_name_length_limits_flush(self): """ Sequence resetting as part of a flush with model with long name and long pk name doesn't error (#8901). """ # A full flush is expensive to the full test, so we dig into the # internals to generate the likely offending SQL and run it manually # Some convenience aliases VLM = VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ VLM_m2m = VLM.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.through tables = [ VLM._meta.db_table, VLM_m2m._meta.db_table, ] sequences = [ { 'column': VLM._meta.pk.column, 'table': VLM._meta.db_table }, ] sql_list = connection.ops.sql_flush(no_style(), tables, sequences) with connection.cursor() as cursor: for statement in sql_list: cursor.execute(statement)
def test_cursor_contextmanager_closing(self): # There isn't a generic way to test that cursors are closed, but # psycopg2 offers us a way to check that by closed attribute. # So, run only on psycopg2 for that reason. with connection.cursor() as cursor: self.assertIsInstance(cursor, CursorWrapper) self.assertTrue(cursor.closed)
def test_parameter_escaping(self): # '%s' escaping support for sqlite3 (#13648). with connection.cursor() as cursor: cursor.execute("select strftime('%s', date('now'))") response = cursor.fetchall()[0][0] # response should be an non-zero integer self.assertTrue(int(response))
def test_cursor_var(self): """Cursor variables can be passed as query parameters.""" from djmodels.db.backends.oracle.base import Database with connection.cursor() as cursor: var = cursor.var(Database.STRING) cursor.execute("BEGIN %s := 'X'; END; ", [var]) self.assertEqual(var.getvalue(), 'X')
def test_postgresql_real_type(self): with connection.cursor() as cursor: cursor.execute( "CREATE TABLE django_ixn_real_test_table (number REAL);") desc = connection.introspection.get_table_description( cursor, 'django_ixn_real_test_table') cursor.execute('DROP TABLE django_ixn_real_test_table;') self.assertEqual(datatype(desc[0][1], desc[0]), 'FloatField')
def test_django_table_names(self): with connection.cursor() as cursor: cursor.execute('CREATE TABLE django_ixn_test_table (id INTEGER);') tl = connection.introspection.django_table_names() cursor.execute("DROP TABLE django_ixn_test_table;") self.assertNotIn( 'django_ixn_test_table', tl, "django_table_names() returned a non-Django table")
def call_executemany(self, connection, params=None): # executemany() must use an update query. Make sure it does nothing # by putting a false condition in the WHERE clause. sql = 'DELETE FROM {} WHERE 0=1 AND 0=%s'.format(Square._meta.db_table) if params is None: params = [(i,) for i in range(3)] with connection.cursor() as cursor: cursor.executemany(sql, params)
def test_get_key_columns(self): with connection.cursor() as cursor: key_columns = connection.introspection.get_key_columns( cursor, Article._meta.db_table) self.assertEqual( set(key_columns), {('reporter_id', Reporter._meta.db_table, 'id'), ('response_to_id', Article._meta.db_table, 'id')})
def test_get_sequences(self): with connection.cursor() as cursor: seqs = connection.introspection.get_sequences( cursor, Person._meta.db_table, Person._meta.local_fields) self.assertEqual(len(seqs), 1) self.assertIsNotNone(seqs[0]['name']) self.assertEqual(seqs[0]['table'], Person._meta.db_table) self.assertEqual(seqs[0]['column'], 'id')
def test_get_primary_key_column(self): with connection.cursor() as cursor: primary_key_column = connection.introspection.get_primary_key_column( cursor, Article._meta.db_table) pk_fk_column = connection.introspection.get_primary_key_column( cursor, District._meta.db_table) self.assertEqual(primary_key_column, 'id') self.assertEqual(pk_fk_column, 'city_id')
def test_large_number_of_parameters(self): # If SQLITE_MAX_VARIABLE_NUMBER (default = 999) has been changed to be # greater than SQLITE_MAX_COLUMN (default = 2000), last_executed_query # can hit the SQLITE_MAX_COLUMN limit (#26063). with connection.cursor() as cursor: sql = "SELECT MAX(%s)" % ", ".join(["%s"] * 2001) params = list(range(2001)) # This should not raise an exception. cursor.db.ops.last_executed_query(cursor.cursor, sql, params)
def test_reraising_backend_specific_database_exception(self): with connection.cursor() as cursor: msg = 'table "X" does not exist' with self.assertRaisesMessage(ProgrammingError, msg) as cm: cursor.execute('DROP TABLE "X"') self.assertNotEqual(type(cm.exception), type(cm.exception.__cause__)) self.assertIsNotNone(cm.exception.__cause__) self.assertIsNotNone(cm.exception.__cause__.pgcode) self.assertIsNotNone(cm.exception.__cause__.pgerror)
def test_database_queried(self): wrapper = self.mock_wrapper() with connection.execute_wrapper(wrapper): with connection.cursor() as cursor: sql = 'SELECT 17' + connection.features.bare_select_suffix cursor.execute(sql) seventeen = cursor.fetchall() self.assertEqual(list(seventeen), [(17,)]) self.call_executemany(connection)
def test_get_table_description_nullable(self): with connection.cursor() as cursor: desc = connection.introspection.get_table_description( cursor, Reporter._meta.db_table) nullable_by_backend = connection.features.interprets_empty_strings_as_nulls self.assertEqual([r[6] for r in desc], [ False, nullable_by_backend, nullable_by_backend, nullable_by_backend, True, True, False ])
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)