PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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/plancache.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tuplestore.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
 

Typedefs

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

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, SQLFunctionCachePtr fcache)
 
static void postquel_sub_params (SQLFunctionCachePtr fcache, FunctionCallInfo fcinfo)
 
static Datum postquel_get_single_result (TupleTableSlot *slot, FunctionCallInfo fcinfo, SQLFunctionCachePtr fcache)
 
static void sql_compile_error_callback (void *arg)
 
static void sql_exec_error_callback (void *arg)
 
static void ShutdownSQLFunction (Datum arg)
 
static void RemoveSQLFunctionCache (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

◆ SQLFunctionHashEntry

Enumeration Type Documentation

◆ ExecStatus

Enumerator
F_EXEC_START 
F_EXEC_RUN 
F_EXEC_DONE 

Definition at line 64 of file functions.c.

65{
ExecStatus
Definition functions.c:65
@ F_EXEC_START
Definition functions.c:66
@ F_EXEC_DONE
Definition functions.c:66
@ F_EXEC_RUN
Definition functions.c:66

Function Documentation

◆ check_sql_fn_retval()

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

Definition at line 2117 of file functions.c.

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

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

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

◆ check_sql_fn_statement()

static void check_sql_fn_statement ( List queryTreeList)
static

Definition at line 2053 of file functions.c.

2054{
2055 ListCell *lc;
2056
2057 foreach(lc, queryTreeList)
2058 {
2059 Query *query = lfirst_node(Query, lc);
2060
2061 /*
2062 * Disallow calling procedures with output arguments. The current
2063 * implementation would just throw the output values away, unless the
2064 * statement is the last one. Per SQL standard, we should assign the
2065 * output values by name. By disallowing this here, we preserve an
2066 * opportunity for future improvement.
2067 */
2068 if (query->commandType == CMD_UTILITY &&
2069 IsA(query->utilityStmt, CallStmt))
2070 {
2071 CallStmt *stmt = (CallStmt *) query->utilityStmt;
2072
2073 if (stmt->outargs != NIL)
2074 ereport(ERROR,
2076 errmsg("calling procedures with output arguments is not supported in SQL functions")));
2077 }
2078 }
2079}
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
#define stmt
#define IsA(nodeptr, _type_)
Definition nodes.h:164
@ CMD_UTILITY
Definition nodes.h:280
static char * errmsg
#define lfirst_node(type, lc)
Definition pg_list.h:176
CmdType commandType
Definition parsenodes.h:121
Node * utilityStmt
Definition parsenodes.h:141

References CMD_UTILITY, Query::commandType, ereport, errcode(), errmsg, ERROR, fb(), 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 2036 of file functions.c.

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

References check_sql_fn_statement(), fb(), 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 2151 of file functions.c.

2154{
2155 bool is_tuple_result = false;
2156 Query *parse;
2158 List *tlist;
2159 int tlistlen;
2161 char fn_typtype;
2162 List *upper_tlist = NIL;
2163 bool upper_tlist_nontrivial = false;
2164 ListCell *lc;
2165
2166 /*
2167 * If it's declared to return VOID, we don't care what's in the function.
2168 * (This takes care of procedures with no output parameters, as well.)
2169 */
2170 if (rettype == VOIDOID)
2171 return false;
2172
2173 /*
2174 * Find the last canSetTag query in the list of Query nodes. This isn't
2175 * necessarily the last parsetree, because rule rewriting can insert
2176 * queries after what the user wrote.
2177 */
2178 parse = NULL;
2179 parse_cell = NULL;
2180 foreach(lc, queryTreeList)
2181 {
2182 Query *q = lfirst_node(Query, lc);
2183
2184 if (q->canSetTag)
2185 {
2186 parse = q;
2187 parse_cell = lc;
2188 }
2189 }
2190
2191 /*
2192 * If it's a plain SELECT, it returns whatever the targetlist says.
2193 * Otherwise, if it's INSERT/UPDATE/DELETE/MERGE with RETURNING, it
2194 * returns that. Otherwise, the function return type must be VOID.
2195 *
2196 * Note: eventually replace this test with QueryReturnsTuples? We'd need
2197 * a more general method of determining the output type, though. Also, it
2198 * seems too dangerous to consider FETCH or EXECUTE as returning a
2199 * determinable rowtype, since they depend on relatively short-lived
2200 * entities.
2201 */
2202 if (parse &&
2203 parse->commandType == CMD_SELECT)
2204 {
2205 tlist = parse->targetList;
2206 /* tlist is modifiable unless it's a dummy in a setop query */
2207 tlist_is_modifiable = (parse->setOperations == NULL);
2208 }
2209 else if (parse &&
2210 (parse->commandType == CMD_INSERT ||
2211 parse->commandType == CMD_UPDATE ||
2212 parse->commandType == CMD_DELETE ||
2213 parse->commandType == CMD_MERGE) &&
2214 parse->returningList)
2215 {
2216 tlist = parse->returningList;
2217 /* returningList can always be modified */
2218 tlist_is_modifiable = true;
2219 }
2220 else
2221 {
2222 /* Last statement is a utility command, or it rewrote to nothing */
2223 ereport(ERROR,
2225 errmsg("return type mismatch in function declared to return %s",
2226 format_type_be(rettype)),
2227 errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.")));
2228 return false; /* keep compiler quiet */
2229 }
2230
2231 /*
2232 * OK, check that the targetlist returns something matching the declared
2233 * type, and modify it if necessary. If possible, we insert any coercion
2234 * steps right into the final statement's targetlist. However, that might
2235 * risk changes in the statement's semantics --- we can't safely change
2236 * the output type of a grouping column, for instance. In such cases we
2237 * handle coercions by inserting an extra level of Query that effectively
2238 * just does a projection.
2239 */
2240
2241 /*
2242 * Count the non-junk entries in the result targetlist.
2243 */
2245
2246 fn_typtype = get_typtype(rettype);
2247
2248 if (fn_typtype == TYPTYPE_BASE ||
2253 {
2254 /*
2255 * For scalar-type returns, the target list must have exactly one
2256 * non-junk entry, and its type must be coercible to rettype.
2257 */
2259
2260 if (tlistlen != 1)
2261 ereport(ERROR,
2263 errmsg("return type mismatch in function declared to return %s",
2264 format_type_be(rettype)),
2265 errdetail("Final statement must return exactly one column.")));
2266
2267 /* We assume here that non-junk TLEs must come first in tlists */
2268 tle = (TargetEntry *) linitial(tlist);
2269 Assert(!tle->resjunk);
2270
2271 if (!coerce_fn_result_column(tle, rettype, -1,
2273 &upper_tlist,
2275 ereport(ERROR,
2277 errmsg("return type mismatch in function declared to return %s",
2278 format_type_be(rettype)),
2279 errdetail("Actual return type is %s.",
2280 format_type_be(exprType((Node *) tle->expr)))));
2281 }
2282 else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
2283 {
2284 /*
2285 * Returns a rowtype.
2286 *
2287 * Note that we will not consider a domain over composite to be a
2288 * "rowtype" return type; it goes through the scalar case above. This
2289 * is because we only provide column-by-column implicit casting, and
2290 * will not cast the complete record result. So the only way to
2291 * produce a domain-over-composite result is to compute it as an
2292 * explicit single-column result. The single-composite-column code
2293 * path just below could handle such cases, but it won't be reached.
2294 */
2295 int tupnatts; /* physical number of columns in tuple */
2296 int tuplogcols; /* # of nondeleted columns in tuple */
2297 int colindex; /* physical column index */
2298
2299 /*
2300 * If the target list has one non-junk entry, and that expression has
2301 * or can be coerced to the declared return type, take it as the
2302 * result. This allows, for example, 'SELECT func2()', where func2
2303 * has the same composite return type as the function that's calling
2304 * it. This provision creates some ambiguity --- maybe the expression
2305 * was meant to be the lone field of the composite result --- but it
2306 * works well enough as long as we don't get too enthusiastic about
2307 * inventing coercions from scalar to composite types.
2308 *
2309 * XXX Note that if rettype is RECORD and the expression is of a named
2310 * composite type, or vice versa, this coercion will succeed, whether
2311 * or not the record type really matches. For the moment we rely on
2312 * runtime type checking to catch any discrepancy, but it'd be nice to
2313 * do better at parse time.
2314 *
2315 * We must *not* do this for a procedure, however. Procedures with
2316 * output parameter(s) have rettype RECORD, and the CALL code expects
2317 * to get results corresponding to the list of output parameters, even
2318 * when there's just one parameter that's composite.
2319 */
2320 if (tlistlen == 1 && prokind != PROKIND_PROCEDURE)
2321 {
2322 TargetEntry *tle = (TargetEntry *) linitial(tlist);
2323
2324 Assert(!tle->resjunk);
2325 if (coerce_fn_result_column(tle, rettype, -1,
2327 &upper_tlist,
2329 {
2330 /* Note that we're NOT setting is_tuple_result */
2332 }
2333 }
2334
2335 /*
2336 * If the caller didn't provide an expected tupdesc, we can't do any
2337 * further checking. Assume we're returning the whole tuple.
2338 */
2339 if (rettupdesc == NULL)
2340 return true;
2341
2342 /*
2343 * Verify that the targetlist matches the return tuple type. We scan
2344 * the non-resjunk columns, and coerce them if necessary to match the
2345 * datatypes of the non-deleted attributes. For deleted attributes,
2346 * insert NULL result columns if the caller asked for that.
2347 */
2348 tupnatts = rettupdesc->natts;
2349 tuplogcols = 0; /* we'll count nondeleted cols as we go */
2350 colindex = 0;
2351
2352 foreach(lc, tlist)
2353 {
2355 Form_pg_attribute attr;
2356
2357 /* resjunk columns can simply be ignored */
2358 if (tle->resjunk)
2359 continue;
2360
2361 do
2362 {
2363 colindex++;
2364 if (colindex > tupnatts)
2365 ereport(ERROR,
2367 errmsg("return type mismatch in function declared to return %s",
2368 format_type_be(rettype)),
2369 errdetail("Final statement returns too many columns.")));
2370 attr = TupleDescAttr(rettupdesc, colindex - 1);
2371 if (attr->attisdropped && insertDroppedCols)
2372 {
2373 Expr *null_expr;
2374
2375 /* The type of the null we insert isn't important */
2377 -1,
2378 InvalidOid,
2379 sizeof(int32),
2380 (Datum) 0,
2381 true, /* isnull */
2382 true /* byval */ );
2386 NULL,
2387 false));
2389 }
2390 } while (attr->attisdropped);
2391 tuplogcols++;
2392
2394 attr->atttypid, attr->atttypmod,
2396 &upper_tlist,
2398 ereport(ERROR,
2400 errmsg("return type mismatch in function declared to return %s",
2401 format_type_be(rettype)),
2402 errdetail("Final statement returns %s instead of %s at column %d.",
2403 format_type_be(exprType((Node *) tle->expr)),
2404 format_type_be(attr->atttypid),
2405 tuplogcols)));
2406 }
2407
2408 /* remaining columns in rettupdesc had better all be dropped */
2409 for (colindex++; colindex <= tupnatts; colindex++)
2410 {
2411 if (!TupleDescCompactAttr(rettupdesc, colindex - 1)->attisdropped)
2412 ereport(ERROR,
2414 errmsg("return type mismatch in function declared to return %s",
2415 format_type_be(rettype)),
2416 errdetail("Final statement returns too few columns.")));
2418 {
2419 Expr *null_expr;
2420
2421 /* The type of the null we insert isn't important */
2423 -1,
2424 InvalidOid,
2425 sizeof(int32),
2426 (Datum) 0,
2427 true, /* isnull */
2428 true /* byval */ );
2432 NULL,
2433 false));
2435 }
2436 }
2437
2438 /* Report that we are returning entire tuple result */
2439 is_tuple_result = true;
2440 }
2441 else
2442 ereport(ERROR,
2444 errmsg("return type %s is not supported for SQL functions",
2445 format_type_be(rettype))));
2446
2448
2449 /*
2450 * If necessary, modify the final Query by injecting an extra Query level
2451 * that just performs a projection. (It'd be dubious to do this to a
2452 * non-SELECT query, but we never have to; RETURNING lists can always be
2453 * modified in-place.)
2454 */
2456 {
2457 Query *newquery;
2458 List *colnames;
2461
2462 Assert(parse->commandType == CMD_SELECT);
2463
2464 /* Most of the upper Query struct can be left as zeroes/nulls */
2466 newquery->commandType = CMD_SELECT;
2467 newquery->querySource = parse->querySource;
2468 newquery->canSetTag = true;
2469 newquery->targetList = upper_tlist;
2470
2471 /* We need a moderately realistic colnames list for the subquery RTE */
2472 colnames = NIL;
2473 foreach(lc, parse->targetList)
2474 {
2476
2477 if (tle->resjunk)
2478 continue;
2479 colnames = lappend(colnames,
2480 makeString(tle->resname ? tle->resname : ""));
2481 }
2482
2483 /* Build a suitable RTE for the subquery */
2485 rte->rtekind = RTE_SUBQUERY;
2486 rte->subquery = parse;
2487 rte->eref = makeAlias("unnamed_subquery", colnames);
2488 rte->lateral = false;
2489 rte->inh = false;
2490 rte->inFromCl = true;
2491 newquery->rtable = list_make1(rte);
2492
2494 rtr->rtindex = 1;
2495 newquery->jointree = makeFromExpr(list_make1(rtr), NULL);
2496
2497 /*
2498 * Make sure the new query is marked as having row security if the
2499 * original one does.
2500 */
2501 newquery->hasRowSecurity = parse->hasRowSecurity;
2502
2503 /* Replace original query in the correct element of the query list */
2505 }
2506
2507 return is_tuple_result;
2508}
#define Assert(condition)
Definition c.h:945
int32_t int32
Definition c.h:614
int errdetail(const char *fmt,...) pg_attribute_printf(1
int ExecCleanTargetListLength(List *targetlist)
Definition execUtils.c:1190
char * format_type_be(Oid type_oid)
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:2521
void parse(int)
Definition parse.c:49
List * lappend(List *list, void *datum)
Definition list.c:339
char get_typtype(Oid typid)
Definition lsyscache.c:2851
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:279
@ CMD_INSERT
Definition nodes.h:277
@ CMD_DELETE
Definition nodes.h:278
@ CMD_UPDATE
Definition nodes.h:276
@ CMD_SELECT
Definition nodes.h:275
#define makeNode(_type_)
Definition nodes.h:161
@ RTE_SUBQUERY
FormData_pg_attribute * Form_pg_attribute
#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
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
Definition nodes.h:135
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:193
String * makeString(char *str)
Definition value.c:63

References Assert, CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_SELECT, CMD_UPDATE, coerce_fn_result_column(), ereport, errcode(), errdetail(), errmsg, ERROR, ExecCleanTargetListLength(), exprType(), fb(), format_type_be(), get_typtype(), InvalidOid, lappend(), lfirst, lfirst_node, linitial, list_length(), list_make1, makeAlias(), makeConst(), makeFromExpr(), makeNode, makeString(), makeTargetEntry(), TupleDescData::natts, NIL, parse(), RTE_SUBQUERY, 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 2521 of file functions.c.

2527{
2531
2532 /*
2533 * If the TLE has a sortgroupref marking, don't change it, as it probably
2534 * is referenced by ORDER BY, DISTINCT, etc, and changing its type would
2535 * break query semantics. Otherwise, it's safe to modify in-place unless
2536 * the query as a whole has issues with that.
2537 */
2538 if (tlist_is_modifiable && src_tle->ressortgroupref == 0)
2539 {
2540 /* OK to modify src_tle in place, if necessary */
2542 (Node *) src_tle->expr,
2543 exprType((Node *) src_tle->expr),
2547 -1);
2548 if (cast_result == NULL)
2549 return false;
2551 src_tle->expr = (Expr *) cast_result;
2552 /* Make a Var referencing the possibly-modified TLE */
2554 }
2555 else
2556 {
2557 /* Any casting must happen in the upper tlist */
2559
2561 (Node *) var,
2562 var->vartype,
2566 -1);
2567 if (cast_result == NULL)
2568 return false;
2570 /* Did the coercion actually do anything? */
2571 if (cast_result != (Node *) var)
2572 *upper_tlist_nontrivial = true;
2574 }
2577 src_tle->resname, false);
2579 return true;
2580}
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)
void assign_expr_collations(ParseState *pstate, Node *expr)
@ COERCE_IMPLICIT_CAST
Definition primnodes.h:769
@ COERCION_ASSIGNMENT
Definition primnodes.h:748

