PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
functions.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "executor/functions.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_func.h"
#include "rewrite/rewriteHandler.h"
#include "storage/proc.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/funccache.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for functions.c:

Go to the source code of this file.

Data Structures

struct  DR_sqlfunction
 
struct  execution_state
 
struct  SQLFunctionHashEntry
 
struct  SQLFunctionCache
 
struct  SQLFunctionLink
 

Typedefs

typedef struct execution_state execution_state
 
typedef struct SQLFunctionHashEntry SQLFunctionHashEntry
 
typedef struct SQLFunctionCache SQLFunctionCache
 
typedef SQLFunctionCacheSQLFunctionCachePtr
 
typedef struct SQLFunctionLink SQLFunctionLink
 

Enumerations

enum  ExecStatus { F_EXEC_START , F_EXEC_RUN , F_EXEC_DONE }
 

Functions

static Nodesql_fn_param_ref (ParseState *pstate, ParamRef *pref)
 
static Nodesql_fn_post_column_ref (ParseState *pstate, ColumnRef *cref, Node *var)
 
static Nodesql_fn_make_param (SQLFunctionParseInfoPtr pinfo, int paramno, int location)
 
static Nodesql_fn_resolve_param_name (SQLFunctionParseInfoPtr pinfo, const char *paramname, int location)
 
static SQLFunctionCacheinit_sql_fcache (FunctionCallInfo fcinfo, bool lazyEvalOK)
 
static bool init_execution_state (SQLFunctionCachePtr fcache)
 
static void prepare_next_query (SQLFunctionHashEntry *func)
 
static void sql_compile_callback (FunctionCallInfo fcinfo, HeapTuple procedureTuple, const CachedFunctionHashKey *hashkey, CachedFunction *cfunc, bool forValidator)
 
static void sql_delete_callback (CachedFunction *cfunc)
 
static void sql_postrewrite_callback (List *querytree_list, void *arg)
 
static void postquel_start (execution_state *es, SQLFunctionCachePtr fcache)
 
static bool postquel_getnext (execution_state *es, SQLFunctionCachePtr fcache)
 
static void postquel_end (execution_state *es)
 
static void postquel_sub_params (SQLFunctionCachePtr fcache, FunctionCallInfo fcinfo)
 
static Datum postquel_get_single_result (TupleTableSlot *slot, FunctionCallInfo fcinfo, SQLFunctionCachePtr fcache, MemoryContext resultcontext)
 
static void sql_compile_error_callback (void *arg)
 
static void sql_exec_error_callback (void *arg)
 
static void ShutdownSQLFunction (Datum arg)
 
static void RemoveSQLFunctionLink (void *arg)
 
static void check_sql_fn_statement (List *queryTreeList)
 
static bool check_sql_stmt_retval (List *queryTreeList, Oid rettype, TupleDesc rettupdesc, char prokind, bool insertDroppedCols)
 
static bool coerce_fn_result_column (TargetEntry *src_tle, Oid res_type, int32 res_typmod, bool tlist_is_modifiable, List **upper_tlist, bool *upper_tlist_nontrivial)
 
static Listget_sql_fn_result_tlist (List *queryTreeList)
 
static void sqlfunction_startup (DestReceiver *self, int operation, TupleDesc typeinfo)
 
static bool sqlfunction_receive (TupleTableSlot *slot, DestReceiver *self)
 
static void sqlfunction_shutdown (DestReceiver *self)
 
static void sqlfunction_destroy (DestReceiver *self)
 
SQLFunctionParseInfoPtr prepare_sql_fn_parse_info (HeapTuple procedureTuple, Node *call_expr, Oid inputCollation)
 
void sql_fn_parser_setup (struct ParseState *pstate, SQLFunctionParseInfoPtr pinfo)
 
Datum fmgr_sql (PG_FUNCTION_ARGS)
 
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

◆ execution_state

◆ SQLFunctionCache

◆ SQLFunctionCachePtr

Definition at line 179 of file functions.c.

◆ SQLFunctionHashEntry

◆ SQLFunctionLink

Enumeration Type Documentation

◆ ExecStatus

enum ExecStatus
Enumerator
F_EXEC_START 
F_EXEC_RUN 
F_EXEC_DONE 

Definition at line 61 of file functions.c.

62{
ExecStatus
Definition: functions.c:62
@ F_EXEC_START
Definition: functions.c:63
@ F_EXEC_DONE
Definition: functions.c:63
@ F_EXEC_RUN
Definition: functions.c:63

Function Documentation

◆ check_sql_fn_retval()

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

Definition at line 2021 of file functions.c.

2025{
2026 List *queryTreeList;
2027
2028 /*
2029 * We consider only the last sublist of Query nodes, so that only the last
2030 * original statement is a candidate to produce the result. This is a
2031 * change from pre-v18 versions, which would back up to the last statement
2032 * that includes a canSetTag query, thus ignoring any ending statement(s)
2033 * that rewrite to DO INSTEAD NOTHING. That behavior was undocumented and
2034 * there seems no good reason for it, except that it was an artifact of
2035 * the original coding.
2036 *
2037 * If the function body is completely empty, handle that the same as if
2038 * the last query had rewritten to nothing.
2039 */
2040 if (queryTreeLists != NIL)
2041 queryTreeList = llast_node(List, queryTreeLists);
2042 else
2043 queryTreeList = NIL;
2044
2045 return check_sql_stmt_retval(queryTreeList,
2046 rettype, rettupdesc,
2047 prokind, insertDroppedCols);
2048}
static bool check_sql_stmt_retval(List *queryTreeList, Oid rettype, TupleDesc rettupdesc, char prokind, bool insertDroppedCols)
Definition: functions.c:2055
#define NIL
Definition: pg_list.h:68
#define llast_node(type, l)
Definition: pg_list.h:202
Definition: pg_list.h:54

References check_sql_stmt_retval(), llast_node, and NIL.

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

◆ check_sql_fn_statement()

static void check_sql_fn_statement ( List queryTreeList)
static

Definition at line 1957 of file functions.c.

1958{
1959 ListCell *lc;
1960
1961 foreach(lc, queryTreeList)
1962 {
1963 Query *query = lfirst_node(Query, lc);
1964
1965 /*
1966 * Disallow calling procedures with output arguments. The current
1967 * implementation would just throw the output values away, unless the
1968 * statement is the last one. Per SQL standard, we should assign the
1969 * output values by name. By disallowing this here, we preserve an
1970 * opportunity for future improvement.
1971 */
1972 if (query->commandType == CMD_UTILITY &&
1973 IsA(query->utilityStmt, CallStmt))
1974 {
1975 CallStmt *stmt = (CallStmt *) query->utilityStmt;
1976
1977 if (stmt->outargs != NIL)
1978 ereport(ERROR,
1979 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1980 errmsg("calling procedures with output arguments is not supported in SQL functions")));
1981 }
1982 }
1983}
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define stmt
Definition: indent_codes.h:59
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
@ CMD_UTILITY
Definition: nodes.h:276
#define lfirst_node(type, lc)
Definition: pg_list.h:176
CmdType commandType
Definition: parsenodes.h:121
Node * utilityStmt
Definition: parsenodes.h:136

References CMD_UTILITY, Query::commandType, ereport, errcode(), errmsg(), ERROR, if(), IsA, lfirst_node, NIL, stmt, and Query::utilityStmt.

Referenced by check_sql_fn_statements(), prepare_next_query(), and sql_postrewrite_callback().

◆ check_sql_fn_statements()

void check_sql_fn_statements ( List queryTreeLists)

Definition at line 1940 of file functions.c.

1941{
1942 ListCell *lc;
1943
1944 /* We are given a list of sublists of Queries */
1945 foreach(lc, queryTreeLists)
1946 {
1947 List *sublist = lfirst_node(List, lc);
1948
1949 check_sql_fn_statement(sublist);
1950 }
1951}
static void check_sql_fn_statement(List *queryTreeList)
Definition: functions.c:1957

References check_sql_fn_statement(), and lfirst_node.

Referenced by fmgr_sql_validator().

◆ check_sql_stmt_retval()

static bool check_sql_stmt_retval ( List queryTreeList,
Oid  rettype,
TupleDesc  rettupdesc,
char  prokind,
bool  insertDroppedCols 
)
static

Definition at line 2055 of file functions.c.

