summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2021-01-21 11:15:06 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2021-01-21 11:15:06 -0500
commit851a3a362ee5e05b8438f92e2e1df63c68f79d68 (patch)
tree2d862d02a1369d1730d78c933e09b709d2ef8bf6 /lib
parent05a31f2708590161d4b3b4c7ff65196c99b4a22b (diff)
downloadsqlalchemy-851a3a362ee5e05b8438f92e2e1df63c68f79d68.tar.gz
Revert "Implement support for functions as FROM with columns clause support"
This reverts commit 05a31f2708590161d4b3b4c7ff65196c99b4a22b. Atom has this little button called "push" and just pushes to master, I wasn't even *on* master. oops
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/dialects/oracle/base.py13
-rw-r--r--lib/sqlalchemy/sql/coercions.py21
-rw-r--r--lib/sqlalchemy/sql/compiler.py34
-rw-r--r--lib/sqlalchemy/sql/elements.py187
-rw-r--r--lib/sqlalchemy/sql/functions.py272
-rw-r--r--lib/sqlalchemy/sql/roles.py4
-rw-r--r--lib/sqlalchemy/sql/selectable.py67
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py4
8 files changed, 75 insertions, 527 deletions
diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py
index 70fe72ec4..4754beebe 100644
--- a/lib/sqlalchemy/dialects/oracle/base.py
+++ b/lib/sqlalchemy/dialects/oracle/base.py
@@ -924,19 +924,6 @@ class OracleCompiler(compiler.SQLCompiler):
else:
return ""
- def visit_function(self, func, **kw):
- text = super(OracleCompiler, self).visit_function(func, **kw)
- if kw.get("asfrom", False):
- text = "TABLE (%s)" % func
- return text
-
- def visit_table_valued_column(self, element, **kw):
- text = super(OracleCompiler, self).visit_table_valued_column(
- element, **kw
- )
- text = "COLUMN_VALUE " + text
- return text
-
def default_from(self):
"""Called when a ``SELECT`` statement has no froms,
and no ``FROM`` clause is to be appended.
diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py
index b5b5082e6..05e0a4fcf 100644
--- a/lib/sqlalchemy/sql/coercions.py
+++ b/lib/sqlalchemy/sql/coercions.py
@@ -431,20 +431,6 @@ class ExpressionElementImpl(_ColumnCoercions, RoleImpl):
except exc.ArgumentError as err:
self._raise_for_expected(element, err=err)
- def _raise_for_expected(self, element, argname=None, resolved=None, **kw):
- if isinstance(element, roles.AnonymizedFromClauseRole):
- advice = (
- "To create a "
- "column expression from a FROM clause row "
- "as a whole, use the .record() method."
- )
- else:
- advice = None
-
- return super(ExpressionElementImpl, self)._raise_for_expected(
- element, argname=argname, resolved=resolved, advice=advice, **kw
- )
-
class BinaryElementImpl(ExpressionElementImpl, RoleImpl):
@@ -611,13 +597,6 @@ class ColumnArgumentOrKeyImpl(_ReturnsStringKey, RoleImpl):
__slots__ = ()
-class StrAsPlainColumnImpl(_CoerceLiterals, RoleImpl):
- __slots__ = ()
-
- def _text_coercion(self, element, argname=None):
- return elements.ColumnClause(element)
-
-
class ByOfImpl(_CoerceLiterals, _ColumnCoercions, RoleImpl, roles.ByOfRole):
__slots__ = ()
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index db13cff01..ef7db0bbe 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -1718,18 +1718,13 @@ class SQLCompiler(Compiled):
extract.expr._compiler_dispatch(self, **kwargs),
)
- def visit_scalar_function_column(self, element, **kw):
- compiled_fn = self.visit_function(element.fn, **kw)
- compiled_col = self.visit_column(element, **kw)
- return "(%s).%s" % (compiled_fn, compiled_col)
-
def visit_function(self, func, add_to_result_map=None, **kwargs):
if add_to_result_map is not None:
add_to_result_map(func.name, func.name, (), func.type)
disp = getattr(self, "visit_%s_func" % func.name.lower(), None)
if disp:
- text = disp(func, **kwargs)
+ return disp(func, **kwargs)
else:
name = FUNCTIONS.get(func.__class__, None)
if name:
@@ -1744,7 +1739,7 @@ class SQLCompiler(Compiled):
else name
)
name = name + "%(expr)s"
- text = ".".join(
+ return ".".join(
[
(
self.preparer.quote(tok)
@@ -1757,10 +1752,6 @@ class SQLCompiler(Compiled):
+ [name]
) % {"expr": self.function_argspec(func, **kwargs)}
- if func._with_ordinality:
- text += " WITH ORDINALITY"
- return text
-
def visit_next_value_func(self, next_value, **kw):
return self.visit_sequence(next_value.sequence)
@@ -2536,27 +2527,6 @@ class SQLCompiler(Compiled):
else:
return self.preparer.format_alias(cte, cte_name)
- def visit_table_valued_alias(self, element, **kw):
- text = self.visit_alias(element, **kw)
- if kw.get("asfrom") and element.named:
- text += "(%s)" % (
- ", ".join(
- "%s%s"
- % (
- col.name,
- " %s"
- % self.dialect.type_compiler.process(col.type, **kw)
- if not col.type._isnull
- else "",
- )
- for col in element.element.c
- )
- )
- return text
-
- def visit_table_valued_column(self, element, **kw):
- return self.visit_column(element, **kw)
-
def visit_alias(
self,
alias,
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index 7dc60ce9d..5ea3526ea 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -4317,82 +4317,11 @@ class Label(roles.LabeledColumnExprRole, ColumnElement):
return self.key, e
-class NamedColumn(ColumnElement):
- is_literal = False
- table = None
-
- def _compare_name_for_result(self, other):
- return (hasattr(other, "name") and self.name == other.name) or (
- hasattr(other, "_label") and self._label == other._label
- )
-
- @util.memoized_property
- def description(self):
- if util.py3k:
- return self.name
- else:
- return self.name.encode("ascii", "backslashreplace")
-
- @HasMemoized.memoized_attribute
- def _key_label(self):
- if self.key != self.name:
- return self._gen_label(self.key)
- else:
- return self._label
-
- @HasMemoized.memoized_attribute
- def _label(self):
- return self._gen_label(self.name)
-
- @HasMemoized.memoized_attribute
- def _render_label_in_columns_clause(self):
- return True
-
- def _gen_label(self, name, dedupe_on_key=True):
- return name
-
- def _bind_param(self, operator, obj, type_=None, expanding=False):
- return BindParameter(
- self.key,
- obj,
- _compared_to_operator=operator,
- _compared_to_type=self.type,
- type_=type_,
- unique=True,
- expanding=expanding,
- )
-
- def _make_proxy(
- self,
- selectable,
- name=None,
- name_is_truncatable=False,
- disallow_is_literal=False,
- **kw
- ):
- c = ColumnClause(
- coercions.expect(roles.TruncatedLabelRole, name or self.name)
- if name_is_truncatable
- else (name or self.name),
- type_=self.type,
- _selectable=selectable,
- is_literal=False,
- )
- c._propagate_attrs = selectable._propagate_attrs
- if name is None:
- c.key = self.key
- c._proxies = [self]
- if selectable._is_clone_of is not None:
- c._is_clone_of = selectable._is_clone_of.columns.get(c.key)
- return c.key, c
-
-
class ColumnClause(
roles.DDLReferredColumnRole,
roles.LabeledColumnExprRole,
- roles.StrAsPlainColumnRole,
Immutable,
- NamedColumn,
+ ColumnElement,
):
"""Represents a column expression from any textual string.
@@ -4431,9 +4360,6 @@ class ColumnClause(
"""
- table = None
- is_literal = False
-
__visit_name__ = "column"
_traverse_internals = [
@@ -4544,6 +4470,27 @@ class ColumnClause(
self.type = type_api.to_instance(type_)
self.is_literal = is_literal
+ def _compare_name_for_result(self, other):
+ if (
+ self.is_literal
+ or self.table is None
+ or self.table._is_textual
+ or not hasattr(other, "proxy_set")
+ or (
+ isinstance(other, ColumnClause)
+ and (
+ other.is_literal
+ or other.table is None
+ or other.table._is_textual
+ )
+ )
+ ):
+ return (hasattr(other, "name") and self.name == other.name) or (
+ hasattr(other, "_label") and self._label == other._label
+ )
+ else:
+ return other.proxy_set.intersection(self.proxy_set)
+
def get_children(self, column_tables=False, **kw):
# override base get_children() to not return the Table
# or selectable that is parent to this column. Traversals
@@ -4558,6 +4505,24 @@ class ColumnClause(
else:
return []
+ @util.memoized_property
+ def description(self):
+ if util.py3k:
+ return self.name
+ else:
+ return self.name.encode("ascii", "backslashreplace")
+
+ @HasMemoized.memoized_attribute
+ def _key_label(self):
+ if self.key != self.name:
+ return self._gen_label(self.key)
+ else:
+ return self._label
+
+ @HasMemoized.memoized_attribute
+ def _label(self):
+ return self._gen_label(self.name)
+
@HasMemoized.memoized_attribute
def _render_label_in_columns_clause(self):
return self.table is not None
@@ -4566,27 +4531,6 @@ class ColumnClause(
def _ddl_label(self):
return self._gen_label(self.name, dedupe_on_key=False)
- def _compare_name_for_result(self, other):
- if (
- self.is_literal
- or self.table is None
- or self.table._is_textual
- or not hasattr(other, "proxy_set")
- or (
- isinstance(other, ColumnClause)
- and (
- other.is_literal
- or other.table is None
- or other.table._is_textual
- )
- )
- ):
- return (hasattr(other, "name") and self.name == other.name) or (
- hasattr(other, "_label") and self._label == other._label
- )
- else:
- return other.proxy_set.intersection(self.proxy_set)
-
def _gen_label(self, name, dedupe_on_key=True):
t = self.table
if self.is_literal:
@@ -4631,6 +4575,17 @@ class ColumnClause(
else:
return name
+ def _bind_param(self, operator, obj, type_=None, expanding=False):
+ return BindParameter(
+ self.key,
+ obj,
+ _compared_to_operator=operator,
+ _compared_to_type=self.type,
+ type_=type_,
+ unique=True,
+ expanding=expanding,
+ )
+
def _make_proxy(
self,
selectable,
@@ -4672,46 +4627,6 @@ class ColumnClause(
return c.key, c
-class Record(NamedColumn):
- _traverse_internals = [
- ("name", InternalTraversal.dp_anon_name),
- ("type", InternalTraversal.dp_type),
- ("fromclause", InternalTraversal.dp_clauseelement),
- ]
-
- __visit_name__ = "column"
-
- @util.preload_module("sqlalchemy.sql.sqltypes")
- def __init__(self, fromclause):
- sqltypes = util.preloaded.sql_sqltypes
- self.name = fromclause.name
- self.fromclause = fromclause
- self.type = sqltypes.RecordType()
-
- @property
- def _from_objects(self):
- return [self.fromclause]
-
-
-class TableValuedColumn(NamedColumn):
- __visit_name__ = "table_valued_column"
-
- _traverse_internals = [
- ("name", InternalTraversal.dp_anon_name),
- ("type", InternalTraversal.dp_type),
- ("scalar_alias", InternalTraversal.dp_clauseelement),
- ]
-
- def __init__(self, scalar_alias):
- self.scalar_alias = scalar_alias
- self.key = self.name = scalar_alias.name
- self.type = scalar_alias.element.type
-
- @property
- def _from_objects(self):
- return [self.scalar_alias]
-
-
class CollationClause(ColumnElement):
__visit_name__ = "collation"
diff --git a/lib/sqlalchemy/sql/functions.py b/lib/sqlalchemy/sql/functions.py
index f493b08db..a9ea98d04 100644
--- a/lib/sqlalchemy/sql/functions.py
+++ b/lib/sqlalchemy/sql/functions.py
@@ -17,25 +17,22 @@ from . import sqltypes
from . import util as sqlutil
from .base import ColumnCollection
from .base import Executable
-from .base import Generative
from .base import HasMemoized
from .elements import _type_from_args
from .elements import BinaryExpression
from .elements import BindParameter
from .elements import Cast
from .elements import ClauseList
-from .elements import ColumnClause
from .elements import ColumnElement
from .elements import Extract
from .elements import FunctionFilter
from .elements import Grouping
from .elements import literal_column
-from .elements import NamedColumn
from .elements import Over
from .elements import WithinGroup
+from .selectable import Alias
from .selectable import FromClause
from .selectable import Select
-from .selectable import TableValuedAlias
from .visitors import InternalTraversal
from .visitors import TraversibleType
from .. import util
@@ -66,7 +63,7 @@ def register_function(identifier, fn, package="_default"):
reg[identifier] = fn
-class FunctionElement(Executable, ColumnElement, FromClause, Generative):
+class FunctionElement(Executable, ColumnElement, FromClause):
"""Base for SQL function-oriented constructs.
.. seealso::
@@ -83,19 +80,11 @@ class FunctionElement(Executable, ColumnElement, FromClause, Generative):
"""
- _traverse_internals = [
- ("clause_expr", InternalTraversal.dp_clauseelement),
- ("_table_valued", InternalTraversal.dp_clauseelement_tuple),
- ("_table_values_named", InternalTraversal.dp_boolean),
- ("_with_ordinality", InternalTraversal.dp_boolean),
- ]
+ _traverse_internals = [("clause_expr", InternalTraversal.dp_clauseelement)]
packagenames = ()
_has_args = False
- _table_valued = None
- _table_values_named = False
- _with_ordinality = False
def __init__(self, *clauses, **kwargs):
r"""Construct a :class:`.FunctionElement`.
@@ -134,171 +123,6 @@ class FunctionElement(Executable, ColumnElement, FromClause, Generative):
self, multiparams, params, execution_options
)
- def scalar_table_valued(self, name, type_=None):
- """Return a column expression that's against this
- :class:`_functions.FunctionElement` as a scalar
- table-valued expression.
-
- The returned expression is similar to that returned by a single column
- accessed off of a :meth:`_functions.FunctionElement.table_valued`
- construct, except no FROM clause is generated; the function is rendered
- in the similar way as a scalar subquery.
-
- E.g.::
-
- >>> from sqlalchemy import func, select
- >>> fn = func.jsonb_each("{'k', 'v'}").scalar_table_valued("key")
- >>> print(select(fn))
- SELECT (jsonb_each(:jsonb_each_1)).key
-
- .. versionadded:: 1.4.0b2
-
- .. seealso::
-
- :meth:`_functions.FunctionElement.table_valued`
-
- :meth:`_functions.FunctionElement.named_table_valued`
-
- :meth:`_functions.FunctionElement.alias`
-
- :meth:`_functions.FunctionElement.column_valued`
-
- """ # noqa E501
-
- return ScalarFunctionColumn(self, name, type_)
-
- def table_valued(self, *expr, **kw):
- """Return a :class:`_sql.TableValuedAlias` representation of this
- :class:`_functions.FunctionElement` with table-valued expressions added.
-
- e.g.::
-
- >>> fn = (
- ... func.generate_series(1, 5).
- ... table_valued("value", "start", "stop", "step")
- ... )
-
- >>> print(select(fn))
- SELECT anon_1.value, anon_1.start, anon_1.stop, anon_1.step
- FROM generate_series(:generate_series_1, :generate_series_2) AS anon_1
-
- >>> print(select(fn.c.value, fn.c.stop).where(fn.c.value > 2))
- SELECT anon_1.value, anon_1.stop
- FROM generate_series(:generate_series_1, :generate_series_2) AS anon_1
- WHERE anon_1.value > :value_1
-
- A WITH ORDINALITY expression may be generated by passing the keyword
- argument "with_ordinality"::
-
- >>> fn = func.generate_series(4, 1, -1).table_valued("gen", with_ordinality="ordinality")
- >>> print(select(fn))
-
- .. versionadded:: 1.4.0b2
-
- .. seealso::
-
- :meth:`_functions.FunctionElement.table_valued`
-
- :meth:`_functions.FunctionElement.named_table_valued`
-
- :meth:`_functions.FunctionElement.alias`
-
-
- """ # noqa 501
-
- new_func = self._generate()
- new_func._table_valued = [
- coercions.expect(roles.StrAsPlainColumnRole, elem) for elem in expr
- ]
-
- with_ordinality = kw.pop("with_ordinality", None)
- if with_ordinality:
- new_func._table_valued += (
- coercions.expect(roles.StrAsPlainColumnRole, with_ordinality),
- )
- new_func._with_ordinality = True
-
- return new_func.alias()
-
- def named_table_valued(self, *expr, **kw):
- """Return a :class:`_sql.TableValuedAlias` representation of this
- :class:`_functions.FunctionElement` with named table-valued
- expressions added.
-
- E.g.::
-
-
- >>> fn = (
- ... func.json_to_recordset(
- ... '[{"a":1,"b":"foo"},{"a":"2","c":"bar"}]'
- ... )
- ... .named_table_valued(column("a", Integer), column("b", String))
- ... )
- >>> print(select(fn.c.a, fn.c.b))
- SELECT anon_1.a, anon_1.b
- FROM json_to_recordset(:json_to_recordset_1) AS anon_1(a INTEGER, b VARCHAR)
-
- A WITH ORDINALITY expression may be generated by passing the keyword
- argument "with_ordinality"::
-
- >>> fn = (
- ... func.json_object_keys('{"a1":"1","a2":"2","a3":"3"}')
- ... .named_table_valued("keys", with_ordinality="n")
- ... )
-
- >>> print(select(fn))
-
- .. seealso::
-
- :meth:`_functions.FunctionElement.table_valued`
-
- :meth:`_functions.FunctionElement.named_table_valued`
-
- :meth:`_functions.FunctionElement.alias`
-
-
- """ # noqa E501
-
- new_func = self._generate()
- new_func._table_valued = [
- coercions.expect(roles.StrAsPlainColumnRole, elem) for elem in expr
- ]
- with_ordinality = kw.pop("with_ordinality", None)
-
- if with_ordinality:
- new_func._table_valued += (
- coercions.expect(roles.StrAsPlainColumnRole, with_ordinality),
- )
- new_func._with_ordinality = True
-
- new_func._table_values_named = True
- return new_func.alias()
-
- def column_valued(self, name=None):
- """Return this :class:`_function.FunctionElement` as a column expression that
- selects from itself as a FROM clause.
-
- E.g.::
-
- >>> from sqlalchemy import select, func
- >>> gs = func.generate_series(1, 5, -1).column_valued()
- >>> print(select(gs))
- SELECT anon_1
- FROM generate_series(:generate_series_1, :generate_series_2, :generate_series_3) AS anon_1
-
- This is shorthand for::
-
- gs = func.generate_series(1, 5, -1).alias().column
-
-
- .. seealso::
-
- :meth:`_functions.FunctionElement.alias`
-
- """ # noqa 501
-
- return self.alias(name=name).column
-
@property
def columns(self):
r"""The set of columns exported by this :class:`.FunctionElement`.
@@ -318,15 +142,8 @@ class FunctionElement(Executable, ColumnElement, FromClause, Generative):
"""
- if self._table_valued:
- cols = [
- ColumnClause(elem) if isinstance(elem, str) else elem
- for elem in self._table_valued
- ]
- else:
- cols = [self.label(None)]
-
- return ColumnCollection(columns=[(col.key, col) for col in cols])
+ col = self.label(None)
+ return ColumnCollection(columns=[(col.key, col)])
@HasMemoized.memoized_attribute
def clauses(self):
@@ -488,65 +305,37 @@ class FunctionElement(Executable, ColumnElement, FromClause, Generative):
return None
- def alias(self, name=None):
+ def alias(self, name=None, flat=False):
r"""Produce a :class:`_expression.Alias` construct against this
:class:`.FunctionElement`.
- .. note::
-
- The :meth:`_functions.FunctionElement.alias` method is part of the
- mechanism by which "table valued" SQL functions are created.
- However, most use cases are covered by higher level methods on
- :class:`_functions.FunctionElement` including
- :meth:`_functions.FunctionElement.table_valued`,
- :meth:`_functions.FunctionElement.named_table_valued`, and
- :meth:`_functions.FunctionElement.column_valued`.
-
This construct wraps the function in a named alias which
is suitable for the FROM clause, in the style accepted for example
- by PostgreSQL. A column expression is also provided using the
- special ``.column`` attribute, which may
- be used to refer to the output of the function as a scalar value
- in the columns or where clause, for a backend such as PostgreSQL.
-
- For a full table-valued expression, use the
- :meth:`_function.FunctionElement.table_valued` method first to
- establish named columns.
+ by PostgreSQL.
e.g.::
- >>> from sqlalchemy import func, select, column
- >>> data_view = func.unnest([1, 2, 3]).alias("data_view")
- >>> print(select(data_view.column))
- SELECT data_view
- FROM unnest(:unnest_1) AS data_view
-
- The :meth:`_functions.FunctionElement.column_valued` method provides
- a shortcut for the above pattern::
-
- >>> data_view = func.unnest([1, 2, 3]).column_valued("data_view")
- >>> print(select(data_view))
- SELECT data_view
- FROM unnest(:unnest_1) AS data_view
-
- .. versionadded:: 1.4.0b2 Added the ``.column`` accessor
-
- .. seealso::
+ from sqlalchemy.sql import column
- :meth:`_functions.FunctionElement.table_valued`
+ stmt = select(column('data_view')).\
+ select_from(SomeTable).\
+ select_from(func.unnest(SomeTable.data).alias('data_view')
+ )
- :meth:`_functions.FunctionElement.named_table_valued`
+ Would produce:
- :meth:`_functions.FunctionElement.scalar_table_valued`
+ .. sourcecode:: sql
- :meth:`_functions.FunctionElement.column_valued`
+ SELECT data_view
+ FROM sometable, unnest(sometable.data) AS data_view
+ .. versionadded:: 0.9.8 The :meth:`.FunctionElement.alias` method
+ is now supported. Previously, this method's behavior was
+ undefined and did not behave consistently across versions.
"""
- return TableValuedAlias._construct(
- self, name, named=self._table_values_named
- )
+ return Alias._construct(self, name)
def select(self):
"""Produce a :func:`_expression.select` construct
@@ -652,24 +441,6 @@ class FunctionAsBinary(BinaryExpression):
self.sql_function.clauses.clauses[self.right_index - 1] = value
-class ScalarFunctionColumn(NamedColumn):
- __visit_name__ = "scalar_function_column"
-
- _traverse_internals = [
- ("name", InternalTraversal.dp_anon_name),
- ("type", InternalTraversal.dp_type),
- ("fn", InternalTraversal.dp_clauseelement),
- ]
-
- is_literal = False
- table = None
-
- def __init__(self, fn, name, type_=None):
- self.fn = fn
- self.name = name
- self.type = sqltypes.to_instance(type_)
-
-
class _FunctionGenerator(object):
"""Generate SQL function expressions.
@@ -815,9 +586,10 @@ class Function(FunctionElement):
func.mypackage.some_function(col1, col2)
+
.. seealso::
- :ref:`tutorial_functions` - in the :ref:`unified_tutorial`
+ :ref:`coretutorial_functions`
:data:`.func` - namespace which produces registered or ad-hoc
:class:`.Function` instances.
diff --git a/lib/sqlalchemy/sql/roles.py b/lib/sqlalchemy/sql/roles.py
index 52743bd50..2c4ff75c4 100644
--- a/lib/sqlalchemy/sql/roles.py
+++ b/lib/sqlalchemy/sql/roles.py
@@ -44,10 +44,6 @@ class ColumnArgumentOrKeyRole(ColumnArgumentRole):
_role_name = "Column expression or string key"
-class StrAsPlainColumnRole(ColumnArgumentRole):
- _role_name = "Column expression or string key"
-
-
class ColumnListRole(SQLRole):
"""Elements suitable for forming comma separated lists of expressions."""
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index c299065ae..8e478583f 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -51,8 +51,6 @@ from .elements import ColumnClause
from .elements import GroupedElement
from .elements import Grouping
from .elements import literal_column
-from .elements import Record
-from .elements import TableValuedColumn
from .elements import UnaryExpression
from .visitors import InternalTraversal
from .. import exc
@@ -625,33 +623,6 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
return Alias._construct(self, name)
- def record(self):
- """Return a :class:`_sql.Record` object for this
- :class:`_expression.FromClause`.
-
- A "record" is a :class:`_sql.ColumnElement` that represents a complete
- row in a table. Support for this construct is backend dependent,
- however databases such as PostgreSQL and Oracle have support
- for "record" datatypes.
-
- E.g.::
-
- >>> from sqlalchemy import select, column, func, table
- >>> a = table("a", column("id"), column("x"), column("y"))
- >>> stmt = select(func.row_to_json(a.record()))
- >>> print(stmt)
- SELECT row_to_json(a) AS row_to_json_1
- FROM a
-
- .. versionadded:: 1.4.0b2
-
- .. seealso::
-
- :ref:`tutorial_functions` - in the :ref:`unified_tutorial`
-
- """
- return Record(self)
-
def tablesample(self, sampling, name=None, seed=None):
"""Return a TABLESAMPLE alias of this :class:`_expression.FromClause`.
@@ -1612,44 +1583,6 @@ class Alias(roles.DMLTableRole, AliasedReturnsRows):
).alias(name=name, flat=flat)
-class TableValuedAlias(Alias):
- """An alias that includes the ability to be used in a columns context.
-
- Provides the :attr:`_sql.ScalarAlias.column` accessor that returns
- a :class:`_sql.ColumnElement` representing this object.
-
- The main use case for this construct is that of PostgreSQL functions
- that may be used in the FROM clause of a SELECT.
-
- .. versionadded:: 1.4.0b2
-
- """
-
- __visit_name__ = "table_valued_alias"
-
- named = False
-
- _traverse_internals = [
- ("element", InternalTraversal.dp_clauseelement),
- ("name", InternalTraversal.dp_anon_name),
- ("named", InternalTraversal.dp_boolean),
- ]
-
- def _init(self, selectable, name=None, named=False):
- self.named = named
- super(TableValuedAlias, self)._init(selectable, name=name)
-
- @HasMemoized.memoized_attribute
- def column(self):
- """Return a column expression representing this
- :class:`_sql.ScalarAlias`."""
-
- return TableValuedColumn(self)
-
- def alias(self, name=None):
- return self.element.alias(name=name)
-
-
class Lateral(AliasedReturnsRows):
"""Represent a LATERAL subquery.
diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index cac7d74a4..d20c8168d 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -3110,10 +3110,6 @@ class NullType(TypeEngine):
comparator_factory = Comparator
-class RecordType(TypeEngine):
- """Refers to a table record type."""
-
-
class MatchType(Boolean):
"""Refers to the return type of the MATCH operator.