summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/dialects
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/dialects')
-rw-r--r--lib/sqlalchemy/dialects/mssql/base.py13
-rw-r--r--lib/sqlalchemy/dialects/mssql/provision.py34
-rw-r--r--lib/sqlalchemy/dialects/oracle/cx_oracle.py1
-rw-r--r--lib/sqlalchemy/dialects/oracle/provision.py42
-rw-r--r--lib/sqlalchemy/dialects/postgresql/asyncpg.py1
-rw-r--r--lib/sqlalchemy/dialects/postgresql/provision.py21
-rw-r--r--lib/sqlalchemy/dialects/sqlite/provision.py6
7 files changed, 93 insertions, 25 deletions
diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py
index 538679fcf..0227e515d 100644
--- a/lib/sqlalchemy/dialects/mssql/base.py
+++ b/lib/sqlalchemy/dialects/mssql/base.py
@@ -2785,15 +2785,14 @@ class MSDialect(default.DefaultDialect):
def has_table(self, connection, tablename, dbname, owner, schema):
if tablename.startswith("#"): # temporary table
tables = ischema.mssql_temp_table_columns
- result = connection.execute(
- sql.select(tables.c.table_name)
- .where(
- tables.c.table_name.like(
- self._temp_table_name_like_pattern(tablename)
- )
+
+ s = sql.select(tables.c.table_name).where(
+ tables.c.table_name.like(
+ self._temp_table_name_like_pattern(tablename)
)
- .limit(1)
)
+
+ result = connection.execute(s.limit(1))
return result.scalar() is not None
else:
tables = ischema.tables
diff --git a/lib/sqlalchemy/dialects/mssql/provision.py b/lib/sqlalchemy/dialects/mssql/provision.py
index 269eb164f..56f3305a7 100644
--- a/lib/sqlalchemy/dialects/mssql/provision.py
+++ b/lib/sqlalchemy/dialects/mssql/provision.py
@@ -1,6 +1,14 @@
+from sqlalchemy import inspect
+from sqlalchemy import Integer
from ... import create_engine
from ... import exc
+from ...schema import Column
+from ...schema import DropConstraint
+from ...schema import ForeignKeyConstraint
+from ...schema import MetaData
+from ...schema import Table
from ...testing.provision import create_db
+from ...testing.provision import drop_all_schema_objects_pre_tables
from ...testing.provision import drop_db
from ...testing.provision import get_temp_table_name
from ...testing.provision import log
@@ -38,7 +46,6 @@ def _mssql_drop_ignore(conn, ident):
# "where database_id=db_id('%s')" % ident):
# log.info("killing SQL server session %s", row['session_id'])
# conn.exec_driver_sql("kill %s" % row['session_id'])
-
conn.exec_driver_sql("drop database %s" % ident)
log.info("Reaped db: %s", ident)
return True
@@ -83,4 +90,27 @@ def _mssql_temp_table_keyword_args(cfg, eng):
@get_temp_table_name.for_db("mssql")
def _mssql_get_temp_table_name(cfg, eng, base_name):
- return "#" + base_name
+ return "##" + base_name
+
+
+@drop_all_schema_objects_pre_tables.for_db("mssql")
+def drop_all_schema_objects_pre_tables(cfg, eng):
+ with eng.connect().execution_options(isolation_level="AUTOCOMMIT") as conn:
+ inspector = inspect(conn)
+ for schema in (None, "dbo", cfg.test_schema, cfg.test_schema_2):
+ for tname in inspector.get_table_names(schema=schema):
+ tb = Table(
+ tname,
+ MetaData(),
+ Column("x", Integer),
+ Column("y", Integer),
+ schema=schema,
+ )
+ for fk in inspect(conn).get_foreign_keys(tname, schema=schema):
+ conn.execute(
+ DropConstraint(
+ ForeignKeyConstraint(
+ [tb.c.x], [tb.c.y], name=fk["name"]
+ )
+ )
+ )
diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
index 042443692..b8b4df760 100644
--- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py
+++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
@@ -93,6 +93,7 @@ The parameters accepted by the cx_oracle dialect are as follows:
* ``encoding_errors`` - see :ref:`cx_oracle_unicode_encoding_errors` for detail.
+
.. _cx_oracle_unicode:
Unicode
diff --git a/lib/sqlalchemy/dialects/oracle/provision.py b/lib/sqlalchemy/dialects/oracle/provision.py
index d51131c0b..e0dadd58e 100644
--- a/lib/sqlalchemy/dialects/oracle/provision.py
+++ b/lib/sqlalchemy/dialects/oracle/provision.py
@@ -6,11 +6,11 @@ from ...testing.provision import create_db
from ...testing.provision import drop_db
from ...testing.provision import follower_url_from_main
from ...testing.provision import log
+from ...testing.provision import post_configure_engine
from ...testing.provision import run_reap_dbs
from ...testing.provision import set_default_schema_on_connection
-from ...testing.provision import stop_test_class
+from ...testing.provision import stop_test_class_outside_fixtures
from ...testing.provision import temp_table_keyword_args
-from ...testing.provision import update_db_opts
@create_db.for_db("oracle")
@@ -57,21 +57,39 @@ def _oracle_drop_db(cfg, eng, ident):
_ora_drop_ignore(conn, "%s_ts2" % ident)
-@update_db_opts.for_db("oracle")
-def _oracle_update_db_opts(db_url, db_opts):
- pass
+@stop_test_class_outside_fixtures.for_db("oracle")
+def stop_test_class_outside_fixtures(config, db, cls):
+ with db.begin() as conn:
+ # run magic command to get rid of identity sequences
+ # https://floo.bar/2019/11/29/drop-the-underlying-sequence-of-an-identity-column/ # noqa E501
+ conn.exec_driver_sql("purge recyclebin")
-@stop_test_class.for_db("oracle")
-def stop_test_class(config, db, cls):
- """run magic command to get rid of identity sequences
+ # clear statement cache on all connections that were used
+ # https://github.com/oracle/python-cx_Oracle/issues/519
- # https://floo.bar/2019/11/29/drop-the-underlying-sequence-of-an-identity-column/
+ for cx_oracle_conn in _all_conns:
+ try:
+ sc = cx_oracle_conn.stmtcachesize
+ except db.dialect.dbapi.InterfaceError:
+ # connection closed
+ pass
+ else:
+ cx_oracle_conn.stmtcachesize = 0
+ cx_oracle_conn.stmtcachesize = sc
+ _all_conns.clear()
- """
- with db.begin() as conn:
- conn.exec_driver_sql("purge recyclebin")
+_all_conns = set()
+
+
+@post_configure_engine.for_db("oracle")
+def _oracle_post_configure_engine(url, engine, follower_ident):
+ from sqlalchemy import event
+
+ @event.listens_for(engine, "checkout")
+ def checkout(dbapi_con, con_record, con_proxy):
+ _all_conns.add(dbapi_con)
@run_reap_dbs.for_db("oracle")
diff --git a/lib/sqlalchemy/dialects/postgresql/asyncpg.py b/lib/sqlalchemy/dialects/postgresql/asyncpg.py
index 7c6e8fb02..e542c77f4 100644
--- a/lib/sqlalchemy/dialects/postgresql/asyncpg.py
+++ b/lib/sqlalchemy/dialects/postgresql/asyncpg.py
@@ -670,7 +670,6 @@ class AsyncAdapt_asyncpg_connection:
def rollback(self):
if self._started:
self.await_(self._transaction.rollback())
-
self._transaction = None
self._started = False
diff --git a/lib/sqlalchemy/dialects/postgresql/provision.py b/lib/sqlalchemy/dialects/postgresql/provision.py
index d345cdfdf..70c390800 100644
--- a/lib/sqlalchemy/dialects/postgresql/provision.py
+++ b/lib/sqlalchemy/dialects/postgresql/provision.py
@@ -8,6 +8,7 @@ from ...testing.provision import drop_all_schema_objects_post_tables
from ...testing.provision import drop_all_schema_objects_pre_tables
from ...testing.provision import drop_db
from ...testing.provision import log
+from ...testing.provision import prepare_for_drop_tables
from ...testing.provision import set_default_schema_on_connection
from ...testing.provision import temp_table_keyword_args
@@ -102,3 +103,23 @@ def drop_all_schema_objects_post_tables(cfg, eng):
postgresql.ENUM(name=enum["name"], schema=enum["schema"])
)
)
+
+
+@prepare_for_drop_tables.for_db("postgresql")
+def prepare_for_drop_tables(config, connection):
+ """Ensure there are no locks on the current username/database."""
+
+ result = connection.exec_driver_sql(
+ "select pid, state, wait_event_type, query "
+ # "select pg_terminate_backend(pid), state, wait_event_type "
+ "from pg_stat_activity where "
+ "usename=current_user "
+ "and datname=current_database() and state='idle in transaction' "
+ "and pid != pg_backend_pid()"
+ )
+ rows = result.all() # noqa
+ assert not rows, (
+ "PostgreSQL may not be able to DROP tables due to "
+ "idle in transaction: %s"
+ % ("; ".join(row._mapping["query"] for row in rows))
+ )
diff --git a/lib/sqlalchemy/dialects/sqlite/provision.py b/lib/sqlalchemy/dialects/sqlite/provision.py
index f26c21e22..a481be27e 100644
--- a/lib/sqlalchemy/dialects/sqlite/provision.py
+++ b/lib/sqlalchemy/dialects/sqlite/provision.py
@@ -7,7 +7,7 @@ from ...testing.provision import follower_url_from_main
from ...testing.provision import log
from ...testing.provision import post_configure_engine
from ...testing.provision import run_reap_dbs
-from ...testing.provision import stop_test_class
+from ...testing.provision import stop_test_class_outside_fixtures
from ...testing.provision import temp_table_keyword_args
@@ -57,8 +57,8 @@ def _sqlite_drop_db(cfg, eng, ident):
os.remove(path)
-@stop_test_class.for_db("sqlite")
-def stop_test_class(config, db, cls):
+@stop_test_class_outside_fixtures.for_db("sqlite")
+def stop_test_class_outside_fixtures(config, db, cls):
with db.connect() as conn:
files = [
row.file