2058{
2059 bool is_tuple_result = false;
2060 Query *parse;
2061 ListCell *parse_cell;
2062 List *tlist;
2063 int tlistlen;
2064 bool tlist_is_modifiable;
2065 char fn_typtype;
2066 List *upper_tlist = NIL;
2067 bool upper_tlist_nontrivial = false;
2068 ListCell *lc;
2069
2070 /*
2071 * If it's declared to return VOID, we don't care what's in the function.
2072 * (This takes care of procedures with no output parameters, as well.)
2073 */
2074 if (rettype == VOIDOID)
2075 return false;
2076
2077 /*
2078 * Find the last canSetTag query in the list of Query nodes. This isn't
2079 * necessarily the last parsetree, because rule rewriting can insert
2080 * queries after what the user wrote.
2081 */
2082 parse = NULL;
2083 parse_cell = NULL;
2084 foreach(lc, queryTreeList)
2085 {
2086 Query *q = lfirst_node(Query, lc);
2087
2088 if (q->canSetTag)
2089 {
2090 parse = q;
2091 parse_cell = lc;
2092 }
2093 }
2094
2095 /*
2096 * If it's a plain SELECT, it returns whatever the targetlist says.
2097 * Otherwise, if it's INSERT/UPDATE/DELETE/MERGE with RETURNING, it
2098 * returns that. Otherwise, the function return type must be VOID.
2099 *
2100 * Note: eventually replace this test with QueryReturnsTuples? We'd need
2101 * a more general method of determining the output type, though. Also, it
2102 * seems too dangerous to consider FETCH or EXECUTE as returning a
2103 * determinable rowtype, since they depend on relatively short-lived
2104 * entities.
2105 */
2106 if (parse &&
2107 parse->commandType == CMD_SELECT)
2108 {
2109 tlist = parse->targetList;
2110 /* tlist is modifiable unless it's a dummy in a setop query */
2111 tlist_is_modifiable = (parse->setOperations == NULL);
2112 }
2113 else if (parse &&
2114 (parse->commandType == CMD_INSERT ||
2115 parse->commandType == CMD_UPDATE ||
2116 parse->commandType == CMD_DELETE ||
2117 parse->commandType == CMD_MERGE) &&
2118 parse->returningList)
2119 {
2120 tlist = parse->returningList;
2121 /* returningList can always be modified */
2122 tlist_is_modifiable = true;
2123 }
2124 else
2125 {
2126 /* Last statement is a utility command, or it rewrote to nothing */
2127 ereport(ERROR,
2128 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2129 errmsg("return type mismatch in function declared to return %s",
2130 format_type_be(rettype)),
2131 errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.")));
2132 return false; /* keep compiler quiet */
2133 }
2134
2135 /*
2136 * OK, check that the targetlist returns something matching the declared
2137 * type, and modify it if necessary. If possible, we insert any coercion
2138 * steps right into the final statement's targetlist. However, that might
2139 * risk changes in the statement's semantics --- we can't safely change
2140 * the output type of a grouping column, for instance. In such cases we
2141 * handle coercions by inserting an extra level of Query that effectively
2142 * just does a projection.
2143 */
2144
2145 /*
2146 * Count the non-junk entries in the result targetlist.
2147 */
2148 tlistlen = ExecCleanTargetListLength(tlist);
2149
2150 fn_typtype = get_typtype(rettype);
2151
2152 if (fn_typtype == TYPTYPE_BASE ||
2153 fn_typtype == TYPTYPE_DOMAIN ||
2154 fn_typtype == TYPTYPE_ENUM ||
2155 fn_typtype == TYPTYPE_RANGE ||
2156 fn_typtype == TYPTYPE_MULTIRANGE)
2157 {
2158 /*
2159 * For scalar-type returns, the target list must have exactly one
2160 * non-junk entry, and its type must be coercible to rettype.
2161 */
2162 TargetEntry *tle;
2163
2164 if (tlistlen != 1)
2165 ereport(ERROR,
2166 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2167 errmsg("return type mismatch in function declared to return %s",
2168 format_type_be(rettype)),
2169 errdetail("Final statement must return exactly one column.")));
2170
2171 /* We assume here that non-junk TLEs must come first in tlists */
2172 tle = (TargetEntry *) linitial(tlist);
2173 Assert(!tle->resjunk);
2174
2175 if (!coerce_fn_result_column(tle, rettype, -1,
2176 tlist_is_modifiable,
2177 &upper_tlist,
2178 &upper_tlist_nontrivial))
2179 ereport(ERROR,
2180 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2181 errmsg("return type mismatch in function declared to return %s",
2182 format_type_be(rettype)),
2183 errdetail("Actual return type is %s.",
2184 format_type_be(exprType((Node *) tle->expr)))));
2185 }
2186 else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
2187 {
2188 /*
2189 * Returns a rowtype.
2190 *
2191 * Note that we will not consider a domain over composite to be a
2192 * "rowtype" return type; it goes through the scalar case above. This
2193 * is because we only provide column-by-column implicit casting, and
2194 * will not cast the complete record result. So the only way to
2195 * produce a domain-over-composite result is to compute it as an
2196 * explicit single-column result. The single-composite-column code
2197 * path just below could handle such cases, but it won't be reached.
2198 */
2199 int tupnatts; /* physical number of columns in tuple */
2200 int tuplogcols; /* # of nondeleted columns in tuple */
2201 int colindex; /* physical column index */
2202
2203 /*
2204 * If the target list has one non-junk entry, and that expression has
2205 * or can be coerced to the declared return type, take it as the
2206 * result. This allows, for example, 'SELECT func2()', where func2
2207 * has the same composite return type as the function that's calling
2208 * it. This provision creates some ambiguity --- maybe the expression
2209 * was meant to be the lone field of the composite result --- but it
2210 * works well enough as long as we don't get too enthusiastic about
2211 * inventing coercions from scalar to composite types.
2212 *
2213 * XXX Note that if rettype is RECORD and the expression is of a named
2214 * composite type, or vice versa, this coercion will succeed, whether
2215 * or not the record type really matches. For the moment we rely on
2216 * runtime type checking to catch any discrepancy, but it'd be nice to
2217 * do better at parse time.
2218 *
2219 * We must *not* do this for a procedure, however. Procedures with
2220 * output parameter(s) have rettype RECORD, and the CALL code expects
2221 * to get results corresponding to the list of output parameters, even
2222 * when there's just one parameter that's composite.
2223 */
2224 if (tlistlen == 1 && prokind != PROKIND_PROCEDURE)
2225 {
2226 TargetEntry *tle = (TargetEntry *) linitial(tlist);
2227
2228 Assert(!tle->resjunk);
2229 if (coerce_fn_result_column(tle, rettype, -1,
2230 tlist_is_modifiable,
2231 &upper_tlist,
2232 &upper_tlist_nontrivial))
2233 {
2234 /* Note that we're NOT setting is_tuple_result */
2235 goto tlist_coercion_finished;
2236 }
2237 }
2238
2239 /*
2240 * If the caller didn't provide an expected tupdesc, we can't do any
2241 * further checking. Assume we're returning the whole tuple.
2242 */
2243 if (rettupdesc == NULL)
2244 return true;
2245
2246 /*
2247 * Verify that the targetlist matches the return tuple type. We scan
2248 * the non-resjunk columns, and coerce them if necessary to match the
2249 * datatypes of the non-deleted attributes. For deleted attributes,
2250 * insert NULL result columns if the caller asked for that.
2251 */
2252 tupnatts = rettupdesc->natts;
2253 tuplogcols = 0; /* we'll count nondeleted cols as we go */
2254 colindex = 0;
2255
2256 foreach(lc, tlist)
2257 {
2258 TargetEntry *tle = (TargetEntry *) lfirst(lc);
2259 Form_pg_attribute attr;
2260
2261 /* resjunk columns can simply be ignored */
2262 if (tle->resjunk)
2263 continue;
2264
2265 do
2266 {
2267 colindex++;
2268 if (colindex > tupnatts)
2269 ereport(ERROR,
2270 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2271 errmsg("return type mismatch in function declared to return %s",
2272 format_type_be(rettype)),
2273 errdetail("Final statement returns too many columns.")));
2274 attr = TupleDescAttr(rettupdesc, colindex - 1);
2275 if (attr->attisdropped && insertDroppedCols)
2276 {
2277 Expr *null_expr;
2278
2279 /* The type of the null we insert isn't important */
2280 null_expr = (Expr *) makeConst(INT4OID,
2281 -1,
2282 InvalidOid,
2283 sizeof(int32),
2284 (Datum) 0,
2285 true, /* isnull */
2286 true /* byval */ );
2287 upper_tlist = lappend(upper_tlist,
2288 makeTargetEntry(null_expr,
2289 list_length(upper_tlist) + 1,
2290 NULL,
2291 false));
2292 upper_tlist_nontrivial = true;
2293 }
2294 } while (attr->attisdropped);
2295 tuplogcols++;
2296
2297 if (!coerce_fn_result_column(tle,
2298 attr->atttypid, attr->atttypmod,
2299 tlist_is_modifiable,
2300 &upper_tlist,
2301 &upper_tlist_nontrivial))
2302 ereport(ERROR,
2303 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2304 errmsg("return type mismatch in function declared to return %s",
2305 format_type_be(rettype)),
2306 errdetail("Final statement returns %s instead of %s at column %d.",
2307 format_type_be(exprType((Node *) tle->expr)),
2308 format_type_be(attr->atttypid),
2309 tuplogcols)));
2310 }
2311
2312 /* remaining columns in rettupdesc had better all be dropped */
2313 for (colindex++; colindex <= tupnatts; colindex++)
2314 {
2315 if (!TupleDescCompactAttr(rettupdesc, colindex - 1)->attisdropped)
2316 ereport(ERROR,
2317 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2318 errmsg("return type mismatch in function declared to return %s",
2319 format_type_be(rettype)),
2320 errdetail("Final statement returns too few columns.")));
2321 if (insertDroppedCols)
2322 {
2323 Expr *null_expr;
2324
2325 /* The type of the null we insert isn't important */
2326 null_expr = (Expr *) makeConst(INT4OID,
2327 -1,
2328 InvalidOid,
2329 sizeof(int32),
2330 (Datum) 0,
2331 true, /* isnull */
2332 true /* byval */ );
2333 upper_tlist = lappend(upper_tlist,
2334 makeTargetEntry(null_expr,
2335 list_length(upper_tlist) + 1,
2336 NULL,
2337 false));
2338 upper_tlist_nontrivial = true;
2339 }
2340 }
2341
2342 /* Report that we are returning entire tuple result */
2343 is_tuple_result = true;
2344 }
2345 else
2346 ereport(ERROR,
2347 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2348 errmsg("return type %s is not supported for SQL functions",
2349 format_type_be(rettype))));
2350
2351tlist_coercion_finished:
2352
2353 /*
2354 * If necessary, modify the final Query by injecting an extra Query level
2355 * that just performs a projection. (It'd be dubious to do this to a
2356 * non-SELECT query, but we never have to; RETURNING lists can always be
2357 * modified in-place.)
2358 */
2359 if (upper_tlist_nontrivial)
2360 {
2361 Query *newquery;
2362 List *colnames;
2363 RangeTblEntry *rte;
2364 RangeTblRef *rtr;
2365
2366 Assert(parse->commandType == CMD_SELECT);
2367
2368 /* Most of the upper Query struct can be left as zeroes/nulls */
2369 newquery = makeNode(Query);
2370 newquery->commandType = CMD_SELECT;
2371 newquery->querySource = parse->querySource;
2372 newquery->canSetTag = true;
2373 newquery->targetList = upper_tlist;
2374
2375 /* We need a moderately realistic colnames list for the subquery RTE */
2376 colnames = NIL;
2377 foreach(lc, parse->targetList)
2378 {
2379 TargetEntry *tle = (TargetEntry *) lfirst(lc);
2380
2381 if (tle->resjunk)
2382 continue;
2383 colnames = lappend(colnames,
2384 makeString(tle->resname ? tle->resname : ""));
2385 }
2386
2387 /* Build a suitable RTE for the subquery */
2388 rte = makeNode(RangeTblEntry);
2389 rte->rtekind = RTE_SUBQUERY;
2390 rte->subquery = parse;
2391 rte->eref = rte->alias = makeAlias("*SELECT*", colnames);
2392 rte->lateral = false;
2393 rte->inh = false;
2394 rte->inFromCl = true;
2395 newquery->rtable = list_make1(rte);
2396
2397 rtr = makeNode(RangeTblRef);
2398 rtr->rtindex = 1;
2399 newquery->jointree = makeFromExpr(list_make1(rtr), NULL);
2400
2401 /*
2402 * Make sure the new query is marked as having row security if the
2403 * original one does.
2404 */
2405 newquery->hasRowSecurity = parse->hasRowSecurity;
2406
2407 /* Replace original query in the correct element of the query list */
2408 lfirst(parse_cell) = newquery;
2409 }
2410
2411 return is_tuple_result;
2412}
int32_t int32
Definition: c.h:498
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int ExecCleanTargetListLength(List *targetlist)
Definition: execUtils.c:1186
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
static bool coerce_fn_result_column(TargetEntry *src_tle, Oid res_type, int32 res_typmod, bool tlist_is_modifiable, List **upper_tlist, bool *upper_tlist_nontrivial)
Definition: functions.c:2425
Assert(PointerIsAligned(start, uint64))
List * lappend(List *list, void *datum)
Definition: list.c:339
char get_typtype(Oid typid)
Definition: lsyscache.c:2769
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:438
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:336
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:289
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:350
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
@ CMD_MERGE
Definition: nodes.h:275
@ CMD_INSERT
Definition: nodes.h:273
@ CMD_DELETE
Definition: nodes.h:274
@ CMD_UPDATE
Definition: nodes.h:272
@ CMD_SELECT
Definition: nodes.h:271
#define makeNode(_type_)
Definition: nodes.h:161
@ RTE_SUBQUERY
Definition: parsenodes.h:1027
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define list_make1(x1)
Definition: pg_list.h:212
#define linitial(l)
Definition: pg_list.h:178
uintptr_t Datum
Definition: postgres.h:69
#define InvalidOid
Definition: postgres_ext.h:35
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
Definition: nodes.h:135
FromExpr * jointree
Definition: parsenodes.h:177
List * rtable
Definition: parsenodes.h:170
List * targetList
Definition: parsenodes.h:193
Query * subquery
Definition: parsenodes.h:1118
RTEKind rtekind
Definition: parsenodes.h:1061
Expr * expr
Definition: primnodes.h:2219
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:175
String * makeString(char *str)
Definition: value.c:63

References Assert(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_SELECT, CMD_UPDATE, coerce_fn_result_column(), Query::commandType, ereport, errcode(), errdetail(), errmsg(), ERROR, ExecCleanTargetListLength(), TargetEntry::expr, exprType(), format_type_be(), get_typtype(), RangeTblEntry::inh, InvalidOid, Query::jointree, lappend(), lfirst, lfirst_node, linitial, list_length(), list_make1, makeAlias(), makeConst(), makeFromExpr(), makeNode, makeString(), makeTargetEntry(), TupleDescData::natts, NIL, parse(), Query::rtable, RTE_SUBQUERY, RangeTblEntry::rtekind, RangeTblRef::rtindex, RangeTblEntry::subquery, Query::targetList, TupleDescAttr(), and TupleDescCompactAttr().

Referenced by check_sql_fn_retval(), prepare_next_query(), and sql_postrewrite_callback().

◆ coerce_fn_result_column()

static bool coerce_fn_result_column ( TargetEntry src_tle,
Oid  res_type,
int32  res_typmod,
bool  tlist_is_modifiable,
List **  upper_tlist,
bool *  upper_tlist_nontrivial 
)
static

Definition at line 2425 of file functions.c.

2431{
2432 TargetEntry *new_tle;
2433 Expr *new_tle_expr;
2434 Node *cast_result;
2435
2436 /*
2437 * If the TLE has a sortgroupref marking, don't change it, as it probably
2438 * is referenced by ORDER BY, DISTINCT, etc, and changing its type would
2439 * break query semantics. Otherwise, it's safe to modify in-place unless
2440 * the query as a whole has issues with that.
2441 */
2442 if (tlist_is_modifiable && src_tle->ressortgroupref == 0)
2443 {
2444 /* OK to modify src_tle in place, if necessary */
2445 cast_result = coerce_to_target_type(NULL,
2446 (Node *) src_tle->expr,
2447 exprType((Node *) src_tle->expr),
2448 res_type, res_typmod,
2451 -1);
2452 if (cast_result == NULL)
2453 return false;
2454 assign_expr_collations(NULL, cast_result);
2455 src_tle->expr = (Expr *) cast_result;
2456 /* Make a Var referencing the possibly-modified TLE */
2457 new_tle_expr = (Expr *) makeVarFromTargetEntry(1, src_tle);
2458 }
2459 else
2460 {
2461 /* Any casting must happen in the upper tlist */
2462 Var *var = makeVarFromTargetEntry(1, src_tle);
2463
2464 cast_result = coerce_to_target_type(NULL,
2465 (Node *) var,
2466 var->vartype,
2467 res_type, res_typmod,
2470 -1);
2471 if (cast_result == NULL)
2472 return false;
2473 assign_expr_collations(NULL, cast_result);
2474 /* Did the coercion actually do anything? */
2475 if (cast_result != (Node *) var)
2476 *upper_tlist_nontrivial = true;
2477 new_tle_expr = (Expr *) cast_result;
2478 }
2479 new_tle = makeTargetEntry(new_tle_expr,
2480 list_length(*upper_tlist) + 1,
2481 src_tle->resname, false);
2482 *upper_tlist = lappend(*upper_tlist, new_tle);
2483 return true;
2484}
Var * makeVarFromTargetEntry(int varno, TargetEntry *tle)
Definition: makefuncs.c:107
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
void assign_expr_collations(ParseState *pstate, Node *expr)
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:753
@ COERCION_ASSIGNMENT
Definition: primnodes.h:732
Index ressortgroupref
Definition: primnodes.h:2225
Definition: primnodes.h:262

References assign_expr_collations(), COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, TargetEntry::expr, exprType(), lappend(), list_length(), makeTargetEntry(), makeVarFromTargetEntry(), and TargetEntry::ressortgroupref.

Referenced by check_sql_stmt_retval().

◆ CreateSQLFunctionDestReceiver()

DestReceiver * CreateSQLFunctionDestReceiver ( void  )

Definition at line 2522 of file functions.c.

2523{
2525
2530 self->pub.mydest = DestSQLFunction;
2531
2532 /* private fields will be set by postquel_start */
2533
2534 return (DestReceiver *) self;
2535}
@ DestSQLFunction
Definition: dest.h:96
static void sqlfunction_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: functions.c:2541
static bool sqlfunction_receive(TupleTableSlot *slot, DestReceiver *self)
Definition: functions.c:2550
static void sqlfunction_destroy(DestReceiver *self)
Definition: functions.c:2576
static void sqlfunction_shutdown(DestReceiver *self)
Definition: functions.c:2567
void * palloc0(Size size)
Definition: mcxt.c:1970
DestReceiver pub
Definition: functions.c:46
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(), 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  )