References assign_expr_collations(), COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, exprType(), fb(), lappend(), list_length(), makeTargetEntry(), and makeVarFromTargetEntry().

Referenced by check_sql_stmt_retval().

◆ CreateSQLFunctionDestReceiver()

DestReceiver * CreateSQLFunctionDestReceiver ( void  )

Definition at line 2618 of file functions.c.

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

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

Referenced by CreateDestReceiver().

◆ fmgr_sql()

Datum fmgr_sql ( PG_FUNCTION_ARGS  )

Definition at line 1577 of file functions.c.

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

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

Referenced by fmgr_info_cxt_security().

◆ get_sql_fn_result_tlist()

static List * get_sql_fn_result_tlist ( List queryTreeList)
static

Definition at line 2587 of file functions.c.

2588{
2589 Query *parse = NULL;
2590 ListCell *lc;
2591
2592 foreach(lc, queryTreeList)
2593 {
2594 Query *q = lfirst_node(Query, lc);
2595
2596 if (q->canSetTag)
2597 parse = q;
2598 }
2599 if (parse &&
2600 parse->commandType == CMD_SELECT)
2601 return parse->targetList;
2602 else if (parse &&
2603 (parse->commandType == CMD_INSERT ||
2604 parse->commandType == CMD_UPDATE ||
2605 parse->commandType == CMD_DELETE ||
2606 parse->commandType == CMD_MERGE) &&
2607 parse->returningList)
2608 return parse->returningList;
2609 else
2610 return NIL;
2611}

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

