PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pl_handler.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "plpgsql.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/varlena.h"
Include dependency graph for pl_handler.c:

Go to the source code of this file.

Functions

static bool plpgsql_extra_checks_check_hook (char **newvalue, void **extra, GucSource source)
 
static void plpgsql_extra_warnings_assign_hook (const char *newvalue, void *extra)
 
static void plpgsql_extra_errors_assign_hook (const char *newvalue, void *extra)
 
 PG_MODULE_MAGIC_EXT (.name="plpgsql",.version=PG_VERSION)
 
void _PG_init (void)
 
 PG_FUNCTION_INFO_V1 (plpgsql_call_handler)
 
Datum plpgsql_call_handler (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (plpgsql_inline_handler)
 
Datum plpgsql_inline_handler (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (plpgsql_validator)
 
Datum plpgsql_validator (PG_FUNCTION_ARGS)
 

Variables

static const struct config_enum_entry variable_conflict_options []
 
int plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR
 
bool plpgsql_print_strict_params = false
 
bool plpgsql_check_asserts = true
 
static char * plpgsql_extra_warnings_string = NULL
 
static char * plpgsql_extra_errors_string = NULL
 
int plpgsql_extra_warnings
 
int plpgsql_extra_errors
 
PLpgSQL_plugin ** plpgsql_plugin_ptr = NULL
 

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 148 of file pl_handler.c.

149{
150 /* Be sure we do initialization only once (should be redundant now) */
151 static bool inited = false;
152
153 if (inited)
154 return;
155
157
158 DefineCustomEnumVariable("plpgsql.variable_conflict",
159 gettext_noop("Sets handling of conflicts between PL/pgSQL variable names and table column names."),
160 NULL,
164 PGC_SUSET, 0,
165 NULL, NULL, NULL);
166
167 DefineCustomBoolVariable("plpgsql.print_strict_params",
168 gettext_noop("Print information about parameters in the DETAIL part of the error messages generated on INTO ... STRICT failures."),
169 NULL,
171 false,
172 PGC_USERSET, 0,
173 NULL, NULL, NULL);
174
175 DefineCustomBoolVariable("plpgsql.check_asserts",
176 gettext_noop("Perform checks given in ASSERT statements."),
177 NULL,
179 true,
180 PGC_USERSET, 0,
181 NULL, NULL, NULL);
182
183 DefineCustomStringVariable("plpgsql.extra_warnings",
184 gettext_noop("List of programming constructs that should produce a warning."),
185 NULL,
187 "none",
191 NULL);
192
193 DefineCustomStringVariable("plpgsql.extra_errors",
194 gettext_noop("List of programming constructs that should produce an error."),
195 NULL,
197 "none",
201 NULL);
202
203 MarkGUCPrefixReserved("plpgsql");
204
207
208 /* Set up a rendezvous point with optional instrumentation plugin */
210
211 inited = true;
212}
#define gettext_noop(x)
Definition: c.h:1167
void ** find_rendezvous_variable(const char *varName)
Definition: dfmgr.c:657
#define TEXTDOMAIN
Definition: elog.h:152
void DefineCustomEnumVariable(const char *name, const char *short_desc, const char *long_desc, int *valueAddr, int bootValue, const struct config_enum_entry *options, GucContext context, int flags, GucEnumCheckHook check_hook, GucEnumAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:5244
void DefineCustomStringVariable(const char *name, const char *short_desc, const char *long_desc, char **valueAddr, const char *bootValue, GucContext context, int flags, GucStringCheckHook check_hook, GucStringAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:5219
void DefineCustomBoolVariable(const char *name, const char *short_desc, const char *long_desc, bool *valueAddr, bool bootValue, GucContext context, int flags, GucBoolCheckHook check_hook, GucBoolAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:5133
void MarkGUCPrefixReserved(const char *className)
Definition: guc.c:5280
#define GUC_LIST_INPUT
Definition: guc.h:214
@ PGC_SUSET
Definition: guc.h:78
@ PGC_USERSET
Definition: guc.h:79
void pg_bindtextdomain(const char *domain)
Definition: miscinit.c:1939
void plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg)
Definition: pl_exec.c:8753
void plpgsql_xact_cb(XactEvent event, void *arg)
Definition: pl_exec.c:8711
int plpgsql_variable_conflict
Definition: pl_handler.c:47
static void plpgsql_extra_errors_assign_hook(const char *newvalue, void *extra)
Definition: pl_handler.c:136
bool plpgsql_check_asserts
Definition: pl_handler.c:51
static const struct config_enum_entry variable_conflict_options[]
Definition: pl_handler.c:40
static char * plpgsql_extra_errors_string
Definition: pl_handler.c:54
bool plpgsql_print_strict_params
Definition: pl_handler.c:49
PLpgSQL_plugin ** plpgsql_plugin_ptr
Definition: pl_handler.c:59
static void plpgsql_extra_warnings_assign_hook(const char *newvalue, void *extra)
Definition: pl_handler.c:130
static bool plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source)
Definition: pl_handler.c:63
static char * plpgsql_extra_warnings_string
Definition: pl_handler.c:53
@ PLPGSQL_RESOLVE_ERROR
Definition: plpgsql.h:186
void RegisterXactCallback(XactCallback callback, void *arg)
Definition: xact.c:3804
void RegisterSubXactCallback(SubXactCallback callback, void *arg)
Definition: xact.c:3864

References DefineCustomBoolVariable(), DefineCustomEnumVariable(), DefineCustomStringVariable(), find_rendezvous_variable(), gettext_noop, GUC_LIST_INPUT, MarkGUCPrefixReserved(), pg_bindtextdomain(), PGC_SUSET, PGC_USERSET, plpgsql_check_asserts, plpgsql_extra_checks_check_hook(), plpgsql_extra_errors_assign_hook(), plpgsql_extra_errors_string, plpgsql_extra_warnings_assign_hook(), plpgsql_extra_warnings_string, plpgsql_plugin_ptr, plpgsql_print_strict_params, PLPGSQL_RESOLVE_ERROR, plpgsql_subxact_cb(), plpgsql_variable_conflict, plpgsql_xact_cb(), RegisterSubXactCallback(), RegisterXactCallback(), TEXTDOMAIN, and variable_conflict_options.

◆ PG_FUNCTION_INFO_V1() [1/3]

PG_FUNCTION_INFO_V1 ( plpgsql_call_handler  )

◆ PG_FUNCTION_INFO_V1() [2/3]

PG_FUNCTION_INFO_V1 ( plpgsql_inline_handler  )

◆ PG_FUNCTION_INFO_V1() [3/3]

PG_FUNCTION_INFO_V1 ( plpgsql_validator  )

◆ PG_MODULE_MAGIC_EXT()

PG_MODULE_MAGIC_EXT ( name = "plpgsql",
version = PG_VERSION 
)

◆ plpgsql_call_handler()

Datum plpgsql_call_handler ( PG_FUNCTION_ARGS  )

Definition at line 224 of file pl_handler.c.

225{
226 bool nonatomic;
227 PLpgSQL_function *func;
228 PLpgSQL_execstate *save_cur_estate;
229 ResourceOwner procedure_resowner;
230 volatile Datum retval = (Datum) 0;
231 int rc;
232
233 nonatomic = fcinfo->context &&
234 IsA(fcinfo->context, CallContext) &&
235 !castNode(CallContext, fcinfo->context)->atomic;
236
237 /*
238 * Connect to SPI manager
239 */
240 SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0);
241
242 /* Find or compile the function */
243 func = plpgsql_compile(fcinfo, false);
244
245 /* Must save and restore prior value of cur_estate */
246 save_cur_estate = func->cur_estate;
247
248 /* Mark the function as busy, so it can't be deleted from under us */
249 func->cfunc.use_count++;
250
251 /*
252 * If we'll need a procedure-lifespan resowner to execute any CALL or DO
253 * statements, create it now. Since this resowner is not tied to any
254 * parent, failing to free it would result in process-lifespan leaks.
255 * Therefore, be very wary of adding any code between here and the PG_TRY
256 * block.
257 */
258 procedure_resowner =
259 (nonatomic && func->requires_procedure_resowner) ?
260 ResourceOwnerCreate(NULL, "PL/pgSQL procedure resources") : NULL;
261
262 PG_TRY();
263 {
264 /*
265 * Determine if called as function or trigger and call appropriate
266 * subhandler
267 */
268 if (CALLED_AS_TRIGGER(fcinfo))
270 (TriggerData *) fcinfo->context));
271 else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
272 {
274 (EventTriggerData *) fcinfo->context);
275 /* there's no return value in this case */
276 }
277 else
278 retval = plpgsql_exec_function(func, fcinfo,
279 NULL, NULL,
280 procedure_resowner,
281 !nonatomic);
282 }
283 PG_FINALLY();
284 {
285 /* Decrement use-count, restore cur_estate */
286 func->cfunc.use_count--;
287 func->cur_estate = save_cur_estate;
288
289 /* Be sure to release the procedure resowner if any */
290 if (procedure_resowner)
291 {
292 ReleaseAllPlanCacheRefsInOwner(procedure_resowner);
293 ResourceOwnerDelete(procedure_resowner);
294 }
295 }
296 PG_END_TRY();
297
298 /*
299 * Disconnect from SPI manager
300 */
301 if ((rc = SPI_finish()) != SPI_OK_FINISH)
302 elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
303
304 return retval;
305}
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define PG_FINALLY(...)
Definition: elog.h:388
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
Definition: event_trigger.h:49
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
PLpgSQL_function * plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator)
Definition: pl_comp.c:106
Datum plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, EState *simple_eval_estate, ResourceOwner simple_eval_resowner, ResourceOwner procedure_resowner, bool atomic)
Definition: pl_exec.c:493
HeapTuple plpgsql_exec_trigger(PLpgSQL_function *func, TriggerData *trigdata)
Definition: pl_exec.c:935
void plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
Definition: pl_exec.c:1175
void ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner)
Definition: plancache.c:2494
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:421
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:871
const char * SPI_result_code_string(int code)
Definition: spi.c:1974
int SPI_finish(void)
Definition: spi.c:183
int SPI_connect_ext(int options)
Definition: spi.c:101
#define SPI_OPT_NONATOMIC
Definition: spi.h:102
#define SPI_OK_FINISH
Definition: spi.h:83
uint64 use_count
Definition: funccache.h:117
bool requires_procedure_resowner
Definition: plpgsql.h:1002
CachedFunction cfunc
Definition: plpgsql.h:960
struct PLpgSQL_execstate * cur_estate
Definition: plpgsql.h:1006
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:26