Definition at line 1444 of file functions.c.

1445{
1446 SQLFunctionCachePtr fcache;
1447 SQLFunctionLink *flink;
1448 ErrorContextCallback sqlerrcontext;
1449 MemoryContext tscontext;
1450 MemoryContext oldcontext;
1451 bool randomAccess;
1452 bool lazyEvalOK;
1453 bool pushed_snapshot;
1454 execution_state *es;
1455 TupleTableSlot *slot;
1456 Datum result;
1457
1458 /* Check call context */
1459 if (fcinfo->flinfo->fn_retset)
1460 {
1461 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1462
1463 /*
1464 * For simplicity, we require callers to support both set eval modes.
1465 * There are cases where we must use one or must use the other, and
1466 * it's not really worthwhile to postpone the check till we know. But
1467 * note we do not require caller to provide an expectedDesc.
1468 */
1469 if (!rsi || !IsA(rsi, ReturnSetInfo) ||
1470 (rsi->allowedModes & SFRM_ValuePerCall) == 0 ||
1471 (rsi->allowedModes & SFRM_Materialize) == 0)
1472 ereport(ERROR,
1473 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1474 errmsg("set-valued function called in context that cannot accept a set")));
1475 randomAccess = rsi->allowedModes & SFRM_Materialize_Random;
1476 lazyEvalOK = !(rsi->allowedModes & SFRM_Materialize_Preferred);
1477 /* tuplestore must have query lifespan */
1478 tscontext = rsi->econtext->ecxt_per_query_memory;
1479 }
1480 else
1481 {
1482 randomAccess = false;
1483 lazyEvalOK = true;
1484 /* tuplestore needn't outlive caller context */
1485 tscontext = CurrentMemoryContext;
1486 }
1487
1488 /*
1489 * Initialize fcache if starting a fresh execution.
1490 */
1491 fcache = init_sql_fcache(fcinfo, lazyEvalOK);
1492 /* init_sql_fcache also ensures we have a SQLFunctionLink */
1493 flink = fcinfo->flinfo->fn_extra;
1494
1495 /*
1496 * Now we can set up error traceback support for ereport()
1497 */
1498 sqlerrcontext.callback = sql_exec_error_callback;
1499 sqlerrcontext.arg = fcache;
1500 sqlerrcontext.previous = error_context_stack;
1501 error_context_stack = &sqlerrcontext;
1502
1503 /*
1504 * Build tuplestore to hold results, if we don't have one already. Make
1505 * sure it's in a suitable context.
1506 */
1507 oldcontext = MemoryContextSwitchTo(tscontext);
1508
1509 if (!fcache->tstore)
1510 fcache->tstore = tuplestore_begin_heap(randomAccess, false, work_mem);
1511
1512 /*
1513 * Switch to context in which the fcache lives. The sub-executor is
1514 * responsible for deleting per-tuple information. (XXX in the case of a
1515 * long-lived FmgrInfo, this policy potentially causes memory leakage, but
1516 * it's not very clear where we could keep stuff instead. Fortunately,
1517 * there are few if any cases where set-returning functions are invoked
1518 * via FmgrInfos that would outlive the calling query.)
1519 */
1521
1522 /*
1523 * Find first unfinished execution_state. If none, advance to the next
1524 * query in function.
1525 */
1526 do
1527 {
1528 es = fcache->eslist;
1529 while (es && es->status == F_EXEC_DONE)
1530 es = es->next;
1531 if (es)
1532 break;
1533 } while (init_execution_state(fcache));
1534
1535 /*
1536 * Execute each command in the function one after another until we either
1537 * run out of commands or get a result row from a lazily-evaluated SELECT.
1538 *
1539 * Notes about snapshot management:
1540 *
1541 * In a read-only function, we just use the surrounding query's snapshot.
1542 *
1543 * In a non-read-only function, we rely on the fact that we'll never
1544 * suspend execution between queries of the function: the only reason to
1545 * suspend execution before completion is if we are returning a row from a
1546 * lazily-evaluated SELECT. So, when first entering this loop, we'll
1547 * either start a new query (and push a fresh snapshot) or re-establish
1548 * the active snapshot from the existing query descriptor. If we need to
1549 * start a new query in a subsequent execution of the loop, either we need
1550 * a fresh snapshot (and pushed_snapshot is false) or the existing
1551 * snapshot is on the active stack and we can just bump its command ID.
1552 */
1553 pushed_snapshot = false;
1554 while (es)
1555 {
1556 bool completed;
1557
1558 if (es->status == F_EXEC_START)
1559 {
1560 /*
1561 * If not read-only, be sure to advance the command counter for
1562 * each command, so that all work to date in this transaction is
1563 * visible. Take a new snapshot if we don't have one yet,
1564 * otherwise just bump the command ID in the existing snapshot.
1565 */
1566 if (!fcache->func->readonly_func)
1567 {
1569 if (!pushed_snapshot)
1570 {
1572 pushed_snapshot = true;
1573 }
1574 else
1576 }
1577
1578 postquel_start(es, fcache);
1579 }
1580 else if (!fcache->func->readonly_func && !pushed_snapshot)
1581 {
1582 /* Re-establish active snapshot when re-entering function */
1584 pushed_snapshot = true;
1585 }
1586
1587 completed = postquel_getnext(es, fcache);
1588
1589 /*
1590 * If we ran the command to completion, we can shut it down now. Any
1591 * row(s) we need to return are safely stashed in the tuplestore, and
1592 * we want to be sure that, for example, AFTER triggers get fired
1593 * before we return anything. Also, if the function doesn't return
1594 * set, we can shut it down anyway because it must be a SELECT and we
1595 * don't care about fetching any more result rows.
1596 */
1597 if (completed || !fcache->func->returnsSet)
1598 postquel_end(es);
1599
1600 /*
1601 * Break from loop if we didn't shut down (implying we got a
1602 * lazily-evaluated row). Otherwise we'll press on till the whole
1603 * function is done, relying on the tuplestore to keep hold of the
1604 * data to eventually be returned. This is necessary since an
1605 * INSERT/UPDATE/DELETE RETURNING that sets the result might be
1606 * followed by additional rule-inserted commands, and we want to
1607 * finish doing all those commands before we return anything.
1608 */
1609 if (es->status != F_EXEC_DONE)
1610 break;
1611
1612 /*
1613 * Advance to next execution_state, and perhaps next query.
1614 */
1615 es = es->next;
1616 while (!es)
1617 {
1618 /*
1619 * Flush the current snapshot so that we will take a new one for
1620 * the new query list. This ensures that new snaps are taken at
1621 * original-query boundaries, matching the behavior of interactive
1622 * execution.
1623 */
1624 if (pushed_snapshot)
1625 {
1627 pushed_snapshot = false;
1628 }
1629
1630 if (!init_execution_state(fcache))
1631 break; /* end of function */
1632
1633 es = fcache->eslist;
1634 }
1635 }
1636
1637 /*
1638 * The tuplestore now contains whatever row(s) we are supposed to return.
1639 */
1640 if (fcache->func->returnsSet)
1641 {
1642 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1643
1644 if (es)
1645 {
1646 /*
1647 * If we stopped short of being done, we must have a lazy-eval
1648 * row.
1649 */
1650 Assert(es->lazyEval);
1651 /* Re-use the junkfilter's output slot to fetch back the tuple */
1652 Assert(fcache->junkFilter);
1653 slot = fcache->junkFilter->jf_resultSlot;
1654 if (!tuplestore_gettupleslot(fcache->tstore, true, false, slot))
1655 elog(ERROR, "failed to fetch lazy-eval tuple");
1656 /* Extract the result as a datum, and copy out from the slot */
1657 result = postquel_get_single_result(slot, fcinfo,
1658 fcache, oldcontext);
1659 /* Clear the tuplestore, but keep it for next time */
1660 /* NB: this might delete the slot's content, but we don't care */
1661 tuplestore_clear(fcache->tstore);
1662
1663 /*
1664 * Let caller know we're not finished.
1665 */
1667
1668 /*
1669 * Ensure we will get shut down cleanly if the exprcontext is not
1670 * run to completion.
1671 */
1672 if (!fcache->shutdown_reg)
1673 {
1676 PointerGetDatum(flink));
1677 fcache->shutdown_reg = true;
1678 }
1679 }
1680 else if (fcache->lazyEval)
1681 {
1682 /*
1683 * We are done with a lazy evaluation. Clean up.
1684 */
1685 tuplestore_clear(fcache->tstore);
1686
1687 /*
1688 * Let caller know we're finished.
1689 */
1690 rsi->isDone = ExprEndResult;
1691
1692 fcinfo->isnull = true;
1693 result = (Datum) 0;
1694
1695 /* Deregister shutdown callback, if we made one */
1696 if (fcache->shutdown_reg)
1697 {
1700 PointerGetDatum(flink));
1701 fcache->shutdown_reg = false;
1702 }
1703 }
1704 else
1705 {
1706 /*
1707 * We are done with a non-lazy evaluation. Return whatever is in
1708 * the tuplestore. (It is now caller's responsibility to free the
1709 * tuplestore when done.)
1710 */
1712 rsi->setResult = fcache->tstore;
1713 fcache->tstore = NULL;
1714 /* must copy desc because execSRF.c will free it */
1715 if (fcache->junkFilter)
1716 {
1717 /* setDesc must be allocated in suitable context */
1718 MemoryContextSwitchTo(tscontext);
1721 }
1722
1723 fcinfo->isnull = true;
1724 result = (Datum) 0;
1725
1726 /* Deregister shutdown callback, if we made one */
1727 if (fcache->shutdown_reg)
1728 {
1731 PointerGetDatum(flink));
1732 fcache->shutdown_reg = false;
1733 }
1734 }
1735 }
1736 else
1737 {
1738 /*
1739 * Non-set function. If we got a row, return it; else return NULL.
1740 */
1741 if (fcache->junkFilter)
1742 {
1743 /* Re-use the junkfilter's output slot to fetch back the tuple */
1744 slot = fcache->junkFilter->jf_resultSlot;
1745 if (tuplestore_gettupleslot(fcache->tstore, true, false, slot))
1746 result = postquel_get_single_result(slot, fcinfo,
1747 fcache, oldcontext);
1748 else
1749 {
1750 fcinfo->isnull = true;
1751 result = (Datum) 0;
1752 }
1753 }
1754 else
1755 {
1756 /* Should only get here for VOID functions and procedures */
1757 Assert(fcache->func->rettype == VOIDOID);
1758 fcinfo->isnull = true;
1759 result = (Datum) 0;
1760 }
1761
1762 /* Clear the tuplestore, but keep it for next time */
1763 tuplestore_clear(fcache->tstore);
1764 }
1765
1766 /* Pop snapshot if we have pushed one */
1767 if (pushed_snapshot)
1769
1770 MemoryContextSwitchTo(oldcontext);
1771
1772 /*
1773 * If we've gone through every command in the function, we are done.
1774 * Release the cache to start over again on next call.
1775 */
1776 if (es == NULL)
1777 {
1778 if (fcache->tstore)
1779 tuplestore_end(fcache->tstore);
1780 Assert(fcache->cplan == NULL);
1781 flink->fcache = NULL;
1783 }
1784
1785 error_context_stack = sqlerrcontext.previous;
1786
1787 return result;
1788}
ErrorContextCallback * error_context_stack
Definition: elog.c:95
#define elog(elevel,...)
Definition: elog.h:226
void UnregisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:990
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:964
@ ExprMultipleResult
Definition: execnodes.h:323
@ ExprEndResult
Definition: execnodes.h:324
@ SFRM_Materialize_Preferred
Definition: execnodes.h:338
@ SFRM_ValuePerCall
Definition: execnodes.h:335
@ SFRM_Materialize_Random
Definition: execnodes.h:337
@ SFRM_Materialize
Definition: execnodes.h:336
static bool postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
Definition: functions.c:1290
static void postquel_end(execution_state *es)
Definition: functions.c:1325
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
Definition: functions.c:1226
static bool init_execution_state(SQLFunctionCachePtr fcache)
Definition: functions.c:657
static Datum postquel_get_single_result(TupleTableSlot *slot, FunctionCallInfo fcinfo, SQLFunctionCachePtr fcache, MemoryContext resultcontext)
Definition: functions.c:1401
static void sql_exec_error_callback(void *arg)
Definition: functions.c:1829
static void ShutdownSQLFunction(Datum arg)
Definition: functions.c:1867
static SQLFunctionCache * init_sql_fcache(FunctionCallInfo fcinfo, bool lazyEvalOK)
Definition: functions.c:537
int work_mem
Definition: globals.c:132
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:485
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:271
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:669
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:731
void PopActiveSnapshot(void)
Definition: snapmgr.c:762
struct ErrorContextCallback * previous
Definition: elog.h:297
void(* callback)(void *arg)
Definition: elog.h:298
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:275
TupleDesc jf_cleanTupType
Definition: execnodes.h:414
TupleTableSlot * jf_resultSlot
Definition: execnodes.h:416
Snapshot snapshot
Definition: execdesc.h:40
SetFunctionReturnMode returnMode
Definition: execnodes.h:355
ExprContext * econtext
Definition: execnodes.h:351
TupleDesc setDesc
Definition: execnodes.h:359
Tuplestorestate * setResult
Definition: execnodes.h:358
int allowedModes
Definition: execnodes.h:353
ExprDoneCond isDone
Definition: execnodes.h:356
MemoryContext fcontext
Definition: functions.c:175
execution_state * eslist
Definition: functions.c:169
SQLFunctionHashEntry * func
Definition: functions.c:148
CachedPlan * cplan
Definition: functions.c:167
JunkFilter * junkFilter
Definition: functions.c:158
Tuplestorestate * tstore
Definition: functions.c:156
ExecStatus status
Definition: functions.c:69
struct execution_state * next
Definition: functions.c:68
QueryDesc * qd
Definition: functions.c:73
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:245
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1130
void tuplestore_clear(Tuplestorestate *state)
Definition: tuplestore.c:430
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:330
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:492
void CommandCounterIncrement(void)
Definition: xact.c:1100

