#include "plpgsql.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"
Go to the source code of this file.
Functions | |
| 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 struct config_enum_entry | variable_conflict_options [] |
| int | plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR |
| PLpgSQL_plugin ** | plugin_ptr = NULL |
| void _PG_init | ( | void | ) |
Definition at line 50 of file pl_handler.c.
References DefineCustomEnumVariable(), EmitWarningsOnPlaceholders(), find_rendezvous_variable(), gettext_noop, NULL, pg_bindtextdomain(), PGC_SUSET, plpgsql_HashTableInit(), PLPGSQL_RESOLVE_ERROR, plpgsql_subxact_cb(), plpgsql_variable_conflict, plpgsql_xact_cb(), RegisterSubXactCallback(), RegisterXactCallback(), and TEXTDOMAIN.
{
/* Be sure we do initialization only once (should be redundant now) */
static bool inited = false;
if (inited)
return;
pg_bindtextdomain(TEXTDOMAIN);
DefineCustomEnumVariable("plpgsql.variable_conflict",
gettext_noop("Sets handling of conflicts between PL/pgSQL variable names and table column names."),
NULL,
&plpgsql_variable_conflict,
PLPGSQL_RESOLVE_ERROR,
variable_conflict_options,
PGC_SUSET, 0,
NULL, NULL, NULL);
EmitWarningsOnPlaceholders("plpgsql");
plpgsql_HashTableInit();
RegisterXactCallback(plpgsql_xact_cb, NULL);
RegisterSubXactCallback(plpgsql_subxact_cb, NULL);
/* Set up a rendezvous point with optional instrumentation plugin */
plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
inited = true;
}
| PG_FUNCTION_INFO_V1 | ( | plpgsql_call_handler | ) |
| PG_FUNCTION_INFO_V1 | ( | plpgsql_inline_handler | ) |
| PG_FUNCTION_INFO_V1 | ( | plpgsql_validator | ) |
| Datum plpgsql_call_handler | ( | PG_FUNCTION_ARGS | ) |
Definition at line 91 of file pl_handler.c.
References CALLED_AS_EVENT_TRIGGER, CALLED_AS_TRIGGER, PLpgSQL_function::cur_estate, elog, ERROR, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, plpgsql_compile(), plpgsql_exec_event_trigger(), plpgsql_exec_function(), plpgsql_exec_trigger(), PointerGetDatum, SPI_connect(), SPI_finish(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_result_code_string(), and PLpgSQL_function::use_count.
{
PLpgSQL_function *func;
PLpgSQL_execstate *save_cur_estate;
Datum retval;
int rc;
/*
* Connect to SPI manager
*/
if ((rc = SPI_connect()) != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
/* Find or compile the function */
func = plpgsql_compile(fcinfo, false);
/* Must save and restore prior value of cur_estate */
save_cur_estate = func->cur_estate;
/* Mark the function as busy, so it can't be deleted from under us */
func->use_count++;
PG_TRY();
{
/*
* Determine if called as function or trigger and call appropriate
* subhandler
*/
if (CALLED_AS_TRIGGER(fcinfo))
retval = PointerGetDatum(plpgsql_exec_trigger(func,
(TriggerData *) fcinfo->context));
else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
{
plpgsql_exec_event_trigger(func,
(EventTriggerData *) fcinfo->context);
retval = (Datum) 0;
}
else
retval = plpgsql_exec_function(func, fcinfo);
}
PG_CATCH();
{
/* Decrement use-count, restore cur_estate, and propagate error */
func->use_count--;
func->cur_estate = save_cur_estate;
PG_RE_THROW();
}
PG_END_TRY();
func->use_count--;
func->cur_estate = save_cur_estate;
/*
* Disconnect from SPI manager
*/
if ((rc = SPI_finish()) != SPI_OK_FINISH)
elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
return retval;
}
| Datum plpgsql_inline_handler | ( | PG_FUNCTION_ARGS | ) |
Definition at line 162 of file pl_handler.c.
References Assert, CurrentMemoryContext, DatumGetPointer, elog, ERROR, FunctionCallInfoData::flinfo, FmgrInfo::fn_mcxt, FmgrInfo::fn_oid, IsA, MemSet, PG_GETARG_DATUM, plpgsql_compile_inline(), plpgsql_exec_function(), plpgsql_free_function_memory(), InlineCodeBlock::source_text, SPI_connect(), SPI_finish(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_result_code_string(), and PLpgSQL_function::use_count.
{
InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
PLpgSQL_function *func;
FunctionCallInfoData fake_fcinfo;
FmgrInfo flinfo;
Datum retval;
int rc;
Assert(IsA(codeblock, InlineCodeBlock));
/*
* Connect to SPI manager
*/
if ((rc = SPI_connect()) != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
/* Compile the anonymous code block */
func = plpgsql_compile_inline(codeblock->source_text);
/* Mark the function as busy, just pro forma */
func->use_count++;
/*
* Set up a fake fcinfo with just enough info to satisfy
* plpgsql_exec_function(). In particular note that this sets things up
* with no arguments passed.
*/
MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
MemSet(&flinfo, 0, sizeof(flinfo));
fake_fcinfo.flinfo = &flinfo;
flinfo.fn_oid = InvalidOid;
flinfo.fn_mcxt = CurrentMemoryContext;
retval = plpgsql_exec_function(func, &fake_fcinfo);
/* Function should now have no remaining use-counts ... */
func->use_count--;
Assert(func->use_count == 0);
/* ... so we can free subsidiary storage */
plpgsql_free_function_memory(func);
/*
* Disconnect from SPI manager
*/
if ((rc = SPI_finish()) != SPI_OK_FINISH)
elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
return retval;
}
| Datum plpgsql_validator | ( | PG_FUNCTION_ARGS | ) |
Definition at line 224 of file pl_handler.c.
References check_function_bodies, FunctionCallInfoData::context, CurrentMemoryContext, elog, ereport, errcode(), errmsg(), ERROR, EVTTRIGGEROID, FunctionCallInfoData::flinfo, FmgrInfo::fn_mcxt, FmgrInfo::fn_oid, format_type_be(), get_func_arg_info(), get_typtype(), GETSTRUCT, HeapTupleIsValid, i, IsPolymorphicType, MemSet, ObjectIdGetDatum, OPAQUEOID, PG_GETARG_OID, PG_RETURN_VOID, plpgsql_compile(), PROCOID, RECORDOID, ReleaseSysCache(), SearchSysCache1, SPI_connect(), SPI_finish(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_result_code_string(), TRIGGEROID, EventTriggerData::type, TriggerData::type, TYPTYPE_PSEUDO, and VOIDOID.
{
Oid funcoid = PG_GETARG_OID(0);
HeapTuple tuple;
Form_pg_proc proc;
char functyptype;
int numargs;
Oid *argtypes;
char **argnames;
char *argmodes;
bool is_dml_trigger = false;
bool is_event_trigger = false;
int i;
/* Get the new function's pg_proc entry */
tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for function %u", funcoid);
proc = (Form_pg_proc) GETSTRUCT(tuple);
functyptype = get_typtype(proc->prorettype);
/* Disallow pseudotype result */
/* except for TRIGGER, RECORD, VOID, or polymorphic */
if (functyptype == TYPTYPE_PSEUDO)
{
/* we assume OPAQUE with no arguments means a trigger */
if (proc->prorettype == TRIGGEROID ||
(proc->prorettype == OPAQUEOID && proc->pronargs == 0))
is_dml_trigger = true;
else if (proc->prorettype == EVTTRIGGEROID)
is_event_trigger = true;
else if (proc->prorettype != RECORDOID &&
proc->prorettype != VOIDOID &&
!IsPolymorphicType(proc->prorettype))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("PL/pgSQL functions cannot return type %s",
format_type_be(proc->prorettype))));
}
/* Disallow pseudotypes in arguments (either IN or OUT) */
/* except for polymorphic */
numargs = get_func_arg_info(tuple,
&argtypes, &argnames, &argmodes);
for (i = 0; i < numargs; i++)
{
if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
{
if (!IsPolymorphicType(argtypes[i]))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("PL/pgSQL functions cannot accept type %s",
format_type_be(argtypes[i]))));
}
}
/* Postpone body checks if !check_function_bodies */
if (check_function_bodies)
{
FunctionCallInfoData fake_fcinfo;
FmgrInfo flinfo;
int rc;
TriggerData trigdata;
EventTriggerData etrigdata;
/*
* Connect to SPI manager (is this needed for compilation?)
*/
if ((rc = SPI_connect()) != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
/*
* Set up a fake fcinfo with just enough info to satisfy
* plpgsql_compile().
*/
MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
MemSet(&flinfo, 0, sizeof(flinfo));
fake_fcinfo.flinfo = &flinfo;
flinfo.fn_oid = funcoid;
flinfo.fn_mcxt = CurrentMemoryContext;
if (is_dml_trigger)
{
MemSet(&trigdata, 0, sizeof(trigdata));
trigdata.type = T_TriggerData;
fake_fcinfo.context = (Node *) &trigdata;
}
else if (is_event_trigger)
{
MemSet(&etrigdata, 0, sizeof(etrigdata));
etrigdata.type = T_EventTriggerData;
fake_fcinfo.context = (Node *) &etrigdata;
}
/* Test-compile the function */
plpgsql_compile(&fake_fcinfo, true);
/*
* Disconnect from SPI manager
*/
if ((rc = SPI_finish()) != SPI_OK_FINISH)
elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
}
ReleaseSysCache(tuple);
PG_RETURN_VOID();
}
Definition at line 28 of file pl_handler.c.
| int plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR |
Definition at line 38 of file pl_handler.c.
Referenced by _PG_init(), do_compile(), and plpgsql_compile_inline().
| PLpgSQL_plugin** plugin_ptr = NULL |
Definition at line 41 of file pl_handler.c.
Referenced by exec_stmt(), plpgsql_estate_setup(), plpgsql_exec_event_trigger(), plpgsql_exec_function(), and plpgsql_exec_trigger().
struct config_enum_entry variable_conflict_options[] [static] |
{
{"error", PLPGSQL_RESOLVE_ERROR, false},
{"use_variable", PLPGSQL_RESOLVE_VARIABLE, false},
{"use_column", PLPGSQL_RESOLVE_COLUMN, false},
{NULL, 0, false}
}
Definition at line 31 of file pl_handler.c.
1.7.1