int plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR;
bool plpgsql_print_strict_params = false;
bool plpgsql_check_asserts = true;
staticchar *plpgsql_extra_warnings_string = NULL; staticchar *plpgsql_extra_errors_string = NULL; int plpgsql_extra_warnings; int plpgsql_extra_errors;
/* Hook for plugins */
PLpgSQL_plugin **plpgsql_plugin_ptr = NULL;
staticbool
plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source)
{ char *rawstring;
List *elemlist;
ListCell *l; int extrachecks = 0; int *myextra;
if (pg_strcasecmp(*newvalue, "all") == 0)
extrachecks = PLPGSQL_XCHECK_ALL; elseif (pg_strcasecmp(*newvalue, "none") == 0)
extrachecks = PLPGSQL_XCHECK_NONE; else
{ /* Need a modifiable copy of string */
rawstring = pstrdup(*newvalue);
/* Parse string into list of identifiers */ if (!SplitIdentifierString(rawstring, ',', &elemlist))
{ /* syntax error in list */
GUC_check_errdetail("List syntax is invalid.");
pfree(rawstring);
list_free(elemlist); returnfalse;
}
/* *_PG_init()-libraryload-timeinitialization * *DONOTmakethisstaticnorchangeitsname!
*/ void
_PG_init(void)
{ /* Be sure we do initialization only once (should be redundant now) */ staticbool 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);
DefineCustomBoolVariable("plpgsql.print_strict_params",
gettext_noop("Print information about parameters in the DETAIL part of the error messages generated on INTO ... STRICT failures."),
NULL,
&plpgsql_print_strict_params, false,
PGC_USERSET, 0,
NULL, NULL, NULL);
DefineCustomBoolVariable("plpgsql.check_asserts",
gettext_noop("Perform checks given in ASSERT statements."),
NULL,
&plpgsql_check_asserts, true,
PGC_USERSET, 0,
NULL, NULL, NULL);
DefineCustomStringVariable("plpgsql.extra_warnings",
gettext_noop("List of programming constructs that should produce a warning."),
NULL,
&plpgsql_extra_warnings_string, "none",
PGC_USERSET, GUC_LIST_INPUT,
plpgsql_extra_checks_check_hook,
plpgsql_extra_warnings_assign_hook,
NULL);
DefineCustomStringVariable("plpgsql.extra_errors",
gettext_noop("List of programming constructs that should produce an error."),
NULL,
&plpgsql_extra_errors_string, "none",
PGC_USERSET, GUC_LIST_INPUT,
plpgsql_extra_checks_check_hook,
plpgsql_extra_errors_assign_hook,
NULL);
/* Set up a rendezvous point with optional instrumentation plugin */
plpgsql_plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
PG_TRY();
{ /* *Determineifcalledasfunctionortriggerandcallappropriate *subhandler
*/ if (CALLED_AS_TRIGGER(fcinfo))
retval = PointerGetDatum(plpgsql_exec_trigger(func,
(TriggerData *) fcinfo->context)); elseif (CALLED_AS_EVENT_TRIGGER(fcinfo))
{
plpgsql_exec_event_trigger(func,
(EventTriggerData *) fcinfo->context); /* there's no return value in this case */
} else
retval = plpgsql_exec_function(func, fcinfo,
NULL, NULL,
procedure_resowner,
!nonatomic);
}
PG_FINALLY();
{ /* Decrement use-count, restore cur_estate */
func->cfunc.use_count--;
func->cur_estate = save_cur_estate;
/* Be sure to release the procedure resowner if any */ if (procedure_resowner)
{
ReleaseAllPlanCacheRefsInOwner(procedure_resowner);
ResourceOwnerDelete(procedure_resowner);
}
}
PG_END_TRY();
/* And run the function */
PG_TRY();
{
retval = plpgsql_exec_function(func, fake_fcinfo,
simple_eval_estate,
simple_eval_resowner,
simple_eval_resowner, /* see above */
codeblock->atomic);
}
PG_CATCH();
{ /* *Weneedtocleanupwhatwouldotherwisebelong-livedresources *accumulatedbythefailedDOblock,principallycachedplansfor *statements(whichcanbeflushedbyplpgsql_free_function_memory), *executiontreesforsimpleexpressions,whichareintheprivate *EState,andcached-planrefcountsheldbytheprivateresowner. * *BeforereleasingtheprivateEState,wemustcleanupany *simple_econtext_stackentriespointingintoit,whichwecandoby *invokingthesubxactcallback.(Itwillbecalledagainlaterif *someoutercontrolleveldoesasubtransactionabort,butnoharm *isdone.)Wecheatabitknowingthatplpgsql_subxact_cbdoesnot *payattentiontoitsparentSubidargument.
*/
plpgsql_subxact_cb(SUBXACT_EVENT_ABORT_SUB,
GetCurrentSubTransactionId(), 0, NULL);
/* Clean up the private EState and resowner */
FreeExecutorState(simple_eval_estate);
ReleaseAllPlanCacheRefsInOwner(simple_eval_resowner);
ResourceOwnerDelete(simple_eval_resowner);
/* Function should now have no remaining use-counts ... */
func->cfunc.use_count--;
Assert(func->cfunc.use_count == 0);
/* ... so we can free subsidiary storage */
plpgsql_free_function_memory(func);
/* And propagate the error */
PG_RE_THROW();
}
PG_END_TRY();
/* Clean up the private EState and resowner */
FreeExecutorState(simple_eval_estate);
ReleaseAllPlanCacheRefsInOwner(simple_eval_resowner);
ResourceOwnerDelete(simple_eval_resowner);
/* Function should now have no remaining use-counts ... */
func->cfunc.use_count--;
Assert(func->cfunc.use_count == 0);
/* ... so we can free subsidiary storage */
plpgsql_free_function_memory(func);
Datum
plpgsql_validator(PG_FUNCTION_ARGS)
{
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;
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
PG_RETURN_VOID();
/* 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, EVTTRIGGER, RECORD, VOID, or polymorphic */ if (functyptype == TYPTYPE_PSEUDO)
{ if (proc->prorettype == TRIGGEROID)
is_dml_trigger = true; elseif (proc->prorettype == EVENT_TRIGGEROID)
is_event_trigger = true; elseif (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 RECORD and polymorphic */
numargs = get_func_arg_info(tuple,
&argtypes, &argnames, &argmodes); for (i = 0; i < numargs; i++)
{ if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
{ if (argtypes[i] != RECORDOID &&
!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)
{
LOCAL_FCINFO(fake_fcinfo, 0);
FmgrInfo flinfo; int rc;
TriggerData trigdata;
EventTriggerData etrigdata;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.