References ReturnSetInfo::allowedModes, ErrorContextCallback::arg, Assert(), ErrorContextCallback::callback, CommandCounterIncrement(), SQLFunctionCache::cplan, CreateTupleDescCopy(), CurrentMemoryContext, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, elog, ereport, errcode(), errmsg(), ERROR, error_context_stack, SQLFunctionCache::eslist, ExprEndResult, ExprMultipleResult, F_EXEC_DONE, F_EXEC_START, SQLFunctionLink::fcache, SQLFunctionCache::fcontext, SQLFunctionCache::func, GetTransactionSnapshot(), if(), init_execution_state(), init_sql_fcache(), IsA, ReturnSetInfo::isDone, JunkFilter::jf_cleanTupType, JunkFilter::jf_resultSlot, SQLFunctionCache::junkFilter, execution_state::lazyEval, SQLFunctionCache::lazyEval, MemoryContextDelete(), MemoryContextSwitchTo(), execution_state::next, PointerGetDatum(), PopActiveSnapshot(), postquel_end(), postquel_get_single_result(), postquel_getnext(), postquel_start(), ErrorContextCallback::previous, PushActiveSnapshot(), execution_state::qd, SQLFunctionHashEntry::readonly_func, RegisterExprContextCallback(), SQLFunctionHashEntry::rettype, ReturnSetInfo::returnMode, SQLFunctionHashEntry::returnsSet, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SFRM_Materialize_Preferred, SFRM_Materialize_Random, SFRM_ValuePerCall, SQLFunctionCache::shutdown_reg, ShutdownSQLFunction(), QueryDesc::snapshot, sql_exec_error_callback(), execution_state::status, SQLFunctionCache::tstore, tuplestore_begin_heap(), tuplestore_clear(), tuplestore_end(), tuplestore_gettupleslot(), UnregisterExprContextCallback(), UpdateActiveSnapshotCommandId(), and work_mem.

Referenced by fmgr_info_cxt_security().

◆ get_sql_fn_result_tlist()

static List * get_sql_fn_result_tlist ( List queryTreeList)
static

Definition at line 2491 of file functions.c.

2492{
2493 Query *parse = NULL;
2494 ListCell *lc;
2495
2496 foreach(lc, queryTreeList)
2497 {
2498 Query *q = lfirst_node(Query, lc);
2499
2500 if (q->canSetTag)
2501 parse = q;
2502 }
2503 if (parse &&
2504 parse->commandType == CMD_SELECT)
2505 return parse->targetList;
2506 else if (parse &&
2507 (parse->commandType == CMD_INSERT ||
2508 parse->commandType == CMD_UPDATE ||
2509 parse->commandType == CMD_DELETE ||
2510 parse->commandType == CMD_MERGE) &&
2511 parse->returningList)
2512 return parse->returningList;
2513 else
2514 return NIL;
2515}

References CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_SELECT, CMD_UPDATE, lfirst_node, NIL, and parse().

Referenced by init_execution_state().

◆ init_execution_state()

static bool init_execution_state ( SQLFunctionCachePtr  fcache)
static

Definition at line 657 of file functions.c.

658{
659 CachedPlanSource *plansource;
660 execution_state *preves = NULL;
661 execution_state *lasttages = NULL;
662 ListCell *lc;
663
664 /*
665 * Clean up after previous query, if there was one. Note that we just
666 * leak the old execution_state records until end of function execution;
667 * there aren't likely to be enough of them to matter.
668 */
669 if (fcache->cplan)
670 {
671 ReleaseCachedPlan(fcache->cplan, fcache->cowner);
672 fcache->cplan = NULL;
673 }
674 fcache->eslist = NULL;
675
676 /*
677 * Get the next CachedPlanSource, or stop if there are no more. We might
678 * need to create the next CachedPlanSource; if so, advance
679 * error_query_index first, so that errors detected in prepare_next_query
680 * are blamed on the right statement.
681 */
682 if (fcache->next_query_index >= list_length(fcache->func->plansource_list))
683 {
684 if (fcache->next_query_index >= fcache->func->num_queries)
685 return false;
686 fcache->error_query_index++;
687 prepare_next_query(fcache->func);
688 }
689 else
690 fcache->error_query_index++;
691
692 plansource = (CachedPlanSource *) list_nth(fcache->func->plansource_list,
693 fcache->next_query_index);
694 fcache->next_query_index++;
695
696 /*
697 * Generate plans for the query or queries within this CachedPlanSource.
698 * Register the CachedPlan with the current resource owner. (Saving
699 * cowner here is mostly paranoia, but this way we needn't assume that
700 * CurrentResourceOwner will be the same when ShutdownSQLFunction runs.)
701 */
703 fcache->cplan = GetCachedPlan(plansource,
704 fcache->paramLI,
705 fcache->cowner,
706 NULL);
707
708 /*
709 * Build execution_state list to match the number of contained plans.
710 */
711 foreach(lc, fcache->cplan->stmt_list)
712 {
714 execution_state *newes;
715
716 /*
717 * Precheck all commands for validity in a function. This should
718 * generally match the restrictions spi.c applies.
719 */
720 if (stmt->commandType == CMD_UTILITY)
721 {
722 if (IsA(stmt->utilityStmt, CopyStmt) &&
723 ((CopyStmt *) stmt->utilityStmt)->filename == NULL)
725 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
726 errmsg("cannot COPY to/from client in an SQL function")));
727
728 if (IsA(stmt->utilityStmt, TransactionStmt))
730 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
731 /* translator: %s is a SQL statement name */
732 errmsg("%s is not allowed in an SQL function",
733 CreateCommandName(stmt->utilityStmt))));
734 }
735
736 if (fcache->func->readonly_func && !CommandIsReadOnly(stmt))
738 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
739 /* translator: %s is a SQL statement name */
740 errmsg("%s is not allowed in a non-volatile function",
742
743 /* OK, build the execution_state for this query */
744 newes = (execution_state *) palloc(sizeof(execution_state));
745 if (preves)
746 preves->next = newes;
747 else
748 fcache->eslist = newes;
749
750 newes->next = NULL;
751 newes->status = F_EXEC_START;
752 newes->setsResult = false; /* might change below */
753 newes->lazyEval = false; /* might change below */
754 newes->stmt = stmt;
755 newes->qd = NULL;
756
757 if (stmt->canSetTag)
758 lasttages = newes;
759
760 preves = newes;
761 }
762
763 /*
764 * If this isn't the last CachedPlanSource, we're done here. Otherwise,
765 * we need to prepare information about how to return the results.
766 */
767 if (fcache->next_query_index < fcache->func->num_queries)
768 return true;
769
770 /*
771 * Construct a JunkFilter we can use to coerce the returned rowtype to the
772 * desired form, unless the result type is VOID, in which case there's
773 * nothing to coerce to. (XXX Frequently, the JunkFilter isn't doing
774 * anything very interesting, but much of this module expects it to be
775 * there anyway.)
776 */
777 if (fcache->func->rettype != VOIDOID)
778 {
781 List *resulttlist;
782
783 /*
784 * Re-fetch the (possibly modified) output tlist of the final
785 * statement. By this point, we should have thrown an error if there
786 * is not one.
787 */
788 resulttlist = get_sql_fn_result_tlist(plansource->query_list);
789
790 /*
791 * We need to make a copy to ensure that it doesn't disappear
792 * underneath us due to plancache invalidation.
793 */
794 resulttlist = copyObject(resulttlist);
795
796 /*
797 * If the result is composite, *and* we are returning the whole tuple
798 * result, we need to insert nulls for any dropped columns. In the
799 * single-column-result case, there might be dropped columns within
800 * the composite column value, but it's not our problem here. There
801 * should be no resjunk entries in resulttlist, so in the second case
802 * the JunkFilter is certainly a no-op.
803 */
804 if (fcache->func->rettupdesc && fcache->func->returnsTuple)
805 fcache->junkFilter = ExecInitJunkFilterConversion(resulttlist,
806 fcache->func->rettupdesc,
807 slot);
808 else
809 fcache->junkFilter = ExecInitJunkFilter(resulttlist, slot);
810 }
811
812 if (fcache->func->returnsTuple)
813 {
814 /* Make sure output rowtype is properly blessed */
816 }
817 else if (fcache->func->returnsSet && type_is_rowtype(fcache->func->rettype))
818 {
819 /*
820 * Returning rowtype as if it were scalar --- materialize won't work.
821 * Right now it's sufficient to override any caller preference for
822 * materialize mode, but this might need more work in future.
823 */
824 fcache->lazyEvalOK = true;
825 }
826
827 /*
828 * Mark the last canSetTag query as delivering the function result; then,
829 * if it is a plain SELECT, mark it for lazy evaluation. If it's not a
830 * SELECT we must always run it to completion.
831 *
832 * Note: at some point we might add additional criteria for whether to use
833 * lazy eval. However, we should prefer to use it whenever the function
834 * doesn't return set, since fetching more than one row is useless in that
835 * case.
836 *
837 * Note: don't set setsResult if the function returns VOID, as evidenced
838 * by not having made a junkfilter. This ensures we'll throw away any
839 * output from the last statement in such a function.
840 */
841 if (lasttages && fcache->junkFilter)
842 {
843 lasttages->setsResult = true;
844 if (fcache->lazyEvalOK &&
845 lasttages->stmt->commandType == CMD_SELECT &&
846 !lasttages->stmt->hasModifyingCTE)
847 fcache->lazyEval = lasttages->lazyEval = true;
848 }
849
850 return true;
851}
JunkFilter * ExecInitJunkFilterConversion(List *targetList, TupleDesc cleanTupType, TupleTableSlot *slot)
Definition: execJunk.c:137
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2260
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1427
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:86
static void prepare_next_query(SQLFunctionHashEntry *func)
Definition: functions.c:859
static List * get_sql_fn_result_tlist(List *queryTreeList)
Definition: functions.c:2491
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2795
void * palloc(Size size)
Definition: mcxt.c:1940
#define copyObject(obj)
Definition: nodes.h:230
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, ResourceOwner owner, QueryEnvironment *queryEnv)
Definition: plancache.c:1422
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1547
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173
List * query_list
Definition: plancache.h:125
List * stmt_list
Definition: plancache.h:165
bool hasModifyingCTE
Definition: plannodes.h:65
CmdType commandType
Definition: plannodes.h:53
ParamListInfo paramLI
Definition: functions.c:154
ResourceOwner cowner
Definition: functions.c:168
TupleDesc rettupdesc
Definition: functions.c:134
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:123
PlannedStmt * stmt
Definition: functions.c:72
bool CommandIsReadOnly(PlannedStmt *pstmt)
Definition: utility.c:94
static const char * CreateCommandName(Node *parsetree)
Definition: utility.h:103

