PostgreSQL Source Code  git master
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 "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/varlena.h"
#include "plpgsql.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
 
char * plpgsql_extra_warnings_string = NULL
 
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 147 of file pl_handler.c.

References DefineCustomBoolVariable(), DefineCustomEnumVariable(), DefineCustomStringVariable(), EmitWarningsOnPlaceholders(), find_rendezvous_variable(), gettext_noop, GUC_LIST_INPUT, pg_bindtextdomain(), PG_FUNCTION_INFO_V1(), PGC_SUSET, PGC_USERSET, plpgsql_call_handler(), 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_print_strict_params, PLPGSQL_RESOLVE_ERROR, plpgsql_subxact_cb(), plpgsql_variable_conflict, plpgsql_xact_cb(), RegisterSubXactCallback(), RegisterXactCallback(), and TEXTDOMAIN.

148 {
149  /* Be sure we do initialization only once (should be redundant now) */
150  static bool inited = false;
151 
152  if (inited)
153  return;
154 
156 
157  DefineCustomEnumVariable("plpgsql.variable_conflict",
158  gettext_noop("Sets handling of conflicts between PL/pgSQL variable names and table column names."),
159  NULL,
163  PGC_SUSET, 0,
164  NULL, NULL, NULL);
165 
166  DefineCustomBoolVariable("plpgsql.print_strict_params",
167  gettext_noop("Print information about parameters in the DETAIL part of the error messages generated on INTO ... STRICT failures."),
168  NULL,
170  false,
171  PGC_USERSET, 0,
172  NULL, NULL, NULL);
173 
174  DefineCustomBoolVariable("plpgsql.check_asserts",
175  gettext_noop("Perform checks given in ASSERT statements."),
176  NULL,
178  true,
179  PGC_USERSET, 0,
180  NULL, NULL, NULL);
181 
182  DefineCustomStringVariable("plpgsql.extra_warnings",
183  gettext_noop("List of programming constructs that should produce a warning."),
184  NULL,
186  "none",
190  NULL);
191 
192  DefineCustomStringVariable("plpgsql.extra_errors",
193  gettext_noop("List of programming constructs that should produce an error."),
194  NULL,
196  "none",
200  NULL);
201 
202  EmitWarningsOnPlaceholders("plpgsql");
203 
207 
208  /* Set up a rendezvous point with optional instrumentation plugin */
210 
211  inited = true;
212 }
#define TEXTDOMAIN
Definition: elog.h:144
char * plpgsql_extra_warnings_string
Definition: pl_handler.c:52
void plpgsql_HashTableInit(void)
Definition: pl_comp.c:2533
#define gettext_noop(x)
Definition: c.h:1117
void ** find_rendezvous_variable(const char *varName)
Definition: dfmgr.c:680
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:8684
char * plpgsql_extra_errors_string
Definition: pl_handler.c:53
Definition: guc.h:75
void EmitWarningsOnPlaceholders(const char *className)
Definition: guc.c:8712
static const struct config_enum_entry variable_conflict_options[]
Definition: pl_handler.c:39
PLpgSQL_plugin ** plpgsql_plugin_ptr
Definition: pl_handler.c:58
static void plpgsql_extra_warnings_assign_hook(const char *newvalue, void *extra)
Definition: pl_handler.c:129
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:8659
void RegisterSubXactCallback(SubXactCallback callback, void *arg)
Definition: xact.c:3532
bool plpgsql_print_strict_params
Definition: pl_handler.c:48
int plpgsql_variable_conflict
Definition: pl_handler.c:46
void RegisterXactCallback(XactCallback callback, void *arg)
Definition: xact.c:3477
static void plpgsql_extra_errors_assign_hook(const char *newvalue, void *extra)
Definition: pl_handler.c:135
void pg_bindtextdomain(const char *domain)
Definition: miscinit.c:1607
void plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg)
Definition: pl_exec.c:8291
static bool plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source)
Definition: pl_handler.c:62
bool plpgsql_check_asserts
Definition: pl_handler.c:50
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:8573
#define GUC_LIST_INPUT
Definition: guc.h:204
void plpgsql_xact_cb(XactEvent event, void *arg)
Definition: pl_exec.c:8260

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

