Files
sqlalchemy/test/dialect/mysql/test_query.py
T
Mike Bayer fc97854f69 Bump minimum MySQL version to 5.0.2; use all-numeric server version
MySQL dialect's server_version_info tuple is now all numeric.  String
tokens like "MariaDB" are no longer present so that numeric comparison
works in all cases.  The .is_mariadb flag on the dialect should be
consulted for whether or not mariadb was detected.   Additionally removed
structures meant to support extremely old MySQL versions 3.x and 4.x;
the minimum MySQL version supported is now version 5.0.2.

In addition, as the "MariaDB" name goes away from server version,
expand upon the change in I330815ebe572b6a9818377da56621397335fa702
to support the name "mariadb" throughout the dialect and test suite
when mariadb-only mode is used.    This changes the "name" field
on the MariaDB dialect to "mariadb", which then implies a change
throughout the testing requirements system as well as all the
dialect-specific DDL argument names such as "mysql_engine" is
now specified as "mariadb_engine", etc.   Make use of the
recent additions to test suite URL provisioning so that we can
force MariaDB databases to have a "mariadb-only" dialect which
allows us to test this name change fully.

Update documentation to refer to MySQL / MariaDB explicitly
as well as indicating the "mariadb_" prefix used for options.

It seems likely that MySQL and MariaDB version numbers are going to
start colliding at some point so having the "mariadb" name
be available as a totally separate dialect name should give us
some options in this regard.

Currently also includes a date related fix to a test for
the postgresql dialect that was implicitly assuming a
non-UTC timezone

Fixes: #4189
Change-Id: I00e76d00f62971e1f067bd61915fa6cc1cf64e5e
2020-08-16 12:18:07 -04:00

268 lines
7.7 KiB
Python