References CALLED_AS_EVENT_TRIGGER, CALLED_AS_TRIGGER, castNode, PLpgSQL_function::cfunc, PLpgSQL_function::cur_estate, elog, ERROR, IsA, PG_END_TRY, PG_FINALLY, PG_TRY, plpgsql_compile(), plpgsql_exec_event_trigger(), plpgsql_exec_function(), plpgsql_exec_trigger(), PointerGetDatum(), ReleaseAllPlanCacheRefsInOwner(), PLpgSQL_function::requires_procedure_resowner, ResourceOwnerCreate(), ResourceOwnerDelete(), SPI_connect_ext(), SPI_finish(), SPI_OK_FINISH, SPI_OPT_NONATOMIC, SPI_result_code_string(), and CachedFunction::use_count.

◆ plpgsql_extra_checks_check_hook()

static bool plpgsql_extra_checks_check_hook ( char **  newvalue,
void **  extra,
GucSource  source 
)
static

Definition at line 63 of file pl_handler.c.

64{
65 char *rawstring;
66 List *elemlist;
67 ListCell *l;
68 int extrachecks = 0;
69 int *myextra;
70
71 if (pg_strcasecmp(*newvalue, "all") == 0)
72 extrachecks = PLPGSQL_XCHECK_ALL;
73 else if (pg_strcasecmp(*newvalue, "none") == 0)
74 extrachecks = PLPGSQL_XCHECK_NONE;
75 else
76 {
77 /* Need a modifiable copy of string */
78 rawstring = pstrdup(*newvalue);
79
80 /* Parse string into list of identifiers */
81 if (!SplitIdentifierString(rawstring, ',', &elemlist))
82 {
83 /* syntax error in list */
84 GUC_check_errdetail("List syntax is invalid.");
85 pfree(rawstring);
86 list_free(elemlist);
87 return false;
88 }
89
90 foreach(l, elemlist)
91 {
92 char *tok = (char *) lfirst(l);
93
94 if (pg_strcasecmp(tok, "shadowed_variables") == 0)
95 extrachecks |= PLPGSQL_XCHECK_SHADOWVAR;
96 else if (pg_strcasecmp(tok, "too_many_rows") == 0)
97 extrachecks |= PLPGSQL_XCHECK_TOOMANYROWS;
98 else if (pg_strcasecmp(tok, "strict_multi_assignment") == 0)
100 else if (pg_strcasecmp(tok, "all") == 0 || pg_strcasecmp(tok, "none") == 0)
101 {
102 GUC_check_errdetail("Key word \"%s\" cannot be combined with other key words.", tok);
103 pfree(rawstring);
104 list_free(elemlist);
105 return false;
106 }
107 else
108 {
109 GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
110 pfree(rawstring);
111 list_free(elemlist);
112 return false;
113 }
114 }
115
116 pfree(rawstring);
117 list_free(elemlist);
118 }
119
120 myextra = (int *) guc_malloc(LOG, sizeof(int));
121 if (!myextra)
122 return false;
123 *myextra = extrachecks;
124 *extra = myextra;
125
126 return true;
127}
#define LOG
Definition: elog.h:31
void * guc_malloc(int elevel, size_t size)
Definition: guc.c:638
#define GUC_check_errdetail
Definition: guc.h:481
void list_free(List *list)
Definition: list.c:1546
char * pstrdup(const char *in)
Definition: mcxt.c:2325
void pfree(void *pointer)
Definition: mcxt.c:2150
#define lfirst(lc)
Definition: pg_list.h:172
#define PLPGSQL_XCHECK_SHADOWVAR
Definition: plpgsql.h:1195
#define PLPGSQL_XCHECK_ALL
Definition: plpgsql.h:1198
#define PLPGSQL_XCHECK_NONE
Definition: plpgsql.h:1194
#define PLPGSQL_XCHECK_TOOMANYROWS
Definition: plpgsql.h:1196
#define PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT
Definition: plpgsql.h:1197
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
Definition: pg_list.h:54
bool SplitIdentifierString(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3525

References GUC_check_errdetail, guc_malloc(), lfirst, list_free(), LOG, pfree(), pg_strcasecmp(), PLPGSQL_XCHECK_ALL, PLPGSQL_XCHECK_NONE, PLPGSQL_XCHECK_SHADOWVAR, PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT, PLPGSQL_XCHECK_TOOMANYROWS, pstrdup(), and SplitIdentifierString().

Referenced by _PG_init().

◆ plpgsql_extra_errors_assign_hook()

static void plpgsql_extra_errors_assign_hook ( const char *  newvalue,
void *  extra 
)
static

Definition at line 136 of file pl_handler.c.

137{
138 plpgsql_extra_errors = *((int *) extra);
139}
int plpgsql_extra_errors
Definition: pl_handler.c:56

References plpgsql_extra_errors.

Referenced by _PG_init().

◆ plpgsql_extra_warnings_assign_hook()

static void plpgsql_extra_warnings_assign_hook ( const char *  newvalue,
void *  extra 
)
static

Definition at line 130 of file pl_handler.c.

131{
132 plpgsql_extra_warnings = *((int *) extra);
133}
int plpgsql_extra_warnings
Definition: pl_handler.c:55

References plpgsql_extra_warnings.

Referenced by _PG_init().

◆ plpgsql_inline_handler()

Datum plpgsql_inline_handler ( PG_FUNCTION_ARGS  )

Definition at line 316 of file pl_handler.c.

317{
318 LOCAL_FCINFO(fake_fcinfo, 0);
320 PLpgSQL_function *func;
321 FmgrInfo flinfo;
322 EState *simple_eval_estate;
323 ResourceOwner simple_eval_resowner;
324 Datum retval;
325 int rc;
326
327 /*
328 * Connect to SPI manager
329 */
330 SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC);
331
332 /* Compile the anonymous code block */
333 func = plpgsql_compile_inline(codeblock->source_text);
334
335 /* Mark the function as busy, just pro forma */
336 func->cfunc.use_count++;
337
338 /*
339 * Set up a fake fcinfo with just enough info to satisfy
340 * plpgsql_exec_function(). In particular note that this sets things up
341 * with no arguments passed.
342 */
343 MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
344 MemSet(&flinfo, 0, sizeof(flinfo));
345 fake_fcinfo->flinfo = &flinfo;
346 flinfo.fn_oid = InvalidOid;
348
349 /*
350 * Create a private EState and resowner for simple-expression execution.
351 * Notice that these are NOT tied to transaction-level resources; they
352 * must survive any COMMIT/ROLLBACK the DO block executes, since we will
353 * unconditionally try to clean them up below. (Hence, be wary of adding
354 * anything that could fail between here and the PG_TRY block.) See the
355 * comments for shared_simple_eval_estate.
356 *
357 * Because this resowner isn't tied to the calling transaction, we can
358 * also use it as the "procedure" resowner for any CALL statements. That
359 * helps reduce the opportunities for failure here.
360 */
361 simple_eval_estate = CreateExecutorState();
362 simple_eval_resowner =
363 ResourceOwnerCreate(NULL, "PL/pgSQL DO block simple expressions");
364
365 /* And run the function */
366 PG_TRY();
367 {
368 retval = plpgsql_exec_function(func, fake_fcinfo,
369 simple_eval_estate,
370 simple_eval_resowner,
371 simple_eval_resowner, /* see above */
372 codeblock->atomic);
373 }
374 PG_CATCH();
375 {
376 /*
377 * We need to clean up what would otherwise be long-lived resources
378 * accumulated by the failed DO block, principally cached plans for
379 * statements (which can be flushed by plpgsql_free_function_memory),
380 * execution trees for simple expressions, which are in the private
381 * EState, and cached-plan refcounts held by the private resowner.
382 *
383 * Before releasing the private EState, we must clean up any
384 * simple_econtext_stack entries pointing into it, which we can do by
385 * invoking the subxact callback. (It will be called again later if
386 * some outer control level does a subtransaction abort, but no harm
387 * is done.) We cheat a bit knowing that plpgsql_subxact_cb does not
388 * pay attention to its parentSubid argument.
389 */
392 0, NULL);
393
394 /* Clean up the private EState and resowner */
395 FreeExecutorState(simple_eval_estate);
396 ReleaseAllPlanCacheRefsInOwner(simple_eval_resowner);
397 ResourceOwnerDelete(simple_eval_resowner);
398
399 /* Function should now have no remaining use-counts ... */
400 func->cfunc.use_count--;
401 Assert(func->cfunc.use_count == 0);
402
403 /* ... so we can free subsidiary storage */
405
406 /* And propagate the error */
407 PG_RE_THROW();
408 }
409 PG_END_TRY();
410
411 /* Clean up the private EState and resowner */
412 FreeExecutorState(simple_eval_estate);
413 ReleaseAllPlanCacheRefsInOwner(simple_eval_resowner);
414 ResourceOwnerDelete(simple_eval_resowner);
415
416 /* Function should now have no remaining use-counts ... */
417 func->cfunc.use_count--;
418 Assert(func->cfunc.use_count == 0);
419
420 /* ... so we can free subsidiary storage */
422
423 /*
424 * Disconnect from SPI manager
425 */
426 if ((rc = SPI_finish()) != SPI_OK_FINISH)
427 elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
428
429 return retval;
430}
#define MemSet(start, val, len)
Definition: c.h:991
#define PG_RE_THROW()
Definition: elog.h:404
#define PG_CATCH(...)
Definition: elog.h:381
void FreeExecutorState(EState *estate)
Definition: execUtils.c:193
EState * CreateExecutorState(void)
Definition: execUtils.c:88
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
Assert(PointerIsAligned(start, uint64))
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
PLpgSQL_function * plpgsql_compile_inline(char *proc_source)
Definition: pl_comp.c:729
void plpgsql_free_function_memory(PLpgSQL_function *func)
Definition: pl_funcs.c:716
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
#define InvalidOid
Definition: postgres_ext.h:35
Definition: fmgr.h:57
MemoryContext fn_mcxt
Definition: fmgr.h:65
Oid fn_oid
Definition: fmgr.h:59
char * source_text
Definition: parsenodes.h:3581
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:791
@ SUBXACT_EVENT_ABORT_SUB
Definition: xact.h:144

