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)
 
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

 PG_MODULE_MAGIC
 
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 145 of file pl_handler.c.

146 {
147  /* Be sure we do initialization only once (should be redundant now) */
148  static bool inited = false;
149 
150  if (inited)
151  return;
152 
154 
155  DefineCustomEnumVariable("plpgsql.variable_conflict",
156  gettext_noop("Sets handling of conflicts between PL/pgSQL variable names and table column names."),
157  NULL,
161  PGC_SUSET, 0,
162  NULL, NULL, NULL);
163 
164  DefineCustomBoolVariable("plpgsql.print_strict_params",
165  gettext_noop("Print information about parameters in the DETAIL part of the error messages generated on INTO ... STRICT failures."),
166  NULL,
168  false,
169  PGC_USERSET, 0,
170  NULL, NULL, NULL);
171 
172  DefineCustomBoolVariable("plpgsql.check_asserts",
173  gettext_noop("Perform checks given in ASSERT statements."),
174  NULL,
176  true,
177  PGC_USERSET, 0,
178  NULL, NULL, NULL);
179 
180  DefineCustomStringVariable("plpgsql.extra_warnings",
181  gettext_noop("List of programming constructs that should produce a warning."),
182  NULL,
184  "none",
188  NULL);
189 
190  DefineCustomStringVariable("plpgsql.extra_errors",
191  gettext_noop("List of programming constructs that should produce an error."),
192  NULL,
194  "none",
198  NULL);
199 
200  MarkGUCPrefixReserved("plpgsql");
201 
205 
206  /* Set up a rendezvous point with optional instrumentation plugin */
208 
209  inited = true;
210 }
#define gettext_noop(x)
Definition: c.h:1201
void ** find_rendezvous_variable(const char *varName)
Definition: dfmgr.c:603
#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:5243
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:5218
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:5132
void MarkGUCPrefixReserved(const char *className)
Definition: guc.c:5279
#define GUC_LIST_INPUT
Definition: guc.h:210
@ PGC_SUSET
Definition: guc.h:74
@ PGC_USERSET
Definition: guc.h:75
void pg_bindtextdomain(const char *domain)
Definition: miscinit.c:1941
void plpgsql_HashTableInit(void)
Definition: pl_comp.c:2594
void plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg)
Definition: pl_exec.c:8524
void plpgsql_xact_cb(XactEvent event, void *arg)
Definition: pl_exec.c:8482
int plpgsql_variable_conflict
Definition: pl_handler.c:44
static void plpgsql_extra_errors_assign_hook(const char *newvalue, void *extra)
Definition: pl_handler.c:133
bool plpgsql_check_asserts
Definition: pl_handler.c:48
static const struct config_enum_entry variable_conflict_options[]
Definition: pl_handler.c:37
static char * plpgsql_extra_errors_string
Definition: pl_handler.c:51
bool plpgsql_print_strict_params
Definition: pl_handler.c:46
PLpgSQL_plugin ** plpgsql_plugin_ptr
Definition: pl_handler.c:56
static void plpgsql_extra_warnings_assign_hook(const char *newvalue, void *extra)
Definition: pl_handler.c:127
static bool plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source)
Definition: pl_handler.c:60
static char * plpgsql_extra_warnings_string
Definition: pl_handler.c:50
@ PLPGSQL_RESOLVE_ERROR
Definition: plpgsql.h:185
void RegisterXactCallback(XactCallback callback, void *arg)
Definition: xact.c:3796
void RegisterSubXactCallback(SubXactCallback callback, void *arg)
Definition: xact.c:3856

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_HashTableInit(), 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  )

◆ plpgsql_call_handler()

Datum plpgsql_call_handler ( PG_FUNCTION_ARGS  )

Definition at line 222 of file pl_handler.c.

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

References CALLED_AS_EVENT_TRIGGER, CALLED_AS_TRIGGER, castNode, 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 PLpgSQL_function::use_count.

◆ plpgsql_extra_checks_check_hook()

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

Definition at line 60 of file pl_handler.c.

