import operator
import sqlalchemy as sa
from sqlalchemy.schema import DDL, Index
from sqlalchemy import inspect, testing
from sqlalchemy import types as sql_types
from sqlalchemy.testing.provision import get_temp_table_name, temp_table_keyword_args
from sqlalchemy.testing.suite import *
from sqlalchemy.testing.suite import ComponentReflectionTestExtra as _ComponentReflectionTestExtra
from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest
from sqlalchemy.testing.suite.test_ddl import LongNameBlowoutTest as _LongNameBlowoutTest
from sqlalchemy.testing.suite.test_reflection import ComponentReflectionTest as _ComponentReflectionTest
from sqlalchemy.testing.suite.test_reflection import CompositeKeyReflectionTest as _CompositeKeyReflectionTest
from sqlalchemy.testing.suite.test_reflection import QuotedNameArgumentTest as _QuotedNameArgumentTest
from sqlalchemy.testing.suite.test_results import ServerSideCursorsTest as _ServerSideCursorsTest
from sqlalchemy.testing.suite.test_select import FetchLimitOffsetTest as _FetchLimitOffsetTest
from sqlalchemy.testing.suite.test_select import JoinTest as _JoinTest
from sqlalchemy.testing.suite.test_unicode_ddl import UnicodeSchemaTest as _UnicodeSchemaTest
from sqlalchemy.engine import ObjectScope, ObjectKind, Inspector
from sqlalchemy.testing import mock, assert_raises_message
from sqlalchemy.testing.suite.test_dialect import IsolationLevelTest as _IsolationLevelTest
from sqlalchemy.testing.suite.test_types import TrueDivTest as _TrueDivTest
class CTETest(_CTETest):
@classmethod
def define_tables(cls, metadata):
if testing.requires.foreign_keys.enabled:
Table(
"some_table",
metadata,
Column("id", Integer, primary_key=True),
Column("data", String(50)),
Column("parent_id", ForeignKey("some_table.id")),
)
else:
Table(
"some_table",
metadata,
Column("id", Integer, primary_key=True),
Column("data", String(50)),
Column("parent_id", Integer),
)
Table(
"some_other_table",
metadata,
Column("id", Integer, primary_key=True),
Column("data", String(50)),
Column("parent_id", Integer),
)
class LongNameBlowoutTest(_LongNameBlowoutTest):
@testing.combinations(
("fk", testing.requires.foreign_keys),
("pk",),
("ix",),
("ck", testing.requires.check_constraint_reflection.as_skips()),
("uq", testing.requires.unique_constraint_reflection.as_skips()),
argnames="type_",
)
def test_long_convention_name(self, type_, metadata, connection):
actual_name, reflected_name = getattr(self, type_)(
metadata, connection
)
assert len(actual_name) > 255
if reflected_name is not None:
overlap = actual_name[0: len(reflected_name)]
if len(overlap) < len(actual_name):
eq_(overlap[0:-5], reflected_name[0: len(overlap) - 5])
else:
eq_(overlap, reflected_name)
def _multi_combination(fn):
schema = testing.combinations(
None,
(
lambda: config.test_schema,
testing.requires.schemas,
),
argnames="schema",
)
scope = testing.combinations(
ObjectScope.DEFAULT,
ObjectScope.TEMPORARY,
ObjectScope.ANY,
argnames="scope",
)
kind = testing.combinations(
ObjectKind.TABLE,
ObjectKind.VIEW,
ObjectKind.MATERIALIZED_VIEW,
ObjectKind.ANY,
ObjectKind.ANY_VIEW,
ObjectKind.TABLE | ObjectKind.VIEW,
ObjectKind.TABLE | ObjectKind.MATERIALIZED_VIEW,
argnames="kind",
)
filter_names = testing.combinations(True, False, argnames="use_filter")
return schema(scope(kind(filter_names(fn))))
class ComponentReflectionTest(_ComponentReflectionTest):
@classmethod
def define_reflected_tables(cls, metadata, schema):
if schema:
schema_prefix = schema + "."
else:
schema_prefix = ""
if testing.requires.self_referential_foreign_keys.enabled:
parent_id_args = (
ForeignKey(
"%susers.user_id" % schema_prefix, name="user_id_fk"
),
)
else:
parent_id_args = ()
users = Table(
"users",
metadata,
Column("user_id", sa.INT, primary_key=True),
Column("test1", sa.CHAR(5), nullable=False),
Column("test2", sa.Float(), nullable=False),
Column("parent_user_id", sa.Integer, *parent_id_args),
sa.CheckConstraint(
"test2 > 0",
name="zz_test2_gt_zero",
comment="users check constraint",
),
sa.CheckConstraint("test2 <= 1000"),
schema=schema,
test_needs_fk=True,
)
if testing.requires.foreign_keys.enabled:
Table(
"dingalings",
metadata,
Column("dingaling_id", sa.Integer, primary_key=True),
Column(
"address_id",
sa.Integer,
ForeignKey(
"%semail_addresses.address_id" % schema_prefix,
name="zz_email_add_id_fg",
comment="di fk comment",
),
),
Column(
"id_user",
sa.Integer,
ForeignKey("%susers.user_id" % schema_prefix),
),
Column("data", sa.String(30), unique=True),
sa.CheckConstraint(
"address_id > 0 AND address_id < 1000",
name="address_id_gt_zero",
),
sa.UniqueConstraint(
"address_id",
"dingaling_id",
name="zz_dingalings_multiple",
comment="di unique comment",
),
schema=schema,
test_needs_fk=True,
)
Table(
"email_addresses",
metadata,
Column("address_id", sa.Integer),
Column("remote_user_id", sa.Integer, ForeignKey(users.c.user_id)),
Column("email_address", sa.String(20), index=True),
sa.PrimaryKeyConstraint(
"address_id", name="email_ad_pk", comment="ea pk comment"
),
schema=schema,
test_needs_fk=True,
)
else:
Table(
"dingalings",
metadata,
Column("dingaling_id", sa.Integer, primary_key=True),
Column(
"address_id",
sa.Integer,
),
Column(
"id_user",
sa.Integer,
),
Column("data", sa.String(30), unique=True),
sa.CheckConstraint(
"address_id > 0 AND address_id < 1000",
name="address_id_gt_zero",
),
sa.UniqueConstraint(
"address_id",
"dingaling_id",
name="zz_dingalings_multiple",
comment="di unique comment",
),
schema=schema,
test_needs_fk=True,
)
Table(
"email_addresses",
metadata,
Column("address_id", sa.Integer),
Column("remote_user_id", sa.Integer),
Column("email_address", sa.String(20), index=True),
sa.PrimaryKeyConstraint(
"address_id", name="email_ad_pk", comment="ea pk comment"
),
schema=schema,
test_needs_fk=True,
)
Table(
"comment_test",
metadata,
Column("id", sa.Integer, primary_key=True, comment="id comment"),
Column("data", sa.String(20), comment="data % comment"),
Column(
"d2",
sa.String(20),
comment=r"""Comment types type speedily ' " \ '' Fun!""",
),
Column("d3", sa.String(42), comment="Comment\nwith\rescapes"),
schema=schema,
comment=r"""the test % ' " \ table comment""",
)
Table(
"no_constraints",
metadata,
Column("data", sa.String(20)),
schema=schema,
comment="no\nconstraints\rhas\fescaped\vcomment",
)
if testing.requires.cross_schema_fk_reflection.enabled:
if schema is None:
Table(
"local_table",
metadata,
Column("id", sa.Integer, primary_key=True),
Column("data", sa.String(20)),
Column(
"remote_id",
ForeignKey(
"%s.remote_table_2.id" % testing.config.test_schema
),
),
test_needs_fk=True,
schema=config.db.dialect.default_schema_name,
)
else:
Table(
"remote_table",
metadata,
Column("id", sa.Integer, primary_key=True),
Column(
"local_id",
ForeignKey(
"%s.local_table.id"
% config.db.dialect.default_schema_name
),
),
Column("data", sa.String(20)),
schema=schema,
test_needs_fk=True,
)
Table(
"remote_table_2",
metadata,
Column("id", sa.Integer, primary_key=True),
Column("data", sa.String(20)),
schema=schema,
test_needs_fk=True,
)
if testing.requires.index_reflection.enabled:
Index("users_t_idx", users.c.test1, users.c.test2, unique=True)
Index(
"users_all_idx", users.c.user_id, users.c.test2, users.c.test1
)
if not schema:
noncol_idx_test_nopk = Table(
"noncol_idx_test_nopk",
metadata,
Column("q", sa.String(5)),
test_needs_fk=True,
)
noncol_idx_test_pk = Table(
"noncol_idx_test_pk",
metadata,
Column("id", sa.Integer, primary_key=True),
Column("q", sa.String(5)),
test_needs_fk=True,
)
if (
testing.requires.indexes_with_ascdesc.enabled
and testing.requires.reflect_indexes_with_ascdesc.enabled
):
Index("noncol_idx_nopk", noncol_idx_test_nopk.c.q.desc())
Index("noncol_idx_pk", noncol_idx_test_pk.c.q.desc())
if testing.requires.view_column_reflection.enabled:
cls.define_views(metadata, schema)
if not schema and testing.requires.temp_table_reflection.enabled:
cls.define_temp_tables(metadata)
@classmethod
def define_temp_tables(cls, metadata):
kw = temp_table_keyword_args(config, config.db)
table_name = cls.temp_table_name()
user_tmp = Table(
table_name,
metadata,
Column("id", sa.INT),
Column("name", sa.VARCHAR(50)),
Column("foo", sa.INT),
sa.UniqueConstraint("name", name=f"user_tmp_uq_{config.ident}"),
sa.Index("user_tmp_ix", "foo"),
**kw
)
if (
testing.requires.view_reflection.enabled
and testing.requires.temporary_views.enabled
):
event.listen(
user_tmp,
"after_create",
DDL(
"create temporary view user_tmp_v as "
"select * from user_tmp_%s" % config.ident
),
)
event.listen(user_tmp, "before_drop", DDL("drop view user_tmp_v"))
@testing.combinations(
(True, testing.requires.schemas), (False,), argnames="use_schema"
)
@testing.requires.unique_constraint_reflection
def test_get_unique_constraints(self, metadata, connection, use_schema):
if use_schema:
schema = config.test_schema
else:
schema = None
uniques = sorted(
[
{"name": "unique_a", "column_names": ["a"]},
{"name": "unique_a_b_c", "column_names": ["a", "b", "c"]},
{"name": "unique_c_a_b", "column_names": ["c", "a", "b"]},
{"name": "unique_asc_key", "column_names": ["asc", "key"]},
{"name": "i.have.dots", "column_names": ["b"]},
{"name": "i have spaces", "column_names": ["c"]},
],
key=operator.itemgetter("name"),
)
if testing.against("opengauss+dc_psycopg2"):
table = Table(
"testtbl",
metadata,
Column("a", sa.String(20)),
Column("b", sa.String(30)),
Column("c", sa.Integer),
Column("asc", sa.String(30)),
Column("key", sa.String(30)),
schema=schema,
opengauss_distribute_by='REPLICATION',
)
else:
table = Table(
"testtbl",
metadata,
Column("a", sa.String(20)),
Column("b", sa.String(30)),
Column("c", sa.Integer),
Column("asc", sa.String(30)),
Column("key", sa.String(30)),
schema=schema,
)
for uc in uniques:
table.append_constraint(
sa.UniqueConstraint(*uc["column_names"], name=uc["name"])
)
table.create(connection)
inspector = inspect(connection)
reflected = sorted(
inspector.get_unique_constraints("testtbl", schema=schema),
key=operator.itemgetter("name"),
)
names_that_duplicate_index = set()
for orig, refl in zip(uniques, reflected):
dupe = refl.pop("duplicates_index", None)
if dupe:
names_that_duplicate_index.add(dupe)
eq_(refl.pop("comment", None), None)
eq_(orig, refl)
reflected_metadata = MetaData()
reflected = Table(
"testtbl",
reflected_metadata,
autoload_with=connection,
schema=schema,
)
idx_names = {idx.name for idx in reflected.indexes}
uq_names = {
uq.name
for uq in reflected.constraints
if isinstance(uq, sa.UniqueConstraint)
}.difference(["unique_c_a_b"])
assert not idx_names.intersection(uq_names)
if names_that_duplicate_index:
eq_(names_that_duplicate_index, idx_names)
eq_(uq_names, set())
no_cst = self.tables.no_constraints.name
eq_(inspector.get_unique_constraints(no_cst, schema=schema), [])
def exp_columns(
self,
schema=None,
scope=ObjectScope.ANY,
kind=ObjectKind.ANY,
filter_names=None,
):
def col(
name, auto=False, default=mock.ANY, comment=None, nullable=True
):
res = {
"name": name,
"autoincrement": auto,
"type": mock.ANY,
"default": default,
"comment": comment,
"nullable": nullable,
}
if auto == "omit":
res.pop("autoincrement")
return res
def pk(name, **kw):
kw = {"auto": True, "default": mock.ANY, "nullable": False, **kw}
return col(name, **kw)
materialized = {
(schema, "dingalings_v"): [
col("dingaling_id", auto="omit", nullable=mock.ANY),
col("address_id"),
col("id_user"),
col("data"),
]
}
views = {
(schema, "email_addresses_v"): [
col("address_id", auto="omit", nullable=mock.ANY),
col("remote_user_id"),
col("email_address"),
],
(schema, "users_v"): [
col("user_id", auto="omit", nullable=mock.ANY),
col("test1", nullable=mock.ANY),
col("test2", nullable=mock.ANY),
col("parent_user_id"),
],
(schema, "user_tmp_v"): [
col("id", auto="omit", nullable=mock.ANY),
col("name"),
col("foo"),
],
}
self._resolve_views(views, materialized)
tables = {
(schema, "users"): [
pk("user_id"),
col("test1", nullable=False),
col("test2", nullable=False),
col("parent_user_id"),
],
(schema, "dingalings"): [
pk("dingaling_id"),
col("address_id"),
col("id_user"),
col("data"),
],
(schema, "email_addresses"): [
pk("address_id"),
col("remote_user_id"),
col("email_address"),
],
(schema, "comment_test"): [
pk("id", comment="id comment"),
col("data", comment="data % comment"),
col(
"d2",
comment=r"""Comment types type speedily ' " \ '' Fun!""",
),
col("d3", comment="Comment\nwith\rescapes"),
],
(schema, "no_constraints"): [col("data")],
(schema, "local_table"): [pk("id"), col("data"), col("remote_id")],
(schema, "remote_table"): [pk("id"), col("local_id"), col("data")],
(schema, "remote_table_2"): [pk("id"), col("data")],
(schema, "noncol_idx_test_nopk"): [col("q")],
(schema, "noncol_idx_test_pk"): [pk("id"), col("q")],
(schema, self.temp_table_name()): [
pk("id", nullable=True, auto=False),
col("name", nullable=True, auto=False),
col("foo", nullable=True, auto=False),
],
}
res = self._resolve_kind(kind, tables, views, materialized)
res = self._resolve_names(schema, scope, filter_names, res)
return res
@property
def _required_column_keys(self):
return {"name", "type", "nullable", "default"}
def exp_pks(
self,
schema=None,
scope=ObjectScope.ANY,
kind=ObjectKind.ANY,
filter_names=None,
):
def pk(*cols, name=mock.ANY, comment=None):
return {
"constrained_columns": list(cols),
"name": name,
"comment": comment,
}
empty = pk(name=None)
if testing.requires.materialized_views_reflect_pk.enabled:
materialized = {(schema, "dingalings_v"): pk("dingaling_id")}
else:
materialized = {(schema, "dingalings_v"): empty}
views = {
(schema, "email_addresses_v"): empty,
(schema, "users_v"): empty,
(schema, "user_tmp_v"): empty,
}
self._resolve_views(views, materialized)
tables = {
(schema, "users"): pk("user_id"),
(schema, "dingalings"): pk("dingaling_id"),
(schema, "email_addresses"): pk(
"address_id", name="email_ad_pk", comment="ea pk comment"
),
(schema, "comment_test"): pk("id"),
(schema, "no_constraints"): empty,
(schema, "local_table"): pk("id"),
(schema, "remote_table"): pk("id"),
(schema, "remote_table_2"): pk("id"),
(schema, "noncol_idx_test_nopk"): empty,
(schema, "noncol_idx_test_pk"): pk("id"),
(schema, self.temp_table_name()): pk(name=None),
}
if not testing.requires.reflects_pk_names.enabled:
for val in tables.values():
if val["name"] is not None:
val["name"] = mock.ANY
res = self._resolve_kind(kind, tables, views, materialized)
res = self._resolve_names(schema, scope, filter_names, res)
return res
class CompositeKeyReflectionTest(_CompositeKeyReflectionTest):
@classmethod
def define_tables(cls, metadata):
tb1 = Table(
"tb1",
metadata,
Column("id", Integer),
Column("attr", Integer),
Column("name", sql_types.VARCHAR(20)),
sa.PrimaryKeyConstraint("name", "id", "attr", name="pk_tb1"),
schema=None,
test_needs_fk=True,
)
if testing.requires.foreign_key_constraint_reflection.enabled:
Table(
"tb2",
metadata,
Column("id", Integer, primary_key=True),
Column("pid", Integer),
Column("pattr", Integer),
Column("pname", sql_types.VARCHAR(20)),
sa.ForeignKeyConstraint(
["pname", "pid", "pattr"],
[tb1.c.name, tb1.c.id, tb1.c.attr],
name="fk_tb1_name_id_attr",
),
schema=None,
test_needs_fk=True,
)
class ComponentReflectionTestExtra(_ComponentReflectionTestExtra):
@testing.combinations(
(
None,
"CASCADE",
None,
testing.requires.foreign_key_constraint_option_reflection_ondelete,
),
(
None,
None,
"SET NULL",
testing.requires.foreign_key_constraint_option_reflection_onupdate,
),
(
{},
None,
"NO ACTION",
testing.requires.foreign_key_constraint_option_reflection_onupdate,
),
(
{},
"NO ACTION",
None,
testing.requires.fk_constraint_option_reflection_ondelete_noaction,
),
(
None,
None,
"RESTRICT",
testing.requires.fk_constraint_option_reflection_onupdate_restrict,
),
(
None,
"RESTRICT",
None,
testing.requires.fk_constraint_option_reflection_ondelete_restrict,
),
argnames="expected,ondelete,onupdate",
)
def test_get_foreign_key_options(
self, connection, metadata, expected, ondelete, onupdate
):
options = {}
if ondelete:
options["ondelete"] = ondelete
if onupdate:
options["onupdate"] = onupdate
if expected is None:
expected = options
Table(
"x",
metadata,
Column("id", Integer, primary_key=True),
test_needs_fk=True,
)
Table(
"table",
metadata,
Column("id", Integer, primary_key=True),
Column("x_id", Integer, sa.ForeignKey("x.id", name="xid")),
Column("test", String(10)),
test_needs_fk=True,
)
Table(
"user",
metadata,
Column("id", Integer, primary_key=True),
Column("name", String(50), nullable=False),
Column("tid_", Integer),
sa.ForeignKeyConstraint(
["tid_"], ["table.id"], name="myfk", **options
),
test_needs_fk=True,
)
metadata.create_all(connection)
insp = inspect(connection)
opts = insp.get_foreign_keys("table")[0]["options"]
eq_({k: opts[k] for k in opts if opts[k]}, {})
opts = insp.get_foreign_keys("user")[0]["options"]
eq_(opts, expected)
@testing.requires.indexes_with_expressions
def test_reflect_expression_based_indexes(self, metadata, connection):
t = Table(
"t",
metadata,
Column("x", String(30)),
Column("y", String(30)),
Column("z", String(30)),
)
Index("t_idx", func.lower(t.c.x), t.c.z, func.lower(t.c.y))
long_str = "long string " * 100
Index("t_idx_long", func.coalesce(t.c.x, long_str))
Index("t_idx_2", t.c.x)
metadata.create_all(connection)
insp = inspect(connection)
expected = [
{
"name": "t_idx_2",
"unique": False,
"column_names": ["x"],
}
]
class lower_index_str(str):
def __eq__(self, other):
ol = other.lower()
return "lower" in ol and ("x" in ol or "y" in ol)
class coalesce_index_str(str):
def __eq__(self, other):
return "coalesce" in other.lower() and long_str in other
if testing.requires.reflect_indexes_with_expressions.enabled:
expr_index = {
"name": "t_idx",
"unique": False,
"column_names": [None, "z", None],
"expressions": [
lower_index_str("lower(x)"),
"z",
lower_index_str("lower(y)"),
],
}
expected.insert(0, expr_index)
expr_index_long = {
"name": "t_idx_long",
"unique": False,
"column_names": [None],
"expressions": [
coalesce_index_str(f"coalesce(x, '{long_str}' ::character varying))")
],
}
expected.append(expr_index_long)
eq_(insp.get_indexes("t"), expected)
m2 = MetaData()
t2 = Table("t", m2, autoload_with=connection)
else:
eq_(insp.get_indexes("t"), expected)
m2 = MetaData()
t2 = Table("t", m2, autoload_with=connection)
self.compare_table_index_with_expected(
t2, expected, connection.engine.name
)
class QuotedNameArgumentTest(_QuotedNameArgumentTest):
@classmethod
def define_tables(cls, metadata):
if testing.requires.foreign_keys.enabled:
Table(
"quote ' one",
metadata,
Column("id", Integer),
Column("name", String(50)),
Column("data", String(50)),
Column("related_id", Integer),
sa.PrimaryKeyConstraint("id", name="pk quote ' one"),
sa.Index("ix quote ' one", "name"),
sa.UniqueConstraint(
"data",
name="uq quote' one",
),
sa.ForeignKeyConstraint(
["id"], ["related.id"], name="fk quote ' one"
),
sa.CheckConstraint("name != 'foo'", name="ck quote ' one"),
comment=r"""quote ' one comment""",
test_needs_fk=True,
)
if testing.requires.symbol_names_w_double_quote.enabled:
Table(
'quote " two',
metadata,
Column("id", Integer),
Column("name", String(50)),
Column("data", String(50)),
Column("related_id", Integer),
sa.PrimaryKeyConstraint("id", name='pk quote " two'),
sa.Index('ix quote " two', "name"),
sa.UniqueConstraint(
"data",
name='uq quote" two',
),
sa.ForeignKeyConstraint(
["id"], ["related.id"], name='fk quote " two'
),
sa.CheckConstraint("name != 'foo'", name='ck quote " two '),
comment=r"""quote " two comment""",
test_needs_fk=True,
)
else:
Table(
"quote ' one",
metadata,
Column("id", Integer),
Column("name", String(50)),
Column("data", String(50)),
Column("related_id", Integer),
sa.PrimaryKeyConstraint("id", name="pk quote ' one"),
sa.Index("ix quote ' one", "name"),
sa.UniqueConstraint(
"data",
name="uq quote' one",
),
sa.CheckConstraint("name != 'foo'", name="ck quote ' one"),
comment=r"""quote ' one comment""",
test_needs_fk=True,
opengauss_distribute_by='REPLICATION',
)
if testing.requires.symbol_names_w_double_quote.enabled:
Table(
'quote " two',
metadata,
Column("id", Integer),
Column("name", String(50)),
Column("data", String(50)),
Column("related_id", Integer),
sa.PrimaryKeyConstraint("id", name='pk quote " two'),
sa.Index('ix quote " two', "name"),
sa.UniqueConstraint(
"data",
name='uq quote" two',
),
sa.CheckConstraint("name != 'foo'", name='ck quote " two '),
comment=r"""quote " two comment""",
test_needs_fk=True,
opengauss_distribute_by='REPLICATION',
)
Table(
"related",
metadata,
Column("id", Integer, primary_key=True),
Column("related", Integer),
test_needs_fk=True,
)
if testing.requires.view_column_reflection.enabled:
if testing.requires.symbol_names_w_double_quote.enabled:
names = [
"quote ' one",
'quote " two',
]
else:
names = [
"quote ' one",
]
for name in names:
query = "CREATE VIEW %s AS SELECT * FROM %s" % (
config.db.dialect.identifier_preparer.quote(
"view %s" % name
),
config.db.dialect.identifier_preparer.quote(name),
)
event.listen(metadata, "after_create", DDL(query))
event.listen(
metadata,
"before_drop",
DDL(
"DROP VIEW %s"
% config.db.dialect.identifier_preparer.quote(
"view %s" % name
)
),
)
def quote_fixtures(fn):
return testing.combinations(
("quote ' one",),
('quote " two', testing.requires.symbol_names_w_double_quote),
)(fn)
@quote_fixtures
@testing.requires.foreign_keys
def test_get_foreign_keys(self, name):
insp = inspect(config.db)
assert insp.get_foreign_keys(name)
class ServerSideCursorsTest(_ServerSideCursorsTest):
def _is_server_side(self, cursor):
if self.engine.dialect.driver in ("psycopg2", "dc_psycopg2"):
return bool(cursor.name)
elif self.engine.dialect.driver == "pymysql":
sscursor = __import__("pymysql.cursors").cursors.SSCursor
return isinstance(cursor, sscursor)
elif self.engine.dialect.driver in ("aiomysql", "asyncmy"):
return cursor.server_side
elif self.engine.dialect.driver == "mysqldb":
sscursor = __import__("MySQLdb.cursors").cursors.SSCursor
return isinstance(cursor, sscursor)
elif self.engine.dialect.driver == "mariadbconnector":
return not cursor.buffered
elif self.engine.dialect.driver in ("asyncpg", "aiosqlite"):
return cursor.server_side
elif self.engine.dialect.driver == "pg8000":
return getattr(cursor, "server_side", False)
else:
return False
class FetchLimitOffsetTest(_FetchLimitOffsetTest):
def test_limit_render_multiple_times(self, connection):
table = self.tables.some_table
if testing.requires.limit_with_strict_isotonicity.enabled:
stmt = select(table.c.id).limit(1).scalar_subquery()
else:
stmt = select(table.c.id).order_by(table.c.id).limit(1).scalar_subquery()
u = union(select(stmt), select(stmt)).subquery().select()
self._assert_result(
connection,
u,
[
(1,),
],
)
class JoinTest(_JoinTest):
@classmethod
def define_tables(cls, metadata):
Table("a", metadata, Column("id", Integer, primary_key=True))
if testing.requires.foreign_keys.enabled:
Table(
"b",
metadata,
Column("id", Integer, primary_key=True),
Column("a_id", ForeignKey("a.id"), nullable=False),
)
else:
Table(
"b",
metadata,
Column("id", Integer, primary_key=True),
Column("a_id", Integer, nullable=False),
)
@testing.requires.foreign_keys
def test_inner_join_fk(self):
a, b = self.tables("a", "b")
stmt = select(a, b).select_from(a.join(b)).order_by(a.c.id, b.c.id)
self._assert_result(stmt, [(1, 1, 1), (1, 2, 1), (2, 4, 2), (3, 5, 3)])
@testing.requires.foreign_keys
def test_outer_join_fk(self):
a, b = self.tables("a", "b")
stmt = select(a, b).select_from(a.join(b)).order_by(a.c.id, b.c.id)
self._assert_result(stmt, [(1, 1, 1), (1, 2, 1), (2, 4, 2), (3, 5, 3)])
class UnicodeSchemaTest(_UnicodeSchemaTest):
@classmethod
def define_tables(cls, metadata):
global t1, t2, t3
t1 = Table(
"unitable1",
metadata,
Column("méil", Integer, primary_key=True),
Column("\u6e2c\u8a66", Integer),
test_needs_fk=True,
)
if testing.requires.foreign_keys.enabled:
t2 = Table(
"Unitéble2",
metadata,
Column("méil", Integer, primary_key=True, key="a"),
Column(
"\u6e2c\u8a66",
Integer,
ForeignKey("unitable1.méil"),
key="b",
),
test_needs_fk=True,
)
else:
t2 = Table(
"Unitéble2",
metadata,
Column("méil", Integer, primary_key=True, key="a"),
Column(
"\u6e2c\u8a66",
Integer,
key="b",
),
test_needs_fk=True,
)
t3 = Table(
"\u6e2c\u8a66",
metadata,
Column(
"\u6e2c\u8a66_id",
Integer,
primary_key=True,
autoincrement=False,
),
Column("unitable1_\u6e2c\u8a66", Integer),
Column("Unitéble2_b", Integer),
Column("\u6e2c\u8a66_self", Integer),
test_needs_fk=True,
)
def test_insert(self, connection):
connection.execute(t1.insert(), {"méil": 1, "\u6e2c\u8a66": 5})
connection.execute(t2.insert(), {"a": 1, "b": 1})
connection.execute(
t3.insert(),
{
"\u6e2c\u8a66_id": 1,
"unitable1_\u6e2c\u8a66": 5,
"Unitéble2_b": 1,
"\u6e2c\u8a66_self": 1,
},
)
eq_(connection.execute(t1.select()).fetchall(), [(1, 5)])
eq_(connection.execute(t2.select()).fetchall(), [(1, 1)])
eq_(connection.execute(t3.select()).fetchall(), [(1, 5, 1, 1)])
def test_col_targeting(self, connection):
connection.execute(t1.insert(), {"méil": 1, "\u6e2c\u8a66": 5})
connection.execute(t2.insert(), {"a": 1, "b": 1})
connection.execute(
t3.insert(),
{
"\u6e2c\u8a66_id": 1,
"unitable1_\u6e2c\u8a66": 5,
"Unitéble2_b": 1,
"\u6e2c\u8a66_self": 1,
},
)
row = connection.execute(t1.select()).first()
eq_(row._mapping[t1.c["méil"]], 1)
eq_(row._mapping[t1.c["\u6e2c\u8a66"]], 5)
row = connection.execute(t2.select()).first()
eq_(row._mapping[t2.c["a"]], 1)
eq_(row._mapping[t2.c["b"]], 1)
row = connection.execute(t3.select()).first()
eq_(row._mapping[t3.c["\u6e2c\u8a66_id"]], 1)
eq_(row._mapping[t3.c["unitable1_\u6e2c\u8a66"]], 5)
eq_(row._mapping[t3.c["Unitéble2_b"]], 1)
eq_(row._mapping[t3.c["\u6e2c\u8a66_self"]], 1)
def test_reflect(self, connection):
connection.execute(t1.insert(), {"méil": 2, "\u6e2c\u8a66": 7})
connection.execute(t2.insert(), {"a": 2, "b": 2})
connection.execute(
t3.insert(),
{
"\u6e2c\u8a66_id": 2,
"unitable1_\u6e2c\u8a66": 7,
"Unitéble2_b": 2,
"\u6e2c\u8a66_self": 2,
},
)
meta = MetaData()
tt1 = Table(t1.name, meta, autoload_with=connection)
tt2 = Table(t2.name, meta, autoload_with=connection)
tt3 = Table(t3.name, meta, autoload_with=connection)
connection.execute(tt1.insert(), {"méil": 1, "\u6e2c\u8a66": 5})
connection.execute(tt2.insert(), {"méil": 1, "\u6e2c\u8a66": 1})
connection.execute(
tt3.insert(),
{
"\u6e2c\u8a66_id": 1,
"unitable1_\u6e2c\u8a66": 5,
"Unitéble2_b": 1,
"\u6e2c\u8a66_self": 1,
},
)
eq_(
connection.execute(tt1.select().order_by(desc("méil"))).fetchall(),
[(2, 7), (1, 5)],
)
eq_(
connection.execute(tt2.select().order_by(desc("méil"))).fetchall(),
[(2, 2), (1, 1)],
)
eq_(
connection.execute(
tt3.select().order_by(desc("\u6e2c\u8a66_id"))
).fetchall(),
[(2, 7, 2, 2), (1, 5, 1, 1)],
)
from sqlalchemy import literal_column, func, select, Integer
class TrueDivTest(_TrueDivTest):
@testing.combinations(
("15", "10", 1), ("-15", "5", -3), argnames="left, right, expected"
)
def test_floordiv_integer(self, connection, left, right, expected):
"""test #4926"""
eq_(
connection.scalar(
select(
func.floor(literal_column(left, type_=Integer()) // literal_column(right, type_=Integer()))
)
),
expected,
)
def test_floordiv_integer_bound(self, connection):
"""test #4926"""
eq_(
connection.scalar(select(func.floor(literal(15) // literal(10)))),
1,
)