# coding: utf-8
from sqlalchemy import all_
from sqlalchemy import and_
from sqlalchemy import any_
from sqlalchemy import Boolean
from sqlalchemy import cast
from sqlalchemy import Column
from sqlalchemy import false
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import or_
from sqlalchemy import select
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy import testing
from sqlalchemy import true
from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
class IdiosyncrasyTest(fixtures.TestBase):
__only_on__ = "mysql", "mariadb"
__backend__ = True
@testing.emits_warning()
def test_is_boolean_symbols_despite_no_native(self, connection):
is_(
connection.scalar(select(cast(true().is_(true()), Boolean))), True,
)
is_(
connection.scalar(select(cast(true().isnot(true()), Boolean))),
False,
)
is_(
connection.scalar(select(cast(false().is_(false()), Boolean))),
True,
)
class MatchTest(fixtures.TestBase):
__only_on__ = "mysql", "mariadb"
__backend__ = True
@classmethod
def setup_class(cls):
global metadata, cattable, matchtable
metadata = MetaData(testing.db)
cattable = Table(
"cattable",
metadata,
Column("id", Integer, primary_key=True),
Column("description", String(50)),
mysql_engine="MyISAM",
mariadb_engine="MyISAM",
)
matchtable = Table(
"matchtable",
metadata,
Column("id", Integer, primary_key=True),
Column("title", String(200)),
Column("category_id", Integer, ForeignKey("cattable.id")),
mysql_engine="MyISAM",
mariadb_engine="MyISAM",
)
metadata.create_all()
cattable.insert().execute(
[
{"id": 1, "description": "Python"},
{"id": 2, "description": "Ruby"},
]
)
matchtable.insert().execute(
[
{
"id": 1,
"title": "Agile Web Development with Ruby On Rails",
"category_id": 2,
},
{"id": 2, "title": "Dive Into Python", "category_id": 1},
{
"id": 3,
"title": "Programming Matz's Ruby",
"category_id": 2,
},
{
"id": 4,
"title": "The Definitive Guide to Django",
"category_id": 1,
},
{"id": 5, "title": "Python in a Nutshell", "category_id": 1},
]
)
@classmethod
def teardown_class(cls):
metadata.drop_all()
def test_simple_match(self):
results = (
matchtable.select()
.where(matchtable.c.title.match("python"))
.order_by(matchtable.c.id)
.execute()
.fetchall()
)
eq_([2, 5], [r.id for r in results])
def test_not_match(self):
results = (
matchtable.select()
.where(~matchtable.c.title.match("python"))
.order_by(matchtable.c.id)
.execute()
.fetchall()
)
eq_([1, 3, 4], [r.id for r in results])
def test_simple_match_with_apostrophe(self):
results = (
matchtable.select()
.where(matchtable.c.title.match("Matz's"))
.execute()
.fetchall()
)
eq_([3], [r.id for r in results])
def test_return_value(self, connection):
# test [ticket:3263]
result = connection.execute(
select(
matchtable.c.title.match("Agile Ruby Programming").label(
"ruby"
),
matchtable.c.title.match("Dive Python").label("python"),
matchtable.c.title,
).order_by(matchtable.c.id)
).fetchall()
eq_(
result,
[
(2.0, 0.0, "Agile Web Development with Ruby On Rails"),
(0.0, 2.0, "Dive Into Python"),
(2.0, 0.0, "Programming Matz's Ruby"),
(0.0, 0.0, "The Definitive Guide to Django"),
(0.0, 1.0, "Python in a Nutshell"),
],
)
def test_or_match(self):
results1 = (
matchtable.select()
.where(
or_(
matchtable.c.title.match("nutshell"),
matchtable.c.title.match("ruby"),
)
)
.order_by(matchtable.c.id)
.execute()
.fetchall()
)
eq_([1, 3, 5], [r.id for r in results1])
results2 = (
matchtable.select()
.where(matchtable.c.title.match("nutshell ruby"))
.order_by(matchtable.c.id)
.execute()
.fetchall()
)
eq_([1, 3, 5], [r.id for r in results2])
def test_and_match(self):
results1 = (
matchtable.select()
.where(
and_(
matchtable.c.title.match("python"),
matchtable.c.title.match("nutshell"),
)
)
.execute()
.fetchall()
)
eq_([5], [r.id for r in results1])
results2 = (
matchtable.select()
.where(matchtable.c.title.match("+python +nutshell"))
.execute()
.fetchall()
)
eq_([5], [r.id for r in results2])
def test_match_across_joins(self):
results = (
matchtable.select()
.where(
and_(
cattable.c.id == matchtable.c.category_id,
or_(
cattable.c.description.match("Ruby"),
matchtable.c.title.match("nutshell"),
),
)
)
.order_by(matchtable.c.id)
.execute()
.fetchall()
)
eq_([1, 3, 5], [r.id for r in results])
class AnyAllTest(fixtures.TablesTest):
__only_on__ = "mysql", "mariadb"
__backend__ = True
@classmethod
def define_tables(cls, metadata):
Table(
"stuff",
metadata,
Column("id", Integer, primary_key=True),
Column("value", Integer),
)
@classmethod
def insert_data(cls, connection):
stuff = cls.tables.stuff
connection.execute(
stuff.insert(),
[
{"id": 1, "value": 1},
{"id": 2, "value": 2},
{"id": 3, "value": 3},
{"id": 4, "value": 4},
{"id": 5, "value": 5},
],
)
def test_any_w_comparator(self, connection):
stuff = self.tables.stuff
stmt = select(stuff.c.id).where(
stuff.c.value > any_(select(stuff.c.value).scalar_subquery())
)
eq_(connection.execute(stmt).fetchall(), [(2,), (3,), (4,), (5,)])
def test_all_w_comparator(self, connection):
stuff = self.tables.stuff
stmt = select(stuff.c.id).where(
stuff.c.value >= all_(select(stuff.c.value).scalar_subquery())
)
eq_(connection.execute(stmt).fetchall(), [(5,)])
def test_any_literal(self, connection):
stuff = self.tables.stuff
stmt = select([4 == any_(select(stuff.c.value).scalar_subquery())])
is_(connection.execute(stmt).scalar(), True)