References CALLED_AS_EVENT_TRIGGER, CALLED_AS_TRIGGER, castNode, PLpgSQL_function::cur_estate, elog, ERROR, IsA, PG_CATCH, PG_END_TRY, PG_FUNCTION_INFO_V1(), PG_RE_THROW, PG_TRY, plpgsql_compile(), plpgsql_exec_event_trigger(), plpgsql_exec_function(), plpgsql_exec_trigger(), plpgsql_inline_handler(), PointerGetDatum, SPI_connect_ext(), SPI_finish(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_OPT_NONATOMIC, SPI_result_code_string(), and PLpgSQL_function::use_count.

Referenced by _PG_init().

225 {
226  bool nonatomic;
227  PLpgSQL_function *func;
228  PLpgSQL_execstate *save_cur_estate;
229  Datum retval;
230  int rc;
231 
232  nonatomic = fcinfo->context &&
233  IsA(fcinfo->context, CallContext) &&
234  !castNode(CallContext, fcinfo->context)->atomic;
235 
236  /*
237  * Connect to SPI manager
238  */
239  if ((rc = SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0)) != SPI_OK_CONNECT)
240  elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
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->use_count++;
250 
251  PG_TRY();
252  {
253  /*
254  * Determine if called as function or trigger and call appropriate
255  * subhandler
256  */
257  if (CALLED_AS_TRIGGER(fcinfo))
259  (TriggerData *) fcinfo->context));
260  else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
261  {
263  (EventTriggerData *) fcinfo->context);
264  retval = (Datum) 0;
265  }
266  else
267  retval = plpgsql_exec_function(func, fcinfo, NULL, !nonatomic);
268  }
269  PG_CATCH();
270  {
271  /* Decrement use-count, restore cur_estate, and propagate error */
272  func->use_count--;
273  func->cur_estate = save_cur_estate;
274  PG_RE_THROW();
275  }
276  PG_END_TRY();
277 
278  func->use_count--;
279 
280  func->cur_estate = save_cur_estate;
281 
282  /*
283  * Disconnect from SPI manager
284  */
285  if ((rc = SPI_finish()) != SPI_OK_FINISH)
286  elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
287 
288  return retval;
289 }
#define SPI_OK_CONNECT
Definition: spi.h:53
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
Definition: event_trigger.h:39
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
void plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
Definition: pl_exec.c:1129
int SPI_connect_ext(int options)
Definition: spi.c:95
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
#define PointerGetDatum(X)
Definition: postgres.h:556
int SPI_finish(void)
Definition: spi.c:176
PLpgSQL_function * plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator)
Definition: pl_comp.c:137
#define ERROR
Definition: elog.h:43
struct PLpgSQL_execstate * cur_estate
Definition: plpgsql.h:1027
#define SPI_OPT_NONATOMIC
Definition: spi.h:71
unsigned long use_count
Definition: plpgsql.h:1028
const char * SPI_result_code_string(int code)
Definition: spi.c:1705
uintptr_t Datum
Definition: postgres.h:367
#define PG_CATCH()
Definition: elog.h:310
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:25
Datum plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, EState *simple_eval_estate, bool atomic)
Definition: pl_exec.c:451
#define SPI_OK_FINISH
Definition: spi.h:54
#define PG_RE_THROW()
Definition: elog.h:331
#define elog(elevel,...)
Definition: elog.h:226
HeapTuple plpgsql_exec_trigger(PLpgSQL_function *func, TriggerData *trigdata)
Definition: pl_exec.c:886
#define PG_TRY()
Definition: elog.h:301
#define PG_END_TRY()
Definition: elog.h:317

◆ plpgsql_extra_checks_check_hook()

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