Referenced by init_execution_state().

◆ init_execution_state()

static bool init_execution_state ( SQLFunctionCachePtr  fcache)
static

Definition at line 654 of file functions.c.

655{
656 CachedPlanSource *plansource;
659 int nstmts;
660 ListCell *lc;
661
662 /*
663 * Clean up after previous query, if there was one.
664 */
665 if (fcache->cplan)
666 {
667 ReleaseCachedPlan(fcache->cplan, fcache->cowner);
668 fcache->cplan = NULL;
669 }
670 fcache->eslist = NULL;
671
672 /*
673 * Get the next CachedPlanSource, or stop if there are no more. We might
674 * need to create the next CachedPlanSource; if so, advance
675 * error_query_index first, so that errors detected in prepare_next_query
676 * are blamed on the right statement.
677 */
678 if (fcache->next_query_index >= list_length(fcache->func->plansource_list))
679 {
680 if (fcache->next_query_index >= fcache->func->num_queries)
681 return false;
682 fcache->error_query_index++;
684 }
685 else
686 fcache->error_query_index++;
687
688 plansource = (CachedPlanSource *) list_nth(fcache->func->plansource_list,
689 fcache->next_query_index);
690 fcache->next_query_index++;
691
692 /*
693 * Generate plans for the query or queries within this CachedPlanSource.
694 * Register the CachedPlan with the current resource owner. (Saving
695 * cowner here is mostly paranoia, but this way we needn't assume that
696 * CurrentResourceOwner will be the same when ShutdownSQLFunction runs.)
697 */
699 fcache->cplan = GetCachedPlan(plansource,
700 fcache->paramLI,
701 fcache->cowner,
702 NULL);
703
704 /*
705 * If necessary, make esarray[] bigger to hold the needed state.
706 */
707 nstmts = list_length(fcache->cplan->stmt_list);
708 if (nstmts > fcache->esarray_len)
709 {
710 if (fcache->esarray == NULL)
711 fcache->esarray = (execution_state *)
712 MemoryContextAlloc(fcache->fcontext,
713 sizeof(execution_state) * nstmts);
714 else
715 fcache->esarray = repalloc_array(fcache->esarray,
717 fcache->esarray_len = nstmts;
718 }
719
720 /*
721 * Build execution_state list to match the number of contained plans.
722 */
723 foreach(lc, fcache->cplan->stmt_list)
724 {
727
728 /*
729 * Precheck all commands for validity in a function. This should
730 * generally match the restrictions spi.c applies.
731 */
732 if (stmt->commandType == CMD_UTILITY)
733 {
734 if (IsA(stmt->utilityStmt, CopyStmt) &&
735 ((CopyStmt *) stmt->utilityStmt)->filename == NULL)
738 errmsg("cannot COPY to/from client in an SQL function")));
739
740 if (IsA(stmt->utilityStmt, TransactionStmt))
743 /* translator: %s is a SQL statement name */
744 errmsg("%s is not allowed in an SQL function",
745 CreateCommandName(stmt->utilityStmt))));
746 }
747
748 if (fcache->func->readonly_func && !CommandIsReadOnly(stmt))
751 /* translator: %s is a SQL statement name */
752 errmsg("%s is not allowed in a non-volatile function",
754
755 /* OK, build the execution_state for this query */
756 newes = &fcache->esarray[foreach_current_index(lc)];
757 if (preves)
758 preves->next = newes;
759 else
760 fcache->eslist = newes;
761
762 newes->next = NULL;
763 newes->status = F_EXEC_START;
764 newes->setsResult = false; /* might change below */
765 newes->lazyEval = false; /* might change below */
766 newes->stmt = stmt;
767 newes->qd = NULL;
768
769 if (stmt->canSetTag)
771
772 preves = newes;
773 }
774
775 /*
776 * If this isn't the last CachedPlanSource, we're done here. Otherwise,
777 * we need to prepare information about how to return the results.
778 */
779 if (fcache->next_query_index < fcache->func->num_queries)
780 return true;
781
782 /*
783 * Construct a JunkFilter we can use to coerce the returned rowtype to the
784 * desired form, unless the result type is VOID, in which case there's
785 * nothing to coerce to. (XXX Frequently, the JunkFilter isn't doing
786 * anything very interesting, but much of this module expects it to be
787 * there anyway.)
788 *
789 * Normally we can re-use the JunkFilter across executions, but if the
790 * plan for the last CachedPlanSource changed, we'd better rebuild it.
791 *
792 * The JunkFilter, its result slot, and its tupledesc are kept in a
793 * subsidiary memory context so that we can free them easily when needed.
794 */
795 if (fcache->func->rettype != VOIDOID &&
796 (fcache->junkFilter == NULL ||
797 fcache->jf_generation != fcache->cplan->generation))
798 {
799 TupleTableSlot *slot;
801 MemoryContext oldcontext;
802
803 /* Create or reset the jfcontext */
804 if (fcache->jfcontext == NULL)
805 fcache->jfcontext = AllocSetContextCreate(fcache->fcontext,
806 "SQL function junkfilter",
808 else
809 MemoryContextReset(fcache->jfcontext);
810 oldcontext = MemoryContextSwitchTo(fcache->jfcontext);
811
813
814 /*
815 * Re-fetch the (possibly modified) output tlist of the final
816 * statement. By this point, we should have thrown an error if there
817 * is not one.
818 */
820
821 /*
822 * If the result is composite, *and* we are returning the whole tuple
823 * result, we need to insert nulls for any dropped columns. In the
824 * single-column-result case, there might be dropped columns within
825 * the composite column value, but it's not our problem here. There
826 * should be no resjunk entries in resulttlist, so in the second case
827 * the JunkFilter is certainly a no-op.
828 */
829 if (fcache->func->rettupdesc && fcache->func->returnsTuple)
831 fcache->func->rettupdesc,
832 slot);
833 else
834 fcache->junkFilter = ExecInitJunkFilter(resulttlist, slot);
835
836 /*
837 * The resulttlist tree belongs to the plancache and might disappear
838 * underneath us due to plancache invalidation. While we could
839 * forestall that by copying it, that'd just be a waste of cycles,
840 * because the junkfilter doesn't need it anymore. (It'd only be used
841 * by ExecFindJunkAttribute(), which we don't use here.) To ensure
842 * there's not a dangling pointer laying about, clear the junkFilter's
843 * pointer.
844 */
845 fcache->junkFilter->jf_targetList = NIL;
846
847 /* Make sure output rowtype is properly blessed */
848 if (fcache->func->returnsTuple)
849 BlessTupleDesc(fcache->junkFilter->jf_resultSlot->tts_tupleDescriptor);
850
851 /* Mark the JunkFilter as up-to-date */
852 fcache->jf_generation = fcache->cplan->generation;
853
854 MemoryContextSwitchTo(oldcontext);
855 }
856
857 if (fcache->func->returnsSet &&
858 !fcache->func->returnsTuple &&
859 type_is_rowtype(fcache->func->rettype))
860 {
861 /*
862 * Returning rowtype as if it were scalar --- materialize won't work.
863 * Right now it's sufficient to override any caller preference for
864 * materialize mode, but this might need more work in future.
865 */
866 fcache->lazyEvalOK = true;
867 }
868
869 /*
870 * Mark the last canSetTag query as delivering the function result; then,
871 * if it is a plain SELECT, mark it for lazy evaluation. If it's not a
872 * SELECT we must always run it to completion.
873 *
874 * Note: at some point we might add additional criteria for whether to use
875 * lazy eval. However, we should prefer to use it whenever the function
876 * doesn't return set, since fetching more than one row is useless in that
877 * case.
878 *
879 * Note: don't set setsResult if the function returns VOID, as evidenced
880 * by not having made a junkfilter. This ensures we'll throw away any
881 * output from the last statement in such a function.
882 */
883 if (lasttages && fcache->junkFilter)
884 {
885 lasttages->setsResult = true;
886 if (fcache->lazyEvalOK &&
887 lasttages->stmt->commandType == CMD_SELECT &&
888 !lasttages->stmt->hasModifyingCTE)
889 fcache->lazyEval = lasttages->lazyEval = true;
890 }
891
892 return true;
893}
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)
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
const TupleTableSlotOps TTSOpsMinimalTuple
Definition execTuples.c:86
#define repalloc_array(pointer, type, count)
Definition fe_memutils.h:78
static void prepare_next_query(SQLFunctionHashEntry *func)
Definition functions.c:901
static List * get_sql_fn_result_tlist(List *queryTreeList)
Definition functions.c:2587
bool type_is_rowtype(Oid typid)
Definition lsyscache.c:2877
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition memutils.h:170
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403
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:1297
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition plancache.c:1428
ResourceOwner CurrentResourceOwner
Definition resowner.c:173
bool CommandIsReadOnly(PlannedStmt *pstmt)
Definition utility.c:96
static const char * CreateCommandName(Node *parsetree)
Definition utility.h:103

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, BlessTupleDesc(), CMD_SELECT, CMD_UTILITY, CommandIsReadOnly(), CreateCommandName(), CurrentResourceOwner, ereport, errcode(), errmsg, ERROR, ExecInitJunkFilter(), ExecInitJunkFilterConversion(), F_EXEC_START, fb(), foreach_current_index, get_sql_fn_result_tlist(), GetCachedPlan(), IsA, lfirst_node, list_length(), list_nth(), MakeSingleTupleTableSlot(), MemoryContextAlloc(), MemoryContextReset(), MemoryContextSwitchTo(), NIL, prepare_next_query(), CachedPlanSource::query_list, ReleaseCachedPlan(), repalloc_array, stmt, 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;
542
543 /*
544 * If this is the first execution for this FmgrInfo, set up a cache struct
545 * (initially containing null pointers). The cache must live as long as
546 * the FmgrInfo, so it goes in fn_mcxt. Also set up a memory context
547 * callback that will be invoked when fn_mcxt is deleted.
548 */
549 fcache = finfo->fn_extra;
550 if (fcache == NULL)
551 {
554 fcache->fcontext = finfo->fn_mcxt;
555 fcache->mcb.func = RemoveSQLFunctionCache;
556 fcache->mcb.arg = fcache;
558 finfo->fn_extra = fcache;
559 }
560
561 /*
562 * If the SQLFunctionCache is marked as active, we must have errored out
563 * of a prior execution. Reset state. (It might seem that we could also
564 * reach this during recursive invocation of a SQL function, but we won't
565 * because that case won't involve re-use of the same FmgrInfo.)
566 */
567 if (fcache->active)
568 {
569 /*
570 * In general, this stanza should clear all the same fields that
571 * ShutdownSQLFunction would. Note we must clear fcache->cplan
572 * without doing ReleaseCachedPlan, because error cleanup from the
573 * prior execution would have taken care of releasing that plan.
574 * Likewise, if tstore is still set then it is pointing at garbage.
575 */
576 fcache->cplan = NULL;
577 fcache->eslist = NULL;
578 fcache->tstore = NULL;
579 fcache->shutdown_reg = false;
580 fcache->active = false;
581 }
582
583 /*
584 * If we are resuming execution of a set-returning function, just keep
585 * using the same cache. We do not ask funccache.c to re-validate the
586 * SQLFunctionHashEntry: we want to run to completion using the function's
587 * initial definition.
588 */
589 if (fcache->eslist != NULL)
590 {
591 Assert(fcache->func != NULL);
592 return fcache;
593 }
594
595 /*
596 * Look up, or re-validate, the long-lived hash entry. Make the hash key
597 * depend on the result of get_call_result_type() when that's composite,
598 * so that we can safely assume that we'll build a new hash entry if the
599 * composite rowtype changes.
600 */
601 func = (SQLFunctionHashEntry *)
603 (CachedFunction *) fcache->func,
606 sizeof(SQLFunctionHashEntry),
607 true,
608 false);
609
610 /*
611 * Install the hash pointer in the SQLFunctionCache, and increment its use
612 * count to reflect that. If cached_function_compile gave us back a
613 * different hash entry than we were using before, we must decrement that
614 * one's use count.
615 */
616 if (func != fcache->func)
617 {
618 if (fcache->func != NULL)
619 {
620 Assert(fcache->func->cfunc.use_count > 0);
621 fcache->func->cfunc.use_count--;
622 }
623 fcache->func = func;
624 func->cfunc.use_count++;
625 /* Assume we need to rebuild the junkFilter */
626 fcache->junkFilter = NULL;
627 }
628
629 /*
630 * We're beginning a new execution of the function, so convert params to
631 * appropriate format.
632 */
634
635 /* Also reset lazyEval state for the new execution. */
636 fcache->lazyEvalOK = lazyEvalOK;
637 fcache->lazyEval = false;
638
639 /* Also reset data about where we are in the function. */
640 fcache->eslist = NULL;
641 fcache->next_query_index = 0;
642 fcache->error_query_index = 0;
643
644 return fcache;
645}
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:1214
static void sql_compile_callback(FunctionCallInfo fcinfo, HeapTuple procedureTuple, const CachedFunctionHashKey *hashkey, CachedFunction *cfunc, bool forValidator)
Definition functions.c:1041
static void postquel_sub_params(SQLFunctionCachePtr fcache, FunctionCallInfo fcinfo)
Definition functions.c:1474
static void RemoveSQLFunctionCache(void *arg)
Definition functions.c:2015
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition mcxt.c:582
uint64 use_count
Definition funccache.h:117
void * fn_extra
Definition fmgr.h:64
MemoryContext fn_mcxt
Definition fmgr.h:65
FmgrInfo * flinfo
Definition fmgr.h:87
CachedFunction cfunc
Definition functions.c:115

