| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104 |
- # sql/functions.py
- # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
- # <see AUTHORS file>
- #
- # This module is part of SQLAlchemy and is released under
- # the MIT License: https://www.opensource.org/licenses/mit-license.php
- """SQL function API, factories, and built-in functions."""
- from __future__ import annotations
- import datetime
- import decimal
- from typing import Any
- from typing import cast
- from typing import Dict
- from typing import List
- from typing import Mapping
- from typing import Optional
- from typing import overload
- from typing import Sequence
- from typing import Tuple
- from typing import Type
- from typing import TYPE_CHECKING
- from typing import TypeVar
- from typing import Union
- from . import annotation
- from . import coercions
- from . import operators
- from . import roles
- from . import schema
- from . import sqltypes
- from . import type_api
- from . import util as sqlutil
- from ._typing import is_table_value_type
- from .base import _entity_namespace
- 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 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 FromClause
- from .selectable import Select
- from .selectable import TableValuedAlias
- from .sqltypes import TableValueType
- from .type_api import TypeEngine
- from .visitors import InternalTraversal
- from .. import util
- if TYPE_CHECKING:
- from ._typing import _ByArgument
- from ._typing import _ColumnExpressionArgument
- from ._typing import _ColumnExpressionOrLiteralArgument
- from ._typing import _ColumnExpressionOrStrLabelArgument
- from ._typing import _StarOrOne
- from ._typing import _TypeEngineArgument
- from .base import _EntityNamespace
- from .elements import ClauseElement
- from .elements import KeyedColumnElement
- from .elements import TableValuedColumn
- from .operators import OperatorType
- from ..engine.base import Connection
- from ..engine.cursor import CursorResult
- from ..engine.interfaces import _CoreMultiExecuteParams
- from ..engine.interfaces import CoreExecuteOptionsParameter
- from ..util.typing import Self
- _T = TypeVar("_T", bound=Any)
- _S = TypeVar("_S", bound=Any)
- _registry: util.defaultdict[str, Dict[str, Type[Function[Any]]]] = (
- util.defaultdict(dict)
- )
- def register_function(
- identifier: str, fn: Type[Function[Any]], package: str = "_default"
- ) -> None:
- """Associate a callable with a particular func. name.
- This is normally called by GenericFunction, but is also
- available by itself so that a non-Function construct
- can be associated with the :data:`.func` accessor (i.e.
- CAST, EXTRACT).
- """
- reg = _registry[package]
- identifier = str(identifier).lower()
- # Check if a function with the same identifier is registered.
- if identifier in reg:
- util.warn(
- "The GenericFunction '{}' is already registered and "
- "is going to be overridden.".format(identifier)
- )
- reg[identifier] = fn
- class FunctionElement(Executable, ColumnElement[_T], FromClause, Generative):
- """Base for SQL function-oriented constructs.
- This is a `generic type <https://peps.python.org/pep-0484/#generics>`_,
- meaning that type checkers and IDEs can be instructed on the types to
- expect in a :class:`_engine.Result` for this function. See
- :class:`.GenericFunction` for an example of how this is done.
- .. seealso::
- :ref:`tutorial_functions` - in the :ref:`unified_tutorial`
- :class:`.Function` - named SQL function.
- :data:`.func` - namespace which produces registered or ad-hoc
- :class:`.Function` instances.
- :class:`.GenericFunction` - allows creation of registered function
- types.
- """
- _traverse_internals = [
- ("clause_expr", InternalTraversal.dp_clauseelement),
- ("_with_ordinality", InternalTraversal.dp_boolean),
- ("_table_value_type", InternalTraversal.dp_has_cache_key),
- ]
- packagenames: Tuple[str, ...] = ()
- _has_args = False
- _with_ordinality = False
- _table_value_type: Optional[TableValueType] = None
- # some attributes that are defined between both ColumnElement and
- # FromClause are set to Any here to avoid typing errors
- primary_key: Any
- _is_clone_of: Any
- clause_expr: Grouping[Any]
- def __init__(
- self, *clauses: _ColumnExpressionOrLiteralArgument[Any]
- ) -> None:
- r"""Construct a :class:`.FunctionElement`.
- :param \*clauses: list of column expressions that form the arguments
- of the SQL function call.
- :param \**kwargs: additional kwargs are typically consumed by
- subclasses.
- .. seealso::
- :data:`.func`
- :class:`.Function`
- """
- args: Sequence[_ColumnExpressionArgument[Any]] = [
- coercions.expect(
- roles.ExpressionElementRole,
- c,
- name=getattr(self, "name", None),
- apply_propagate_attrs=self,
- )
- for c in clauses
- ]
- self._has_args = self._has_args or bool(args)
- self.clause_expr = Grouping(
- ClauseList(operator=operators.comma_op, group_contents=True, *args)
- )
- _non_anon_label = None
- @property
- def _proxy_key(self) -> Any:
- return super()._proxy_key or getattr(self, "name", None)
- def _execute_on_connection(
- self,
- connection: Connection,
- distilled_params: _CoreMultiExecuteParams,
- execution_options: CoreExecuteOptionsParameter,
- ) -> CursorResult[Any]:
- return connection._execute_function(
- self, distilled_params, execution_options
- )
- def scalar_table_valued(
- self, name: str, type_: Optional[_TypeEngineArgument[_T]] = None
- ) -> ScalarFunctionColumn[_T]:
- """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.:
- .. sourcecode:: pycon+sql
- >>> from sqlalchemy import func, select
- >>> fn = func.jsonb_each("{'k', 'v'}").scalar_table_valued("key")
- >>> print(select(fn))
- {printsql}SELECT (jsonb_each(:jsonb_each_1)).key
- .. versionadded:: 1.4.0b2
- .. seealso::
- :meth:`_functions.FunctionElement.table_valued`
- :meth:`_functions.FunctionElement.alias`
- :meth:`_functions.FunctionElement.column_valued`
- """ # noqa: E501
- return ScalarFunctionColumn(self, name, type_)
- def table_valued(
- self, *expr: _ColumnExpressionOrStrLabelArgument[Any], **kw: Any
- ) -> TableValuedAlias:
- r"""Return a :class:`_sql.TableValuedAlias` representation of this
- :class:`_functions.FunctionElement` with table-valued expressions added.
- e.g.:
- .. sourcecode:: pycon+sql
- >>> fn = func.generate_series(1, 5).table_valued(
- ... "value", "start", "stop", "step"
- ... )
- >>> print(select(fn))
- {printsql}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{stop}
- >>> print(select(fn.c.value, fn.c.stop).where(fn.c.value > 2))
- {printsql}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{stop}
- A WITH ORDINALITY expression may be generated by passing the keyword
- argument "with_ordinality":
- .. sourcecode:: pycon+sql
- >>> fn = func.generate_series(4, 1, -1).table_valued(
- ... "gen", with_ordinality="ordinality"
- ... )
- >>> print(select(fn))
- {printsql}SELECT anon_1.gen, anon_1.ordinality
- FROM generate_series(:generate_series_1, :generate_series_2, :generate_series_3) WITH ORDINALITY AS anon_1
- :param \*expr: A series of string column names that will be added to the
- ``.c`` collection of the resulting :class:`_sql.TableValuedAlias`
- construct as columns. :func:`_sql.column` objects with or without
- datatypes may also be used.
- :param name: optional name to assign to the alias name that's generated.
- If omitted, a unique anonymizing name is used.
- :param with_ordinality: string name that when present results in the
- ``WITH ORDINALITY`` clause being added to the alias, and the given
- string name will be added as a column to the .c collection
- of the resulting :class:`_sql.TableValuedAlias`.
- :param joins_implicitly: when True, the table valued function may be
- used in the FROM clause without any explicit JOIN to other tables
- in the SQL query, and no "cartesian product" warning will be generated.
- May be useful for SQL functions such as ``func.json_each()``.
- .. versionadded:: 1.4.33
- .. versionadded:: 1.4.0b2
- .. seealso::
- :ref:`tutorial_functions_table_valued` - in the :ref:`unified_tutorial`
- :ref:`postgresql_table_valued` - in the :ref:`postgresql_toplevel` documentation
- :meth:`_functions.FunctionElement.scalar_table_valued` - variant of
- :meth:`_functions.FunctionElement.table_valued` which delivers the
- complete table valued expression as a scalar column expression
- :meth:`_functions.FunctionElement.column_valued`
- :meth:`_sql.TableValuedAlias.render_derived` - renders the alias
- using a derived column clause, e.g. ``AS name(col1, col2, ...)``
- """ # noqa: 501
- new_func = self._generate()
- with_ordinality = kw.pop("with_ordinality", None)
- joins_implicitly = kw.pop("joins_implicitly", None)
- name = kw.pop("name", None)
- if with_ordinality:
- expr += (with_ordinality,)
- new_func._with_ordinality = True
- new_func.type = new_func._table_value_type = TableValueType(*expr)
- return new_func.alias(name=name, joins_implicitly=joins_implicitly)
- def column_valued(
- self, name: Optional[str] = None, joins_implicitly: bool = False
- ) -> TableValuedColumn[_T]:
- """Return this :class:`_functions.FunctionElement` as a column expression that
- selects from itself as a FROM clause.
- E.g.:
- .. sourcecode:: pycon+sql
- >>> from sqlalchemy import select, func
- >>> gs = func.generate_series(1, 5, -1).column_valued()
- >>> print(select(gs))
- {printsql}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
- :param name: optional name to assign to the alias name that's generated.
- If omitted, a unique anonymizing name is used.
- :param joins_implicitly: when True, the "table" portion of the column
- valued function may be a member of the FROM clause without any
- explicit JOIN to other tables in the SQL query, and no "cartesian
- product" warning will be generated. May be useful for SQL functions
- such as ``func.json_array_elements()``.
- .. versionadded:: 1.4.46
- .. seealso::
- :ref:`tutorial_functions_column_valued` - in the :ref:`unified_tutorial`
- :ref:`postgresql_column_valued` - in the :ref:`postgresql_toplevel` documentation
- :meth:`_functions.FunctionElement.table_valued`
- """ # noqa: 501
- return self.alias(name=name, joins_implicitly=joins_implicitly).column
- @util.ro_non_memoized_property
- def columns(self) -> ColumnCollection[str, KeyedColumnElement[Any]]: # type: ignore[override] # noqa: E501
- r"""The set of columns exported by this :class:`.FunctionElement`.
- This is a placeholder collection that allows the function to be
- placed in the FROM clause of a statement:
- .. sourcecode:: pycon+sql
- >>> from sqlalchemy import column, select, func
- >>> stmt = select(column("x"), column("y")).select_from(func.myfunction())
- >>> print(stmt)
- {printsql}SELECT x, y FROM myfunction()
- The above form is a legacy feature that is now superseded by the
- fully capable :meth:`_functions.FunctionElement.table_valued`
- method; see that method for details.
- .. seealso::
- :meth:`_functions.FunctionElement.table_valued` - generates table-valued
- SQL function expressions.
- """ # noqa: E501
- return self.c
- @util.ro_memoized_property
- def c(self) -> ColumnCollection[str, KeyedColumnElement[Any]]: # type: ignore[override] # noqa: E501
- """synonym for :attr:`.FunctionElement.columns`."""
- return ColumnCollection(
- columns=[(col.key, col) for col in self._all_selected_columns]
- )
- @property
- def _all_selected_columns(self) -> Sequence[KeyedColumnElement[Any]]:
- if is_table_value_type(self.type):
- # TODO: this might not be fully accurate
- cols = cast(
- "Sequence[KeyedColumnElement[Any]]", self.type._elements
- )
- else:
- cols = [self.label(None)]
- return cols
- @property
- def exported_columns( # type: ignore[override]
- self,
- ) -> ColumnCollection[str, KeyedColumnElement[Any]]:
- return self.columns
- @HasMemoized.memoized_attribute
- def clauses(self) -> ClauseList:
- """Return the underlying :class:`.ClauseList` which contains
- the arguments for this :class:`.FunctionElement`.
- """
- return cast(ClauseList, self.clause_expr.element)
- def over(
- self,
- *,
- partition_by: Optional[_ByArgument] = None,
- order_by: Optional[_ByArgument] = None,
- rows: Optional[Tuple[Optional[int], Optional[int]]] = None,
- range_: Optional[Tuple[Optional[int], Optional[int]]] = None,
- groups: Optional[Tuple[Optional[int], Optional[int]]] = None,
- ) -> Over[_T]:
- """Produce an OVER clause against this function.
- Used against aggregate or so-called "window" functions,
- for database backends that support window functions.
- The expression::
- func.row_number().over(order_by="x")
- is shorthand for::
- from sqlalchemy import over
- over(func.row_number(), order_by="x")
- See :func:`_expression.over` for a full description.
- .. seealso::
- :func:`_expression.over`
- :ref:`tutorial_window_functions` - in the :ref:`unified_tutorial`
- """
- return Over(
- self,
- partition_by=partition_by,
- order_by=order_by,
- rows=rows,
- range_=range_,
- groups=groups,
- )
- def within_group(
- self, *order_by: _ColumnExpressionArgument[Any]
- ) -> WithinGroup[_T]:
- """Produce a WITHIN GROUP (ORDER BY expr) clause against this function.
- Used against so-called "ordered set aggregate" and "hypothetical
- set aggregate" functions, including :class:`.percentile_cont`,
- :class:`.rank`, :class:`.dense_rank`, etc.
- See :func:`_expression.within_group` for a full description.
- .. seealso::
- :ref:`tutorial_functions_within_group` -
- in the :ref:`unified_tutorial`
- """
- return WithinGroup(self, *order_by)
- @overload
- def filter(self) -> Self: ...
- @overload
- def filter(
- self,
- __criterion0: _ColumnExpressionArgument[bool],
- *criterion: _ColumnExpressionArgument[bool],
- ) -> FunctionFilter[_T]: ...
- def filter(
- self, *criterion: _ColumnExpressionArgument[bool]
- ) -> Union[Self, FunctionFilter[_T]]:
- """Produce a FILTER clause against this function.
- Used against aggregate and window functions,
- for database backends that support the "FILTER" clause.
- The expression::
- func.count(1).filter(True)
- is shorthand for::
- from sqlalchemy import funcfilter
- funcfilter(func.count(1), True)
- .. seealso::
- :ref:`tutorial_functions_within_group` -
- in the :ref:`unified_tutorial`
- :class:`.FunctionFilter`
- :func:`.funcfilter`
- """
- if not criterion:
- return self
- return FunctionFilter(self, *criterion)
- def as_comparison(
- self, left_index: int, right_index: int
- ) -> FunctionAsBinary:
- """Interpret this expression as a boolean comparison between two
- values.
- This method is used for an ORM use case described at
- :ref:`relationship_custom_operator_sql_function`.
- A hypothetical SQL function "is_equal()" which compares to values
- for equality would be written in the Core expression language as::
- expr = func.is_equal("a", "b")
- If "is_equal()" above is comparing "a" and "b" for equality, the
- :meth:`.FunctionElement.as_comparison` method would be invoked as::
- expr = func.is_equal("a", "b").as_comparison(1, 2)
- Where above, the integer value "1" refers to the first argument of the
- "is_equal()" function and the integer value "2" refers to the second.
- This would create a :class:`.BinaryExpression` that is equivalent to::
- BinaryExpression("a", "b", operator=op.eq)
- However, at the SQL level it would still render as
- "is_equal('a', 'b')".
- The ORM, when it loads a related object or collection, needs to be able
- to manipulate the "left" and "right" sides of the ON clause of a JOIN
- expression. The purpose of this method is to provide a SQL function
- construct that can also supply this information to the ORM, when used
- with the :paramref:`_orm.relationship.primaryjoin` parameter. The
- return value is a containment object called :class:`.FunctionAsBinary`.
- An ORM example is as follows::
- class Venue(Base):
- __tablename__ = "venue"
- id = Column(Integer, primary_key=True)
- name = Column(String)
- descendants = relationship(
- "Venue",
- primaryjoin=func.instr(
- remote(foreign(name)), name + "/"
- ).as_comparison(1, 2)
- == 1,
- viewonly=True,
- order_by=name,
- )
- Above, the "Venue" class can load descendant "Venue" objects by
- determining if the name of the parent Venue is contained within the
- start of the hypothetical descendant value's name, e.g. "parent1" would
- match up to "parent1/child1", but not to "parent2/child1".
- Possible use cases include the "materialized path" example given above,
- as well as making use of special SQL functions such as geometric
- functions to create join conditions.
- :param left_index: the integer 1-based index of the function argument
- that serves as the "left" side of the expression.
- :param right_index: the integer 1-based index of the function argument
- that serves as the "right" side of the expression.
- .. versionadded:: 1.3
- .. seealso::
- :ref:`relationship_custom_operator_sql_function` -
- example use within the ORM
- """
- return FunctionAsBinary(self, left_index, right_index)
- @property
- def _from_objects(self) -> Any:
- return self.clauses._from_objects
- def within_group_type(
- self, within_group: WithinGroup[_S]
- ) -> Optional[TypeEngine[_S]]:
- """For types that define their return type as based on the criteria
- within a WITHIN GROUP (ORDER BY) expression, called by the
- :class:`.WithinGroup` construct.
- Returns None by default, in which case the function's normal ``.type``
- is used.
- """
- return None
- def alias(
- self, name: Optional[str] = None, joins_implicitly: bool = False
- ) -> TableValuedAlias:
- r"""Produce a :class:`_expression.Alias` construct against this
- :class:`.FunctionElement`.
- .. tip::
- 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`, 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:`_functions.FunctionElement.table_valued` method first to
- establish named columns.
- e.g.:
- .. sourcecode:: pycon+sql
- >>> from sqlalchemy import func, select, column
- >>> data_view = func.unnest([1, 2, 3]).alias("data_view")
- >>> print(select(data_view.column))
- {printsql}SELECT data_view
- FROM unnest(:unnest_1) AS data_view
- The :meth:`_functions.FunctionElement.column_valued` method provides
- a shortcut for the above pattern:
- .. sourcecode:: pycon+sql
- >>> data_view = func.unnest([1, 2, 3]).column_valued("data_view")
- >>> print(select(data_view))
- {printsql}SELECT data_view
- FROM unnest(:unnest_1) AS data_view
- .. versionadded:: 1.4.0b2 Added the ``.column`` accessor
- :param name: alias name, will be rendered as ``AS <name>`` in the
- FROM clause
- :param joins_implicitly: when True, the table valued function may be
- used in the FROM clause without any explicit JOIN to other tables
- in the SQL query, and no "cartesian product" warning will be
- generated. May be useful for SQL functions such as
- ``func.json_each()``.
- .. versionadded:: 1.4.33
- .. seealso::
- :ref:`tutorial_functions_table_valued` -
- in the :ref:`unified_tutorial`
- :meth:`_functions.FunctionElement.table_valued`
- :meth:`_functions.FunctionElement.scalar_table_valued`
- :meth:`_functions.FunctionElement.column_valued`
- """
- return TableValuedAlias._construct(
- self,
- name=name,
- table_value_type=self.type,
- joins_implicitly=joins_implicitly,
- )
- def select(self) -> Select[Tuple[_T]]:
- """Produce a :func:`_expression.select` construct
- against this :class:`.FunctionElement`.
- This is shorthand for::
- s = select(function_element)
- """
- s: Select[Any] = Select(self)
- if self._execution_options:
- s = s.execution_options(**self._execution_options)
- return s
- def _bind_param(
- self,
- operator: OperatorType,
- obj: Any,
- type_: Optional[TypeEngine[_T]] = None,
- expanding: bool = False,
- **kw: Any,
- ) -> BindParameter[_T]:
- return BindParameter(
- None,
- obj,
- _compared_to_operator=operator,
- _compared_to_type=self.type,
- unique=True,
- type_=type_,
- expanding=expanding,
- **kw,
- )
- def self_group(self, against: Optional[OperatorType] = None) -> ClauseElement: # type: ignore[override] # noqa E501
- # for the moment, we are parenthesizing all array-returning
- # expressions against getitem. This may need to be made
- # more portable if in the future we support other DBs
- # besides postgresql.
- if against in (operators.getitem, operators.json_getitem_op):
- return Grouping(self)
- else:
- return super().self_group(against=against)
- @property
- def entity_namespace(self) -> _EntityNamespace:
- """overrides FromClause.entity_namespace as functions are generally
- column expressions and not FromClauses.
- """
- # ideally functions would not be fromclauses but we failed to make
- # this adjustment in 1.4
- return _entity_namespace(self.clause_expr)
- class FunctionAsBinary(BinaryExpression[Any]):
- _traverse_internals = [
- ("sql_function", InternalTraversal.dp_clauseelement),
- ("left_index", InternalTraversal.dp_plain_obj),
- ("right_index", InternalTraversal.dp_plain_obj),
- ("modifiers", InternalTraversal.dp_plain_dict),
- ]
- sql_function: FunctionElement[Any]
- left_index: int
- right_index: int
- def _gen_cache_key(self, anon_map: Any, bindparams: Any) -> Any:
- return ColumnElement._gen_cache_key(self, anon_map, bindparams)
- def __init__(
- self, fn: FunctionElement[Any], left_index: int, right_index: int
- ) -> None:
- self.sql_function = fn
- self.left_index = left_index
- self.right_index = right_index
- self.operator = operators.function_as_comparison_op
- self.type = sqltypes.BOOLEANTYPE
- self.negate = None
- self._is_implicitly_boolean = True
- self.modifiers = util.immutabledict({})
- @property
- def left_expr(self) -> ColumnElement[Any]:
- return self.sql_function.clauses.clauses[self.left_index - 1]
- @left_expr.setter
- def left_expr(self, value: ColumnElement[Any]) -> None:
- self.sql_function.clauses.clauses[self.left_index - 1] = value
- @property
- def right_expr(self) -> ColumnElement[Any]:
- return self.sql_function.clauses.clauses[self.right_index - 1]
- @right_expr.setter
- def right_expr(self, value: ColumnElement[Any]) -> None:
- self.sql_function.clauses.clauses[self.right_index - 1] = value
- if not TYPE_CHECKING:
- # mypy can't accommodate @property to replace an instance
- # variable
- left = left_expr
- right = right_expr
- class ScalarFunctionColumn(NamedColumn[_T]):
- __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: FunctionElement[_T],
- name: str,
- type_: Optional[_TypeEngineArgument[_T]] = None,
- ) -> None:
- self.fn = fn
- self.name = name
- # if type is None, we get NULLTYPE, which is our _T. But I don't
- # know how to get the overloads to express that correctly
- self.type = type_api.to_instance(type_) # type: ignore
- class _FunctionGenerator:
- """Generate SQL function expressions.
- :data:`.func` is a special object instance which generates SQL
- functions based on name-based attributes, e.g.:
- .. sourcecode:: pycon+sql
- >>> print(func.count(1))
- {printsql}count(:param_1)
- The returned object is an instance of :class:`.Function`, and is a
- column-oriented SQL element like any other, and is used in that way:
- .. sourcecode:: pycon+sql
- >>> print(select(func.count(table.c.id)))
- {printsql}SELECT count(sometable.id) FROM sometable
- Any name can be given to :data:`.func`. If the function name is unknown to
- SQLAlchemy, it will be rendered exactly as is. For common SQL functions
- which SQLAlchemy is aware of, the name may be interpreted as a *generic
- function* which will be compiled appropriately to the target database:
- .. sourcecode:: pycon+sql
- >>> print(func.current_timestamp())
- {printsql}CURRENT_TIMESTAMP
- To call functions which are present in dot-separated packages,
- specify them in the same manner:
- .. sourcecode:: pycon+sql
- >>> print(func.stats.yield_curve(5, 10))
- {printsql}stats.yield_curve(:yield_curve_1, :yield_curve_2)
- SQLAlchemy can be made aware of the return type of functions to enable
- type-specific lexical and result-based behavior. For example, to ensure
- that a string-based function returns a Unicode value and is similarly
- treated as a string in expressions, specify
- :class:`~sqlalchemy.types.Unicode` as the type:
- .. sourcecode:: pycon+sql
- >>> print(
- ... func.my_string("hi", type_=Unicode)
- ... + " "
- ... + func.my_string("there", type_=Unicode)
- ... )
- {printsql}my_string(:my_string_1) || :my_string_2 || my_string(:my_string_3)
- The object returned by a :data:`.func` call is usually an instance of
- :class:`.Function`.
- This object meets the "column" interface, including comparison and labeling
- functions. The object can also be passed the :meth:`~.Connectable.execute`
- method of a :class:`_engine.Connection` or :class:`_engine.Engine`,
- where it will be
- wrapped inside of a SELECT statement first::
- print(connection.execute(func.current_timestamp()).scalar())
- In a few exception cases, the :data:`.func` accessor
- will redirect a name to a built-in expression such as :func:`.cast`
- or :func:`.extract`, as these names have well-known meaning
- but are not exactly the same as "functions" from a SQLAlchemy
- perspective.
- Functions which are interpreted as "generic" functions know how to
- calculate their return type automatically. For a listing of known generic
- functions, see :ref:`generic_functions`.
- .. note::
- The :data:`.func` construct has only limited support for calling
- standalone "stored procedures", especially those with special
- parameterization concerns.
- See the section :ref:`stored_procedures` for details on how to use
- the DBAPI-level ``callproc()`` method for fully traditional stored
- procedures.
- .. seealso::
- :ref:`tutorial_functions` - in the :ref:`unified_tutorial`
- :class:`.Function`
- """ # noqa
- def __init__(self, **opts: Any) -> None:
- self.__names: List[str] = []
- self.opts = opts
- def __getattr__(self, name: str) -> _FunctionGenerator:
- # passthru __ attributes; fixes pydoc
- if name.startswith("__"):
- try:
- return self.__dict__[name] # type: ignore
- except KeyError:
- raise AttributeError(name)
- elif name.endswith("_"):
- name = name[0:-1]
- f = _FunctionGenerator(**self.opts)
- f.__names = list(self.__names) + [name]
- return f
- @overload
- def __call__(
- self, *c: Any, type_: _TypeEngineArgument[_T], **kwargs: Any
- ) -> Function[_T]: ...
- @overload
- def __call__(self, *c: Any, **kwargs: Any) -> Function[Any]: ...
- def __call__(self, *c: Any, **kwargs: Any) -> Function[Any]:
- o = self.opts.copy()
- o.update(kwargs)
- tokens = len(self.__names)
- if tokens == 2:
- package, fname = self.__names
- elif tokens == 1:
- package, fname = "_default", self.__names[0]
- else:
- package = None
- if package is not None:
- func = _registry[package].get(fname.lower())
- if func is not None:
- return func(*c, **o)
- return Function(
- self.__names[-1], packagenames=tuple(self.__names[0:-1]), *c, **o
- )
- if TYPE_CHECKING:
- # START GENERATED FUNCTION ACCESSORS
- # code within this block is **programmatically,
- # statically generated** by tools/generate_sql_functions.py
- @property
- def aggregate_strings(self) -> Type[aggregate_strings]: ...
- @property
- def ansifunction(self) -> Type[AnsiFunction[Any]]: ...
- # set ColumnElement[_T] as a separate overload, to appease
- # mypy which seems to not want to accept _T from
- # _ColumnExpressionArgument. Seems somewhat related to the covariant
- # _HasClauseElement as of mypy 1.15
- @overload
- def array_agg(
- self,
- col: ColumnElement[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> array_agg[_T]: ...
- @overload
- def array_agg(
- self,
- col: _ColumnExpressionArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> array_agg[_T]: ...
- @overload
- def array_agg(
- self,
- col: _T,
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> array_agg[_T]: ...
- def array_agg(
- self,
- col: _ColumnExpressionOrLiteralArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> array_agg[_T]: ...
- @property
- def cast(self) -> Type[Cast[Any]]: ...
- @property
- def char_length(self) -> Type[char_length]: ...
- # set ColumnElement[_T] as a separate overload, to appease
- # mypy which seems to not want to accept _T from
- # _ColumnExpressionArgument. Seems somewhat related to the covariant
- # _HasClauseElement as of mypy 1.15
- @overload
- def coalesce(
- self,
- col: ColumnElement[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> coalesce[_T]: ...
- @overload
- def coalesce(
- self,
- col: _ColumnExpressionArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> coalesce[_T]: ...
- @overload
- def coalesce(
- self,
- col: _T,
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> coalesce[_T]: ...
- def coalesce(
- self,
- col: _ColumnExpressionOrLiteralArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> coalesce[_T]: ...
- @property
- def concat(self) -> Type[concat]: ...
- @property
- def count(self) -> Type[count]: ...
- @property
- def cube(self) -> Type[cube[Any]]: ...
- @property
- def cume_dist(self) -> Type[cume_dist]: ...
- @property
- def current_date(self) -> Type[current_date]: ...
- @property
- def current_time(self) -> Type[current_time]: ...
- @property
- def current_timestamp(self) -> Type[current_timestamp]: ...
- @property
- def current_user(self) -> Type[current_user]: ...
- @property
- def dense_rank(self) -> Type[dense_rank]: ...
- @property
- def extract(self) -> Type[Extract]: ...
- @property
- def grouping_sets(self) -> Type[grouping_sets[Any]]: ...
- @property
- def localtime(self) -> Type[localtime]: ...
- @property
- def localtimestamp(self) -> Type[localtimestamp]: ...
- # set ColumnElement[_T] as a separate overload, to appease
- # mypy which seems to not want to accept _T from
- # _ColumnExpressionArgument. Seems somewhat related to the covariant
- # _HasClauseElement as of mypy 1.15
- @overload
- def max( # noqa: A001
- self,
- col: ColumnElement[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> max[_T]: ...
- @overload
- def max( # noqa: A001
- self,
- col: _ColumnExpressionArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> max[_T]: ...
- @overload
- def max( # noqa: A001
- self,
- col: _T,
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> max[_T]: ...
- def max( # noqa: A001
- self,
- col: _ColumnExpressionOrLiteralArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> max[_T]: ...
- # set ColumnElement[_T] as a separate overload, to appease
- # mypy which seems to not want to accept _T from
- # _ColumnExpressionArgument. Seems somewhat related to the covariant
- # _HasClauseElement as of mypy 1.15
- @overload
- def min( # noqa: A001
- self,
- col: ColumnElement[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> min[_T]: ...
- @overload
- def min( # noqa: A001
- self,
- col: _ColumnExpressionArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> min[_T]: ...
- @overload
- def min( # noqa: A001
- self,
- col: _T,
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> min[_T]: ...
- def min( # noqa: A001
- self,
- col: _ColumnExpressionOrLiteralArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> min[_T]: ...
- @property
- def mode(self) -> Type[mode[Any]]: ...
- @property
- def next_value(self) -> Type[next_value]: ...
- @property
- def now(self) -> Type[now]: ...
- @property
- def orderedsetagg(self) -> Type[OrderedSetAgg[Any]]: ...
- @property
- def percent_rank(self) -> Type[percent_rank]: ...
- @property
- def percentile_cont(self) -> Type[percentile_cont[Any]]: ...
- @property
- def percentile_disc(self) -> Type[percentile_disc[Any]]: ...
- @property
- def random(self) -> Type[random]: ...
- @property
- def rank(self) -> Type[rank]: ...
- @property
- def rollup(self) -> Type[rollup[Any]]: ...
- @property
- def session_user(self) -> Type[session_user]: ...
- # set ColumnElement[_T] as a separate overload, to appease
- # mypy which seems to not want to accept _T from
- # _ColumnExpressionArgument. Seems somewhat related to the covariant
- # _HasClauseElement as of mypy 1.15
- @overload
- def sum( # noqa: A001
- self,
- col: ColumnElement[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> sum[_T]: ...
- @overload
- def sum( # noqa: A001
- self,
- col: _ColumnExpressionArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> sum[_T]: ...
- @overload
- def sum( # noqa: A001
- self,
- col: _T,
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> sum[_T]: ...
- def sum( # noqa: A001
- self,
- col: _ColumnExpressionOrLiteralArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> sum[_T]: ...
- @property
- def sysdate(self) -> Type[sysdate]: ...
- @property
- def user(self) -> Type[user]: ...
- # END GENERATED FUNCTION ACCESSORS
- func = _FunctionGenerator()
- func.__doc__ = _FunctionGenerator.__doc__
- modifier = _FunctionGenerator(group=False)
- class Function(FunctionElement[_T]):
- r"""Describe a named SQL function.
- The :class:`.Function` object is typically generated from the
- :data:`.func` generation object.
- :param \*clauses: list of column expressions that form the arguments
- of the SQL function call.
- :param type\_: optional :class:`.TypeEngine` datatype object that will be
- used as the return value of the column expression generated by this
- function call.
- :param packagenames: a string which indicates package prefix names
- to be prepended to the function name when the SQL is generated.
- The :data:`.func` generator creates these when it is called using
- dotted format, e.g.::
- func.mypackage.some_function(col1, col2)
- .. seealso::
- :ref:`tutorial_functions` - in the :ref:`unified_tutorial`
- :data:`.func` - namespace which produces registered or ad-hoc
- :class:`.Function` instances.
- :class:`.GenericFunction` - allows creation of registered function
- types.
- """
- __visit_name__ = "function"
- _traverse_internals = FunctionElement._traverse_internals + [
- ("packagenames", InternalTraversal.dp_plain_obj),
- ("name", InternalTraversal.dp_string),
- ("type", InternalTraversal.dp_type),
- ]
- name: str
- identifier: str
- type: TypeEngine[_T]
- """A :class:`_types.TypeEngine` object which refers to the SQL return
- type represented by this SQL function.
- This datatype may be configured when generating a
- :class:`_functions.Function` object by passing the
- :paramref:`_functions.Function.type_` parameter, e.g.::
- >>> select(func.lower("some VALUE", type_=String))
- The small number of built-in classes of :class:`_functions.Function` come
- with a built-in datatype that's appropriate to the class of function and
- its arguments. For functions that aren't known, the type defaults to the
- "null type".
- """
- @overload
- def __init__(
- self,
- name: str,
- *clauses: _ColumnExpressionOrLiteralArgument[_T],
- type_: None = ...,
- packagenames: Optional[Tuple[str, ...]] = ...,
- ) -> None: ...
- @overload
- def __init__(
- self,
- name: str,
- *clauses: _ColumnExpressionOrLiteralArgument[Any],
- type_: _TypeEngineArgument[_T] = ...,
- packagenames: Optional[Tuple[str, ...]] = ...,
- ) -> None: ...
- def __init__(
- self,
- name: str,
- *clauses: _ColumnExpressionOrLiteralArgument[Any],
- type_: Optional[_TypeEngineArgument[_T]] = None,
- packagenames: Optional[Tuple[str, ...]] = None,
- ) -> None:
- """Construct a :class:`.Function`.
- The :data:`.func` construct is normally used to construct
- new :class:`.Function` instances.
- """
- self.packagenames = packagenames or ()
- self.name = name
- # if type is None, we get NULLTYPE, which is our _T. But I don't
- # know how to get the overloads to express that correctly
- self.type = type_api.to_instance(type_) # type: ignore
- FunctionElement.__init__(self, *clauses)
- def _bind_param(
- self,
- operator: OperatorType,
- obj: Any,
- type_: Optional[TypeEngine[_T]] = None,
- expanding: bool = False,
- **kw: Any,
- ) -> BindParameter[_T]:
- return BindParameter(
- self.name,
- obj,
- _compared_to_operator=operator,
- _compared_to_type=self.type,
- type_=type_,
- unique=True,
- expanding=expanding,
- **kw,
- )
- class GenericFunction(Function[_T]):
- """Define a 'generic' function.
- A generic function is a pre-established :class:`.Function`
- class that is instantiated automatically when called
- by name from the :data:`.func` attribute. Note that
- calling any name from :data:`.func` has the effect that
- a new :class:`.Function` instance is created automatically,
- given that name. The primary use case for defining
- a :class:`.GenericFunction` class is so that a function
- of a particular name may be given a fixed return type.
- It can also include custom argument parsing schemes as well
- as additional methods.
- Subclasses of :class:`.GenericFunction` are automatically
- registered under the name of the class. For
- example, a user-defined function ``as_utc()`` would
- be available immediately::
- from sqlalchemy.sql.functions import GenericFunction
- from sqlalchemy.types import DateTime
- class as_utc(GenericFunction):
- type = DateTime()
- inherit_cache = True
- print(select(func.as_utc()))
- User-defined generic functions can be organized into
- packages by specifying the "package" attribute when defining
- :class:`.GenericFunction`. Third party libraries
- containing many functions may want to use this in order
- to avoid name conflicts with other systems. For example,
- if our ``as_utc()`` function were part of a package
- "time"::
- class as_utc(GenericFunction):
- type = DateTime()
- package = "time"
- inherit_cache = True
- The above function would be available from :data:`.func`
- using the package name ``time``::
- print(select(func.time.as_utc()))
- A final option is to allow the function to be accessed
- from one name in :data:`.func` but to render as a different name.
- The ``identifier`` attribute will override the name used to
- access the function as loaded from :data:`.func`, but will retain
- the usage of ``name`` as the rendered name::
- class GeoBuffer(GenericFunction):
- type = Geometry()
- package = "geo"
- name = "ST_Buffer"
- identifier = "buffer"
- inherit_cache = True
- The above function will render as follows:
- .. sourcecode:: pycon+sql
- >>> print(func.geo.buffer())
- {printsql}ST_Buffer()
- The name will be rendered as is, however without quoting unless the name
- contains special characters that require quoting. To force quoting
- on or off for the name, use the :class:`.sqlalchemy.sql.quoted_name`
- construct::
- from sqlalchemy.sql import quoted_name
- class GeoBuffer(GenericFunction):
- type = Geometry()
- package = "geo"
- name = quoted_name("ST_Buffer", True)
- identifier = "buffer"
- inherit_cache = True
- The above function will render as:
- .. sourcecode:: pycon+sql
- >>> print(func.geo.buffer())
- {printsql}"ST_Buffer"()
- Type parameters for this class as a
- `generic type <https://peps.python.org/pep-0484/#generics>`_ can be passed
- and should match the type seen in a :class:`_engine.Result`. For example::
- class as_utc(GenericFunction[datetime.datetime]):
- type = DateTime()
- inherit_cache = True
- The above indicates that the following expression returns a ``datetime``
- object::
- connection.scalar(select(func.as_utc()))
- .. versionadded:: 1.3.13 The :class:`.quoted_name` construct is now
- recognized for quoting when used with the "name" attribute of the
- object, so that quoting can be forced on or off for the function
- name.
- """
- coerce_arguments = True
- inherit_cache = True
- _register: bool
- name = "GenericFunction"
- def __init_subclass__(cls) -> None:
- if annotation.Annotated not in cls.__mro__:
- cls._register_generic_function(cls.__name__, cls.__dict__)
- super().__init_subclass__()
- @classmethod
- def _register_generic_function(
- cls, clsname: str, clsdict: Mapping[str, Any]
- ) -> None:
- cls.name = name = clsdict.get("name", clsname)
- cls.identifier = identifier = clsdict.get("identifier", name)
- package = clsdict.get("package", "_default")
- # legacy
- if "__return_type__" in clsdict:
- cls.type = clsdict["__return_type__"]
- # Check _register attribute status
- cls._register = getattr(cls, "_register", True)
- # Register the function if required
- if cls._register:
- register_function(identifier, cls, package)
- else:
- # Set _register to True to register child classes by default
- cls._register = True
- def __init__(
- self, *args: _ColumnExpressionOrLiteralArgument[Any], **kwargs: Any
- ) -> None:
- parsed_args = kwargs.pop("_parsed_args", None)
- if parsed_args is None:
- parsed_args = [
- coercions.expect(
- roles.ExpressionElementRole,
- c,
- name=self.name,
- apply_propagate_attrs=self,
- )
- for c in args
- ]
- self._has_args = self._has_args or bool(parsed_args)
- self.packagenames = ()
- self.clause_expr = Grouping(
- ClauseList(
- operator=operators.comma_op, group_contents=True, *parsed_args
- )
- )
- self.type = type_api.to_instance( # type: ignore
- kwargs.pop("type_", None) or getattr(self, "type", None)
- )
- register_function("cast", Cast) # type: ignore
- register_function("extract", Extract) # type: ignore
- class next_value(GenericFunction[int]):
- """Represent the 'next value', given a :class:`.Sequence`
- as its single argument.
- Compiles into the appropriate function on each backend,
- or will raise NotImplementedError if used on a backend
- that does not provide support for sequences.
- """
- type = sqltypes.Integer()
- name = "next_value"
- _traverse_internals = [
- ("sequence", InternalTraversal.dp_named_ddl_element)
- ]
- def __init__(self, seq: schema.Sequence, **kw: Any) -> None:
- assert isinstance(
- seq, schema.Sequence
- ), "next_value() accepts a Sequence object as input."
- self.sequence = seq
- self.type = sqltypes.to_instance( # type: ignore
- seq.data_type or getattr(self, "type", None)
- )
- def compare(self, other: Any, **kw: Any) -> bool:
- return (
- isinstance(other, next_value)
- and self.sequence.name == other.sequence.name
- )
- @property
- def _from_objects(self) -> Any:
- return []
- class AnsiFunction(GenericFunction[_T]):
- """Define a function in "ansi" format, which doesn't render parenthesis."""
- inherit_cache = True
- def __init__(
- self, *args: _ColumnExpressionArgument[Any], **kwargs: Any
- ) -> None:
- GenericFunction.__init__(self, *args, **kwargs)
- class ReturnTypeFromArgs(GenericFunction[_T]):
- """Define a function whose return type is bound to the type of its
- arguments.
- """
- inherit_cache = True
- # set ColumnElement[_T] as a separate overload, to appease
- # mypy which seems to not want to accept _T from
- # _ColumnExpressionArgument. Seems somewhat related to the covariant
- # _HasClauseElement as of mypy 1.15
- @overload
- def __init__(
- self,
- col: ColumnElement[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> None: ...
- @overload
- def __init__(
- self,
- col: _ColumnExpressionArgument[_T],
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> None: ...
- @overload
- def __init__(
- self,
- col: _T,
- *args: _ColumnExpressionOrLiteralArgument[Any],
- **kwargs: Any,
- ) -> None: ...
- def __init__(
- self, *args: _ColumnExpressionOrLiteralArgument[_T], **kwargs: Any
- ) -> None:
- fn_args: Sequence[ColumnElement[Any]] = [
- coercions.expect(
- roles.ExpressionElementRole,
- c,
- name=self.name,
- apply_propagate_attrs=self,
- )
- for c in args
- ]
- kwargs.setdefault("type_", _type_from_args(fn_args))
- kwargs["_parsed_args"] = fn_args
- super().__init__(*fn_args, **kwargs)
- class coalesce(ReturnTypeFromArgs[_T]):
- _has_args = True
- inherit_cache = True
- class max(ReturnTypeFromArgs[_T]): # noqa: A001
- """The SQL MAX() aggregate function."""
- inherit_cache = True
- class min(ReturnTypeFromArgs[_T]): # noqa: A001
- """The SQL MIN() aggregate function."""
- inherit_cache = True
- class sum(ReturnTypeFromArgs[_T]): # noqa: A001
- """The SQL SUM() aggregate function."""
- inherit_cache = True
- class now(GenericFunction[datetime.datetime]):
- """The SQL now() datetime function.
- SQLAlchemy dialects will usually render this particular function
- in a backend-specific way, such as rendering it as ``CURRENT_TIMESTAMP``.
- """
- type = sqltypes.DateTime()
- inherit_cache = True
- class concat(GenericFunction[str]):
- """The SQL CONCAT() function, which concatenates strings.
- E.g.:
- .. sourcecode:: pycon+sql
- >>> print(select(func.concat("a", "b")))
- {printsql}SELECT concat(:concat_2, :concat_3) AS concat_1
- String concatenation in SQLAlchemy is more commonly available using the
- Python ``+`` operator with string datatypes, which will render a
- backend-specific concatenation operator, such as :
- .. sourcecode:: pycon+sql
- >>> print(select(literal("a") + "b"))
- {printsql}SELECT :param_1 || :param_2 AS anon_1
- """
- type = sqltypes.String()
- inherit_cache = True
- class char_length(GenericFunction[int]):
- """The CHAR_LENGTH() SQL function."""
- type = sqltypes.Integer()
- inherit_cache = True
- def __init__(self, arg: _ColumnExpressionArgument[str], **kw: Any) -> None:
- # slight hack to limit to just one positional argument
- # not sure why this one function has this special treatment
- super().__init__(arg, **kw)
- class random(GenericFunction[float]):
- """The RANDOM() SQL function."""
- _has_args = True
- inherit_cache = True
- class count(GenericFunction[int]):
- r"""The ANSI COUNT aggregate function. With no arguments,
- emits COUNT \*.
- E.g.::
- from sqlalchemy import func
- from sqlalchemy import select
- from sqlalchemy import table, column
- my_table = table("some_table", column("id"))
- stmt = select(func.count()).select_from(my_table)
- Executing ``stmt`` would emit:
- .. sourcecode:: sql
- SELECT count(*) AS count_1
- FROM some_table
- """
- type = sqltypes.Integer()
- inherit_cache = True
- def __init__(
- self,
- expression: Union[
- _ColumnExpressionArgument[Any], _StarOrOne, None
- ] = None,
- **kwargs: Any,
- ) -> None:
- if expression is None:
- expression = literal_column("*")
- super().__init__(expression, **kwargs)
- class current_date(AnsiFunction[datetime.date]):
- """The CURRENT_DATE() SQL function."""
- type = sqltypes.Date()
- inherit_cache = True
- class current_time(AnsiFunction[datetime.time]):
- """The CURRENT_TIME() SQL function."""
- type = sqltypes.Time()
- inherit_cache = True
- class current_timestamp(AnsiFunction[datetime.datetime]):
- """The CURRENT_TIMESTAMP() SQL function."""
- type = sqltypes.DateTime()
- inherit_cache = True
- class current_user(AnsiFunction[str]):
- """The CURRENT_USER() SQL function."""
- type = sqltypes.String()
- inherit_cache = True
- class localtime(AnsiFunction[datetime.datetime]):
- """The localtime() SQL function."""
- type = sqltypes.DateTime()
- inherit_cache = True
- class localtimestamp(AnsiFunction[datetime.datetime]):
- """The localtimestamp() SQL function."""
- type = sqltypes.DateTime()
- inherit_cache = True
- class session_user(AnsiFunction[str]):
- """The SESSION_USER() SQL function."""
- type = sqltypes.String()
- inherit_cache = True
- class sysdate(AnsiFunction[datetime.datetime]):
- """The SYSDATE() SQL function."""
- type = sqltypes.DateTime()
- inherit_cache = True
- class user(AnsiFunction[str]):
- """The USER() SQL function."""
- type = sqltypes.String()
- inherit_cache = True
- class array_agg(ReturnTypeFromArgs[Sequence[_T]]):
- """Support for the ARRAY_AGG function.
- The ``func.array_agg(expr)`` construct returns an expression of
- type :class:`_types.ARRAY`.
- e.g.::
- stmt = select(func.array_agg(table.c.values)[2:5])
- .. seealso::
- :func:`_postgresql.array_agg` - PostgreSQL-specific version that
- returns :class:`_postgresql.ARRAY`, which has PG-specific operators
- added.
- """
- inherit_cache = True
- def __init__(
- self, *args: _ColumnExpressionArgument[Any], **kwargs: Any
- ) -> None:
- fn_args: Sequence[ColumnElement[Any]] = [
- coercions.expect(
- roles.ExpressionElementRole, c, apply_propagate_attrs=self
- )
- for c in args
- ]
- default_array_type = kwargs.pop("_default_array_type", sqltypes.ARRAY)
- if "type_" not in kwargs:
- type_from_args = _type_from_args(fn_args)
- if isinstance(type_from_args, sqltypes.ARRAY):
- kwargs["type_"] = type_from_args
- else:
- kwargs["type_"] = default_array_type(
- type_from_args, dimensions=1
- )
- kwargs["_parsed_args"] = fn_args
- super().__init__(*fn_args, **kwargs)
- class OrderedSetAgg(GenericFunction[_T]):
- """Define a function where the return type is based on the sort
- expression type as defined by the expression passed to the
- :meth:`.FunctionElement.within_group` method."""
- array_for_multi_clause = False
- inherit_cache = True
- def within_group_type(
- self, within_group: WithinGroup[Any]
- ) -> TypeEngine[Any]:
- func_clauses = cast(ClauseList, self.clause_expr.element)
- order_by: Sequence[ColumnElement[Any]] = sqlutil.unwrap_order_by(
- within_group.order_by
- )
- if self.array_for_multi_clause and len(func_clauses.clauses) > 1:
- return sqltypes.ARRAY(order_by[0].type)
- else:
- return order_by[0].type
- class mode(OrderedSetAgg[_T]):
- """Implement the ``mode`` ordered-set aggregate function.
- This function must be used with the :meth:`.FunctionElement.within_group`
- modifier to supply a sort expression to operate upon.
- The return type of this function is the same as the sort expression.
- """
- inherit_cache = True
- class percentile_cont(OrderedSetAgg[_T]):
- """Implement the ``percentile_cont`` ordered-set aggregate function.
- This function must be used with the :meth:`.FunctionElement.within_group`
- modifier to supply a sort expression to operate upon.
- The return type of this function is the same as the sort expression,
- or if the arguments are an array, an :class:`_types.ARRAY` of the sort
- expression's type.
- """
- array_for_multi_clause = True
- inherit_cache = True
- class percentile_disc(OrderedSetAgg[_T]):
- """Implement the ``percentile_disc`` ordered-set aggregate function.
- This function must be used with the :meth:`.FunctionElement.within_group`
- modifier to supply a sort expression to operate upon.
- The return type of this function is the same as the sort expression,
- or if the arguments are an array, an :class:`_types.ARRAY` of the sort
- expression's type.
- """
- array_for_multi_clause = True
- inherit_cache = True
- class rank(GenericFunction[int]):
- """Implement the ``rank`` hypothetical-set aggregate function.
- This function must be used with the :meth:`.FunctionElement.within_group`
- modifier to supply a sort expression to operate upon.
- The return type of this function is :class:`.Integer`.
- """
- type = sqltypes.Integer()
- inherit_cache = True
- class dense_rank(GenericFunction[int]):
- """Implement the ``dense_rank`` hypothetical-set aggregate function.
- This function must be used with the :meth:`.FunctionElement.within_group`
- modifier to supply a sort expression to operate upon.
- The return type of this function is :class:`.Integer`.
- """
- type = sqltypes.Integer()
- inherit_cache = True
- class percent_rank(GenericFunction[decimal.Decimal]):
- """Implement the ``percent_rank`` hypothetical-set aggregate function.
- This function must be used with the :meth:`.FunctionElement.within_group`
- modifier to supply a sort expression to operate upon.
- The return type of this function is :class:`.Numeric`.
- """
- type: sqltypes.Numeric[decimal.Decimal] = sqltypes.Numeric()
- inherit_cache = True
- class cume_dist(GenericFunction[decimal.Decimal]):
- """Implement the ``cume_dist`` hypothetical-set aggregate function.
- This function must be used with the :meth:`.FunctionElement.within_group`
- modifier to supply a sort expression to operate upon.
- The return type of this function is :class:`.Numeric`.
- """
- type: sqltypes.Numeric[decimal.Decimal] = sqltypes.Numeric()
- inherit_cache = True
- class cube(GenericFunction[_T]):
- r"""Implement the ``CUBE`` grouping operation.
- This function is used as part of the GROUP BY of a statement,
- e.g. :meth:`_expression.Select.group_by`::
- stmt = select(
- func.sum(table.c.value), table.c.col_1, table.c.col_2
- ).group_by(func.cube(table.c.col_1, table.c.col_2))
- .. versionadded:: 1.2
- """
- _has_args = True
- inherit_cache = True
- class rollup(GenericFunction[_T]):
- r"""Implement the ``ROLLUP`` grouping operation.
- This function is used as part of the GROUP BY of a statement,
- e.g. :meth:`_expression.Select.group_by`::
- stmt = select(
- func.sum(table.c.value), table.c.col_1, table.c.col_2
- ).group_by(func.rollup(table.c.col_1, table.c.col_2))
- .. versionadded:: 1.2
- """
- _has_args = True
- inherit_cache = True
- class grouping_sets(GenericFunction[_T]):
- r"""Implement the ``GROUPING SETS`` grouping operation.
- This function is used as part of the GROUP BY of a statement,
- e.g. :meth:`_expression.Select.group_by`::
- stmt = select(
- func.sum(table.c.value), table.c.col_1, table.c.col_2
- ).group_by(func.grouping_sets(table.c.col_1, table.c.col_2))
- In order to group by multiple sets, use the :func:`.tuple_` construct::
- from sqlalchemy import tuple_
- stmt = select(
- func.sum(table.c.value), table.c.col_1, table.c.col_2, table.c.col_3
- ).group_by(
- func.grouping_sets(
- tuple_(table.c.col_1, table.c.col_2),
- tuple_(table.c.value, table.c.col_3),
- )
- )
- .. versionadded:: 1.2
- """ # noqa: E501
- _has_args = True
- inherit_cache = True
- class aggregate_strings(GenericFunction[str]):
- """Implement a generic string aggregation function.
- This function will concatenate non-null values into a string and
- separate the values by a delimiter.
- This function is compiled on a per-backend basis, into functions
- such as ``group_concat()``, ``string_agg()``, or ``LISTAGG()``.
- e.g. Example usage with delimiter '.'::
- stmt = select(func.aggregate_strings(table.c.str_col, "."))
- The return type of this function is :class:`.String`.
- .. versionadded: 2.0.21
- """
- type = sqltypes.String()
- _has_args = True
- inherit_cache = True
- def __init__(
- self, clause: _ColumnExpressionArgument[Any], separator: str
- ) -> None:
- super().__init__(clause, separator)
|