PostgreSQL Source Code git master
Loading...
Searching...
No Matches
functions.h File Reference
#include "nodes/execnodes.h"
#include "tcop/dest.h"
Include dependency graph for functions.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  SQLFunctionParseInfo
 

Typedefs

typedef struct SQLFunctionParseInfo SQLFunctionParseInfo
 
typedef SQLFunctionParseInfoSQLFunctionParseInfoPtr
 

Functions

Datum fmgr_sql (PG_FUNCTION_ARGS)
 
SQLFunctionParseInfoPtr prepare_sql_fn_parse_info (HeapTuple procedureTuple, Node *call_expr, Oid inputCollation)
 
void sql_fn_parser_setup (struct ParseState *pstate, SQLFunctionParseInfoPtr pinfo)
 
void check_sql_fn_statements (List *queryTreeLists)
 
bool check_sql_fn_retval (List *queryTreeLists, Oid rettype, TupleDesc rettupdesc, char prokind, bool insertDroppedCols)
 
DestReceiverCreateSQLFunctionDestReceiver (void)
 

Typedef Documentation

◆ SQLFunctionParseInfo

◆ SQLFunctionParseInfoPtr

Function Documentation

◆ check_sql_fn_retval()

bool check_sql_fn_retval ( List queryTreeLists,
Oid  rettype,
TupleDesc  rettupdesc,
char  prokind,
bool  insertDroppedCols 
)
extern

Definition at line 2117 of file functions.c.

2121{
2123
2124 /*
2125 * We consider only the last sublist of Query nodes, so that only the last
2126 * original statement is a candidate to produce the result. This is a
2127 * change from pre-v18 versions, which would back up to the last statement
2128 * that includes a canSetTag query, thus ignoring any ending statement(s)
2129 * that rewrite to DO INSTEAD NOTHING. That behavior was undocumented and
2130 * there seems no good reason for it, except that it was an artifact of
2131 * the original coding.
2132 *
2133 * If the function body is completely empty, handle that the same as if
2134 * the last query had rewritten to nothing.
2135 */
2136 if (queryTreeLists != NIL)
2138 else
2140
2142 rettype, rettupdesc,
2143 prokind, insertDroppedCols);
2144}
static bool check_sql_stmt_retval(List *queryTreeList, Oid rettype, TupleDesc rettupdesc, char prokind, bool insertDroppedCols)
Definition functions.c:2151
#define NIL
Definition pg_list.h:68
#define llast_node(type, l)
Definition pg_list.h:202
static int fb(int x)
Definition pg_list.h:54

References check_sql_stmt_retval(), fb(), llast_node, and NIL.

Referenced by fmgr_sql_validator(), inline_function(), and inline_sql_function_in_from().

◆ check_sql_fn_statements()

void check_sql_fn_statements ( List queryTreeLists)
extern

Definition at line 2036 of file functions.c.

2037{
2038 ListCell *lc;
2039
2040 /* We are given a list of sublists of Queries */
2041 foreach(lc, queryTreeLists)
2042 {
2044
2046 }
2047}
static void check_sql_fn_statement(List *queryTreeList)
Definition functions.c:2053
#define lfirst_node(type, lc)
Definition pg_list.h:176

References check_sql_fn_statement(), fb(), and lfirst_node.

Referenced by fmgr_sql_validator().

◆ CreateSQLFunctionDestReceiver()

DestReceiver * CreateSQLFunctionDestReceiver ( void  )
extern

Definition at line 2618 of file functions.c.