61 {
62  char *rawstring;
63  List *elemlist;
64  ListCell *l;
65  int extrachecks = 0;
66  int *myextra;
67 
68  if (pg_strcasecmp(*newvalue, "all") == 0)
69  extrachecks = PLPGSQL_XCHECK_ALL;
70  else if (pg_strcasecmp(*newvalue, "none") == 0)
71  extrachecks = PLPGSQL_XCHECK_NONE;
72  else
73  {
74  /* Need a modifiable copy of string */
75  rawstring = pstrdup(*newvalue);
76 
77  /* Parse string into list of identifiers */
78  if (!SplitIdentifierString(rawstring, ',', &elemlist))
79  {
80  /* syntax error in list */
81  GUC_check_errdetail("List syntax is invalid.");
82  pfree(rawstring);
83  list_free(elemlist);
84  return false;
85  }
86 
87  foreach(l, elemlist)
88  {
89  char *tok = (char *) lfirst(l);
90 
91  if (pg_strcasecmp(tok, "shadowed_variables") == 0)
92  extrachecks |= PLPGSQL_XCHECK_SHADOWVAR;
93  else if (pg_strcasecmp(tok, "too_many_rows") == 0)
94  extrachecks |= PLPGSQL_XCHECK_TOOMANYROWS;
95  else if (pg_strcasecmp(tok, "strict_multi_assignment") == 0)
97  else if (pg_strcasecmp(tok, "all") == 0 || pg_strcasecmp(tok, "none") == 0)
98  {
99  GUC_check_errdetail("Key word \"%s\" cannot be combined with other key words.", tok);
100  pfree(rawstring);
101  list_free(elemlist);
102  return false;
103  }
104  else
105  {
106  GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
107  pfree(rawstring);
108  list_free(elemlist);
109  return false;
110  }
111  }
112 
113  pfree(rawstring);
114  list_free(elemlist);
115  }
116 
117  myextra = (int *) guc_malloc(LOG, sizeof(int));
118  if (!myextra)
119  return false;
120  *myextra = extrachecks;
121  *extra = (void *) myextra;
122 
123  return true;
124 }
#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:476
void list_free(List *list)
Definition: list.c:1546
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
#define lfirst(lc)
Definition: pg_list.h:172
#define PLPGSQL_XCHECK_SHADOWVAR
Definition: plpgsql.h:1204
#define PLPGSQL_XCHECK_ALL
Definition: plpgsql.h:1207
#define PLPGSQL_XCHECK_NONE
Definition: plpgsql.h:1203
#define PLPGSQL_XCHECK_TOOMANYROWS
Definition: plpgsql.h:1205
#define PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT
Definition: plpgsql.h:1206
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:3432

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 133 of file pl_handler.c.

134 {
135  plpgsql_extra_errors = *((int *) extra);
136 }
int plpgsql_extra_errors
Definition: pl_handler.c:53

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 127 of file pl_handler.c.

128 {
129  plpgsql_extra_warnings = *((int *) extra);
130 }
int plpgsql_extra_warnings
Definition: pl_handler.c:52

References plpgsql_extra_warnings.

Referenced by _PG_init().

◆ plpgsql_inline_handler()

Datum plpgsql_inline_handler ( PG_FUNCTION_ARGS  )

Definition at line 314 of file pl_handler.c.

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

References Assert, InlineCodeBlock::atomic, castNode, 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 PLpgSQL_function::use_count.

◆ plpgsql_validator()

Datum plpgsql_validator ( PG_FUNCTION_ARGS  )

Definition at line 440 of file pl_handler.c.

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

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 34 of file pl_handler.c.

◆ plpgsql_check_asserts

bool plpgsql_check_asserts = true

Definition at line 48 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 51 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 50 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 46 of file pl_handler.c.

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

◆ plpgsql_variable_conflict

int plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR

Definition at line 44 of file pl_handler.c.

Referenced by _PG_init(), do_compile(), 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:187
@ PLPGSQL_RESOLVE_VARIABLE
Definition: plpgsql.h:186

Definition at line 34 of file pl_handler.c.

Referenced by _PG_init().