References Assert, cached_function_compile(), SQLFunctionHashEntry::cfunc, fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, MemoryContextAllocZero(), MemoryContextRegisterResetCallback(), postquel_sub_params(), RemoveSQLFunctionCache(), sql_compile_callback(), sql_delete_callback(), and CachedFunction::use_count.

Referenced by fmgr_sql().

◆ postquel_end()

static void postquel_end ( execution_state es,
SQLFunctionCachePtr  fcache 
)
static

Definition at line 1442 of file functions.c.

1443{
1444 MemoryContext oldcontext;
1445
1446 /* Run the sub-executor in subcontext */
1447 oldcontext = MemoryContextSwitchTo(fcache->subcontext);
1448
1449 /* mark status done to ensure we don't do ExecutorEnd twice */
1450 es->status = F_EXEC_DONE;
1451
1452 /* Utility commands don't need Executor. */
1453 if (es->qd->operation != CMD_UTILITY)
1454 {
1455 ExecutorFinish(es->qd);
1456 ExecutorEnd(es->qd);
1457 }
1458
1459 es->qd->dest->rDestroy(es->qd->dest);
1460
1461 FreeQueryDesc(es->qd);
1462 es->qd = NULL;
1463
1464 MemoryContextSwitchTo(oldcontext);
1465
1466 /* Delete the subcontext, if it's actually a separate context */
1467 if (fcache->ownSubcontext)
1468 MemoryContextDelete(fcache->subcontext);
1469 fcache->subcontext = NULL;
1470}
void ExecutorEnd(QueryDesc *queryDesc)
Definition execMain.c:468
void ExecutorFinish(QueryDesc *queryDesc)
Definition execMain.c:408
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
void FreeQueryDesc(QueryDesc *qdesc)
Definition pquery.c:106
DestReceiver * dest
Definition execdesc.h:41
CmdType operation
Definition execdesc.h:36