2619{
2621
2626 self->pub.mydest = DestSQLFunction;
2627
2628 /* private fields will be set by postquel_start */
2629
2630 return (DestReceiver *) self;
2631}
@ DestSQLFunction
Definition dest.h:96
#define palloc0_object(type)
Definition fe_memutils.h:75
static void sqlfunction_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition functions.c:2637
static bool sqlfunction_receive(TupleTableSlot *slot, DestReceiver *self)
Definition functions.c:2646
static void sqlfunction_destroy(DestReceiver *self)
Definition functions.c:2693
static void sqlfunction_shutdown(DestReceiver *self)
Definition functions.c:2684
DestReceiver pub
Definition functions.c:48
void(* rStartup)(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition dest.h:121
void(* rShutdown)(DestReceiver *self)
Definition dest.h:124
bool(* receiveSlot)(TupleTableSlot *slot, DestReceiver *self)
Definition dest.h:118
void(* rDestroy)(DestReceiver *self)
Definition dest.h:126
CommandDest mydest
Definition dest.h:128

References DestSQLFunction, _DestReceiver::mydest, palloc0_object, DR_sqlfunction::pub, _DestReceiver::rDestroy, _DestReceiver::receiveSlot, _DestReceiver::rShutdown, _DestReceiver::rStartup, sqlfunction_destroy(), sqlfunction_receive(), sqlfunction_shutdown(), and sqlfunction_startup().

Referenced by CreateDestReceiver().

◆ fmgr_sql()

Datum fmgr_sql ( PG_FUNCTION_ARGS  )
extern

Definition at line 1577 of file functions.c.

1578{
1581 MemoryContext tscontext;
1582 bool randomAccess;
1583 bool lazyEvalOK;
1584 bool pushed_snapshot;
1585 execution_state *es;
1586 TupleTableSlot *slot;
1587 Datum result;
1588
1589 /* Check call context */
1590 if (fcinfo->flinfo->fn_retset)
1591 {
1592 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1593
1594 /*
1595 * For simplicity, we require callers to support both set eval modes.
1596 * There are cases where we must use one or must use the other, and
1597 * it's not really worthwhile to postpone the check till we know. But
1598 * note we do not require caller to provide an expectedDesc.
1599 */
1600 if (!rsi || !IsA(rsi, ReturnSetInfo) ||
1601 (rsi->allowedModes & SFRM_ValuePerCall) == 0 ||
1602 (rsi->allowedModes & SFRM_Materialize) == 0)
1603 ereport(ERROR,
1605 errmsg("set-valued function called in context that cannot accept a set")));
1606 randomAccess = rsi->allowedModes & SFRM_Materialize_Random;
1607 lazyEvalOK = !(rsi->allowedModes & SFRM_Materialize_Preferred);
1608 /* tuplestore, if used, must have query lifespan */
1609 tscontext = rsi->econtext->ecxt_per_query_memory;
1610 }
1611 else
1612 {
1613 randomAccess = false;
1614 lazyEvalOK = true;
1615 /* we won't need a tuplestore */
1616 tscontext = NULL;
1617 }
1618
1619 /*
1620 * Initialize fcache if starting a fresh execution.
1621 */
1622 fcache = init_sql_fcache(fcinfo, lazyEvalOK);
1623
1624 /* Mark fcache as active */
1625 fcache->active = true;
1626
1627 /* Remember info that we might need later to construct tuplestore */
1628 fcache->tscontext = tscontext;
1629 fcache->randomAccess = randomAccess;
1630
1631 /*
1632 * Now we can set up error traceback support for ereport()
1633 */
1635 sqlerrcontext.arg = fcache;
1638
1639 /*
1640 * Find first unfinished execution_state. If none, advance to the next
1641 * query in function.
1642 */
1643 do
1644 {
1645 es = fcache->eslist;
1646 while (es && es->status == F_EXEC_DONE)
1647 es = es->next;
1648 if (es)
1649 break;
1650 } while (init_execution_state(fcache));
1651
1652 /*
1653 * Execute each command in the function one after another until we either
1654 * run out of commands or get a result row from a lazily-evaluated SELECT.
1655 *
1656 * Notes about snapshot management:
1657 *
1658 * In a read-only function, we just use the surrounding query's snapshot.
1659 *
1660 * In a non-read-only function, we rely on the fact that we'll never
1661 * suspend execution between queries of the function: the only reason to
1662 * suspend execution before completion is if we are returning a row from a
1663 * lazily-evaluated SELECT. So, when first entering this loop, we'll
1664 * either start a new query (and push a fresh snapshot) or re-establish
1665 * the active snapshot from the existing query descriptor. If we need to
1666 * start a new query in a subsequent execution of the loop, either we need
1667 * a fresh snapshot (and pushed_snapshot is false) or the existing
1668 * snapshot is on the active stack and we can just bump its command ID.
1669 */
1670 pushed_snapshot = false;
1671 while (es)
1672 {
1673 bool completed;
1674
1675 if (es->status == F_EXEC_START)
1676 {
1677 /*
1678 * If not read-only, be sure to advance the command counter for
1679 * each command, so that all work to date in this transaction is
1680 * visible. Take a new snapshot if we don't have one yet,
1681 * otherwise just bump the command ID in the existing snapshot.
1682 */
1683 if (!fcache->func->readonly_func)
1684 {
1686 if (!pushed_snapshot)
1687 {
1689 pushed_snapshot = true;
1690 }
1691 else
1693 }
1694
1696 }
1697 else if (!fcache->func->readonly_func && !pushed_snapshot)
1698 {
1699 /* Re-establish active snapshot when re-entering function */
1701 pushed_snapshot = true;
1702 }
1703
1704 completed = postquel_getnext(es, fcache);
1705
1706 /*
1707 * If we ran the command to completion, we can shut it down now. Any
1708 * row(s) we need to return are safely stashed in the result slot or
1709 * tuplestore, and we want to be sure that, for example, AFTER
1710 * triggers get fired before we return anything. Also, if the
1711 * function doesn't return set, we can shut it down anyway because it
1712 * must be a SELECT and we don't care about fetching any more result
1713 * rows.
1714 */
1715 if (completed || !fcache->func->returnsSet)
1716 postquel_end(es, fcache);
1717
1718 /*
1719 * Break from loop if we didn't shut down (implying we got a
1720 * lazily-evaluated row). Otherwise we'll press on till the whole
1721 * function is done, relying on the tuplestore to keep hold of the
1722 * data to eventually be returned. This is necessary since an
1723 * INSERT/UPDATE/DELETE RETURNING that sets the result might be
1724 * followed by additional rule-inserted commands, and we want to
1725 * finish doing all those commands before we return anything.
1726 */
1727 if (es->status != F_EXEC_DONE)
1728 break;
1729
1730 /*
1731 * Advance to next execution_state, and perhaps next query.
1732 */
1733 es = es->next;
1734 while (!es)
1735 {
1736 /*
1737 * Flush the current snapshot so that we will take a new one for
1738 * the new query list. This ensures that new snaps are taken at
1739 * original-query boundaries, matching the behavior of interactive
1740 * execution.
1741 */
1742 if (pushed_snapshot)
1743 {
1745 pushed_snapshot = false;
1746 }
1747
1749 break; /* end of function */
1750
1751 es = fcache->eslist;
1752 }
1753 }
1754
1755 /*
1756 * The result slot or tuplestore now contains whatever row(s) we are
1757 * supposed to return.
1758 */
1759 if (fcache->func->returnsSet)
1760 {
1761 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1762
1763 if (es)
1764 {
1765 /*
1766 * If we stopped short of being done, we must have a lazy-eval
1767 * row.
1768 */
1769 Assert(es->lazyEval);
1770 /* The junkfilter's result slot contains the query result tuple */
1771 Assert(fcache->junkFilter);
1772 slot = fcache->junkFilter->jf_resultSlot;
1773 Assert(!TTS_EMPTY(slot));
1774 /* Extract the result as a datum, and copy out from the slot */
1775 result = postquel_get_single_result(slot, fcinfo, fcache);
1776
1777 /*
1778 * Let caller know we're not finished.
1779 */
1780 rsi->isDone = ExprMultipleResult;
1781
1782 /*
1783 * Ensure we will get shut down cleanly if the exprcontext is not
1784 * run to completion.
1785 */
1786 if (!fcache->shutdown_reg)
1787 {
1788 RegisterExprContextCallback(rsi->econtext,
1791 fcache->shutdown_reg = true;
1792 }
1793 }
1794 else if (fcache->lazyEval)
1795 {
1796 /*
1797 * We are done with a lazy evaluation. Let caller know we're
1798 * finished.
1799 */
1800 rsi->isDone = ExprEndResult;
1801
1802 fcinfo->isnull = true;
1803 result = (Datum) 0;
1804
1805 /* Deregister shutdown callback, if we made one */
1806 if (fcache->shutdown_reg)
1807 {
1808 UnregisterExprContextCallback(rsi->econtext,
1811 fcache->shutdown_reg = false;
1812 }
1813 }
1814 else
1815 {
1816 /*
1817 * We are done with a non-lazy evaluation. Return whatever is in
1818 * the tuplestore. (It is now caller's responsibility to free the
1819 * tuplestore when done.)
1820 *
1821 * Note an edge case: we could get here without having made a
1822 * tuplestore if the function is declared to return SETOF VOID.
1823 * ExecMakeTableFunctionResult will cope with null setResult.
1824 */
1825 Assert(fcache->tstore || fcache->func->rettype == VOIDOID);
1826 rsi->returnMode = SFRM_Materialize;
1827 rsi->setResult = fcache->tstore;
1828 fcache->tstore = NULL;
1829 /* must copy desc because execSRF.c will free it */
1830 if (fcache->junkFilter)
1831 rsi->setDesc = CreateTupleDescCopy(fcache->junkFilter->jf_cleanTupType);
1832
1833 fcinfo->isnull = true;
1834 result = (Datum) 0;
1835
1836 /* Deregister shutdown callback, if we made one */
1837 if (fcache->shutdown_reg)
1838 {
1839 UnregisterExprContextCallback(rsi->econtext,
1842 fcache->shutdown_reg = false;
1843 }
1844 }
1845 }
1846 else
1847 {
1848 /*
1849 * Non-set function. If we got a row, return it; else return NULL.
1850 */
1851 if (fcache->junkFilter)
1852 {
1853 /* The junkfilter's result slot contains the query result tuple */
1854 slot = fcache->junkFilter->jf_resultSlot;
1855 if (!TTS_EMPTY(slot))
1856 result = postquel_get_single_result(slot, fcinfo, fcache);
1857 else
1858 {
1859 fcinfo->isnull = true;
1860 result = (Datum) 0;
1861 }
1862 }
1863 else
1864 {
1865 /* Should only get here for VOID functions and procedures */
1866 Assert(fcache->func->rettype == VOIDOID);
1867 fcinfo->isnull = true;
1868 result = (Datum) 0;
1869 }
1870 }
1871
1872 /* Pop snapshot if we have pushed one */
1873 if (pushed_snapshot)
1875
1876 /*
1877 * If we've gone through every command in the function, we are done. Reset
1878 * state to start over again on next call.
1879 */
1880 if (es == NULL)
1881 fcache->eslist = NULL;
1882
1883 /* Mark fcache as inactive */
1884 fcache->active = false;
1885
1887
1888 return result;
1889}
#define Assert(condition)
Definition c.h:945
ErrorContextCallback * error_context_stack
Definition elog.c:99
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
void UnregisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition execUtils.c:994
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition execUtils.c:968
@ ExprMultipleResult
Definition execnodes.h:339
@ ExprEndResult
Definition execnodes.h:340
@ SFRM_Materialize_Preferred
Definition execnodes.h:354
@ SFRM_ValuePerCall
Definition execnodes.h:351
@ SFRM_Materialize_Random
Definition execnodes.h:353
@ SFRM_Materialize
Definition execnodes.h:352
static Datum postquel_get_single_result(TupleTableSlot *slot, FunctionCallInfo fcinfo, SQLFunctionCachePtr fcache)
Definition functions.c:1537
static bool postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
Definition functions.c:1401
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
Definition functions.c:1277
static bool init_execution_state(SQLFunctionCachePtr fcache)
Definition functions.c:654
static void postquel_end(execution_state *es, SQLFunctionCachePtr fcache)
Definition functions.c:1442
static void sql_exec_error_callback(void *arg)
Definition functions.c:1930
static void ShutdownSQLFunction(Datum arg)
Definition functions.c:1968
@ F_EXEC_START
Definition functions.c:66
@ F_EXEC_DONE
Definition functions.c:66
static SQLFunctionCache * init_sql_fcache(FunctionCallInfo fcinfo, bool lazyEvalOK)
Definition functions.c:537
#define IsA(nodeptr, _type_)
Definition nodes.h:164
static char * errmsg
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
uint64_t Datum
Definition postgres.h:70
Snapshot GetTransactionSnapshot(void)
Definition snapmgr.c:272
void PushActiveSnapshot(Snapshot snapshot)
Definition snapmgr.c:682
void UpdateActiveSnapshotCommandId(void)
Definition snapmgr.c:744
void PopActiveSnapshot(void)
Definition snapmgr.c:775
struct ErrorContextCallback * previous
Definition elog.h:297
Snapshot snapshot
Definition execdesc.h:39
ExecStatus status
Definition functions.c:72
struct execution_state * next
Definition functions.c:71
QueryDesc * qd
Definition functions.c:76
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition tupdesc.c:242
#define TTS_EMPTY(slot)
Definition tuptable.h:92
void CommandCounterIncrement(void)
Definition xact.c:1102

References ReturnSetInfo::allowedModes, Assert, CommandCounterIncrement(), CreateTupleDescCopy(), ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, ereport, errcode(), errmsg, ERROR, error_context_stack, ExprEndResult, ExprMultipleResult, F_EXEC_DONE, F_EXEC_START, fb(), GetTransactionSnapshot(), init_execution_state(), init_sql_fcache(), IsA, ReturnSetInfo::isDone, execution_state::lazyEval, execution_state::next, PointerGetDatum(), PopActiveSnapshot(), postquel_end(), postquel_get_single_result(), postquel_getnext(), postquel_start(), ErrorContextCallback::previous, PushActiveSnapshot(), execution_state::qd, RegisterExprContextCallback(), ReturnSetInfo::returnMode, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SFRM_Materialize_Preferred, SFRM_Materialize_Random, SFRM_ValuePerCall, ShutdownSQLFunction(), QueryDesc::snapshot, sql_exec_error_callback(), execution_state::status, TTS_EMPTY, UnregisterExprContextCallback(), and UpdateActiveSnapshotCommandId().

Referenced by fmgr_info_cxt_security().

◆ prepare_sql_fn_parse_info()

SQLFunctionParseInfoPtr prepare_sql_fn_parse_info ( HeapTuple  procedureTuple,
Node call_expr,
Oid  inputCollation 
)
extern

Definition at line 252 of file functions.c.

255{
258 int nargs;
259
261
262 /* Function's name (only) can be used to qualify argument names */
263 pinfo->fname = pstrdup(NameStr(procedureStruct->proname));
264
265 /* Save the function's input collation */
266 pinfo->collation = inputCollation;
267
268 /*
269 * Copy input argument types from the pg_proc entry, then resolve any
270 * polymorphic types.
271 */
272 pinfo->nargs = nargs = procedureStruct->pronargs;
273 if (nargs > 0)
274 {
276 int argnum;
277
278 argOidVect = (Oid *) palloc(nargs * sizeof(Oid));
280 procedureStruct->proargtypes.values,
281 nargs * sizeof(Oid));
282
283 for (argnum = 0; argnum < nargs; argnum++)
284 {
285 Oid argtype = argOidVect[argnum];
286
287 if (IsPolymorphicType(argtype))
288 {
290 if (argtype == InvalidOid)
293 errmsg("could not determine actual type of argument declared %s",
295 argOidVect[argnum] = argtype;
296 }
297 }
298
299 pinfo->argtypes = argOidVect;
300 }
301
302 /*
303 * Collect names of arguments, too, if any
304 */
305 if (nargs > 0)
306 {
309 int n_arg_names;
310 bool isNull;
311
314 &isNull);
315 if (isNull)
316 proargnames = PointerGetDatum(NULL); /* just to be sure */
317
320 &isNull);
321 if (isNull)
322 proargmodes = PointerGetDatum(NULL); /* just to be sure */
323
325 &pinfo->argnames);
326
327 /* Paranoia: ignore the result if too few array entries */
328 if (n_arg_names < nargs)
329 pinfo->argnames = NULL;
330 }
331 else
332 pinfo->argnames = NULL;
333
334 return pinfo;
335}
#define NameStr(name)
Definition c.h:837
Oid get_call_expr_argtype(Node *expr, int argnum)
Definition fmgr.c:1895
char * format_type_be(Oid type_oid)
int get_func_input_arg_names(Datum proargnames, Datum proargmodes, char ***arg_names)
Definition funcapi.c:1525
SQLFunctionParseInfo * SQLFunctionParseInfoPtr
Definition functions.h:35
static void * GETSTRUCT(const HeapTupleData *tuple)
char * pstrdup(const char *in)
Definition mcxt.c:1781
void * palloc(Size size)
Definition mcxt.c:1387
END_CATALOG_STRUCT typedef FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:140
#define InvalidOid
unsigned int Oid
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:595

