Deprecate usage of ``DISTINCT ON`` in dialect other than PostgreSQL.
Previously this was silently ignored.
Deprecate old usage of string distinct in MySQL dialect
Fixes: #4002
Change-Id: I38fc64aef75e77748083c11d388ec831f161c9c9
--- /dev/null
+.. change::
+ :tags: bug, sql
+ :tickets: 4002
+
+ Deprecate usage of ``DISTINCT ON`` in dialect other than PostgreSQL.
+ Deprecate old usage of string distinct in MySQL dialect
result += "FIRST %s " % self.process(select._limit_clause, **kw)
if select._offset_clause is not None:
result += "SKIP %s " % self.process(select._offset_clause, **kw)
- if select._distinct:
- result += "DISTINCT "
+ result += super(FBCompiler, self).get_select_precolumns(select, **kw)
return result
def limit_clause(self, select, **kw):
def get_select_precolumns(self, select, **kw):
""" MS-SQL puts TOP, it's version of LIMIT here """
- s = ""
- if select._distinct:
- s += "DISTINCT "
+ s = super(MSSQLCompiler, self).get_select_precolumns(select, **kw)
if select._simple_int_limit and (
select._offset_clause is None
# so have to use literal here.
kw["literal_execute"] = True
s += "TOP %s " % self.process(select._limit_clause, **kw)
- if s:
- return s
- else:
- return compiler.SQLCompiler.get_select_precolumns(
- self, select, **kw
- )
+
+ return s
def get_from_hint_text(self, table, text):
return text
def get_select_precolumns(self, select, **kw):
"""Add special MySQL keywords in place of DISTINCT.
- .. note::
-
- this usage is deprecated. :meth:`_expression.Select.prefix_with`
- should be used for special keywords at the start
- of a SELECT.
+ .. deprecated 1.4:: this usage is deprecated.
+ :meth:`_expression.Select.prefix_with` should be used for special
+ keywords at the start of a SELECT.
"""
if isinstance(select._distinct, util.string_types):
+ util.warn_deprecated(
+ "Sending string values for 'distinct' is deprecated in the "
+ "MySQL dialect and will be removed in a future release. "
+ "Please use :meth:`.Select.prefix_with` for special keywords "
+ "at the start of a SELECT statement",
+ version="1.4",
+ )
return select._distinct.upper() + " "
- elif select._distinct:
- return "DISTINCT "
- else:
- return ""
+
+ return super(MySQLCompiler, self).get_select_precolumns(select, **kw)
def visit_join(self, join, asfrom=False, from_linter=None, **kwargs):
if from_linter:
return "ONLY " + sqltext
def get_select_precolumns(self, select, **kw):
+ # Do not call super().get_select_precolumns because
+ # it will warn/raise when distinct on is present
if select._distinct or select._distinct_on:
if select._distinct_on:
return (
the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)``
construct.
+ .. deprecated:: 1.4 Using \*expr in other dialects is deprecated
+ and will raise :class:`_exc.CompileError` in a future version.
+
"""
if not expr:
self._distinct = True
before column list.
"""
- return select._distinct and "DISTINCT " or ""
+ if select._distinct_on:
+ util.warn_deprecated(
+ "DISTINCT ON is currently supported only by the PostgreSQL "
+ "dialect. Use of DISTINCT ON for other backends is currently "
+ "silently ignored, however this usage is deprecated, and will "
+ "raise CompileError in a future release for all backends "
+ "that do not support this syntax.",
+ version="1.4",
+ )
+ return "DISTINCT " if select._distinct else ""
def group_by_clause(self, select, **kw):
"""allow dialects to customize how GROUP BY is rendered."""
the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>>)``
construct.
+ .. deprecated:: 1.4 Using \*expr in other dialects is deprecated
+ and will raise :class:`_exc.CompileError` in a future version.
+
"""
if expr:
self._distinct = True
c = clause.compile(dialect=dialect, **kw)
param_str = repr(getattr(c, "params", {}))
-
if util.py3k:
param_str = param_str.encode("utf-8").decode("ascii", "ignore")
print(
computed columns"""
return exclusions.closed()
+ @property
+ def supports_distinct_on(self):
+ """If a backend supports the DISTINCT ON in a select"""
+ return exclusions.closed()
+
@property
def supports_is_distinct_from(self):
"""Supports some form of "x IS [NOT] DISTINCT FROM y" construct.
from ..schema import Table
from ... import bindparam
from ... import case
+from ... import column
from ... import Computed
from ... import false
from ... import func
from ... import null
from ... import select
from ... import String
+from ... import table
from ... import testing
from ... import text
from ... import true
eq_(res, [(100, 40), (1764, 168)])
+class DistinctOnTest(AssertsCompiledSQL, fixtures.TablesTest):
+ __backend__ = True
+ __requires__ = ("standard_cursor_sql",)
+
+ @testing.fails_if(testing.requires.supports_distinct_on)
+ def test_distinct_on(self):
+ stm = select(["*"]).distinct(column("q")).select_from(table("foo"))
+ with testing.expect_deprecated(
+ "DISTINCT ON is currently supported only by the PostgreSQL "
+ ):
+ self.assert_compile(stm, "SELECT DISTINCT * FROM foo")
+
+
class IsOrIsNotDistinctFromTest(fixtures.TablesTest):
__backend__ = True
__requires__ = ("supports_is_distinct_from",)
+from sqlalchemy import select
+from sqlalchemy import table
+from sqlalchemy.dialects.mysql import base as mysql
from sqlalchemy.dialects.mysql import ENUM
from sqlalchemy.dialects.mysql import SET
+from sqlalchemy.testing import AssertsCompiledSQL
+from sqlalchemy.testing import expect_deprecated
from sqlalchemy.testing import expect_deprecated_20
from sqlalchemy.testing import fixtures
+class CompileTest(AssertsCompiledSQL, fixtures.TestBase):
+
+ __dialect__ = mysql.dialect()
+
+ def test_distinct_string(self):
+ s = select(["*"]).select_from(table("foo"))
+ s._distinct = "foo"
+
+ with expect_deprecated(
+ "Sending string values for 'distinct' is deprecated in the MySQL "
+ "dialect and will be removed in a future release"
+ ):
+ self.assert_compile(s, "SELECT FOO * FROM foo")
+
+
class DeprecateQuoting(fixtures.TestBase):
def test_enum_warning(self):
ENUM("a", "b")
@property
def computed_columns_reflect_persisted(self):
return self.computed_columns + skip_if("oracle")
+
+ @property
+ def supports_distinct_on(self):
+ """If a backend supports the DISTINCT ON in a select"""
+ return only_if(["postgresql"])
"SELECT count(DISTINCT mytable.myid) AS count_1 FROM mytable",
)
+ def test_distinct_on(self):
+ with testing.expect_deprecated(
+ "DISTINCT ON is currently supported only by the PostgreSQL "
+ "dialect"
+ ):
+ select(["*"]).distinct(table1.c.myid).compile()
+
def test_where_empty(self):
self.assert_compile(
select([table1.c.myid]).where(