References Assert(), InlineCodeBlock::atomic, castNode, PLpgSQL_function::cfunc, CreateExecutorState(), CurrentMemoryContext, DatumGetPointer(), elog, ERROR, FmgrInfo::fn_mcxt, FmgrInfo::fn_oid, FreeExecutorState(), GetCurrentSubTransactionId(), InvalidOid, LOCAL_FCINFO, MemSet, PG_CATCH, PG_END_TRY, PG_GETARG_DATUM, PG_RE_THROW, PG_TRY, plpgsql_compile_inline(), plpgsql_exec_function(), plpgsql_free_function_memory(), plpgsql_subxact_cb(), ReleaseAllPlanCacheRefsInOwner(), ResourceOwnerCreate(), ResourceOwnerDelete(), SizeForFunctionCallInfo, InlineCodeBlock::source_text, SPI_connect_ext(), SPI_finish(), SPI_OK_FINISH, SPI_OPT_NONATOMIC, SPI_result_code_string(), SUBXACT_EVENT_ABORT_SUB, and CachedFunction::use_count.

◆ plpgsql_validator()

Datum plpgsql_validator ( PG_FUNCTION_ARGS  )

Definition at line 442 of file pl_handler.c.

443{
444 Oid funcoid = PG_GETARG_OID(0);
445 HeapTuple tuple;
446 Form_pg_proc proc;
447 char functyptype;
448 int numargs;
449 Oid *argtypes;
450 char **argnames;
451 char *argmodes;
452 bool is_dml_trigger = false;
453 bool is_event_trigger = false;
454 int i;
455
456 if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
458
459 /* Get the new function's pg_proc entry */
460 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
461 if (!HeapTupleIsValid(tuple))
462 elog(ERROR, "cache lookup failed for function %u", funcoid);
463 proc = (Form_pg_proc) GETSTRUCT(tuple);
464
465 functyptype = get_typtype(proc->prorettype);
466
467 /* Disallow pseudotype result */
468 /* except for TRIGGER, EVTTRIGGER, RECORD, VOID, or polymorphic */
469 if (functyptype == TYPTYPE_PSEUDO)
470 {
471 if (proc->prorettype == TRIGGEROID)
472 is_dml_trigger = true;
473 else if (proc->prorettype == EVENT_TRIGGEROID)
474 is_event_trigger = true;
475 else if (proc->prorettype != RECORDOID &&
476 proc->prorettype != VOIDOID &&
477 !IsPolymorphicType(proc->prorettype))
479 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
480 errmsg("PL/pgSQL functions cannot return type %s",
481 format_type_be(proc->prorettype))));
482 }
483
484 /* Disallow pseudotypes in arguments (either IN or OUT) */
485 /* except for RECORD and polymorphic */
486 numargs = get_func_arg_info(tuple,
487 &argtypes, &argnames, &argmodes);
488 for (i = 0; i < numargs; i++)
489 {
490 if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
491 {
492 if (argtypes[i] != RECORDOID &&
493 !IsPolymorphicType(argtypes[i]))
495 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
496 errmsg("PL/pgSQL functions cannot accept type %s",
497 format_type_be(argtypes[i]))));
498 }
499 }
500
501 /* Postpone body checks if !check_function_bodies */
503 {
504 LOCAL_FCINFO(fake_fcinfo, 0);
505 FmgrInfo flinfo;
506 int rc;
507 TriggerData trigdata;
508 EventTriggerData etrigdata;
509
510 /*
511 * Connect to SPI manager (is this needed for compilation?)
512 */
513 SPI_connect();
514
515 /*
516 * Set up a fake fcinfo with just enough info to satisfy
517 * plpgsql_compile().
518 */
519 MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
520 MemSet(&flinfo, 0, sizeof(flinfo));
521 fake_fcinfo->flinfo = &flinfo;
522 flinfo.fn_oid = funcoid;
524 if (is_dml_trigger)
525 {
526 MemSet(&trigdata, 0, sizeof(trigdata));
527 trigdata.type = T_TriggerData;
528 fake_fcinfo->context = (Node *) &trigdata;
529 }
530 else if (is_event_trigger)
531 {
532 MemSet(&etrigdata, 0, sizeof(etrigdata));
533 etrigdata.type = T_EventTriggerData;
534 fake_fcinfo->context = (Node *) &etrigdata;
535 }
536
537 /* Test-compile the function */
538 plpgsql_compile(fake_fcinfo, true);
539
540 /*
541 * Disconnect from SPI manager
542 */
543 if ((rc = SPI_finish()) != SPI_OK_FINISH)
544 elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
545 }
546
547 ReleaseSysCache(tuple);
548
550}
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereport(elevel,...)
Definition: elog.h:149
bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid)
Definition: fmgr.c:2145
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:1379
bool check_function_bodies
Definition: guc_tables.c:528
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
int i
Definition: isn.c:77
char get_typtype(Oid typid)
Definition: lsyscache.c:2769
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
unsigned int Oid
Definition: postgres_ext.h:30
int SPI_connect(void)
Definition: spi.c:95
Definition: nodes.h:135
NodeTag type
Definition: trigger.h:33
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References check_function_bodies, CheckFunctionValidatorAccess(), CurrentMemoryContext, elog, ereport, errcode(), errmsg(), ERROR, FmgrInfo::fn_mcxt, FmgrInfo::fn_oid, format_type_be(), get_func_arg_info(), get_typtype(), GETSTRUCT(), HeapTupleIsValid, i, LOCAL_FCINFO, MemSet, ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_VOID, plpgsql_compile(), ReleaseSysCache(), SearchSysCache1(), SizeForFunctionCallInfo, SPI_connect(), SPI_finish(), SPI_OK_FINISH, SPI_result_code_string(), EventTriggerData::type, and TriggerData::type.

