#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.