References BlessTupleDesc(), CMD_SELECT, CMD_UTILITY, CommandIsReadOnly(), PlannedStmt::commandType, copyObject, SQLFunctionCache::cowner, SQLFunctionCache::cplan, CreateCommandName(), CurrentResourceOwner, ereport, errcode(), errmsg(), ERROR, SQLFunctionCache::error_query_index, SQLFunctionCache::eslist, ExecInitJunkFilter(), ExecInitJunkFilterConversion(), F_EXEC_START, SQLFunctionCache::func, get_sql_fn_result_tlist(), GetCachedPlan(), PlannedStmt::hasModifyingCTE, IsA, JunkFilter::jf_resultSlot, SQLFunctionCache::junkFilter, execution_state::lazyEval, SQLFunctionCache::lazyEval, SQLFunctionCache::lazyEvalOK, lfirst_node, list_length(), list_nth(), MakeSingleTupleTableSlot(), execution_state::next, SQLFunctionCache::next_query_index, SQLFunctionHashEntry::num_queries, palloc(), SQLFunctionCache::paramLI, SQLFunctionHashEntry::plansource_list, prepare_next_query(), execution_state::qd, CachedPlanSource::query_list, SQLFunctionHashEntry::readonly_func, ReleaseCachedPlan(), SQLFunctionHashEntry::rettupdesc, SQLFunctionHashEntry::rettype, SQLFunctionHashEntry::returnsSet, SQLFunctionHashEntry::returnsTuple, execution_state::setsResult, execution_state::status, execution_state::stmt, stmt, CachedPlan::stmt_list, TupleTableSlot::tts_tupleDescriptor, TTSOpsMinimalTuple, and type_is_rowtype().

Referenced by fmgr_sql().

◆ init_sql_fcache()

static SQLFunctionCache * init_sql_fcache ( FunctionCallInfo  fcinfo,
bool  lazyEvalOK 
)
static

Definition at line 537 of file functions.c.

538{
539 FmgrInfo *finfo = fcinfo->flinfo;
541 SQLFunctionCache *fcache;
542 SQLFunctionLink *flink;
543 MemoryContext pcontext;
544 MemoryContext fcontext;
545 MemoryContext oldcontext;
546
547 /*
548 * If this is the first execution for this FmgrInfo, set up a link struct
549 * (initially containing null pointers). The link must live as long as
550 * the FmgrInfo, so it goes in fn_mcxt. Also set up a memory context
551 * callback that will be invoked when fn_mcxt is deleted.
552 */
553 flink = finfo->fn_extra;
554 if (flink == NULL)
555 {
556 flink = (SQLFunctionLink *)
559 flink->mcb.arg = flink;
561 finfo->fn_extra = flink;
562 }
563
564 /*
565 * If we are resuming execution of a set-returning function, just keep
566 * using the same cache. We do not ask funccache.c to re-validate the
567 * SQLFunctionHashEntry: we want to run to completion using the function's
568 * initial definition.
569 */
570 if (flink->fcache != NULL)
571 {
572 Assert(flink->fcache->func == flink->func);
573 return flink->fcache;
574 }
575
576 /*
577 * Look up, or re-validate, the long-lived hash entry. Make the hash key
578 * depend on the result of get_call_result_type() when that's composite,
579 * so that we can safely assume that we'll build a new hash entry if the
580 * composite rowtype changes.
581 */
582 func = (SQLFunctionHashEntry *)
584 (CachedFunction *) flink->func,
587 sizeof(SQLFunctionHashEntry),
588 true,
589 false);
590
591 /*
592 * Install the hash pointer in the SQLFunctionLink, and increment its use
593 * count to reflect that. If cached_function_compile gave us back a
594 * different hash entry than we were using before, we must decrement that
595 * one's use count.
596 */
597 if (func != flink->func)
598 {
599 if (flink->func != NULL)
600 {
601 Assert(flink->func->cfunc.use_count > 0);
602 flink->func->cfunc.use_count--;
603 }
604 flink->func = func;
605 func->cfunc.use_count++;
606 }
607
608 /*
609 * Create memory context that holds all the SQLFunctionCache data. If we
610 * return a set, we must keep this in whatever context holds the FmgrInfo
611 * (anything shorter-lived risks leaving a dangling pointer in flink). But
612 * in a non-SRF we'll delete it before returning, and there's no need for
613 * it to outlive the caller's context.
614 */
615 pcontext = func->returnsSet ? finfo->fn_mcxt : CurrentMemoryContext;
616 fcontext = AllocSetContextCreate(pcontext,
617 "SQL function execution",
619
620 oldcontext = MemoryContextSwitchTo(fcontext);
621
622 /*
623 * Create the struct proper, link it to func and fcontext.
624 */
625 fcache = (SQLFunctionCache *) palloc0(sizeof(SQLFunctionCache));
626 fcache->func = func;
627 fcache->fcontext = fcontext;
628 fcache->lazyEvalOK = lazyEvalOK;
629
630 /*
631 * If we return a set, we must link the fcache into fn_extra so that we
632 * can find it again during future calls. But in a non-SRF there is no
633 * need to link it into fn_extra at all. Not doing so removes the risk of
634 * having a dangling pointer in a long-lived FmgrInfo.
635 */
636 if (func->returnsSet)
637 flink->fcache = fcache;
638
639 /*
640 * We're beginning a new execution of the function, so convert params to
641 * appropriate format.
642 */
643 postquel_sub_params(fcache, fcinfo);
644
645 MemoryContextSwitchTo(oldcontext);
646
647 return fcache;
648}
CachedFunction * cached_function_compile(FunctionCallInfo fcinfo, CachedFunction *function, CachedFunctionCompileCallback ccallback, CachedFunctionDeleteCallback dcallback, Size cacheEntrySize, bool includeResultType, bool forValidator)
Definition: funccache.c:480
static void sql_delete_callback(CachedFunction *cfunc)
Definition: functions.c:1163
static void sql_compile_callback(FunctionCallInfo fcinfo, HeapTuple procedureTuple, const CachedFunctionHashKey *hashkey, CachedFunction *cfunc, bool forValidator)
Definition: functions.c:999
static void postquel_sub_params(SQLFunctionCachePtr fcache, FunctionCallInfo fcinfo)
Definition: functions.c:1345
static void RemoveSQLFunctionLink(void *arg)
Definition: functions.c:1920
struct SQLFunctionHashEntry SQLFunctionHashEntry
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1290
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition: mcxt.c:599
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:180
uint64 use_count
Definition: funccache.h:117
Definition: fmgr.h:57
void * fn_extra
Definition: fmgr.h:64
MemoryContext fn_mcxt
Definition: fmgr.h:65
FmgrInfo * flinfo
Definition: fmgr.h:87
MemoryContextCallbackFunction func
Definition: palloc.h:49
CachedFunction cfunc
Definition: functions.c:119

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, MemoryContextCallback::arg, Assert(), cached_function_compile(), SQLFunctionHashEntry::cfunc, CurrentMemoryContext, SQLFunctionLink::fcache, SQLFunctionCache::fcontext, FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, SQLFunctionCache::func, SQLFunctionLink::func, MemoryContextCallback::func, SQLFunctionCache::lazyEvalOK, SQLFunctionLink::mcb, MemoryContextAllocZero(), MemoryContextRegisterResetCallback(), MemoryContextSwitchTo(), palloc0(), postquel_sub_params(), RemoveSQLFunctionLink(), SQLFunctionHashEntry::returnsSet, sql_compile_callback(), sql_delete_callback(), and CachedFunction::use_count.

Referenced by fmgr_sql().

◆ postquel_end()

static void postquel_end ( execution_state es)
static

Definition at line 1325 of file functions.c.

1326{
1327 /* mark status done to ensure we don't do ExecutorEnd twice */
1328 es->status = F_EXEC_DONE;
1329
1330 /* Utility commands don't need Executor. */
1331 if (es->qd->operation != CMD_UTILITY)
1332 {
1333 ExecutorFinish(es->qd);
1334 ExecutorEnd(es->qd);
1335 }
1336
1337 es->qd->dest->rDestroy(es->qd->dest);
1338
1339 FreeQueryDesc(es->qd);
1340 es->qd = NULL;
1341}
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:538
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:475
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:112
DestReceiver * dest
Definition: execdesc.h:42
CmdType operation
Definition: execdesc.h:36

References CMD_UTILITY, QueryDesc::dest, ExecutorEnd(), ExecutorFinish(), F_EXEC_DONE, FreeQueryDesc(), QueryDesc::operation, execution_state::qd, _DestReceiver::rDestroy, and execution_state::status.

Referenced by fmgr_sql(), and ShutdownSQLFunction().

◆ postquel_get_single_result()

static Datum postquel_get_single_result ( TupleTableSlot slot,
FunctionCallInfo  fcinfo,
SQLFunctionCachePtr  fcache,
MemoryContext  resultcontext 
)
static

Definition at line 1401 of file functions.c.

1405{
1406 Datum value;
1407 MemoryContext oldcontext;
1408
1409 /*
1410 * Set up to return the function value. For pass-by-reference datatypes,
1411 * be sure to allocate the result in resultcontext, not the current memory
1412 * context (which has query lifespan). We can't leave the data in the
1413 * TupleTableSlot because we intend to clear the slot before returning.
1414 */
1415 oldcontext = MemoryContextSwitchTo(resultcontext);
1416
1417 if (fcache->func->returnsTuple)
1418 {
1419 /* We must return the whole tuple as a Datum. */
1420 fcinfo->isnull = false;
1422 }
1423 else
1424 {
1425 /*
1426 * Returning a scalar, which we have to extract from the first column
1427 * of the SELECT result, and then copy into result context if needed.
1428 */
1429 value = slot_getattr(slot, 1, &(fcinfo->isnull));
1430
1431 if (!fcinfo->isnull)
1432 value = datumCopy(value, fcache->func->typbyval, fcache->func->typlen);
1433 }
1434
1435 MemoryContextSwitchTo(oldcontext);
1436
1437 return value;
1438}
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
Datum ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
Definition: execTuples.c:1912
static struct @165 value
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:399

References datumCopy(), ExecFetchSlotHeapTupleDatum(), SQLFunctionCache::func, FunctionCallInfoBaseData::isnull, MemoryContextSwitchTo(), SQLFunctionHashEntry::returnsTuple, slot_getattr(), SQLFunctionHashEntry::typbyval, SQLFunctionHashEntry::typlen, and value.

Referenced by fmgr_sql().

◆ postquel_getnext()

static bool postquel_getnext ( execution_state es,
SQLFunctionCachePtr  fcache 
)
static

Definition at line 1290 of file functions.c.

1291{
1292 bool result;
1293
1294 if (es->qd->operation == CMD_UTILITY)
1295 {
1297 fcache->func->src,
1298 true, /* protect function cache's parsetree */
1300 es->qd->params,
1301 es->qd->queryEnv,
1302 es->qd->dest,
1303 NULL);
1304 result = true; /* never stops early */
1305 }
1306 else
1307 {
1308 /* Run regular commands to completion unless lazyEval */
1309 uint64 count = (es->lazyEval) ? 1 : 0;
1310
1311 ExecutorRun(es->qd, ForwardScanDirection, count);
1312
1313 /*
1314 * If we requested run to completion OR there was no tuple returned,
1315 * command must be complete.
1316 */
1317 result = (count == 0 || es->qd->estate->es_processed == 0);
1318 }
1319
1320 return result;
1321}
uint64_t uint64
Definition: c.h:503
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:365
@ ForwardScanDirection
Definition: sdir.h:28
uint64 es_processed
Definition: execnodes.h:712
ParamListInfo params
Definition: execdesc.h:43
EState * estate
Definition: execdesc.h:49
PlannedStmt * plannedstmt
Definition: execdesc.h:37
QueryEnvironment * queryEnv
Definition: execdesc.h:44
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:499
@ PROCESS_UTILITY_QUERY
Definition: utility.h:23

References CMD_UTILITY, QueryDesc::dest, EState::es_processed, QueryDesc::estate, ExecutorRun(), ForwardScanDirection, SQLFunctionCache::func, execution_state::lazyEval, QueryDesc::operation, QueryDesc::params, QueryDesc::plannedstmt, PROCESS_UTILITY_QUERY, ProcessUtility(), execution_state::qd, QueryDesc::queryEnv, and SQLFunctionHashEntry::src.

Referenced by fmgr_sql().

◆ postquel_start()

static void postquel_start ( execution_state es,
SQLFunctionCachePtr  fcache 
)
static

Definition at line 1226 of file functions.c.