Definition at line 62 of file pl_handler.c.

References GUC_check_errdetail, lfirst, list_free(), malloc, 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().

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

◆ plpgsql_extra_errors_assign_hook()

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

Definition at line 135 of file pl_handler.c.

References plpgsql_extra_errors.

Referenced by _PG_init().

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

◆ plpgsql_extra_warnings_assign_hook()

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

Definition at line 129 of file pl_handler.c.

References plpgsql_extra_warnings.

Referenced by _PG_init().

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

◆ plpgsql_inline_handler()

Datum plpgsql_inline_handler ( PG_FUNCTION_ARGS  )

Definition at line 300 of file pl_handler.c.

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_FUNCTION_INFO_V1(), PG_GETARG_DATUM, PG_RE_THROW, PG_TRY, plpgsql_compile_inline(), plpgsql_exec_function(), plpgsql_free_function_memory(), plpgsql_subxact_cb(), plpgsql_validator(), SizeForFunctionCallInfo, InlineCodeBlock::source_text, SPI_connect_ext(), SPI_finish(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_OPT_NONATOMIC, SPI_result_code_string(), SUBXACT_EVENT_ABORT_SUB, and PLpgSQL_function::use_count.

Referenced by plpgsql_call_handler().

301 {
302  LOCAL_FCINFO(fake_fcinfo, 0);
304  PLpgSQL_function *func;
305  FmgrInfo flinfo;
306  EState *simple_eval_estate;
307  Datum retval;
308  int rc;
309 
310  /*
311  * Connect to SPI manager
312  */
313  if ((rc = SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC)) != SPI_OK_CONNECT)
314  elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
315 
316  /* Compile the anonymous code block */
317  func = plpgsql_compile_inline(codeblock->source_text);
318 
319  /* Mark the function as busy, just pro forma */
320  func->use_count++;
321 
322  /*
323  * Set up a fake fcinfo with just enough info to satisfy
324  * plpgsql_exec_function(). In particular note that this sets things up
325  * with no arguments passed.
326  */
327  MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
328  MemSet(&flinfo, 0, sizeof(flinfo));
329  fake_fcinfo->flinfo = &flinfo;
330  flinfo.fn_oid = InvalidOid;
331  flinfo.fn_mcxt = CurrentMemoryContext;
332 
333  /* Create a private EState for simple-expression execution */
334  simple_eval_estate = CreateExecutorState();
335 
336  /* And run the function */
337  PG_TRY();
338  {
339  retval = plpgsql_exec_function(func, fake_fcinfo, simple_eval_estate, codeblock->atomic);
340  }
341  PG_CATCH();
342  {
343  /*
344  * We need to clean up what would otherwise be long-lived resources
345  * accumulated by the failed DO block, principally cached plans for
346  * statements (which can be flushed with plpgsql_free_function_memory)
347  * and execution trees for simple expressions, which are in the
348  * private EState.
349  *
350  * Before releasing the private EState, we must clean up any
351  * simple_econtext_stack entries pointing into it, which we can do by
352  * invoking the subxact callback. (It will be called again later if
353  * some outer control level does a subtransaction abort, but no harm
354  * is done.) We cheat a bit knowing that plpgsql_subxact_cb does not
355  * pay attention to its parentSubid argument.
356  */
359  0, NULL);
360 
361  /* Clean up the private EState */
362  FreeExecutorState(simple_eval_estate);
363 
364  /* Function should now have no remaining use-counts ... */
365  func->use_count--;
366  Assert(func->use_count == 0);
367 
368  /* ... so we can free subsidiary storage */
370 
371  /* And propagate the error */
372  PG_RE_THROW();
373  }
374  PG_END_TRY();
375 
376  /* Clean up the private EState */
377  FreeExecutorState(simple_eval_estate);
378 
379  /* Function should now have no remaining use-counts ... */
380  func->use_count--;
381  Assert(func->use_count == 0);
382 
383  /* ... so we can free subsidiary storage */
385 
386  /*
387  * Disconnect from SPI manager
388  */
389  if ((rc = SPI_finish()) != SPI_OK_FINISH)
390  elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
391 
392  return retval;
393 }
PLpgSQL_function * plpgsql_compile_inline(char *proc_source)
Definition: pl_comp.c:843
#define SPI_OK_CONNECT
Definition: spi.h:53
void plpgsql_free_function_memory(PLpgSQL_function *func)
Definition: pl_funcs.c:739
Definition: fmgr.h:56
MemoryContext fn_mcxt
Definition: fmgr.h:65
int SPI_connect_ext(int options)
Definition: spi.c:95
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:263
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
int SPI_finish(void)
Definition: spi.c:176
#define MemSet(start, val, len)
Definition: c.h:955
void FreeExecutorState(EState *estate)
Definition: execUtils.c:190
#define ERROR
Definition: elog.h:43
#define SPI_OPT_NONATOMIC
Definition: spi.h:71
unsigned long use_count
Definition: plpgsql.h:1028
const char * SPI_result_code_string(int code)
Definition: spi.c:1705
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
EState * CreateExecutorState(void)
Definition: execUtils.c:88
uintptr_t Datum
Definition: postgres.h:367
#define InvalidOid
Definition: postgres_ext.h:36
Oid fn_oid
Definition: fmgr.h:59
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define PG_CATCH()
Definition: elog.h:310
Datum plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, EState *simple_eval_estate, bool atomic)
Definition: pl_exec.c:451
#define Assert(condition)
Definition: c.h:732
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:708
#define SPI_OK_FINISH
Definition: spi.h:54
#define PG_RE_THROW()
Definition: elog.h:331
#define DatumGetPointer(X)
Definition: postgres.h:549
#define elog(elevel,...)
Definition: elog.h:226
void plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg)
Definition: pl_exec.c:8291
char * source_text
Definition: parsenodes.h:2861
#define PG_TRY()
Definition: elog.h:301
#define PG_END_TRY()
Definition: elog.h:317

