diff options
Diffstat (limited to 'src/pl/plpython/plpy_procedure.c')
-rw-r--r-- | src/pl/plpython/plpy_procedure.c | 148 |
1 files changed, 40 insertions, 108 deletions
diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c index 26acc88b27..58d6988202 100644 --- a/src/pl/plpython/plpy_procedure.c +++ b/src/pl/plpython/plpy_procedure.c @@ -15,6 +15,7 @@ #include "utils/builtins.h" #include "utils/hsearch.h" #include "utils/inval.h" +#include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/syscache.h" @@ -29,7 +30,6 @@ static HTAB *PLy_procedure_cache = NULL; static PLyProcedure *PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger); -static bool PLy_procedure_argument_valid(PLyTypeInfo *arg); static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup); static char *PLy_procedure_munge_source(const char *name, const char *src); @@ -165,6 +165,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) *ptr = '_'; } + /* Create long-lived context that all procedure info will live in */ cxt = AllocSetContextCreate(TopMemoryContext, procName, ALLOCSET_DEFAULT_SIZES); @@ -188,11 +189,9 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) proc->fn_tid = procTup->t_self; proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE); proc->is_setof = procStruct->proretset; - PLy_typeinfo_init(&proc->result, proc->mcxt); proc->src = NULL; proc->argnames = NULL; - for (i = 0; i < FUNC_MAX_ARGS; i++) - PLy_typeinfo_init(&proc->args[i], proc->mcxt); + proc->args = NULL; proc->nargs = 0; proc->langid = procStruct->prolang; protrftypes_datum = SysCacheGetAttr(PROCOID, procTup, @@ -211,50 +210,48 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) */ if (!is_trigger) { + Oid rettype = procStruct->prorettype; HeapTuple rvTypeTup; Form_pg_type rvTypeStruct; - rvTypeTup = SearchSysCache1(TYPEOID, - ObjectIdGetDatum(procStruct->prorettype)); + rvTypeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettype)); if (!HeapTupleIsValid(rvTypeTup)) - elog(ERROR, "cache lookup failed for type %u", - procStruct->prorettype); + elog(ERROR, "cache lookup failed for type %u", rettype); rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup); /* Disallow pseudotype result, except for void or record */ if (rvTypeStruct->typtype == TYPTYPE_PSEUDO) { - if (procStruct->prorettype == TRIGGEROID) + if (rettype == VOIDOID || + rettype == RECORDOID) + /* okay */ ; + else if (rettype == TRIGGEROID || rettype == EVTTRIGGEROID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("trigger functions can only be called as triggers"))); - else if (procStruct->prorettype != VOIDOID && - procStruct->prorettype != RECORDOID) + else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Python functions cannot return type %s", - format_type_be(procStruct->prorettype)))); + format_type_be(rettype)))); } - if (rvTypeStruct->typtype == TYPTYPE_COMPOSITE || - procStruct->prorettype == RECORDOID) - { - /* - * Tuple: set up later, during first call to - * PLy_function_handler - */ - proc->result.out.d.typoid = procStruct->prorettype; - proc->result.out.d.typmod = -1; - proc->result.is_rowtype = 2; - } - else - { - /* do the real work */ - PLy_output_datum_func(&proc->result, rvTypeTup, proc->langid, proc->trftypes); - } + /* set up output function for procedure result */ + PLy_output_setup_func(&proc->result, proc->mcxt, + rettype, -1, proc); ReleaseSysCache(rvTypeTup); } + else + { + /* + * In a trigger function, we use proc->result and proc->result_in + * for converting tuples, but we don't yet have enough info to set + * them up. PLy_exec_trigger will deal with it. + */ + proc->result.typoid = InvalidOid; + proc->result_in.typoid = InvalidOid; + } /* * Now get information required for input conversion of the @@ -287,7 +284,10 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) } } + /* Allocate arrays for per-input-argument data */ proc->argnames = (char **) palloc0(sizeof(char *) * proc->nargs); + proc->args = (PLyDatumToOb *) palloc0(sizeof(PLyDatumToOb) * proc->nargs); + for (i = pos = 0; i < total; i++) { HeapTuple argTypeTup; @@ -306,28 +306,17 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) elog(ERROR, "cache lookup failed for type %u", types[i]); argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup); - /* check argument type is OK, set up I/O function info */ - switch (argTypeStruct->typtype) - { - case TYPTYPE_PSEUDO: - /* Disallow pseudotype argument */ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("PL/Python functions cannot accept type %s", - format_type_be(types[i])))); - break; - case TYPTYPE_COMPOSITE: - /* we'll set IO funcs at first call */ - proc->args[pos].is_rowtype = 2; - break; - default: - PLy_input_datum_func(&(proc->args[pos]), - types[i], - argTypeTup, - proc->langid, - proc->trftypes); - break; - } + /* disallow pseudotype arguments */ + if (argTypeStruct->typtype == TYPTYPE_PSEUDO) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("PL/Python functions cannot accept type %s", + format_type_be(types[i])))); + + /* set up I/O function info */ + PLy_input_setup_func(&proc->args[pos], proc->mcxt, + types[i], -1, /* typmod not known */ + proc); /* get argument name */ proc->argnames[pos] = names ? pstrdup(names[i]) : NULL; @@ -425,53 +414,11 @@ PLy_procedure_delete(PLyProcedure *proc) } /* - * Check if our cached information about a datatype is still valid - */ -static bool -PLy_procedure_argument_valid(PLyTypeInfo *arg) -{ - HeapTuple relTup; - bool valid; - - /* Nothing to cache unless type is composite */ - if (arg->is_rowtype != 1) - return true; - - /* - * Zero typ_relid means that we got called on an output argument of a - * function returning an unnamed record type; the info for it can't - * change. - */ - if (!OidIsValid(arg->typ_relid)) - return true; - - /* Else we should have some cached data */ - Assert(TransactionIdIsValid(arg->typrel_xmin)); - Assert(ItemPointerIsValid(&arg->typrel_tid)); - - /* Get the pg_class tuple for the data type */ - relTup = SearchSysCache1(RELOID, ObjectIdGetDatum(arg->typ_relid)); - if (!HeapTupleIsValid(relTup)) - elog(ERROR, "cache lookup failed for relation %u", arg->typ_relid); - - /* If it has changed, the cached data is not valid */ - valid = (arg->typrel_xmin == HeapTupleHeaderGetRawXmin(relTup->t_data) && - ItemPointerEquals(&arg->typrel_tid, &relTup->t_self)); - - ReleaseSysCache(relTup); - - return valid; -} - -/* * Decide whether a cached PLyProcedure struct is still valid */ static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup) { - int i; - bool valid; - if (proc == NULL) return false; @@ -480,22 +427,7 @@ PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup) ItemPointerEquals(&proc->fn_tid, &procTup->t_self))) return false; - /* Else check the input argument datatypes */ - valid = true; - for (i = 0; i < proc->nargs; i++) - { - valid = PLy_procedure_argument_valid(&proc->args[i]); - - /* Short-circuit on first changed argument */ - if (!valid) - break; - } - - /* if the output type is composite, it might have changed */ - if (valid) - valid = PLy_procedure_argument_valid(&proc->result); - - return valid; + return true; } static char * |