Header And Logo

PostgreSQL
| The world's most advanced open source database.

pl_handler.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pl_handler.c     - Handler for the PL/pgSQL
00004  *            procedural language
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/pl/plpgsql/src/pl_handler.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 
00016 #include "plpgsql.h"
00017 
00018 #include "access/htup_details.h"
00019 #include "catalog/pg_proc.h"
00020 #include "catalog/pg_type.h"
00021 #include "funcapi.h"
00022 #include "miscadmin.h"
00023 #include "utils/builtins.h"
00024 #include "utils/guc.h"
00025 #include "utils/lsyscache.h"
00026 #include "utils/syscache.h"
00027 
00028 PG_MODULE_MAGIC;
00029 
00030 /* Custom GUC variable */
00031 static const struct config_enum_entry variable_conflict_options[] = {
00032     {"error", PLPGSQL_RESOLVE_ERROR, false},
00033     {"use_variable", PLPGSQL_RESOLVE_VARIABLE, false},
00034     {"use_column", PLPGSQL_RESOLVE_COLUMN, false},
00035     {NULL, 0, false}
00036 };
00037 
00038 int         plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR;
00039 
00040 /* Hook for plugins */
00041 PLpgSQL_plugin **plugin_ptr = NULL;
00042 
00043 
00044 /*
00045  * _PG_init()           - library load-time initialization
00046  *
00047  * DO NOT make this static nor change its name!
00048  */
00049 void
00050 _PG_init(void)
00051 {
00052     /* Be sure we do initialization only once (should be redundant now) */
00053     static bool inited = false;
00054 
00055     if (inited)
00056         return;
00057 
00058     pg_bindtextdomain(TEXTDOMAIN);
00059 
00060     DefineCustomEnumVariable("plpgsql.variable_conflict",
00061                              gettext_noop("Sets handling of conflicts between PL/pgSQL variable names and table column names."),
00062                              NULL,
00063                              &plpgsql_variable_conflict,
00064                              PLPGSQL_RESOLVE_ERROR,
00065                              variable_conflict_options,
00066                              PGC_SUSET, 0,
00067                              NULL, NULL, NULL);
00068 
00069     EmitWarningsOnPlaceholders("plpgsql");
00070 
00071     plpgsql_HashTableInit();
00072     RegisterXactCallback(plpgsql_xact_cb, NULL);
00073     RegisterSubXactCallback(plpgsql_subxact_cb, NULL);
00074 
00075     /* Set up a rendezvous point with optional instrumentation plugin */
00076     plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
00077 
00078     inited = true;
00079 }
00080 
00081 /* ----------
00082  * plpgsql_call_handler
00083  *
00084  * The PostgreSQL function manager and trigger manager
00085  * call this function for execution of PL/pgSQL procedures.
00086  * ----------
00087  */
00088 PG_FUNCTION_INFO_V1(plpgsql_call_handler);
00089 
00090 Datum
00091 plpgsql_call_handler(PG_FUNCTION_ARGS)
00092 {
00093     PLpgSQL_function *func;
00094     PLpgSQL_execstate *save_cur_estate;
00095     Datum       retval;
00096     int         rc;
00097 
00098     /*
00099      * Connect to SPI manager
00100      */
00101     if ((rc = SPI_connect()) != SPI_OK_CONNECT)
00102         elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
00103 
00104     /* Find or compile the function */
00105     func = plpgsql_compile(fcinfo, false);
00106 
00107     /* Must save and restore prior value of cur_estate */
00108     save_cur_estate = func->cur_estate;
00109 
00110     /* Mark the function as busy, so it can't be deleted from under us */
00111     func->use_count++;
00112 
00113     PG_TRY();
00114     {
00115         /*
00116          * Determine if called as function or trigger and call appropriate
00117          * subhandler
00118          */
00119         if (CALLED_AS_TRIGGER(fcinfo))
00120             retval = PointerGetDatum(plpgsql_exec_trigger(func,
00121                                            (TriggerData *) fcinfo->context));
00122         else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
00123         {
00124             plpgsql_exec_event_trigger(func,
00125                                        (EventTriggerData *) fcinfo->context);
00126             retval = (Datum) 0;
00127         }
00128         else
00129             retval = plpgsql_exec_function(func, fcinfo);
00130     }
00131     PG_CATCH();
00132     {
00133         /* Decrement use-count, restore cur_estate, and propagate error */
00134         func->use_count--;
00135         func->cur_estate = save_cur_estate;
00136         PG_RE_THROW();
00137     }
00138     PG_END_TRY();
00139 
00140     func->use_count--;
00141 
00142     func->cur_estate = save_cur_estate;
00143 
00144     /*
00145      * Disconnect from SPI manager
00146      */
00147     if ((rc = SPI_finish()) != SPI_OK_FINISH)
00148         elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
00149 
00150     return retval;
00151 }
00152 
00153 /* ----------
00154  * plpgsql_inline_handler
00155  *
00156  * Called by PostgreSQL to execute an anonymous code block
00157  * ----------
00158  */
00159 PG_FUNCTION_INFO_V1(plpgsql_inline_handler);
00160 
00161 Datum
00162 plpgsql_inline_handler(PG_FUNCTION_ARGS)
00163 {
00164     InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
00165     PLpgSQL_function *func;
00166     FunctionCallInfoData fake_fcinfo;
00167     FmgrInfo    flinfo;
00168     Datum       retval;
00169     int         rc;
00170 
00171     Assert(IsA(codeblock, InlineCodeBlock));
00172 
00173     /*
00174      * Connect to SPI manager
00175      */
00176     if ((rc = SPI_connect()) != SPI_OK_CONNECT)
00177         elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
00178 
00179     /* Compile the anonymous code block */
00180     func = plpgsql_compile_inline(codeblock->source_text);
00181 
00182     /* Mark the function as busy, just pro forma */
00183     func->use_count++;
00184 
00185     /*
00186      * Set up a fake fcinfo with just enough info to satisfy
00187      * plpgsql_exec_function().  In particular note that this sets things up
00188      * with no arguments passed.
00189      */
00190     MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
00191     MemSet(&flinfo, 0, sizeof(flinfo));
00192     fake_fcinfo.flinfo = &flinfo;
00193     flinfo.fn_oid = InvalidOid;
00194     flinfo.fn_mcxt = CurrentMemoryContext;
00195 
00196     retval = plpgsql_exec_function(func, &fake_fcinfo);
00197 
00198     /* Function should now have no remaining use-counts ... */
00199     func->use_count--;
00200     Assert(func->use_count == 0);
00201 
00202     /* ... so we can free subsidiary storage */
00203     plpgsql_free_function_memory(func);
00204 
00205     /*
00206      * Disconnect from SPI manager
00207      */
00208     if ((rc = SPI_finish()) != SPI_OK_FINISH)
00209         elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
00210 
00211     return retval;
00212 }
00213 
00214 /* ----------
00215  * plpgsql_validator
00216  *
00217  * This function attempts to validate a PL/pgSQL function at
00218  * CREATE FUNCTION time.
00219  * ----------
00220  */
00221 PG_FUNCTION_INFO_V1(plpgsql_validator);
00222 
00223 Datum
00224 plpgsql_validator(PG_FUNCTION_ARGS)
00225 {
00226     Oid         funcoid = PG_GETARG_OID(0);
00227     HeapTuple   tuple;
00228     Form_pg_proc proc;
00229     char        functyptype;
00230     int         numargs;
00231     Oid        *argtypes;
00232     char      **argnames;
00233     char       *argmodes;
00234     bool        is_dml_trigger = false;
00235     bool        is_event_trigger = false;
00236     int         i;
00237 
00238     /* Get the new function's pg_proc entry */
00239     tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
00240     if (!HeapTupleIsValid(tuple))
00241         elog(ERROR, "cache lookup failed for function %u", funcoid);
00242     proc = (Form_pg_proc) GETSTRUCT(tuple);
00243 
00244     functyptype = get_typtype(proc->prorettype);
00245 
00246     /* Disallow pseudotype result */
00247     /* except for TRIGGER, RECORD, VOID, or polymorphic */
00248     if (functyptype == TYPTYPE_PSEUDO)
00249     {
00250         /* we assume OPAQUE with no arguments means a trigger */
00251         if (proc->prorettype == TRIGGEROID ||
00252             (proc->prorettype == OPAQUEOID && proc->pronargs == 0))
00253             is_dml_trigger = true;
00254         else if (proc->prorettype == EVTTRIGGEROID)
00255             is_event_trigger = true;
00256         else if (proc->prorettype != RECORDOID &&
00257                  proc->prorettype != VOIDOID &&
00258                  !IsPolymorphicType(proc->prorettype))
00259             ereport(ERROR,
00260                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00261                      errmsg("PL/pgSQL functions cannot return type %s",
00262                             format_type_be(proc->prorettype))));
00263     }
00264 
00265     /* Disallow pseudotypes in arguments (either IN or OUT) */
00266     /* except for polymorphic */
00267     numargs = get_func_arg_info(tuple,
00268                                 &argtypes, &argnames, &argmodes);
00269     for (i = 0; i < numargs; i++)
00270     {
00271         if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
00272         {
00273             if (!IsPolymorphicType(argtypes[i]))
00274                 ereport(ERROR,
00275                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00276                          errmsg("PL/pgSQL functions cannot accept type %s",
00277                                 format_type_be(argtypes[i]))));
00278         }
00279     }
00280 
00281     /* Postpone body checks if !check_function_bodies */
00282     if (check_function_bodies)
00283     {
00284         FunctionCallInfoData fake_fcinfo;
00285         FmgrInfo    flinfo;
00286         int         rc;
00287         TriggerData trigdata;
00288         EventTriggerData etrigdata;
00289 
00290         /*
00291          * Connect to SPI manager (is this needed for compilation?)
00292          */
00293         if ((rc = SPI_connect()) != SPI_OK_CONNECT)
00294             elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
00295 
00296         /*
00297          * Set up a fake fcinfo with just enough info to satisfy
00298          * plpgsql_compile().
00299          */
00300         MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
00301         MemSet(&flinfo, 0, sizeof(flinfo));
00302         fake_fcinfo.flinfo = &flinfo;
00303         flinfo.fn_oid = funcoid;
00304         flinfo.fn_mcxt = CurrentMemoryContext;
00305         if (is_dml_trigger)
00306         {
00307             MemSet(&trigdata, 0, sizeof(trigdata));
00308             trigdata.type = T_TriggerData;
00309             fake_fcinfo.context = (Node *) &trigdata;
00310         }
00311         else if (is_event_trigger)
00312         {
00313             MemSet(&etrigdata, 0, sizeof(etrigdata));
00314             etrigdata.type = T_EventTriggerData;
00315             fake_fcinfo.context = (Node *) &etrigdata;
00316         }
00317 
00318         /* Test-compile the function */
00319         plpgsql_compile(&fake_fcinfo, true);
00320 
00321         /*
00322          * Disconnect from SPI manager
00323          */
00324         if ((rc = SPI_finish()) != SPI_OK_FINISH)
00325             elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
00326     }
00327 
00328     ReleaseSysCache(tuple);
00329 
00330     PG_RETURN_VOID();
00331 }