◆ plpgsql_validator()

Datum plpgsql_validator ( PG_FUNCTION_ARGS  )

Definition at line 405 of file pl_handler.c.

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(), PROCOID, ReleaseSysCache(), SearchSysCache1(), SizeForFunctionCallInfo, SPI_connect(), SPI_finish(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_result_code_string(), T_EventTriggerData, T_TriggerData, EventTriggerData::type, and TriggerData::type.

Referenced by plpgsql_inline_handler().

406 {
407  Oid funcoid = PG_GETARG_OID(0);
408  HeapTuple tuple;
409  Form_pg_proc proc;
410  char functyptype;
411  int numargs;
412  Oid *argtypes;
413  char **argnames;
414  char *argmodes;
415  bool is_dml_trigger = false;
416  bool is_event_trigger = false;
417  int i;
418 
419  if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
420  PG_RETURN_VOID();
421 
422  /* Get the new function's pg_proc entry */
423  tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
424  if (!HeapTupleIsValid(tuple))
425  elog(ERROR, "cache lookup failed for function %u", funcoid);
426  proc = (Form_pg_proc) GETSTRUCT(tuple);
427 
428  functyptype = get_typtype(proc->prorettype);
429 
430  /* Disallow pseudotype result */
431  /* except for TRIGGER, RECORD, VOID, or polymorphic */
432  if (functyptype == TYPTYPE_PSEUDO)
433  {
434  /* we assume OPAQUE with no arguments means a trigger */
435  if (proc->prorettype == TRIGGEROID ||
436  (proc->prorettype == OPAQUEOID && proc->pronargs == 0))
437  is_dml_trigger = true;
438  else if (proc->prorettype == EVTTRIGGEROID)
439  is_event_trigger = true;
440  else if (proc->prorettype != RECORDOID &&
441  proc->prorettype != VOIDOID &&
442  !IsPolymorphicType(proc->prorettype))
443  ereport(ERROR,
444  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
445  errmsg("PL/pgSQL functions cannot return type %s",
446  format_type_be(proc->prorettype))));
447  }
448 
449  /* Disallow pseudotypes in arguments (either IN or OUT) */
450  /* except for RECORD and polymorphic */
451  numargs = get_func_arg_info(tuple,
452  &argtypes, &argnames, &argmodes);
453  for (i = 0; i < numargs; i++)
454  {
455  if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
456  {
457  if (argtypes[i] != RECORDOID &&
458  !IsPolymorphicType(argtypes[i]))
459  ereport(ERROR,
460  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
461  errmsg("PL/pgSQL functions cannot accept type %s",
462  format_type_be(argtypes[i]))));
463  }
464  }
465 
466  /* Postpone body checks if !check_function_bodies */
468  {
469  LOCAL_FCINFO(fake_fcinfo, 0);
470  FmgrInfo flinfo;
471  int rc;
472  TriggerData trigdata;
473  EventTriggerData etrigdata;
474 
475  /*
476  * Connect to SPI manager (is this needed for compilation?)
477  */
478  if ((rc = SPI_connect()) != SPI_OK_CONNECT)
479  elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
480 
481  /*
482  * Set up a fake fcinfo with just enough info to satisfy
483  * plpgsql_compile().
484  */
485  MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
486  MemSet(&flinfo, 0, sizeof(flinfo));
487  fake_fcinfo->flinfo = &flinfo;
488  flinfo.fn_oid = funcoid;
489  flinfo.fn_mcxt = CurrentMemoryContext;
490  if (is_dml_trigger)
491  {
492  MemSet(&trigdata, 0, sizeof(trigdata));
493  trigdata.type = T_TriggerData;
494  fake_fcinfo->context = (Node *) &trigdata;
495  }
496  else if (is_event_trigger)
497  {
498  MemSet(&etrigdata, 0, sizeof(etrigdata));
499  etrigdata.type = T_EventTriggerData;
500  fake_fcinfo->context = (Node *) &etrigdata;
501  }
502 
503  /* Test-compile the function */
504  plpgsql_compile(fake_fcinfo, true);
505 
506  /*
507  * Disconnect from SPI manager
508  */
509  if ((rc = SPI_finish()) != SPI_OK_FINISH)
510  elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
511  }
512 
513  ReleaseSysCache(tuple);
514 
515  PG_RETURN_VOID();
516 }
#define SPI_OK_CONNECT
Definition: spi.h:53
Definition: fmgr.h:56
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
MemoryContext fn_mcxt
Definition: fmgr.h:65
int SPI_connect(void)
Definition: spi.c:89
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
int SPI_finish(void)
Definition: spi.c:176
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:831
Definition: nodes.h:525
int errcode(int sqlerrcode)
Definition: elog.c:570
char get_typtype(Oid typid)
Definition: lsyscache.c:2407
#define MemSet(start, val, len)
Definition: c.h:955
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
bool check_function_bodies
Definition: guc.c:500
unsigned int Oid
Definition: postgres_ext.h:31
PLpgSQL_function * plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator)
Definition: pl_comp.c:137
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid)
Definition: fmgr.c:2001
const char * SPI_result_code_string(int code)
Definition: spi.c:1705
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define ereport(elevel, rest)
Definition: elog.h:141
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:134
Oid fn_oid
Definition: fmgr.h:59
#define PG_RETURN_VOID()
Definition: fmgr.h:339
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define SPI_OK_FINISH
Definition: spi.h:54
int errmsg(const char *fmt,...)
Definition: elog.c:784
NodeTag type
Definition: trigger.h:32
#define elog(elevel,...)
Definition: elog.h:226
int i

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 36 of file pl_handler.c.

◆ plpgsql_check_asserts

bool plpgsql_check_asserts = true

Definition at line 50 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

Definition at line 53 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

Definition at line 52 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 48 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 46 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}
}

Definition at line 39 of file pl_handler.c.