References CMD_UTILITY, QueryDesc::dest, ExecutorEnd(), ExecutorFinish(), F_EXEC_DONE, fb(), FreeQueryDesc(), MemoryContextDelete(), MemoryContextSwitchTo(), 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 
)
static

Definition at line 1537 of file functions.c.

1540{
1541 Datum value;
1542
1543 /*
1544 * Set up to return the function value. For pass-by-reference datatypes,
1545 * be sure to copy the result into the current context. We can't leave
1546 * the data in the TupleTableSlot because we must clear the slot before
1547 * returning.
1548 */
1549 if (fcache->func->returnsTuple)
1550 {
1551 /* We must return the whole tuple as a Datum. */
1552 fcinfo->isnull = false;
1554 }
1555 else
1556 {
1557 /*
1558 * Returning a scalar, which we have to extract from the first column
1559 * of the SELECT result, and then copy into current context if needed.
1560 */
1561 value = slot_getattr(slot, 1, &(fcinfo->isnull));
1562
1563 if (!fcinfo->isnull)
1564 value = datumCopy(value, fcache->func->typbyval, fcache->func->typlen);
1565 }
1566
1567 /* Clear the slot for next time */
1568 ExecClearTuple(slot);
1569
1570 return value;
1571}
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition datum.c:132
Datum ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
static struct @174 value
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition tuptable.h:417
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476

References datumCopy(), ExecClearTuple(), ExecFetchSlotHeapTupleDatum(), fb(), FunctionCallInfoBaseData::isnull, slot_getattr(), and value.

Referenced by fmgr_sql().

◆ postquel_getnext()

static bool postquel_getnext ( execution_state es,
SQLFunctionCachePtr  fcache 
)
static

Definition at line 1401 of file functions.c.

1402{
1403 bool result;
1404 MemoryContext oldcontext;
1405
1406 /* Run the sub-executor in subcontext */
1407 oldcontext = MemoryContextSwitchTo(fcache->subcontext);
1408
1409 if (es->qd->operation == CMD_UTILITY)
1410 {
1412 fcache->func->src,
1413 true, /* protect function cache's parsetree */
1415 es->qd->params,
1416 es->qd->queryEnv,
1417 es->qd->dest,
1418 NULL);
1419 result = true; /* never stops early */
1420 }
1421 else
1422 {
1423 /* Run regular commands to completion unless lazyEval */
1424 uint64 count = (es->lazyEval) ? 1 : 0;
1425
1426 ExecutorRun(es->qd, ForwardScanDirection, count);
1427
1428 /*
1429 * If we requested run to completion OR there was no tuple returned,
1430 * command must be complete.
1431 */
1432 result = (count == 0 || es->qd->estate->es_processed == 0);
1433 }
1434
1435 MemoryContextSwitchTo(oldcontext);
1436
1437 return result;
1438}
uint64_t uint64
Definition c.h:619
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition execMain.c:299
@ ForwardScanDirection
Definition sdir.h:28
uint64 es_processed
Definition execnodes.h:726
ParamListInfo params
Definition execdesc.h:42
EState * estate
Definition execdesc.h:48
PlannedStmt * plannedstmt
Definition execdesc.h:37
QueryEnvironment * queryEnv
Definition execdesc.h:43
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition utility.c:504
@ PROCESS_UTILITY_QUERY
Definition utility.h:23

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

Referenced by fmgr_sql().

◆ postquel_start()

static void postquel_start ( execution_state es,
SQLFunctionCachePtr  fcache 
)
static

Definition at line 1277 of file functions.c.