1227{
1229
1230 Assert(es->qd == NULL);
1231
1232 /* Caller should have ensured a suitable snapshot is active */
1234
1235 /*
1236 * If this query produces the function result, send its output to the
1237 * tuplestore; else discard any output.
1238 */
1239 if (es->setsResult)
1240 {
1241 DR_sqlfunction *myState;
1242
1244 /* pass down the needed info to the dest receiver routines */
1245 myState = (DR_sqlfunction *) dest;
1246 Assert(myState->pub.mydest == DestSQLFunction);
1247 myState->tstore = fcache->tstore;
1248 myState->cxt = CurrentMemoryContext;
1249 myState->filter = fcache->junkFilter;
1250 }
1251 else
1253
1254 es->qd = CreateQueryDesc(es->stmt,
1255 NULL,
1256 fcache->func->src,
1259 dest,
1260 fcache->paramLI,
1261 es->qd ? es->qd->queryEnv : NULL,
1262 0);
1263
1264 /* Utility commands don't need Executor. */
1265 if (es->qd->operation != CMD_UTILITY)
1266 {
1267 /*
1268 * In lazyEval mode, do not let the executor set up an AfterTrigger
1269 * context. This is necessary not just an optimization, because we
1270 * mustn't exit from the function execution with a stacked
1271 * AfterTrigger level still active. We are careful not to select
1272 * lazyEval mode for any statement that could possibly queue triggers.
1273 */
1274 int eflags;
1275
1276 if (es->lazyEval)
1277 eflags = EXEC_FLAG_SKIP_TRIGGERS;
1278 else
1279 eflags = 0; /* default run-to-completion flags */
1280 if (!ExecutorStart(es->qd, eflags))
1281 elog(ERROR, "ExecutorStart() failed unexpectedly");
1282 }
1283
1284 es->status = F_EXEC_RUN;
1285}
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
DestReceiver * None_Receiver
Definition: dest.c:96
bool ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:128
#define EXEC_FLAG_SKIP_TRIGGERS
Definition: executor.h:71
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, CachedPlan *cplan, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:72
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:799
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:787
#define InvalidSnapshot
Definition: snapshot.h:119
JunkFilter * filter
Definition: functions.c:49
MemoryContext cxt
Definition: functions.c:48
Tuplestorestate * tstore
Definition: functions.c:47

References ActiveSnapshotSet(), Assert(), CMD_UTILITY, CreateDestReceiver(), CreateQueryDesc(), CurrentMemoryContext, DR_sqlfunction::cxt, generate_unaccent_rules::dest, DestSQLFunction, elog, ERROR, EXEC_FLAG_SKIP_TRIGGERS, ExecutorStart(), F_EXEC_RUN, DR_sqlfunction::filter, SQLFunctionCache::func, GetActiveSnapshot(), InvalidSnapshot, SQLFunctionCache::junkFilter, execution_state::lazyEval, _DestReceiver::mydest, None_Receiver, QueryDesc::operation, SQLFunctionCache::paramLI, DR_sqlfunction::pub, execution_state::qd, QueryDesc::queryEnv, execution_state::setsResult, SQLFunctionHashEntry::src, execution_state::status, execution_state::stmt, DR_sqlfunction::tstore, and SQLFunctionCache::tstore.

Referenced by fmgr_sql().

◆ postquel_sub_params()

static void postquel_sub_params ( SQLFunctionCachePtr  fcache,
FunctionCallInfo  fcinfo 
)
static

Definition at line 1345 of file functions.c.

1347{
1348 int nargs = fcinfo->nargs;
1349
1350 if (nargs > 0)
1351 {
1352 ParamListInfo paramLI;
1353 Oid *argtypes = fcache->func->pinfo->argtypes;
1354
1355 if (fcache->paramLI == NULL)
1356 {
1357 paramLI = makeParamList(nargs);
1358 fcache->paramLI = paramLI;
1359 }
1360 else
1361 {
1362 paramLI = fcache->paramLI;
1363 Assert(paramLI->numParams == nargs);
1364 }
1365
1366 for (int i = 0; i < nargs; i++)
1367 {
1368 ParamExternData *prm = &paramLI->params[i];
1369
1370 /*
1371 * If an incoming parameter value is a R/W expanded datum, we
1372 * force it to R/O. We'd be perfectly entitled to scribble on it,
1373 * but the problem is that if the parameter is referenced more
1374 * than once in the function, earlier references might mutate the
1375 * value seen by later references, which won't do at all. We
1376 * could do better if we could be sure of the number of Param
1377 * nodes in the function's plans; but we might not have planned
1378 * all the statements yet, nor do we have plan tree walker
1379 * infrastructure. (Examining the parse trees is not good enough,
1380 * because of possible function inlining during planning.)
1381 */
1382 prm->isnull = fcinfo->args[i].isnull;
1384 prm->isnull,
1385 get_typlen(argtypes[i]));
1386 /* Allow the value to be substituted into custom plans */
1387 prm->pflags = PARAM_FLAG_CONST;
1388 prm->ptype = argtypes[i];
1389 }
1390 }
1391 else
1392 fcache->paramLI = NULL;
1393}
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
int i
Definition: isn.c:77
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2337
ParamListInfo makeParamList(int numParams)
Definition: params.c:44
#define PARAM_FLAG_CONST
Definition: params.h:88
unsigned int Oid
Definition: postgres_ext.h:30
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Datum value
Definition: postgres.h:80
bool isnull
Definition: postgres.h:82
bool isnull
Definition: params.h:93
uint16 pflags
Definition: params.h:94
Datum value
Definition: params.h:92
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:125
SQLFunctionParseInfoPtr pinfo
Definition: functions.c:124

References FunctionCallInfoBaseData::args, SQLFunctionParseInfo::argtypes, Assert(), SQLFunctionCache::func, get_typlen(), i, ParamExternData::isnull, NullableDatum::isnull, MakeExpandedObjectReadOnly, makeParamList(), FunctionCallInfoBaseData::nargs, ParamListInfoData::numParams, PARAM_FLAG_CONST, SQLFunctionCache::paramLI, ParamListInfoData::params, ParamExternData::pflags, SQLFunctionHashEntry::pinfo, ParamExternData::ptype, ParamExternData::value, and NullableDatum::value.

Referenced by init_sql_fcache().

◆ prepare_next_query()

static void prepare_next_query ( SQLFunctionHashEntry func)
static

Definition at line 859 of file functions.c.

