]> granicus.if.org Git - postgresql/blobdiff - src/pl/plpgsql/src/pl_handler.c
Update copyright for 2014
[postgresql] / src / pl / plpgsql / src / pl_handler.c
index e6e71432ff9ae72e43c402a4873446234dc7d7da..f02203a5fb8eeed8a7de3d6f07a6be2ca5bdddf0 100644 (file)
@@ -3,7 +3,7 @@
  * pl_handler.c                - Handler for the PL/pgSQL
  *                       procedural language
  *
- * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
@@ -15,6 +15,7 @@
 
 #include "plpgsql.h"
 
+#include "access/htup_details.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
@@ -36,6 +37,8 @@ static const struct config_enum_entry variable_conflict_options[] = {
 
 int                    plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR;
 
+bool           plpgsql_print_strict_params = false;
+
 /* Hook for plugins */
 PLpgSQL_plugin **plugin_ptr = NULL;
 
@@ -65,6 +68,14 @@ _PG_init(void)
                                                         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);
+
        EmitWarningsOnPlaceholders("plpgsql");
 
        plpgsql_HashTableInit();
@@ -118,8 +129,14 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
                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);
+                       retval = plpgsql_exec_function(func, fcinfo, NULL);
        }
        PG_CATCH();
        {
@@ -158,6 +175,7 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS)
        PLpgSQL_function *func;
        FunctionCallInfoData fake_fcinfo;
        FmgrInfo        flinfo;
+       EState     *simple_eval_estate;
        Datum           retval;
        int                     rc;
 
@@ -186,7 +204,51 @@ plpgsql_inline_handler(PG_FUNCTION_ARGS)
        flinfo.fn_oid = InvalidOid;
        flinfo.fn_mcxt = CurrentMemoryContext;
 
-       retval = plpgsql_exec_function(func, &fake_fcinfo);
+       /* Create a private EState for simple-expression execution */
+       simple_eval_estate = CreateExecutorState();
+
+       /* And run the function */
+       PG_TRY();
+       {
+               retval = plpgsql_exec_function(func, &fake_fcinfo, simple_eval_estate);
+       }
+       PG_CATCH();
+       {
+               /*
+                * We need to clean up what would otherwise be long-lived resources
+                * accumulated by the failed DO block, principally cached plans for
+                * statements (which can be flushed with plpgsql_free_function_memory)
+                * and execution trees for simple expressions, which are in the
+                * private EState.
+                *
+                * Before releasing the private EState, we must clean up any
+                * simple_econtext_stack entries pointing into it, which we can do by
+                * invoking the subxact callback.  (It will be called again later if
+                * some outer control level does a subtransaction abort, but no harm
+                * is done.)  We cheat a bit knowing that plpgsql_subxact_cb does not
+                * pay attention to its parentSubid argument.
+                */
+               plpgsql_subxact_cb(SUBXACT_EVENT_ABORT_SUB,
+                                                  GetCurrentSubTransactionId(),
+                                                  0, NULL);
+
+               /* Clean up the private EState */
+               FreeExecutorState(simple_eval_estate);
+
+               /* 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);
+
+               /* And propagate the error */
+               PG_RE_THROW();
+       }
+       PG_END_TRY();
+
+       /* Clean up the private EState */
+       FreeExecutorState(simple_eval_estate);
 
        /* Function should now have no remaining use-counts ... */
        func->use_count--;
@@ -224,7 +286,8 @@ plpgsql_validator(PG_FUNCTION_ARGS)
        Oid                *argtypes;
        char      **argnames;
        char       *argmodes;
-       bool            istrigger = false;
+       bool            is_dml_trigger = false;
+       bool            is_event_trigger = false;
        int                     i;
 
        /* Get the new function's pg_proc entry */
@@ -242,7 +305,9 @@ plpgsql_validator(PG_FUNCTION_ARGS)
                /* we assume OPAQUE with no arguments means a trigger */
                if (proc->prorettype == TRIGGEROID ||
                        (proc->prorettype == OPAQUEOID && proc->pronargs == 0))
-                       istrigger = true;
+                       is_dml_trigger = true;
+               else if (proc->prorettype == EVTTRIGGEROID)
+                       is_event_trigger = true;
                else if (proc->prorettype != RECORDOID &&
                                 proc->prorettype != VOIDOID &&
                                 !IsPolymorphicType(proc->prorettype))
@@ -273,8 +338,9 @@ plpgsql_validator(PG_FUNCTION_ARGS)
        {
                FunctionCallInfoData fake_fcinfo;
                FmgrInfo        flinfo;
-               TriggerData trigdata;
                int                     rc;
+               TriggerData trigdata;
+               EventTriggerData etrigdata;
 
                /*
                 * Connect to SPI manager (is this needed for compilation?)
@@ -291,12 +357,18 @@ plpgsql_validator(PG_FUNCTION_ARGS)
                fake_fcinfo.flinfo = &flinfo;
                flinfo.fn_oid = funcoid;
                flinfo.fn_mcxt = CurrentMemoryContext;
-               if (istrigger)
+               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);