1278{
1281
1282 Assert(es->qd == NULL);
1283
1284 /* Caller should have ensured a suitable snapshot is active */
1286
1287 /*
1288 * In lazyEval mode for a SRF, we must run the sub-executor in a child of
1289 * fcontext, so that it can survive across multiple calls to fmgr_sql.
1290 * (XXX in the case of a long-lived FmgrInfo, this policy potentially
1291 * causes memory leakage, but it's not very clear where we could keep
1292 * stuff instead. Fortunately, there are few if any cases where
1293 * set-returning functions are invoked via FmgrInfos that would outlive
1294 * the calling query.) Otherwise, we're going to run it to completion
1295 * before exiting fmgr_sql, so it can perfectly well run in the caller's
1296 * context.
1297 */
1298 if (es->lazyEval && fcache->func->returnsSet)
1299 {
1300 fcache->subcontext = AllocSetContextCreate(fcache->fcontext,
1301 "SQL function execution",
1303 fcache->ownSubcontext = true;
1304 }
1305 else if (es->stmt->commandType == CMD_UTILITY)
1306 {
1307 /*
1308 * The code path using a sub-executor is pretty good about cleaning up
1309 * cruft, since the executor will make its own sub-context. We don't
1310 * really need an additional layer of sub-context in that case.
1311 * However, if this is a utility statement, it won't make its own
1312 * sub-context, so it seems advisable to make one that we can free on
1313 * completion.
1314 */
1316 "SQL function execution",
1318 fcache->ownSubcontext = true;
1319 }
1320 else
1321 {
1322 fcache->subcontext = CurrentMemoryContext;
1323 fcache->ownSubcontext = false;
1324 }
1325
1326 /*
1327 * Build a tuplestore if needed, that is if it's a set-returning function
1328 * and we're producing the function result without using lazyEval mode.
1329 */
1330 if (es->setsResult)
1331 {
1332 Assert(fcache->tstore == NULL);
1333 if (fcache->func->returnsSet && !es->lazyEval)
1334 {
1335 MemoryContextSwitchTo(fcache->tscontext);
1336 fcache->tstore = tuplestore_begin_heap(fcache->randomAccess,
1337 false, work_mem);
1338 }
1339 }
1340
1341 /* Switch into the selected subcontext (might be a no-op) */
1342 MemoryContextSwitchTo(fcache->subcontext);
1343
1344 /*
1345 * If this query produces the function result, collect its output using
1346 * our custom DestReceiver; else discard any output.
1347 */
1348 if (es->setsResult)
1349 {
1351
1353 /* pass down the needed info to the dest receiver routines */
1354 myState = (DR_sqlfunction *) dest;
1355 Assert(myState->pub.mydest == DestSQLFunction);
1356 myState->tstore = fcache->tstore; /* might be NULL */
1357 myState->filter = fcache->junkFilter;
1358
1359 /* Make very sure the junkfilter's result slot is empty */
1360 ExecClearTuple(fcache->junkFilter->jf_resultSlot);
1361 }
1362 else
1364
1365 es->qd = CreateQueryDesc(es->stmt,
1366 fcache->func->src,
1369 dest,
1370 fcache->paramLI,
1371 es->qd ? es->qd->queryEnv : NULL,
1372 0);
1373
1374 /* Utility commands don't need Executor. */
1375 if (es->qd->operation != CMD_UTILITY)
1376 {
1377 /*
1378 * In lazyEval mode, do not let the executor set up an AfterTrigger
1379 * context. This is necessary not just an optimization, because we
1380 * mustn't exit from the function execution with a stacked
1381 * AfterTrigger level still active. We are careful not to select
1382 * lazyEval mode for any statement that could possibly queue triggers.
1383 */
1384 int eflags;
1385
1386 if (es->lazyEval)
1387 eflags = EXEC_FLAG_SKIP_TRIGGERS;
1388 else
1389 eflags = 0; /* default run-to-completion flags */
1390 ExecutorStart(es->qd, eflags);
1391 }
1392
1393 es->status = F_EXEC_RUN;
1394
1395 MemoryContextSwitchTo(oldcontext);
1396}
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition dest.c:113
DestReceiver * None_Receiver
Definition dest.c:96
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition execMain.c:124
#define EXEC_FLAG_SKIP_TRIGGERS
Definition executor.h:72
int work_mem
Definition globals.c:131
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition pquery.c:68
bool ActiveSnapshotSet(void)
Definition snapmgr.c:812
Snapshot GetActiveSnapshot(void)
Definition snapmgr.c:800
#define InvalidSnapshot
Definition snapshot.h:119
CmdType commandType
Definition plannodes.h:66
PlannedStmt * stmt
Definition functions.c:75
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition tuplestore.c:331

References ActiveSnapshotSet(), ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, CMD_UTILITY, PlannedStmt::commandType, CreateDestReceiver(), CreateQueryDesc(), CurrentMemoryContext, DestSQLFunction, EXEC_FLAG_SKIP_TRIGGERS, ExecClearTuple(), ExecutorStart(), F_EXEC_RUN, fb(), GetActiveSnapshot(), InvalidSnapshot, execution_state::lazyEval, MemoryContextSwitchTo(), None_Receiver, QueryDesc::operation, execution_state::qd, QueryDesc::queryEnv, execution_state::setsResult, execution_state::status, execution_state::stmt, tuplestore_begin_heap(), and work_mem.

Referenced by fmgr_sql().

◆ postquel_sub_params()

static void postquel_sub_params ( SQLFunctionCachePtr  fcache,
FunctionCallInfo  fcinfo 
)
static

Definition at line 1474 of file functions.c.

1476{
1477 int nargs = fcinfo->nargs;
1478
1479 if (nargs > 0)
1480 {
1481 ParamListInfo paramLI;
1482 Oid *argtypes = fcache->func->pinfo->argtypes;
1483 int16 *argtyplen = fcache->func->argtyplen;
1484
1485 if (fcache->paramLI == NULL)
1486 {
1487 /* First time through: build a persistent ParamListInfo struct */
1488 MemoryContext oldcontext;
1489
1490 oldcontext = MemoryContextSwitchTo(fcache->fcontext);
1491 paramLI = makeParamList(nargs);
1492 fcache->paramLI = paramLI;
1493 MemoryContextSwitchTo(oldcontext);
1494 }
1495 else
1496 {
1497 paramLI = fcache->paramLI;
1498 Assert(paramLI->numParams == nargs);
1499 }
1500
1501 for (int i = 0; i < nargs; i++)
1502 {
1503 ParamExternData *prm = &paramLI->params[i];
1504
1505 /*
1506 * If an incoming parameter value is a R/W expanded datum, we
1507 * force it to R/O. We'd be perfectly entitled to scribble on it,
1508 * but the problem is that if the parameter is referenced more
1509 * than once in the function, earlier references might mutate the
1510 * value seen by later references, which won't do at all. We
1511 * could do better if we could be sure of the number of Param
1512 * nodes in the function's plans; but we might not have planned
1513 * all the statements yet, nor do we have plan tree walker
1514 * infrastructure. (Examining the parse trees is not good enough,
1515 * because of possible function inlining during planning.)
1516 */
1517 prm->isnull = fcinfo->args[i].isnull;
1518 prm->value = MakeExpandedObjectReadOnly(fcinfo->args[i].value,
1519 prm->isnull,
1520 argtyplen[i]);
1521 /* Allow the value to be substituted into custom plans */
1522 prm->pflags = PARAM_FLAG_CONST;
1523 prm->ptype = argtypes[i];
1524 }
1525 }
1526 else
1527 fcache->paramLI = NULL;
1528}
int16_t int16
Definition c.h:613
#define MakeExpandedObjectReadOnly(d, isnull, typlen)
int i
Definition isn.c:77
ParamListInfo makeParamList(int numParams)
Definition params.c:44
#define PARAM_FLAG_CONST
Definition params.h:87
unsigned int Oid
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition fmgr.h:95
Datum value
Definition postgres.h:87
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition params.h:124

References FunctionCallInfoBaseData::args, Assert, fb(), i, ParamExternData::isnull, NullableDatum::isnull, MakeExpandedObjectReadOnly, makeParamList(), MemoryContextSwitchTo(), FunctionCallInfoBaseData::nargs, ParamListInfoData::numParams, PARAM_FLAG_CONST, ParamListInfoData::params, and NullableDatum::value.

Referenced by init_sql_fcache().

◆ prepare_next_query()

static void prepare_next_query ( SQLFunctionHashEntry func)
static

Definition at line 901 of file functions.c.

902{
903 int qindex;
904 bool islast;
905 CachedPlanSource *plansource;
907 MemoryContext oldcontext;
908
909 /* Which query should we process? */
911 Assert(qindex < func->num_queries); /* else caller error */
912 islast = (qindex + 1 >= func->num_queries);
913
914 /*
915 * Parse and/or rewrite the query, creating a CachedPlanSource that holds
916 * a copy of the original parsetree. Note fine point: we make a copy of
917 * each original parsetree to ensure that the source_list in pcontext
918 * remains unmodified during parse analysis and rewrite. This is normally
919 * unnecessary, but we have to do it in case an error is raised during
920 * parse analysis. Otherwise, a fresh attempt to execute the function
921 * will arrive back here and try to work from a corrupted source_list.
922 */
923 if (!func->raw_source)
924 {
925 /* Source queries are already parse-analyzed */
926 Query *parsetree = list_nth_node(Query, func->source_list, qindex);
927
928 parsetree = copyObject(parsetree);
929 plansource = CreateCachedPlanForQuery(parsetree,
930 func->src,
931 CreateCommandTag((Node *) parsetree));
932 AcquireRewriteLocks(parsetree, true, false);
933 queryTree_list = pg_rewrite_query(parsetree);
934 }
935 else
936 {
937 /* Source queries are raw parsetrees */
938 RawStmt *parsetree = list_nth_node(RawStmt, func->source_list, qindex);
939
940 parsetree = copyObject(parsetree);
941 plansource = CreateCachedPlan(parsetree,
942 func->src,
943 CreateCommandTag(parsetree->stmt));
945 func->src,
947 func->pinfo,
948 NULL);
949 }
950
951 /*
952 * Check that there are no statements we don't want to allow.
953 */
955
956 /*
957 * If this is the last query, check that the function returns the type it
958 * claims to. Although in simple cases this was already done when the
959 * function was defined, we have to recheck because database objects used
960 * in the function's queries might have changed type. We'd have to
961 * recheck anyway if the function had any polymorphic arguments. Moreover,
962 * check_sql_stmt_retval takes care of injecting any required column type
963 * coercions. (But we don't ask it to insert nulls for dropped columns;
964 * the junkfilter handles that.)
965 *
966 * Note: we set func->returnsTuple according to whether we are returning
967 * the whole tuple result or just a single column. In the latter case we
968 * clear returnsTuple because we need not act different from the scalar
969 * result case, even if it's a rowtype column. (However, we have to force
970 * lazy eval mode in that case; otherwise we'd need extra code to expand
971 * the rowtype column into multiple columns, since we have no way to
972 * notify the caller that it should do that.)
973 */
974 if (islast)
976 func->rettype,
977 func->rettupdesc,
978 func->prokind,
979 false);
980
981 /*
982 * Now that check_sql_stmt_retval has done its thing, we can complete plan
983 * cache entry creation.
984 */
985 CompleteCachedPlan(plansource,
987 NULL,
988 NULL,
989 0,
991 func->pinfo,
993 false);
994
995 /*
996 * Install post-rewrite hook. Its arg is the hash entry if this is the
997 * last statement, else NULL.
998 */
999 SetPostRewriteHook(plansource,
1001 islast ? func : NULL);
1002
1003 /*
1004 * While the CachedPlanSources can take care of themselves, our List
1005 * pointing to them had better be in the hcontext.
1006 */
1007 oldcontext = MemoryContextSwitchTo(func->hcontext);
1008 func->plansource_list = lappend(func->plansource_list, plansource);
1009 MemoryContextSwitchTo(oldcontext);
1010
1011 /*
1012 * As soon as we've linked the CachedPlanSource into the list, mark it as
1013 * "saved".
1014 */
1015 SaveCachedPlan(plansource);
1016
1017 /*
1018 * Finally, if this was the last statement, we can flush the pcontext with
1019 * the original query trees; they're all safely copied into
1020 * CachedPlanSources now.
1021 */
1022 if (islast)
1023 {
1024 func->source_list = NIL; /* avoid dangling pointer */
1026 func->pcontext = NULL;
1027 }
1028}
static void sql_postrewrite_callback(List *querytree_list, void *arg)
Definition functions.c:1244
void sql_fn_parser_setup(struct ParseState *pstate, SQLFunctionParseInfoPtr pinfo)
Definition functions.c:341
#define copyObject(obj)
Definition nodes.h:232
void(* ParserSetupHook)(ParseState *pstate, void *arg)
Definition params.h:107
#define CURSOR_OPT_PARALLEL_OK
#define CURSOR_OPT_NO_SCROLL
#define list_nth_node(type, list, n)
Definition pg_list.h:327
void SaveCachedPlan(CachedPlanSource *plansource)
Definition plancache.c:547
CachedPlanSource * CreateCachedPlan(const RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
Definition plancache.c:185
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:393
CachedPlanSource * CreateCachedPlanForQuery(Query *analyzed_parse_tree, const char *query_string, CommandTag commandTag)
Definition plancache.c:265
void SetPostRewriteHook(CachedPlanSource *plansource, PostRewriteHook postRewrite, void *postRewriteArg)
Definition plancache.c:522
List * pg_analyze_and_rewrite_withcb(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg, QueryEnvironment *queryEnv)
Definition postgres.c:763
List * pg_rewrite_query(Query *query)
Definition postgres.c:803
void AcquireRewriteLocks(Query *parsetree, bool forExecute, bool forUpdatePushedDown)
Node * stmt
SQLFunctionParseInfoPtr pinfo
Definition functions.c:120
MemoryContext pcontext
Definition functions.c:139
MemoryContext hcontext
Definition functions.c:140
CommandTag CreateCommandTag(Node *parsetree)
Definition utility.c:2384

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

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

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

◆ RemoveSQLFunctionCache()

static void RemoveSQLFunctionCache ( void arg)
static

Definition at line 2015 of file functions.c.

2016{
2018
2019 /* Release reference count on SQLFunctionHashEntry */
2020 if (fcache->func != NULL)
2021 {
2022 Assert(fcache->func->cfunc.use_count > 0);
2023 fcache->func->cfunc.use_count--;
2024 /* This should be unnecessary, but let's just be sure: */
2025 fcache->func = NULL;
2026 }
2027}
Datum arg
Definition elog.c:1322

References arg, Assert, and fb().

Referenced by init_sql_fcache().

◆ ShutdownSQLFunction()

static void ShutdownSQLFunction ( Datum  arg)
static

Definition at line 1968 of file functions.c.

1969{
1971 execution_state *es;
1972
1973 es = fcache->eslist;
1974 while (es)
1975 {
1976 /* Shut down anything still running */
1977 if (es->status == F_EXEC_RUN)
1978 {
1979 /* Re-establish active snapshot for any called functions */
1980 if (!fcache->func->readonly_func)
1982
1983 postquel_end(es, fcache);
1984
1985 if (!fcache->func->readonly_func)
1987 }
1988 es = es->next;
1989 }
1990 fcache->eslist = NULL;
1991
1992 /* Release tuplestore if we have one */
1993 if (fcache->tstore)
1994 tuplestore_end(fcache->tstore);
1995 fcache->tstore = NULL;
1996
1997 /* Release CachedPlan if we have one */
1998 if (fcache->cplan)
1999 ReleaseCachedPlan(fcache->cplan, fcache->cowner);
2000 fcache->cplan = NULL;
2001
2002 /* execUtils will deregister the callback... */
2003 fcache->shutdown_reg = false;
2004}
SQLFunctionCache * SQLFunctionCachePtr
Definition functions.c:193
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
void tuplestore_end(Tuplestorestate *state)
Definition tuplestore.c:493

References arg, DatumGetPointer(), F_EXEC_RUN, fb(), execution_state::next, PopActiveSnapshot(), postquel_end(), PushActiveSnapshot(), execution_state::qd, ReleaseCachedPlan(), QueryDesc::snapshot, execution_state::status, 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 1041 of file functions.c.

1046{
1050 MemoryContext hcontext;
1051 MemoryContext pcontext;
1053 Oid rettype;
1054 TupleDesc rettupdesc;
1055 Datum tmp;
1056 bool isNull;
1057 List *source_list;
1058
1059 /*
1060 * Setup error traceback support for ereport() during compile. (This is
1061 * mainly useful for reporting parse errors from pg_parse_query.)
1062 */
1064 comperrcontext.arg = func;
1067
1068 /*
1069 * Create the hash entry's memory context. For now it's a child of the
1070 * caller's context, so that it will go away if we fail partway through.
1071 */
1073 "SQL function",
1075
1076 /*
1077 * Create the not-as-long-lived pcontext. We make this a child of
1078 * hcontext so that it doesn't require separate deletion.
1079 */
1080 pcontext = AllocSetContextCreate(hcontext,
1081 "SQL function parse trees",
1083 func->pcontext = pcontext;
1084
1085 /*
1086 * copy function name immediately for use by error reporting callback, and
1087 * for use as memory context identifier
1088 */
1089 func->fname = MemoryContextStrdup(hcontext,
1090 NameStr(procedureStruct->proname));
1091 MemoryContextSetIdentifier(hcontext, func->fname);
1092
1093 /*
1094 * Resolve any polymorphism, obtaining the actual result type, and the
1095 * corresponding tupdesc if it's a rowtype.
1096 */
1097 (void) get_call_result_type(fcinfo, &rettype, &rettupdesc);
1098
1099 func->rettype = rettype;
1100 if (rettupdesc)
1101 {
1102 MemoryContextSwitchTo(hcontext);
1103 func->rettupdesc = CreateTupleDescCopy(rettupdesc);
1104 MemoryContextSwitchTo(oldcontext);
1105 }
1106
1107 /* Fetch the typlen and byval info for the result type */
1108 get_typlenbyval(rettype, &func->typlen, &func->typbyval);
1109
1110 /* Remember whether we're returning setof something */
1111 func->returnsSet = procedureStruct->proretset;
1112
1113 /* Remember if function is STABLE/IMMUTABLE */
1114 func->readonly_func =
1115 (procedureStruct->provolatile != PROVOLATILE_VOLATILE);
1116
1117 /* Remember routine kind */
1118 func->prokind = procedureStruct->prokind;
1119
1120 /*
1121 * We need the actual argument types to pass to the parser. Also make
1122 * sure that parameter symbols are considered to have the function's
1123 * resolved input collation.
1124 */
1125 MemoryContextSwitchTo(hcontext);
1127 fcinfo->flinfo->fn_expr,
1129 MemoryContextSwitchTo(oldcontext);
1130
1131 /*
1132 * Now that we have the resolved argument types, collect their typlens for
1133 * use in postquel_sub_params.
1134 */
1135 func->argtyplen = (int16 *)
1136 MemoryContextAlloc(hcontext, func->pinfo->nargs * sizeof(int16));
1137 for (int i = 0; i < func->pinfo->nargs; i++)
1138 func->argtyplen[i] = get_typlen(func->pinfo->argtypes[i]);
1139
1140 /*
1141 * And of course we need the function body text.
1142 */
1144 func->src = MemoryContextStrdup(hcontext,
1145 TextDatumGetCString(tmp));
1146
1147 /* If we have prosqlbody, pay attention to that not prosrc. */
1151 &isNull);
1152 if (!isNull)
1153 {
1154 /* Source queries are already parse-analyzed */
1155 Node *n;
1156
1158 if (IsA(n, List))
1159 source_list = linitial_node(List, castNode(List, n));
1160 else
1161 source_list = list_make1(n);
1162 func->raw_source = false;
1163 }
1164 else
1165 {
1166 /* Source queries are raw parsetrees */
1167 source_list = pg_parse_query(func->src);
1168 func->raw_source = true;
1169 }
1170
1171 /*
1172 * Note: we must save the number of queries so that we'll still remember
1173 * how many there are after we discard source_list.
1174 */
1175 func->num_queries = list_length(source_list);
1176
1177 /*
1178 * Edge case: empty function body is OK only if it returns VOID. Normally
1179 * we validate that the last statement returns the right thing in
1180 * check_sql_stmt_retval, but we'll never reach that if there's no last
1181 * statement.
1182 */
1183 if (func->num_queries == 0 && rettype != VOIDOID)
1184 ereport(ERROR,
1186 errmsg("return type mismatch in function declared to return %s",
1187 format_type_be(rettype)),
1188 errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.")));
1189
1190 /* Save the source trees in pcontext for now. */
1191 MemoryContextSwitchTo(pcontext);
1192 func->source_list = copyObject(source_list);
1193 MemoryContextSwitchTo(oldcontext);
1194
1195 /*
1196 * We now have a fully valid hash entry, so reparent hcontext under
1197 * CacheMemoryContext to make all the subsidiary data long-lived, and only
1198 * then install the hcontext link so that sql_delete_callback will know to
1199 * delete it.
1200 */
1202 func->hcontext = hcontext;
1203
1205}
#define TextDatumGetCString(d)
Definition builtins.h:99
#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:1896
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:2471
int16 get_typlen(Oid typid)
Definition lsyscache.c:2417
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition mcxt.c:1768
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition mcxt.c:686
MemoryContext CacheMemoryContext
Definition mcxt.c:169
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition mcxt.c:661
#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:604
void * stringToNode(const char *str)
Definition read.c:90
Node * fn_expr
Definition fmgr.h:66
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:625

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, SQLFunctionParseInfo::argtypes, SQLFunctionHashEntry::argtyplen, CacheMemoryContext, castNode, copyObject, CreateTupleDescCopy(), CurrentMemoryContext, ereport, errcode(), errdetail(), errmsg, ERROR, error_context_stack, fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_expr, SQLFunctionHashEntry::fname, Form_pg_proc, format_type_be(), get_call_result_type(), get_typlen(), get_typlenbyval(), GETSTRUCT(), SQLFunctionHashEntry::hcontext, i, IsA, linitial_node, list_length(), list_make1, MemoryContextAlloc(), MemoryContextSetIdentifier(), MemoryContextSetParent(), MemoryContextStrdup(), MemoryContextSwitchTo(), NameStr, SQLFunctionParseInfo::nargs, 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 1896 of file functions.c.

1897{
1900
1901 /*
1902 * We can do nothing useful if sql_compile_callback() didn't get as far as
1903 * copying the function name
1904 */
1905 if (func->fname == NULL)
1906 return;
1907
1908 /*
1909 * If there is a syntax error position, convert to internal syntax error
1910 */
1912 if (syntaxerrposition > 0 && func->src != NULL)
1913 {
1914 errposition(0);
1916 internalerrquery(func->src);
1917 }
1918
1919 /*
1920 * sql_compile_callback() doesn't do any per-query processing, so just
1921 * report the context as "during startup".
1922 */
1923 errcontext("SQL function \"%s\" during startup", func->fname);
1924}
#define errcontext
Definition elog.h:198
int internalerrquery(const char *query)
int internalerrposition(int cursorpos)
int geterrposition(void)
int errposition(int cursorpos)

References arg, errcontext, errposition(), fb(), 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 1214 of file functions.c.

1215{
1217 ListCell *lc;
1218
1219 /* Release the CachedPlanSources */
1220 foreach(lc, func->plansource_list)
1221 {
1222 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
1223
1224 DropCachedPlan(plansource);
1225 }
1226 func->plansource_list = NIL;
1227
1228 /*
1229 * If we have an hcontext, free it, thereby getting rid of all subsidiary
1230 * data. (If we still have a pcontext, this gets rid of that too.)
1231 */
1232 if (func->hcontext)
1234 func->hcontext = NULL;
1235}
void DropCachedPlan(CachedPlanSource *plansource)
Definition plancache.c:591

References DropCachedPlan(), fb(), 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 1930 of file functions.c.

1931{
1934
1935 /*
1936 * If there is a syntax error position, convert to internal syntax error
1937 */
1939 if (syntaxerrposition > 0 && fcache->func->src != NULL)
1940 {
1941 errposition(0);
1943 internalerrquery(fcache->func->src);
1944 }
1945
1946 /*
1947 * If we failed while executing an identifiable query within the function,
1948 * report that. Otherwise say it was "during startup".
1949 */
1950 if (fcache->error_query_index > 0)
1951 errcontext("SQL function \"%s\" statement %d",
1952 fcache->func->fname, fcache->error_query_index);
1953 else
1954 errcontext("SQL function \"%s\" during startup", fcache->func->fname);
1955}

References arg, errcontext, errposition(), fb(), geterrposition(), internalerrposition(), and internalerrquery().

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:860
Oid get_typcollation(Oid typid)
Definition lsyscache.c:3278
@ PARAM_EXTERN
Definition primnodes.h:385
ParseLoc location
Definition primnodes.h:404
int32 paramtypmod
Definition primnodes.h:400
int paramid
Definition primnodes.h:397
Oid paramtype
Definition primnodes.h:398
ParamKind paramkind
Definition primnodes.h:396
Oid paramcollid
Definition primnodes.h:402

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

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
void * p_ref_hook_state
Definition parse_node.h:258

References fb(), SQLFunctionParseInfo::nargs, 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 fb(), ParseState::p_paramref_hook, ParseState::p_post_columnref_hook, ParseState::p_pre_columnref_hook, ParseState::p_ref_hook_state, sql_fn_param_ref(), and sql_fn_post_column_ref().

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

◆ 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);
398 if (nnames > 1)
399 {
400 subfield = (Node *) lsecond(cref->fields);
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);
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,
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:92
#define llast(l)
Definition pg_list.h:198
#define lthird(l)
Definition pg_list.h:188
#define lsecond(l)
Definition pg_list.h:183
Node * p_last_srf
Definition parse_node.h:248
Definition value.h:64
#define strVal(v)
Definition value.h:82

References Assert, fb(), SQLFunctionParseInfo::fname, IsA, linitial, list_length(), list_make1, llast, 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, fb(), 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 1244 of file functions.c.

1245{
1246 /*
1247 * Check that there are no statements we don't want to allow. (Presently,
1248 * there's no real point in this because the result can't change from what
1249 * we saw originally. But it's cheap and maybe someday it will matter.)
1250 */
1252
1253 /*
1254 * If this is the last query, we must re-do what check_sql_stmt_retval did
1255 * to its targetlist. Also check that returnsTuple didn't change (it
1256 * probably cannot, but be cautious).
1257 */
1258 if (arg != NULL)
1259 {
1261 bool returnsTuple;
1262
1264 func->rettype,
1265 func->rettupdesc,
1266 func->prokind,
1267 false);
1268 if (returnsTuple != func->returnsTuple)
1269 ereport(ERROR,
1271 errmsg("cached plan must not change result type")));
1272 }
1273}