860{
861 int qindex;
862 bool islast;
863 CachedPlanSource *plansource;
864 List *queryTree_list;
865 MemoryContext oldcontext;
866
867 /* Which query should we process? */
868 qindex = list_length(func->plansource_list);
869 Assert(qindex < func->num_queries); /* else caller error */
870 islast = (qindex + 1 >= func->num_queries);
871
872 /*
873 * Parse and/or rewrite the query, creating a CachedPlanSource that holds
874 * a copy of the original parsetree. Note fine point: we make a copy of
875 * each original parsetree to ensure that the source_list in pcontext
876 * remains unmodified during parse analysis and rewrite. This is normally
877 * unnecessary, but we have to do it in case an error is raised during
878 * parse analysis. Otherwise, a fresh attempt to execute the function
879 * will arrive back here and try to work from a corrupted source_list.
880 */
881 if (!func->raw_source)
882 {
883 /* Source queries are already parse-analyzed */
884 Query *parsetree = list_nth_node(Query, func->source_list, qindex);
885
886 parsetree = copyObject(parsetree);
887 plansource = CreateCachedPlanForQuery(parsetree,
888 func->src,
889 CreateCommandTag((Node *) parsetree));
890 AcquireRewriteLocks(parsetree, true, false);
891 queryTree_list = pg_rewrite_query(parsetree);
892 }
893 else
894 {
895 /* Source queries are raw parsetrees */
896 RawStmt *parsetree = list_nth_node(RawStmt, func->source_list, qindex);
897
898 parsetree = copyObject(parsetree);
899 plansource = CreateCachedPlan(parsetree,
900 func->src,
901 CreateCommandTag(parsetree->stmt));
902 queryTree_list = pg_analyze_and_rewrite_withcb(parsetree,
903 func->src,
905 func->pinfo,
906 NULL);
907 }
908
909 /*
910 * Check that there are no statements we don't want to allow.
911 */
912 check_sql_fn_statement(queryTree_list);
913
914 /*
915 * If this is the last query, check that the function returns the type it
916 * claims to. Although in simple cases this was already done when the
917 * function was defined, we have to recheck because database objects used
918 * in the function's queries might have changed type. We'd have to
919 * recheck anyway if the function had any polymorphic arguments. Moreover,
920 * check_sql_stmt_retval takes care of injecting any required column type
921 * coercions. (But we don't ask it to insert nulls for dropped columns;
922 * the junkfilter handles that.)
923 *
924 * Note: we set func->returnsTuple according to whether we are returning
925 * the whole tuple result or just a single column. In the latter case we
926 * clear returnsTuple because we need not act different from the scalar
927 * result case, even if it's a rowtype column. (However, we have to force
928 * lazy eval mode in that case; otherwise we'd need extra code to expand
929 * the rowtype column into multiple columns, since we have no way to
930 * notify the caller that it should do that.)
931 */
932 if (islast)
933 func->returnsTuple = check_sql_stmt_retval(queryTree_list,
934 func->rettype,
935 func->rettupdesc,
936 func->prokind,
937 false);
938
939 /*
940 * Now that check_sql_stmt_retval has done its thing, we can complete plan
941 * cache entry creation.
942 */
943 CompleteCachedPlan(plansource,
944 queryTree_list,
945 NULL,
946 NULL,
947 0,
949 func->pinfo,
951 false);
952
953 /*
954 * Install post-rewrite hook. Its arg is the hash entry if this is the
955 * last statement, else NULL.
956 */
957 SetPostRewriteHook(plansource,
959 islast ? func : NULL);
960
961 /*
962 * While the CachedPlanSources can take care of themselves, our List
963 * pointing to them had better be in the hcontext.
964 */
965 oldcontext = MemoryContextSwitchTo(func->hcontext);
966 func->plansource_list = lappend(func->plansource_list, plansource);
967 MemoryContextSwitchTo(oldcontext);
968
969 /*
970 * As soon as we've linked the CachedPlanSource into the list, mark it as
971 * "saved".
972 */
973 SaveCachedPlan(plansource);
974
975 /*
976 * Finally, if this was the last statement, we can flush the pcontext with
977 * the original query trees; they're all safely copied into
978 * CachedPlanSources now.
979 */
980 if (islast)
981 {
982 func->source_list = NIL; /* avoid dangling pointer */
984 func->pcontext = NULL;
985 }
986}
static void sql_postrewrite_callback(List *querytree_list, void *arg)
Definition: functions.c:1193
void sql_fn_parser_setup(struct ParseState *pstate, SQLFunctionParseInfoPtr pinfo)
Definition: functions.c:341
void(* ParserSetupHook)(struct ParseState *pstate, void *arg)
Definition: params.h:108
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3385
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3377
#define list_nth_node(type, list, n)
Definition: pg_list.h:327
void SaveCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:531
void CompleteCachedPlan(CachedPlanSource *plansource, List *querytree_list, MemoryContext querytree_context, Oid *param_types, int num_params, ParserSetupHook parserSetup, void *parserSetupArg, int cursor_options, bool fixed_result)
Definition: plancache.c:392
CachedPlanSource * CreateCachedPlanForQuery(Query *analyzed_parse_tree, const char *query_string, CommandTag commandTag)
Definition: plancache.c:264
void SetPostRewriteHook(CachedPlanSource *plansource, PostRewriteHook postRewrite, void *postRewriteArg)
Definition: plancache.c:506
CachedPlanSource * CreateCachedPlan(RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
Definition: plancache.c:184
List * pg_analyze_and_rewrite_withcb(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg, QueryEnvironment *queryEnv)
Definition: postgres.c:758
List * pg_rewrite_query(Query *query)
Definition: postgres.c:798
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
Node * stmt
Definition: parsenodes.h:2071
MemoryContext pcontext
Definition: functions.c:142
MemoryContext hcontext
Definition: functions.c:143
CommandTag CreateCommandTag(Node *parsetree)
Definition: utility.c:2362

References AcquireRewriteLocks(), Assert(), check_sql_fn_statement(), check_sql_stmt_retval(), CompleteCachedPlan(), copyObject, CreateCachedPlan(), CreateCachedPlanForQuery(), CreateCommandTag(), CURSOR_OPT_NO_SCROLL, CURSOR_OPT_PARALLEL_OK, SQLFunctionHashEntry::hcontext, lappend(), list_length(), list_nth_node, MemoryContextDelete(), MemoryContextSwitchTo(), NIL, SQLFunctionHashEntry::num_queries, SQLFunctionHashEntry::pcontext, pg_analyze_and_rewrite_withcb(), pg_rewrite_query(), SQLFunctionHashEntry::pinfo, SQLFunctionHashEntry::plansource_list, SQLFunctionHashEntry::prokind, SQLFunctionHashEntry::raw_source, SQLFunctionHashEntry::rettupdesc, SQLFunctionHashEntry::rettype, SQLFunctionHashEntry::returnsTuple, SaveCachedPlan(), SetPostRewriteHook(), SQLFunctionHashEntry::source_list, sql_fn_parser_setup(), sql_postrewrite_callback(), SQLFunctionHashEntry::src, and RawStmt::stmt.

Referenced by init_execution_state().

◆ prepare_sql_fn_parse_info()

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

Definition at line 252 of file functions.c.

255{
257 Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
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 {
275 Oid *argOidVect;
276 int argnum;
277
278 argOidVect = (Oid *) palloc(nargs * sizeof(Oid));
279 memcpy(argOidVect,
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 {
289 argtype = get_call_expr_argtype(call_expr, argnum);
290 if (argtype == InvalidOid)
292 (errcode(ERRCODE_DATATYPE_MISMATCH),
293 errmsg("could not determine actual type of argument declared %s",
294 format_type_be(argOidVect[argnum]))));
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 {
307 Datum proargnames;
308 Datum proargmodes;
309 int n_arg_names;
310 bool isNull;
311
312 proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, procedureTuple,
313 Anum_pg_proc_proargnames,
314 &isNull);
315 if (isNull)
316 proargnames = PointerGetDatum(NULL); /* just to be sure */
317
318 proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, procedureTuple,
319 Anum_pg_proc_proargmodes,
320 &isNull);
321 if (isNull)
322 proargmodes = PointerGetDatum(NULL); /* just to be sure */
323
324 n_arg_names = get_func_input_arg_names(proargnames, proargmodes,
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:717
Oid get_call_expr_argtype(Node *expr, int argnum)
Definition: fmgr.c:1929
int get_func_input_arg_names(Datum proargnames, Datum proargmodes, char ***arg_names)
Definition: funcapi.c:1522
SQLFunctionParseInfo * SQLFunctionParseInfoPtr
Definition: functions.h:35
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
char * pstrdup(const char *in)
Definition: mcxt.c:2322
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600

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

Referenced by fmgr_sql_validator(), inline_function(), inline_set_returning_function(), and sql_compile_callback().

◆ RemoveSQLFunctionLink()

static void RemoveSQLFunctionLink ( void *  arg)
static

Definition at line 1920 of file functions.c.

1921{
1922 SQLFunctionLink *flink = (SQLFunctionLink *) arg;
1923
1924 if (flink->func != NULL)
1925 {
1926 Assert(flink->func->cfunc.use_count > 0);
1927 flink->func->cfunc.use_count--;
1928 /* This should be unnecessary, but let's just be sure: */
1929 flink->func = NULL;
1930 }
1931}
void * arg

References arg, Assert(), SQLFunctionHashEntry::cfunc, SQLFunctionLink::func, and CachedFunction::use_count.

Referenced by init_sql_fcache().

◆ ShutdownSQLFunction()

static void ShutdownSQLFunction ( Datum  arg)
static

Definition at line 1867 of file functions.c.

1868{
1870 SQLFunctionCachePtr fcache = flink->fcache;
1871
1872 if (fcache != NULL)
1873 {
1874 execution_state *es;
1875
1876 /* Make sure we don't somehow try to do this twice */
1877 flink->fcache = NULL;
1878
1879 es = fcache->eslist;
1880 while (es)
1881 {
1882 /* Shut down anything still running */
1883 if (es->status == F_EXEC_RUN)
1884 {
1885 /* Re-establish active snapshot for any called functions */
1886 if (!fcache->func->readonly_func)
1888
1889 postquel_end(es);
1890
1891 if (!fcache->func->readonly_func)
1893 }
1894 es = es->next;
1895 }
1896
1897 /* Release tuplestore if we have one */
1898 if (fcache->tstore)
1899 tuplestore_end(fcache->tstore);
1900
1901 /* Release CachedPlan if we have one */
1902 if (fcache->cplan)
1903 ReleaseCachedPlan(fcache->cplan, fcache->cowner);
1904
1905 /* Release the cache */
1907 }
1908 /* execUtils will deregister the callback... */
1909}
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317

References arg, SQLFunctionCache::cowner, SQLFunctionCache::cplan, DatumGetPointer(), SQLFunctionCache::eslist, F_EXEC_RUN, SQLFunctionLink::fcache, SQLFunctionCache::fcontext, SQLFunctionCache::func, MemoryContextDelete(), execution_state::next, PopActiveSnapshot(), postquel_end(), PushActiveSnapshot(), execution_state::qd, SQLFunctionHashEntry::readonly_func, ReleaseCachedPlan(), QueryDesc::snapshot, execution_state::status, SQLFunctionCache::tstore, and tuplestore_end().

Referenced by fmgr_sql().

◆ sql_compile_callback()

static void sql_compile_callback ( FunctionCallInfo  fcinfo,
HeapTuple  procedureTuple,
const CachedFunctionHashKey hashkey,
CachedFunction cfunc,
bool  forValidator 
)
static

Definition at line 999 of file functions.c.

1004{
1006 Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
1007 ErrorContextCallback comperrcontext;
1008 MemoryContext hcontext;
1009 MemoryContext pcontext;
1011 Oid rettype;
1012 TupleDesc rettupdesc;
1013 Datum tmp;
1014 bool isNull;
1015 List *source_list;
1016
1017 /*
1018 * Setup error traceback support for ereport() during compile. (This is
1019 * mainly useful for reporting parse errors from pg_parse_query.)
1020 */
1021 comperrcontext.callback = sql_compile_error_callback;
1022 comperrcontext.arg = func;
1023 comperrcontext.previous = error_context_stack;
1024 error_context_stack = &comperrcontext;
1025
1026 /*
1027 * Create the hash entry's memory context. For now it's a child of the
1028 * caller's context, so that it will go away if we fail partway through.
1029 */
1031 "SQL function",
1033
1034 /*
1035 * Create the not-as-long-lived pcontext. We make this a child of
1036 * hcontext so that it doesn't require separate deletion.
1037 */
1038 pcontext = AllocSetContextCreate(hcontext,
1039 "SQL function parse trees",
1041 func->pcontext = pcontext;
1042
1043 /*
1044 * copy function name immediately for use by error reporting callback, and
1045 * for use as memory context identifier
1046 */
1047 func->fname = MemoryContextStrdup(hcontext,
1048 NameStr(procedureStruct->proname));
1049 MemoryContextSetIdentifier(hcontext, func->fname);
1050
1051 /*
1052 * Resolve any polymorphism, obtaining the actual result type, and the
1053 * corresponding tupdesc if it's a rowtype.
1054 */
1055 (void) get_call_result_type(fcinfo, &rettype, &rettupdesc);
1056
1057 func->rettype = rettype;
1058 if (rettupdesc)
1059 {
1060 MemoryContextSwitchTo(hcontext);
1061 func->rettupdesc = CreateTupleDescCopy(rettupdesc);
1062 MemoryContextSwitchTo(oldcontext);
1063 }
1064
1065 /* Fetch the typlen and byval info for the result type */
1066 get_typlenbyval(rettype, &func->typlen, &func->typbyval);
1067
1068 /* Remember whether we're returning setof something */
1069 func->returnsSet = procedureStruct->proretset;
1070
1071 /* Remember if function is STABLE/IMMUTABLE */
1072 func->readonly_func =
1073 (procedureStruct->provolatile != PROVOLATILE_VOLATILE);
1074
1075 /* Remember routine kind */
1076 func->prokind = procedureStruct->prokind;
1077
1078 /*
1079 * We need the actual argument types to pass to the parser. Also make
1080 * sure that parameter symbols are considered to have the function's
1081 * resolved input collation.
1082 */
1083 MemoryContextSwitchTo(hcontext);
1084 func->pinfo = prepare_sql_fn_parse_info(procedureTuple,
1085 fcinfo->flinfo->fn_expr,
1087 MemoryContextSwitchTo(oldcontext);
1088
1089 /*
1090 * And of course we need the function body text.
1091 */
1092 tmp = SysCacheGetAttrNotNull(PROCOID, procedureTuple, Anum_pg_proc_prosrc);
1093 func->src = MemoryContextStrdup(hcontext,
1094 TextDatumGetCString(tmp));
1095
1096 /* If we have prosqlbody, pay attention to that not prosrc. */
1097 tmp = SysCacheGetAttr(PROCOID,
1098 procedureTuple,
1099 Anum_pg_proc_prosqlbody,
1100 &isNull);
1101 if (!isNull)
1102 {
1103 /* Source queries are already parse-analyzed */
1104 Node *n;
1105
1107 if (IsA(n, List))
1108 source_list = linitial_node(List, castNode(List, n));
1109 else
1110 source_list = list_make1(n);
1111 func->raw_source = false;
1112 }
1113 else
1114 {
1115 /* Source queries are raw parsetrees */
1116 source_list = pg_parse_query(func->src);
1117 func->raw_source = true;
1118 }
1119
1120 /*
1121 * Note: we must save the number of queries so that we'll still remember
1122 * how many there are after we discard source_list.
1123 */
1124 func->num_queries = list_length(source_list);
1125
1126 /*
1127 * Edge case: empty function body is OK only if it returns VOID. Normally
1128 * we validate that the last statement returns the right thing in
1129 * check_sql_stmt_retval, but we'll never reach that if there's no last
1130 * statement.
1131 */
1132 if (func->num_queries == 0 && rettype != VOIDOID)
1133 ereport(ERROR,
1134 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1135 errmsg("return type mismatch in function declared to return %s",
1136 format_type_be(rettype)),
1137 errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.")));
1138
1139 /* Save the source trees in pcontext for now. */
1140 MemoryContextSwitchTo(pcontext);
1141 func->source_list = copyObject(source_list);
1142 MemoryContextSwitchTo(oldcontext);
1143
1144 /*
1145 * We now have a fully valid hash entry, so reparent hcontext under
1146 * CacheMemoryContext to make all the subsidiary data long-lived, and only
1147 * then install the hcontext link so that sql_delete_callback will know to
1148 * delete it.
1149 */
1151 func->hcontext = hcontext;
1152
1153 error_context_stack = comperrcontext.previous;
1154}
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define PG_GET_COLLATION()
Definition: fmgr.h:198
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
static void sql_compile_error_callback(void *arg)
Definition: functions.c:1795
SQLFunctionParseInfoPtr prepare_sql_fn_parse_info(HeapTuple procedureTuple, Node *call_expr, Oid inputCollation)
Definition: functions.c:252
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2391
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:2309
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:668
MemoryContext CacheMemoryContext
Definition: mcxt.c:168
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:643
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:190
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
#define linitial_node(type, l)
Definition: pg_list.h:181
List * pg_parse_query(const char *query_string)
Definition: postgres.c:603
void * stringToNode(const char *str)
Definition: read.c:90
fmNodePtr fn_expr
Definition: fmgr.h:66
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:631

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, ErrorContextCallback::arg, CacheMemoryContext, ErrorContextCallback::callback, castNode, copyObject, CreateTupleDescCopy(), CurrentMemoryContext, ereport, errcode(), errdetail(), errmsg(), ERROR, error_context_stack, FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_expr, SQLFunctionHashEntry::fname, format_type_be(), get_call_result_type(), get_typlenbyval(), GETSTRUCT(), SQLFunctionHashEntry::hcontext, IsA, linitial_node, list_length(), list_make1, MemoryContextSetIdentifier(), MemoryContextSetParent(), MemoryContextStrdup(), MemoryContextSwitchTo(), NameStr, SQLFunctionHashEntry::num_queries, SQLFunctionHashEntry::pcontext, PG_GET_COLLATION, pg_parse_query(), SQLFunctionHashEntry::pinfo, prepare_sql_fn_parse_info(), ErrorContextCallback::previous, SQLFunctionHashEntry::prokind, SQLFunctionHashEntry::raw_source, SQLFunctionHashEntry::readonly_func, SQLFunctionHashEntry::rettupdesc, SQLFunctionHashEntry::rettype, SQLFunctionHashEntry::returnsSet, SQLFunctionHashEntry::source_list, sql_compile_error_callback(), SQLFunctionHashEntry::src, stringToNode(), SysCacheGetAttr(), SysCacheGetAttrNotNull(), TextDatumGetCString, SQLFunctionHashEntry::typbyval, and SQLFunctionHashEntry::typlen.

Referenced by init_sql_fcache().

◆ sql_compile_error_callback()

static void sql_compile_error_callback ( void *  arg)
static

Definition at line 1795 of file functions.c.

1796{
1798 int syntaxerrposition;
1799
1800 /*
1801 * We can do nothing useful if sql_compile_callback() didn't get as far as
1802 * copying the function name
1803 */
1804 if (func->fname == NULL)
1805 return;
1806
1807 /*
1808 * If there is a syntax error position, convert to internal syntax error
1809 */
1810 syntaxerrposition = geterrposition();
1811 if (syntaxerrposition > 0 && func->src != NULL)
1812 {
1813 errposition(0);
1814 internalerrposition(syntaxerrposition);
1815 internalerrquery(func->src);
1816 }
1817
1818 /*
1819 * sql_compile_callback() doesn't do any per-query processing, so just
1820 * report the context as "during startup".
1821 */
1822 errcontext("SQL function \"%s\" during startup", func->fname);
1823}
int internalerrquery(const char *query)
Definition: elog.c:1504
int internalerrposition(int cursorpos)
Definition: elog.c:1484
int geterrposition(void)
Definition: elog.c:1617
int errposition(int cursorpos)
Definition: elog.c:1468
#define errcontext
Definition: elog.h:197

References arg, errcontext, errposition(), SQLFunctionHashEntry::fname, geterrposition(), internalerrposition(), internalerrquery(), and SQLFunctionHashEntry::src.

Referenced by sql_compile_callback().

◆ sql_delete_callback()

static void sql_delete_callback ( CachedFunction cfunc)
static

Definition at line 1163 of file functions.c.

1164{
1166 ListCell *lc;
1167
1168 /* Release the CachedPlanSources */
1169 foreach(lc, func->plansource_list)
1170 {
1171 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
1172
1173 DropCachedPlan(plansource);
1174 }
1175 func->plansource_list = NIL;
1176
1177 /*
1178 * If we have an hcontext, free it, thereby getting rid of all subsidiary
1179 * data. (If we still have a pcontext, this gets rid of that too.)
1180 */
1181 if (func->hcontext)
1183 func->hcontext = NULL;
1184}
void DropCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:575

References DropCachedPlan(), SQLFunctionHashEntry::hcontext, lfirst, MemoryContextDelete(), NIL, and SQLFunctionHashEntry::plansource_list.

Referenced by init_sql_fcache().

◆ sql_exec_error_callback()

static void sql_exec_error_callback ( void *  arg)
static

Definition at line 1829 of file functions.c.

1830{
1832 int syntaxerrposition;
1833
1834 /*
1835 * If there is a syntax error position, convert to internal syntax error
1836 */
1837 syntaxerrposition = geterrposition();
1838 if (syntaxerrposition > 0 && fcache->func->src != NULL)
1839 {
1840 errposition(0);
1841 internalerrposition(syntaxerrposition);
1842 internalerrquery(fcache->func->src);
1843 }
1844
1845 /*
1846 * If we failed while executing an identifiable query within the function,
1847 * report that. Otherwise say it was "during startup".
1848 */
1849 if (fcache->error_query_index > 0)
1850 errcontext("SQL function \"%s\" statement %d",
1851 fcache->func->fname, fcache->error_query_index);
1852 else
1853 errcontext("SQL function \"%s\" during startup", fcache->func->fname);
1854}
SQLFunctionCache * SQLFunctionCachePtr
Definition: functions.c:179

References arg, errcontext, SQLFunctionCache::error_query_index, errposition(), SQLFunctionHashEntry::fname, SQLFunctionCache::func, geterrposition(), internalerrposition(), internalerrquery(), and SQLFunctionHashEntry::src.

Referenced by fmgr_sql().

◆ sql_fn_make_param()

static Node * sql_fn_make_param ( SQLFunctionParseInfoPtr  pinfo,
int  paramno,
int  location 
)
static

Definition at line 486 of file functions.c.

488{
489 Param *param;
490
491 param = makeNode(Param);
492 param->paramkind = PARAM_EXTERN;
493 param->paramid = paramno;
494 param->paramtype = pinfo->argtypes[paramno - 1];
495 param->paramtypmod = -1;
496 param->paramcollid = get_typcollation(param->paramtype);
497 param->location = location;
498
499 /*
500 * If we have a function input collation, allow it to override the
501 * type-derived collation for parameter symbols. (XXX perhaps this should
502 * not happen if the type collation is not default?)
503 */
504 if (OidIsValid(pinfo->collation) && OidIsValid(param->paramcollid))
505 param->paramcollid = pinfo->collation;
506
507 return (Node *) param;
508}
#define OidIsValid(objectId)
Definition: c.h:746
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3196
@ PARAM_EXTERN
Definition: primnodes.h:384
ParseLoc location
Definition: primnodes.h:401
int paramid
Definition: primnodes.h:394
Oid paramtype
Definition: primnodes.h:395
ParamKind paramkind
Definition: primnodes.h:393

References SQLFunctionParseInfo::argtypes, SQLFunctionParseInfo::collation, get_typcollation(), Param::location, makeNode, OidIsValid, PARAM_EXTERN, Param::paramid, Param::paramkind, and Param::paramtype.

Referenced by sql_fn_param_ref(), and sql_fn_resolve_param_name().

◆ sql_fn_param_ref()

static Node * sql_fn_param_ref ( ParseState pstate,
ParamRef pref 
)
static

Definition at line 470 of file functions.c.

471{
473 int paramno = pref->number;
474
475 /* Check parameter number is valid */
476 if (paramno <= 0 || paramno > pinfo->nargs)
477 return NULL; /* unknown parameter number */
478
479 return sql_fn_make_param(pinfo, paramno, pref->location);
480}
static Node * sql_fn_make_param(SQLFunctionParseInfoPtr pinfo, int paramno, int location)
Definition: functions.c:486
ParseLoc location
Definition: parsenodes.h:316
int number
Definition: parsenodes.h:315
void * p_ref_hook_state
Definition: parse_node.h:258

References if(), ParamRef::location, SQLFunctionParseInfo::nargs, ParamRef::number, ParseState::p_ref_hook_state, and sql_fn_make_param().

Referenced by sql_fn_parser_setup().

◆ sql_fn_parser_setup()

void sql_fn_parser_setup ( struct ParseState pstate,
SQLFunctionParseInfoPtr  pinfo 
)

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
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 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_set_returning_function(), interpret_AS_clause(), and prepare_next_query().

◆ sql_fn_post_column_ref()

static Node * sql_fn_post_column_ref ( ParseState pstate,
ColumnRef cref,
Node var 
)
static

Definition at line 354 of file functions.c.

355{
357 int nnames;
358 Node *field1;
359 Node *subfield = NULL;
360 const char *name1;
361 const char *name2 = NULL;
362 Node *param;
363
364 /*
365 * Never override a table-column reference. This corresponds to
366 * considering the parameter names to appear in a scope outside the
367 * individual SQL commands, which is what we want.
368 */
369 if (var != NULL)
370 return NULL;
371
372 /*----------
373 * The allowed syntaxes are:
374 *
375 * A A = parameter name
376 * A.B A = function name, B = parameter name
377 * OR: A = record-typed parameter name, B = field name
378 * (the first possibility takes precedence)
379 * A.B.C A = function name, B = record-typed parameter name,
380 * C = field name
381 * A.* Whole-row reference to composite parameter A.
382 * A.B.* Same, with A = function name, B = parameter name
383 *
384 * Here, it's sufficient to ignore the "*" in the last two cases --- the
385 * main parser will take care of expanding the whole-row reference.
386 *----------
387 */
388 nnames = list_length(cref->fields);
389
390 if (nnames > 3)
391 return NULL;
392
393 if (IsA(llast(cref->fields), A_Star))
394 nnames--;
395
396 field1 = (Node *) linitial(cref->fields);
397 name1 = strVal(field1);
398 if (nnames > 1)
399 {
400 subfield = (Node *) lsecond(cref->fields);
401 name2 = strVal(subfield);
402 }
403
404 if (nnames == 3)
405 {
406 /*
407 * Three-part name: if the first part doesn't match the function name,
408 * we can fail immediately. Otherwise, look up the second part, and
409 * take the third part to be a field reference.
410 */
411 if (strcmp(name1, pinfo->fname) != 0)
412 return NULL;
413
414 param = sql_fn_resolve_param_name(pinfo, name2, cref->location);
415
416 subfield = (Node *) lthird(cref->fields);
417 Assert(IsA(subfield, String));
418 }
419 else if (nnames == 2 && strcmp(name1, pinfo->fname) == 0)
420 {
421 /*
422 * Two-part name with first part matching function name: first see if
423 * second part matches any parameter name.
424 */
425 param = sql_fn_resolve_param_name(pinfo, name2, cref->location);
426
427 if (param)
428 {
429 /* Yes, so this is a parameter reference, no subfield */
430 subfield = NULL;
431 }
432 else
433 {
434 /* No, so try to match as parameter name and subfield */
435 param = sql_fn_resolve_param_name(pinfo, name1, cref->location);
436 }
437 }
438 else
439 {
440 /* Single name, or parameter name followed by subfield */
441 param = sql_fn_resolve_param_name(pinfo, name1, cref->location);
442 }
443
444 if (!param)
445 return NULL; /* No match */
446
447 if (subfield)
448 {
449 /*
450 * Must be a reference to a field of a composite parameter; otherwise
451 * ParseFuncOrColumn will return NULL, and we'll fail back at the
452 * caller.
453 */
454 param = ParseFuncOrColumn(pstate,
455 list_make1(subfield),
456 list_make1(param),
457 pstate->p_last_srf,
458 NULL,
459 false,
460 cref->location);
461 }
462
463 return param;
464}
static Node * sql_fn_resolve_param_name(SQLFunctionParseInfoPtr pinfo, const char *paramname, int location)
Definition: functions.c:516
Node * ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, Node *last_srf, FuncCall *fn, bool proc_call, int location)
Definition: parse_func.c:90
#define llast(l)
Definition: pg_list.h:198
#define lthird(l)
Definition: pg_list.h:188
#define lsecond(l)
Definition: pg_list.h:183
ParseLoc location
Definition: parsenodes.h:306
List * fields
Definition: parsenodes.h:305
Node * p_last_srf
Definition: parse_node.h:248
Definition: value.h:64
#define strVal(v)
Definition: value.h:82

References Assert(), ColumnRef::fields, SQLFunctionParseInfo::fname, if(), IsA, linitial, list_length(), list_make1, llast, ColumnRef::location, lsecond, lthird, ParseState::p_last_srf, ParseState::p_ref_hook_state, ParseFuncOrColumn(), sql_fn_resolve_param_name(), and strVal.

Referenced by sql_fn_parser_setup().

◆ sql_fn_resolve_param_name()

static Node * sql_fn_resolve_param_name ( SQLFunctionParseInfoPtr  pinfo,
const char *  paramname,
int  location 
)
static

Definition at line 516 of file functions.c.

518{
519 int i;
520
521 if (pinfo->argnames == NULL)
522 return NULL;
523
524 for (i = 0; i < pinfo->nargs; i++)
525 {
526 if (pinfo->argnames[i] && strcmp(pinfo->argnames[i], paramname) == 0)
527 return sql_fn_make_param(pinfo, i + 1, location);
528 }
529
530 return NULL;
531}

References SQLFunctionParseInfo::argnames, i, SQLFunctionParseInfo::nargs, and sql_fn_make_param().

Referenced by sql_fn_post_column_ref().

◆ sql_postrewrite_callback()

static void sql_postrewrite_callback ( List querytree_list,
void *  arg 
)
static

Definition at line 1193 of file functions.c.

1194{
1195 /*
1196 * Check that there are no statements we don't want to allow. (Presently,
1197 * there's no real point in this because the result can't change from what
1198 * we saw originally. But it's cheap and maybe someday it will matter.)
1199 */
1200 check_sql_fn_statement(querytree_list);
1201
1202 /*
1203 * If this is the last query, we must re-do what check_sql_stmt_retval did
1204 * to its targetlist. Also check that returnsTuple didn't change (it
1205 * probably cannot, but be cautious).
1206 */
1207 if (arg != NULL)
1208 {
1210 bool returnsTuple;
1211
1212 returnsTuple = check_sql_stmt_retval(querytree_list,
1213 func->rettype,
1214 func->rettupdesc,
1215 func->prokind,
1216 false);
1217 if (returnsTuple != func->returnsTuple)
1218 ereport(ERROR,
1219 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1220 errmsg("cached plan must not change result type")));
1221 }
1222}

References arg, check_sql_fn_statement(), check_sql_stmt_retval(), ereport, errcode(), errmsg(), ERROR, SQLFunctionHashEntry::prokind, SQLFunctionHashEntry::rettupdesc, SQLFunctionHashEntry::rettype, and SQLFunctionHashEntry::returnsTuple.

Referenced by prepare_next_query().

◆ sqlfunction_destroy()

static void sqlfunction_destroy ( DestReceiver self)
static

Definition at line 2576 of file functions.c.

2577{
2578 pfree(self);
2579}
void pfree(void *pointer)
Definition: mcxt.c:2147

References pfree().

Referenced by CreateSQLFunctionDestReceiver().

◆ sqlfunction_receive()

static bool sqlfunction_receive ( TupleTableSlot slot,
DestReceiver self 
)
static

Definition at line 2550 of file functions.c.

2551{
2552 DR_sqlfunction *myState = (DR_sqlfunction *) self;
2553
2554 /* Filter tuple as needed */
2555 slot = ExecFilterJunk(myState->filter, slot);
2556
2557 /* Store the filtered tuple into the tuplestore */
2558 tuplestore_puttupleslot(myState->tstore, slot);
2559
2560 return true;
2561}
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:247
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition: tuplestore.c:742

References ExecFilterJunk(), DR_sqlfunction::filter, DR_sqlfunction::tstore, and tuplestore_puttupleslot().

Referenced by CreateSQLFunctionDestReceiver().

◆ sqlfunction_shutdown()

static void sqlfunction_shutdown ( DestReceiver self)
static

Definition at line 2567 of file functions.c.

2568{
2569 /* no-op */
2570}

Referenced by CreateSQLFunctionDestReceiver().

◆ sqlfunction_startup()

static void sqlfunction_startup ( DestReceiver self,
int  operation,
TupleDesc  typeinfo 
)
static

Definition at line 2541 of file functions.c.

2542{
2543 /* no-op */
2544}

Referenced by CreateSQLFunctionDestReceiver().