00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
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
00041 PLpgSQL_plugin **plugin_ptr = NULL;
00042
00043
00044
00045
00046
00047
00048
00049 void
00050 _PG_init(void)
00051 {
00052
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
00076 plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
00077
00078 inited = true;
00079 }
00080
00081
00082
00083
00084
00085
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
00100
00101 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
00102 elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
00103
00104
00105 func = plpgsql_compile(fcinfo, false);
00106
00107
00108 save_cur_estate = func->cur_estate;
00109
00110
00111 func->use_count++;
00112
00113 PG_TRY();
00114 {
00115
00116
00117
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
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
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
00155
00156
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
00175
00176 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
00177 elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
00178
00179
00180 func = plpgsql_compile_inline(codeblock->source_text);
00181
00182
00183 func->use_count++;
00184
00185
00186
00187
00188
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
00199 func->use_count--;
00200 Assert(func->use_count == 0);
00201
00202
00203 plpgsql_free_function_memory(func);
00204
00205
00206
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
00216
00217
00218
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
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
00247
00248 if (functyptype == TYPTYPE_PSEUDO)
00249 {
00250
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
00266
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
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
00292
00293 if ((rc = SPI_connect()) != SPI_OK_CONNECT)
00294 elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
00295
00296
00297
00298
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
00319 plpgsql_compile(&fake_fcinfo, true);
00320
00321
00322
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 }