References arg, check_sql_fn_statement(), check_sql_stmt_retval(), ereport, errcode(), errmsg, ERROR, fb(), 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 2693 of file functions.c.

2694{
2695 pfree(self);
2696}
void pfree(void *pointer)
Definition mcxt.c:1616

References pfree().

Referenced by CreateSQLFunctionDestReceiver().

◆ sqlfunction_receive()

static bool sqlfunction_receive ( TupleTableSlot slot,
DestReceiver self 
)
static

Definition at line 2646 of file functions.c.

2647{
2649
2650 if (myState->tstore)
2651 {
2652 /* We are collecting all of a set result into the tuplestore */
2653
2654 /* Filter tuple as needed */
2655 slot = ExecFilterJunk(myState->filter, slot);
2656
2657 /* Store the filtered tuple into the tuplestore */
2658 tuplestore_puttupleslot(myState->tstore, slot);
2659 }
2660 else
2661 {
2662 /*
2663 * We only want the first tuple, which we'll save in the junkfilter's
2664 * result slot. Ignore any additional tuples passed.
2665 */
2666 if (TTS_EMPTY(myState->filter->jf_resultSlot))
2667 {
2668 /* Filter tuple as needed */
2669 slot = ExecFilterJunk(myState->filter, slot);
2670 Assert(slot == myState->filter->jf_resultSlot);
2671
2672 /* Materialize the slot so it preserves pass-by-ref values */
2673 ExecMaterializeSlot(slot);
2674 }
2675 }
2676
2677 return true;
2678}
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition execJunk.c:247
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition tuplestore.c:743
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition tuptable.h:494

References Assert, ExecFilterJunk(), ExecMaterializeSlot(), fb(), TTS_EMPTY, and tuplestore_puttupleslot().

Referenced by CreateSQLFunctionDestReceiver().

◆ sqlfunction_shutdown()

static void sqlfunction_shutdown ( DestReceiver self)
static

Definition at line 2684 of file functions.c.

2685{
2686 /* no-op */
2687}

Referenced by CreateSQLFunctionDestReceiver().

◆ sqlfunction_startup()

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

Definition at line 2637 of file functions.c.

2638{
2639 /* no-op */
2640}

Referenced by CreateSQLFunctionDestReceiver().