References SQLFunctionParseInfo::argnames, SQLFunctionParseInfo::argtypes, SQLFunctionParseInfo::collation, ereport, errcode(), errmsg, ERROR, fb(), SQLFunctionParseInfo::fname, Form_pg_proc, format_type_be(), get_call_expr_argtype(), get_func_input_arg_names(), GETSTRUCT(), InvalidOid, NameStr, SQLFunctionParseInfo::nargs, palloc(), palloc0_object, PointerGetDatum(), pstrdup(), and SysCacheGetAttr().

Referenced by fmgr_sql_validator(), inline_function(), inline_sql_function_in_from(), sql_compile_callback(), and test_inline_in_from_support_func().

◆ sql_fn_parser_setup()

void sql_fn_parser_setup ( struct ParseState pstate,
SQLFunctionParseInfoPtr  pinfo 
)
extern

Definition at line 341 of file functions.c.

342{
343 pstate->p_pre_columnref_hook = NULL;
346 /* no need to use p_coerce_param_hook */
347 pstate->p_ref_hook_state = pinfo;
348}
static Node * sql_fn_param_ref(ParseState *pstate, ParamRef *pref)
Definition functions.c:470
static Node * sql_fn_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var)
Definition functions.c:354
void * p_ref_hook_state
Definition parse_node.h:258
ParseParamRefHook p_paramref_hook
Definition parse_node.h:256
PreParseColumnRefHook p_pre_columnref_hook
Definition parse_node.h:254
PostParseColumnRefHook p_post_columnref_hook
Definition parse_node.h:255

References fb(), ParseState::p_paramref_hook, ParseState::p_post_columnref_hook, ParseState::p_pre_columnref_hook, ParseState::p_ref_hook_state, sql_fn_param_ref(), and sql_fn_post_column_ref().

Referenced by fmgr_sql_validator(), inline_function(), inline_sql_function_in_from(), interpret_AS_clause(), prepare_next_query(), and test_inline_in_from_support_func().