Variable Documentation

◆ plpgsql_check_asserts

bool plpgsql_check_asserts = true

Definition at line 51 of file pl_handler.c.

Referenced by _PG_init(), and exec_stmt_assert().

◆ plpgsql_extra_errors

int plpgsql_extra_errors

◆ plpgsql_extra_errors_string

char* plpgsql_extra_errors_string = NULL
static

Definition at line 54 of file pl_handler.c.

Referenced by _PG_init().

◆ plpgsql_extra_warnings

int plpgsql_extra_warnings

◆ plpgsql_extra_warnings_string

char* plpgsql_extra_warnings_string = NULL
static

Definition at line 53 of file pl_handler.c.

Referenced by _PG_init().

◆ plpgsql_plugin_ptr

◆ plpgsql_print_strict_params

bool plpgsql_print_strict_params = false

Definition at line 49 of file pl_handler.c.

Referenced by _PG_init(), plpgsql_compile_callback(), and plpgsql_compile_inline().

◆ plpgsql_variable_conflict

int plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR

Definition at line 47 of file pl_handler.c.

Referenced by _PG_init(), plpgsql_compile_callback(), and plpgsql_compile_inline().

◆ variable_conflict_options

const struct config_enum_entry variable_conflict_options[]
static
Initial value:
= {
{"error", PLPGSQL_RESOLVE_ERROR, false},
{"use_variable", PLPGSQL_RESOLVE_VARIABLE, false},
{"use_column", PLPGSQL_RESOLVE_COLUMN, false},
{NULL, 0, false}
}
@ PLPGSQL_RESOLVE_COLUMN
Definition: plpgsql.h:188
@ PLPGSQL_RESOLVE_VARIABLE
Definition: plpgsql.h:187

Definition at line 40 of file pl_handler.c.

Referenced by _PG_init().