diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index b545928d9b..b450b2ee54 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -7,7 +7,7 @@ * Copyright (c) 2002-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.27 2005/11/17 22:14:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.28 2005/12/28 18:11:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -628,6 +628,109 @@ get_type_func_class(Oid typid) } +/* + * get_func_arg_info + * + * Fetch info about the argument types, names, and IN/OUT modes from the + * pg_proc tuple. Return value is the total number of arguments. + * Other results are palloc'd. *p_argtypes is always filled in, but + * *p_argnames and *p_argmodes will be set NULL in the default cases + * (no names, and all IN arguments, respectively). + * + * Note that this function simply fetches what is in the pg_proc tuple; + * it doesn't do any interpretation of polymorphic types. + */ +int +get_func_arg_info(HeapTuple procTup, + Oid **p_argtypes, char ***p_argnames, char **p_argmodes) +{ + Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup); + Datum proallargtypes; + Datum proargmodes; + Datum proargnames; + bool isNull; + ArrayType *arr; + int numargs; + Datum *elems; + int nelems; + int i; + + /* First discover the total number of parameters and get their types */ + proallargtypes = SysCacheGetAttr(PROCOID, procTup, + Anum_pg_proc_proallargtypes, + &isNull); + if (!isNull) + { + /* + * We expect the arrays to be 1-D arrays of the right types; verify + * that. For the OID and char arrays, we don't need to use + * deconstruct_array() since the array data is just going to look like + * a C array of values. + */ + arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */ + numargs = ARR_DIMS(arr)[0]; + if (ARR_NDIM(arr) != 1 || + numargs < 0 || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != OIDOID) + elog(ERROR, "proallargtypes is not a 1-D Oid array"); + Assert(numargs >= procStruct->pronargs); + *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid)); + memcpy(*p_argtypes, ARR_DATA_PTR(arr), + numargs * sizeof(Oid)); + } + else + { + /* If no proallargtypes, use proargtypes */ + numargs = procStruct->proargtypes.dim1; + Assert(numargs == procStruct->pronargs); + *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid)); + memcpy(*p_argtypes, procStruct->proargtypes.values, + numargs * sizeof(Oid)); + } + + /* Get argument names, if available */ + proargnames = SysCacheGetAttr(PROCOID, procTup, + Anum_pg_proc_proargnames, + &isNull); + if (isNull) + *p_argnames = NULL; + else + { + deconstruct_array(DatumGetArrayTypeP(proargnames), + TEXTOID, -1, false, 'i', + &elems, NULL, &nelems); + if (nelems != numargs) /* should not happen */ + elog(ERROR, "proargnames must have the same number of elements as the function has arguments"); + *p_argnames = (char **) palloc(sizeof(char *) * numargs); + for (i = 0; i < numargs; i++) + (*p_argnames)[i] = DatumGetCString(DirectFunctionCall1(textout, + elems[i])); + } + + /* Get argument modes, if available */ + proargmodes = SysCacheGetAttr(PROCOID, procTup, + Anum_pg_proc_proargmodes, + &isNull); + if (isNull) + *p_argmodes = NULL; + else + { + arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */ + if (ARR_NDIM(arr) != 1 || + ARR_DIMS(arr)[0] != numargs || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != CHAROID) + elog(ERROR, "proargmodes is not a 1-D char array"); + *p_argmodes = (char *) palloc(numargs * sizeof(char)); + memcpy(*p_argmodes, ARR_DATA_PTR(arr), + numargs * sizeof(char)); + } + + return numargs; +} + + /* * get_func_result_name * diff --git a/src/include/funcapi.h b/src/include/funcapi.h index 1f455d3eea..ccc61dfbf0 100644 --- a/src/include/funcapi.h +++ b/src/include/funcapi.h @@ -9,7 +9,7 @@ * * Copyright (c) 2002-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/funcapi.h,v 1.21 2005/11/22 18:17:29 momjian Exp $ + * $PostgreSQL: pgsql/src/include/funcapi.h,v 1.22 2005/12/28 18:11:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -165,12 +165,16 @@ extern TypeFuncClass get_func_result_type(Oid functionId, Oid *resultTypeId, TupleDesc *resultTupleDesc); -extern char *get_func_result_name(Oid functionId); - extern bool resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes, Node *call_expr); +extern int get_func_arg_info(HeapTuple procTup, + Oid **p_argtypes, char ***p_argnames, + char **p_argmodes); + +extern char *get_func_result_name(Oid functionId); + extern TupleDesc build_function_result_tupdesc_d(Datum proallargtypes, Datum proargmodes, Datum proargnames); diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index b89f975981..d9fa1f0e42 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.97 2005/12/09 17:08:49 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.98 2005/12/28 18:11:25 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -123,9 +123,6 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo, HeapTuple procTup, PLpgSQL_func_hashkey *hashkey, bool forValidator); -static int fetchArgInfo(HeapTuple procTup, - Oid **p_argtypes, char ***p_argnames, - char **p_argmodes); static PLpgSQL_row *build_row_from_class(Oid classOid); static PLpgSQL_row *build_row_from_vars(PLpgSQL_variable **vars, int numvars); static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod); @@ -358,7 +355,8 @@ do_compile(FunctionCallInfo fcinfo, */ MemoryContextSwitchTo(compile_tmp_cxt); - numargs = fetchArgInfo(procTup, &argtypes, &argnames, &argmodes); + numargs = get_func_arg_info(procTup, + &argtypes, &argnames, &argmodes); plpgsql_resolve_polymorphic_argtypes(numargs, argtypes, argmodes, fcinfo->flinfo->fn_expr, @@ -751,102 +749,6 @@ plpgsql_compile_error_callback(void *arg) } -/* - * Fetch info about the argument types, names, and IN/OUT modes from the - * pg_proc tuple. Return value is the number of arguments. - * Other results are palloc'd. - */ -static int -fetchArgInfo(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, - char **p_argmodes) -{ - Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup); - Datum proallargtypes; - Datum proargmodes; - Datum proargnames; - bool isNull; - ArrayType *arr; - int numargs; - Datum *elems; - int nelems; - int i; - - /* First discover the total number of parameters and get their types */ - proallargtypes = SysCacheGetAttr(PROCOID, procTup, - Anum_pg_proc_proallargtypes, - &isNull); - if (!isNull) - { - /* - * We expect the arrays to be 1-D arrays of the right types; verify - * that. For the OID and char arrays, we don't need to use - * deconstruct_array() since the array data is just going to look like - * a C array of values. - */ - arr = DatumGetArrayTypeP(proallargtypes); /* ensure not toasted */ - numargs = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - numargs < 0 || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != OIDOID) - elog(ERROR, "proallargtypes is not a 1-D Oid array"); - Assert(numargs >= procStruct->pronargs); - *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid)); - memcpy(*p_argtypes, ARR_DATA_PTR(arr), - numargs * sizeof(Oid)); - } - else - { - /* If no proallargtypes, use proargtypes */ - numargs = procStruct->proargtypes.dim1; - Assert(numargs == procStruct->pronargs); - *p_argtypes = (Oid *) palloc(numargs * sizeof(Oid)); - memcpy(*p_argtypes, procStruct->proargtypes.values, - numargs * sizeof(Oid)); - } - - /* Get argument names, if available */ - proargnames = SysCacheGetAttr(PROCOID, procTup, - Anum_pg_proc_proargnames, - &isNull); - if (isNull) - *p_argnames = NULL; - else - { - deconstruct_array(DatumGetArrayTypeP(proargnames), - TEXTOID, -1, false, 'i', - &elems, NULL, &nelems); - if (nelems != numargs) /* should not happen */ - elog(ERROR, "proargnames must have the same number of elements as the function has arguments"); - *p_argnames = (char **) palloc(sizeof(char *) * numargs); - for (i = 0; i < numargs; i++) - (*p_argnames)[i] = DatumGetCString(DirectFunctionCall1(textout, - elems[i])); - } - - /* Get argument modes, if available */ - proargmodes = SysCacheGetAttr(PROCOID, procTup, - Anum_pg_proc_proargmodes, - &isNull); - if (isNull) - *p_argmodes = NULL; - else - { - arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */ - if (ARR_NDIM(arr) != 1 || - ARR_DIMS(arr)[0] != numargs || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != CHAROID) - elog(ERROR, "proargmodes is not a 1-D char array"); - *p_argmodes = (char *) palloc(numargs * sizeof(char)); - memcpy(*p_argmodes, ARR_DATA_PTR(arr), - numargs * sizeof(char)); - } - - return numargs; -} - - /* ---------- * plpgsql_parse_word The scanner calls this to postparse * any single word not found by a diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 69d128e869..59e6acc789 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.26 2005/10/15 02:49:50 momjian Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.27 2005/12/28 18:11:25 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -41,6 +41,7 @@ #include "access/heapam.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" +#include "funcapi.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/syscache.h" @@ -147,9 +148,11 @@ plpgsql_validator(PG_FUNCTION_ARGS) HeapTuple tuple; Form_pg_proc proc; char functyptype; + int numargs; + Oid *argtypes; + char **argnames; + char *argmodes; bool istrigger = false; - bool haspolyresult; - bool haspolyarg; int i; /* perform initialization */ @@ -173,32 +176,30 @@ plpgsql_validator(PG_FUNCTION_ARGS) if (proc->prorettype == TRIGGEROID || (proc->prorettype == OPAQUEOID && proc->pronargs == 0)) istrigger = true; - else if (proc->prorettype == ANYARRAYOID || - proc->prorettype == ANYELEMENTOID) - haspolyresult = true; else if (proc->prorettype != RECORDOID && - proc->prorettype != VOIDOID) + proc->prorettype != VOIDOID && + proc->prorettype != ANYARRAYOID && + proc->prorettype != ANYELEMENTOID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("plpgsql functions cannot return type %s", format_type_be(proc->prorettype)))); } - /* Disallow pseudotypes in arguments */ + /* Disallow pseudotypes in arguments (either IN or OUT) */ /* except for ANYARRAY or ANYELEMENT */ - haspolyarg = false; - for (i = 0; i < proc->pronargs; i++) + numargs = get_func_arg_info(tuple, + &argtypes, &argnames, &argmodes); + for (i = 0; i < numargs; i++) { - if (get_typtype(proc->proargtypes.values[i]) == 'p') + if (get_typtype(argtypes[i]) == 'p') { - if (proc->proargtypes.values[i] == ANYARRAYOID || - proc->proargtypes.values[i] == ANYELEMENTOID) - haspolyarg = true; - else + if (argtypes[i] != ANYARRAYOID && + argtypes[i] != ANYELEMENTOID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("plpgsql functions cannot take type %s", - format_type_be(proc->proargtypes.values[i])))); + format_type_be(argtypes[i])))); } }