PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
pl_handler.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pl_handler.c - Handler for the PL/pgSQL
4  * procedural language
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/pl/plpgsql/src/pl_handler.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include "access/htup_details.h"
19 #include "catalog/pg_proc.h"
20 #include "catalog/pg_type.h"
21 #include "funcapi.h"
22 #include "miscadmin.h"
23 #include "utils/builtins.h"
24 #include "utils/guc.h"
25 #include "utils/lsyscache.h"
26 #include "utils/syscache.h"
27 #include "utils/varlena.h"
28 
29 #include "plpgsql.h"
30 
31 
32 static bool plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source);
33 static void plpgsql_extra_warnings_assign_hook(const char *newvalue, void *extra);
34 static void plpgsql_extra_errors_assign_hook(const char *newvalue, void *extra);
35 
37 
38 /* Custom GUC variable */
40  {"error", PLPGSQL_RESOLVE_ERROR, false},
41  {"use_variable", PLPGSQL_RESOLVE_VARIABLE, false},
42  {"use_column", PLPGSQL_RESOLVE_COLUMN, false},
43  {NULL, 0, false}
44 };
45 
47 
49 
51 
56 
57 /* Hook for plugins */
59 
60 
61 static bool
62 plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source)
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, "all") == 0 || pg_strcasecmp(tok, "none") == 0)
96  {
97  GUC_check_errdetail("Key word \"%s\" cannot be combined with other key words.", tok);
98  pfree(rawstring);
99  list_free(elemlist);
100  return false;
101  }
102  else
103  {
104  GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
105  pfree(rawstring);
106  list_free(elemlist);
107  return false;
108  }
109  }
110 
111  pfree(rawstring);
112  list_free(elemlist);
113  }
114 
115  myextra = (int *) malloc(sizeof(int));
116  if (!myextra)
117  return false;
118  *myextra = extrachecks;
119  *extra = (void *) myextra;
120 
121  return true;
122 }
123 
124 static void
125 plpgsql_extra_warnings_assign_hook(const char *newvalue, void *extra)
126 {
127  plpgsql_extra_warnings = *((int *) extra);
128 }
129 
130 static void
131 plpgsql_extra_errors_assign_hook(const char *newvalue, void *extra)
132 {
133  plpgsql_extra_errors = *((int *) extra);
134 }
135 
136 
137 /*
138  * _PG_init() - library load-time initialization
139  *
140  * DO NOT make this static nor change its name!
141  */
142 void
143 _PG_init(void)
144 {
145  /* Be sure we do initialization only once (should be redundant now) */
146  static bool inited = false;
147 
148  if (inited)
149  return;
150 
152 
153  DefineCustomEnumVariable("plpgsql.variable_conflict",
154  gettext_noop("Sets handling of conflicts between PL/pgSQL variable names and table column names."),
155  NULL,
158  variable_conflict_options,
159  PGC_SUSET, 0,
160  NULL, NULL, NULL);
161 
162  DefineCustomBoolVariable("plpgsql.print_strict_params",
163  gettext_noop("Print information about parameters in the DETAIL part of the error messages generated on INTO ... STRICT failures."),
164  NULL,
166  false,
167  PGC_USERSET, 0,
168  NULL, NULL, NULL);
169 
170  DefineCustomBoolVariable("plpgsql.check_asserts",
171  gettext_noop("Perform checks given in ASSERT statements."),
172  NULL,
174  true,
175  PGC_USERSET, 0,
176  NULL, NULL, NULL);
177 
178  DefineCustomStringVariable("plpgsql.extra_warnings",
179  gettext_noop("List of programming constructs that should produce a warning."),
180  NULL,
182  "none",
186  NULL);
187 
188  DefineCustomStringVariable("plpgsql.extra_errors",
189  gettext_noop("List of programming constructs that should produce an error."),
190  NULL,
192  "none",
196  NULL);
197 
198  EmitWarningsOnPlaceholders("plpgsql");
199 
203 
204  /* Set up a rendezvous point with optional instrumentation plugin */
205  plpgsql_plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
206 
207  inited = true;
208 }
209 
210 /* ----------
211  * plpgsql_call_handler
212  *
213  * The PostgreSQL function manager and trigger manager
214  * call this function for execution of PL/pgSQL procedures.
215  * ----------
216  */
218 
219 Datum
221 {
222  PLpgSQL_function *func;
223  PLpgSQL_execstate *save_cur_estate;
224  Datum retval;
225  int rc;
226 
227  /*
228  * Connect to SPI manager
229  */
230  if ((rc = SPI_connect()) != SPI_OK_CONNECT)
231  elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
232 
233  /* Find or compile the function */
234  func = plpgsql_compile(fcinfo, false);
235 
236  /* Must save and restore prior value of cur_estate */
237  save_cur_estate = func->cur_estate;
238 
239  /* Mark the function as busy, so it can't be deleted from under us */
240  func->use_count++;
241 
242  PG_TRY();
243  {
244  /*
245  * Determine if called as function or trigger and call appropriate
246  * subhandler
247  */
248  if (CALLED_AS_TRIGGER(fcinfo))
250  (TriggerData *) fcinfo->context));
251  else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
252  {
254  (EventTriggerData *) fcinfo->context);
255  retval = (Datum) 0;
256  }
257  else
258  retval = plpgsql_exec_function(func, fcinfo, NULL);
259  }
260  PG_CATCH();
261  {
262  /* Decrement use-count, restore cur_estate, and propagate error */
263  func->use_count--;
264  func->cur_estate = save_cur_estate;
265  PG_RE_THROW();
266  }
267  PG_END_TRY();
268 
269  func->use_count--;
270 
271  func->cur_estate = save_cur_estate;
272 
273  /*
274  * Disconnect from SPI manager
275  */
276  if ((rc = SPI_finish()) != SPI_OK_FINISH)
277  elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
278 
279  return retval;
280 }
281 
282 /* ----------
283  * plpgsql_inline_handler
284  *
285  * Called by PostgreSQL to execute an anonymous code block
286  * ----------
287  */
289 
290 Datum
292 {
294  PLpgSQL_function *func;
295  FunctionCallInfoData fake_fcinfo;
296  FmgrInfo flinfo;
297  EState *simple_eval_estate;
298  Datum retval;
299  int rc;
300 
301  /*
302  * Connect to SPI manager
303  */
304  if ((rc = SPI_connect()) != SPI_OK_CONNECT)
305  elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
306 
307  /* Compile the anonymous code block */
308  func = plpgsql_compile_inline(codeblock->source_text);
309 
310  /* Mark the function as busy, just pro forma */
311  func->use_count++;
312 
313  /*
314  * Set up a fake fcinfo with just enough info to satisfy
315  * plpgsql_exec_function(). In particular note that this sets things up
316  * with no arguments passed.
317  */
318  MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
319  MemSet(&flinfo, 0, sizeof(flinfo));
320  fake_fcinfo.flinfo = &flinfo;
321  flinfo.fn_oid = InvalidOid;
322  flinfo.fn_mcxt = CurrentMemoryContext;
323 
324  /* Create a private EState for simple-expression execution */
325  simple_eval_estate = CreateExecutorState();
326 
327  /* And run the function */
328  PG_TRY();
329  {
330  retval = plpgsql_exec_function(func, &fake_fcinfo, simple_eval_estate);
331  }
332  PG_CATCH();
333  {
334  /*
335  * We need to clean up what would otherwise be long-lived resources
336  * accumulated by the failed DO block, principally cached plans for
337  * statements (which can be flushed with plpgsql_free_function_memory)
338  * and execution trees for simple expressions, which are in the
339  * private EState.
340  *
341  * Before releasing the private EState, we must clean up any
342  * simple_econtext_stack entries pointing into it, which we can do by
343  * invoking the subxact callback. (It will be called again later if
344  * some outer control level does a subtransaction abort, but no harm
345  * is done.) We cheat a bit knowing that plpgsql_subxact_cb does not
346  * pay attention to its parentSubid argument.
347  */
350  0, NULL);
351 
352  /* Clean up the private EState */
353  FreeExecutorState(simple_eval_estate);
354 
355  /* Function should now have no remaining use-counts ... */
356  func->use_count--;
357  Assert(func->use_count == 0);
358 
359  /* ... so we can free subsidiary storage */
361 
362  /* And propagate the error */
363  PG_RE_THROW();
364  }
365  PG_END_TRY();
366 
367  /* Clean up the private EState */
368  FreeExecutorState(simple_eval_estate);
369 
370  /* Function should now have no remaining use-counts ... */
371  func->use_count--;
372  Assert(func->use_count == 0);
373 
374  /* ... so we can free subsidiary storage */
376 
377  /*
378  * Disconnect from SPI manager
379  */
380  if ((rc = SPI_finish()) != SPI_OK_FINISH)
381  elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
382 
383  return retval;
384 }
385 
386 /* ----------
387  * plpgsql_validator
388  *
389  * This function attempts to validate a PL/pgSQL function at
390  * CREATE FUNCTION time.
391  * ----------
392  */
394 
395 Datum
397 {
398  Oid funcoid = PG_GETARG_OID(0);
399  HeapTuple tuple;
400  Form_pg_proc proc;
401  char functyptype;
402  int numargs;
403  Oid *argtypes;
404  char **argnames;
405  char *argmodes;
406  bool is_dml_trigger = false;
407  bool is_event_trigger = false;
408  int i;
409 
410  if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
411  PG_RETURN_VOID();
412 
413  /* Get the new function's pg_proc entry */
414  tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
415  if (!HeapTupleIsValid(tuple))
416  elog(ERROR, "cache lookup failed for function %u", funcoid);
417  proc = (Form_pg_proc) GETSTRUCT(tuple);
418 
419  functyptype = get_typtype(proc->prorettype);
420 
421  /* Disallow pseudotype result */
422  /* except for TRIGGER, RECORD, VOID, or polymorphic */
423  if (functyptype == TYPTYPE_PSEUDO)
424  {
425  /* we assume OPAQUE with no arguments means a trigger */
426  if (proc->prorettype == TRIGGEROID ||
427  (proc->prorettype == OPAQUEOID && proc->pronargs == 0))
428  is_dml_trigger = true;
429  else if (proc->prorettype == EVTTRIGGEROID)
430  is_event_trigger = true;
431  else if (proc->prorettype != RECORDOID &&
432  proc->prorettype != VOIDOID &&
433  !IsPolymorphicType(proc->prorettype))
434  ereport(ERROR,
435  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
436  errmsg("PL/pgSQL functions cannot return type %s",
437  format_type_be(proc->prorettype))));
438  }
439 
440  /* Disallow pseudotypes in arguments (either IN or OUT) */
441  /* except for polymorphic */
442  numargs = get_func_arg_info(tuple,
443  &argtypes, &argnames, &argmodes);
444  for (i = 0; i < numargs; i++)
445  {
446  if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
447  {
448  if (!IsPolymorphicType(argtypes[i]))
449  ereport(ERROR,
450  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
451  errmsg("PL/pgSQL functions cannot accept type %s",
452  format_type_be(argtypes[i]))));
453  }
454  }
455 
456  /* Postpone body checks if !check_function_bodies */
458  {
459  FunctionCallInfoData fake_fcinfo;
460  FmgrInfo flinfo;
461  int rc;
462  TriggerData trigdata;
463  EventTriggerData etrigdata;
464 
465  /*
466  * Connect to SPI manager (is this needed for compilation?)
467  */
468  if ((rc = SPI_connect()) != SPI_OK_CONNECT)
469  elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
470 
471  /*
472  * Set up a fake fcinfo with just enough info to satisfy
473  * plpgsql_compile().
474  */
475  MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
476  MemSet(&flinfo, 0, sizeof(flinfo));
477  fake_fcinfo.flinfo = &flinfo;
478  flinfo.fn_oid = funcoid;
479  flinfo.fn_mcxt = CurrentMemoryContext;
480  if (is_dml_trigger)
481  {
482  MemSet(&trigdata, 0, sizeof(trigdata));
483  trigdata.type = T_TriggerData;
484  fake_fcinfo.context = (Node *) &trigdata;
485  }
486  else if (is_event_trigger)
487  {
488  MemSet(&etrigdata, 0, sizeof(etrigdata));
489  etrigdata.type = T_EventTriggerData;
490  fake_fcinfo.context = (Node *) &etrigdata;
491  }
492 
493  /* Test-compile the function */
494  plpgsql_compile(&fake_fcinfo, true);
495 
496  /*
497  * Disconnect from SPI manager
498  */
499  if ((rc = SPI_finish()) != SPI_OK_FINISH)
500  elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
501  }
502 
503  ReleaseSysCache(tuple);
504 
505  PG_RETURN_VOID();
506 }
PLpgSQL_function * plpgsql_compile_inline(char *proc_source)
Definition: pl_comp.c:794
#define SPI_OK_CONNECT
Definition: spi.h:47
void plpgsql_free_function_memory(PLpgSQL_function *func)
Definition: pl_funcs.c:695
Definition: fmgr.h:56
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
Definition: event_trigger.h:40
PG_FUNCTION_INFO_V1(plpgsql_call_handler)
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
MemoryContext fn_mcxt
Definition: fmgr.h:65
void plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
Definition: pl_exec.c:886
#define TEXTDOMAIN
Definition: elog.h:125
Definition: guc.h:164
char * plpgsql_extra_warnings_string
Definition: pl_handler.c:52
int SPI_connect(void)
Definition: spi.c:84
#define castNode(_type_, nodeptr)
Definition: nodes.h:573
#define GUC_check_errdetail
Definition: guc.h:407
fmNodePtr context
Definition: fmgr.h:80
#define PointerGetDatum(X)
Definition: postgres.h:562
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:233
char * pstrdup(const char *in)
Definition: mcxt.c:1077
#define PLPGSQL_XCHECK_NONE
Definition: plpgsql.h:1025
int SPI_finish(void)
Definition: spi.c:147
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:791
void plpgsql_HashTableInit(void)
Definition: pl_comp.c:2563
#define PLPGSQL_XCHECK_SHADOWVAR
Definition: plpgsql.h:1026
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:504
int plpgsql_extra_errors
Definition: pl_handler.c:55
int errcode(int sqlerrcode)
Definition: elog.c:575
char get_typtype(Oid typid)
Definition: lsyscache.c:2347
#define MemSet(start, val, len)
Definition: c.h:857
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
bool check_function_bodies
Definition: guc.c:450
unsigned int Oid
Definition: postgres_ext.h:31
void ** find_rendezvous_variable(const char *varName)
Definition: dfmgr.c:667
Datum plpgsql_inline_handler(PG_FUNCTION_ARGS)
Definition: pl_handler.c:291
#define SearchSysCache1(cacheId, key1)
Definition: syscache.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:7816
Datum plpgsql_validator(PG_FUNCTION_ARGS)
Definition: pl_handler.c:396
char * plpgsql_extra_errors_string
Definition: pl_handler.c:53
GucSource
Definition: guc.h:105
#define malloc(a)
Definition: header.h:50
void FreeExecutorState(EState *estate)
Definition: execUtils.c:173
FmgrInfo * flinfo
Definition: fmgr.h:79
void pfree(void *pointer)
Definition: mcxt.c:950
#define VOIDOID
Definition: pg_type.h:686
#define OPAQUEOID
Definition: pg_type.h:696
PLpgSQL_function * plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator)
Definition: pl_comp.c:137
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define IsPolymorphicType(typid)
Definition: pg_type.h:741
struct PLpgSQL_execstate * cur_estate
Definition: plpgsql.h:873
bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid)
Definition: fmgr.c:2462
unsigned long use_count
Definition: plpgsql.h:874
Definition: guc.h:75
void EmitWarningsOnPlaceholders(const char *className)
Definition: guc.c:7844
#define TRIGGEROID
Definition: pg_type.h:688
int plpgsql_extra_warnings
Definition: pl_handler.c:54
const char * SPI_result_code_string(int code)
Definition: spi.c:1509
static const struct config_enum_entry variable_conflict_options[]
Definition: pl_handler.c:39
#define PG_GETARG_OID(n)
Definition: fmgr.h:240
bool SplitIdentifierString(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3240
#define RECORDOID
Definition: pg_type.h:676
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
void _PG_init(void)
Definition: pl_handler.c:143
#define ereport(elevel, rest)
Definition: elog.h:122
PLpgSQL_plugin ** plpgsql_plugin_ptr
Definition: pl_handler.c:58
EState * CreateExecutorState(void)
Definition: execUtils.c:77
static void plpgsql_extra_warnings_assign_hook(const char *newvalue, void *extra)
Definition: pl_handler.c:125
PG_MODULE_MAGIC
Definition: pl_handler.c:36
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:7791
uintptr_t Datum
Definition: postgres.h:372
void RegisterSubXactCallback(SubXactCallback callback, void *arg)
Definition: xact.c:3360
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
#define InvalidOid
Definition: postgres_ext.h:36
Oid fn_oid
Definition: fmgr.h:59
bool plpgsql_print_strict_params
Definition: pl_handler.c:48
#define PG_RETURN_VOID()
Definition: fmgr.h:309
int plpgsql_variable_conflict
Definition: pl_handler.c:46
#define PG_CATCH()
Definition: elog.h:293
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define EVTTRIGGEROID
Definition: pg_type.h:690
#define NULL
Definition: c.h:229
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:25
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:649
void RegisterXactCallback(XactCallback callback, void *arg)
Definition: xact.c:3305
static void plpgsql_extra_errors_assign_hook(const char *newvalue, void *extra)
Definition: pl_handler.c:131
#define SPI_OK_FINISH
Definition: spi.h:48
#define PG_RE_THROW()
Definition: elog.h:314
#define TYPTYPE_PSEUDO
Definition: pg_type.h:720
#define DatumGetPointer(X)
Definition: postgres.h:555
int errmsg(const char *fmt,...)
Definition: elog.c:797
NodeTag type
Definition: trigger.h:32
Datum plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, EState *simple_eval_estate)
Definition: pl_exec.c:330
void list_free(List *list)
Definition: list.c:1133
int i
void pg_bindtextdomain(const char *domain)
Definition: miscinit.c:1505
void plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg)
Definition: pl_exec.c:7114
static bool plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source)
Definition: pl_handler.c:62
char * source_text
Definition: parsenodes.h:2730
#define PG_FUNCTION_ARGS
Definition: fmgr.h:158
HeapTuple plpgsql_exec_trigger(PLpgSQL_function *func, TriggerData *trigdata)
Definition: pl_exec.c:616
#define elog
Definition: elog.h:219
bool plpgsql_check_asserts
Definition: pl_handler.c:50
#define PG_TRY()
Definition: elog.h:284
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:7705
Definition: pg_list.h:45
Datum plpgsql_call_handler(PG_FUNCTION_ARGS)
Definition: pl_handler.c:220
#define PG_END_TRY()
Definition: elog.h:300
#define GUC_LIST_INPUT
Definition: guc.h:204
#define PLPGSQL_XCHECK_ALL
Definition: plpgsql.h:1027
void plpgsql_xact_cb(XactEvent event, void *arg)
Definition: pl_exec.c:7082