aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/pg_proc.c86
-rw-r--r--src/backend/executor/functions.c68
-rw-r--r--src/backend/optimizer/util/clauses.c13
-rw-r--r--src/backend/utils/adt/array_userfuncs.c6
-rw-r--r--src/backend/utils/adt/arrayfuncs.c4
-rw-r--r--src/backend/utils/fmgr/fmgr.c21
-rw-r--r--src/include/catalog/pg_proc.h5
-rw-r--r--src/include/fmgr.h6
8 files changed, 152 insertions, 57 deletions
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 48b90e56ef1..4ec4c44bd40 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.97 2003/06/15 17:59:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.98 2003/07/01 00:04:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,7 +33,6 @@
#include "utils/syscache.h"
-static void checkretval(Oid rettype, char fn_typtype, List *queryTreeList);
Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
Datum fmgr_c_validator(PG_FUNCTION_ARGS);
Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
@@ -317,15 +316,20 @@ ProcedureCreate(const char *procedureName,
}
/*
- * checkretval() -- check return value of a list of sql parse trees.
+ * check_sql_fn_retval() -- check return value of a list of sql parse trees.
*
* The return value of a sql function is the value returned by
- * the final query in the function. We do some ad-hoc define-time
- * type checking here to be sure that the user is returning the
- * type he claims.
+ * the final query in the function. We do some ad-hoc type checking here
+ * to be sure that the user is returning the type he claims.
+ *
+ * This is normally applied during function definition, but in the case
+ * of a function with polymorphic arguments, we instead apply it during
+ * function execution startup. The rettype is then the actual resolved
+ * output type of the function, rather than the declared type. (Therefore,
+ * we should never see ANYARRAY or ANYELEMENT as rettype.)
*/
-static void
-checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
+void
+check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
{
Query *parse;
int cmd;
@@ -472,7 +476,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
relation_close(reln, AccessShareLock);
}
- else if (fn_typtype == 'p' && rettype == RECORDOID)
+ else if (rettype == RECORDOID)
{
/* Shouldn't have a typerelid */
Assert(typerelid == InvalidOid);
@@ -482,6 +486,14 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
* tuple.
*/
}
+ else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
+ {
+ /*
+ * This should already have been caught ...
+ */
+ elog(ERROR, "functions returning ANYARRAY or ANYELEMENT must " \
+ "have at least one argument of either type");
+ }
else
elog(ERROR, "return type %s is not supported for SQL functions",
format_type_be(rettype));
@@ -505,7 +517,9 @@ fmgr_internal_validator(PG_FUNCTION_ARGS)
Datum tmp;
char *prosrc;
- tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+ tuple = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcoid),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup of function %u failed", funcoid);
proc = (Form_pg_proc) GETSTRUCT(tuple);
@@ -544,7 +558,9 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
char *prosrc;
char *probin;
- tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+ tuple = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcoid),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup of function %u failed", funcoid);
proc = (Form_pg_proc) GETSTRUCT(tuple);
@@ -585,38 +601,62 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
Datum tmp;
char *prosrc;
char functyptype;
+ bool haspolyarg;
int i;
- tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+ tuple = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcoid),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup of function %u failed", funcoid);
proc = (Form_pg_proc) GETSTRUCT(tuple);
functyptype = get_typtype(proc->prorettype);
- /* Disallow pseudotypes in arguments and result */
- /* except that return type can be RECORD or VOID */
+ /* Disallow pseudotype result */
+ /* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */
if (functyptype == 'p' &&
proc->prorettype != RECORDOID &&
- proc->prorettype != VOIDOID)
+ proc->prorettype != VOIDOID &&
+ proc->prorettype != ANYARRAYOID &&
+ proc->prorettype != ANYELEMENTOID)
elog(ERROR, "SQL functions cannot return type %s",
format_type_be(proc->prorettype));
+ /* Disallow pseudotypes in arguments */
+ /* except for ANYARRAY or ANYELEMENT */
+ haspolyarg = false;
for (i = 0; i < proc->pronargs; i++)
{
if (get_typtype(proc->proargtypes[i]) == 'p')
- elog(ERROR, "SQL functions cannot have arguments of type %s",
- format_type_be(proc->proargtypes[i]));
+ {
+ if (proc->proargtypes[i] == ANYARRAYOID ||
+ proc->proargtypes[i] == ANYELEMENTOID)
+ haspolyarg = true;
+ else
+ elog(ERROR, "SQL functions cannot have arguments of type %s",
+ format_type_be(proc->proargtypes[i]));
+ }
}
- tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
- if (isnull)
- elog(ERROR, "null prosrc");
+ /*
+ * We can't precheck the function definition if there are any polymorphic
+ * input types, because actual datatypes of expression results will be
+ * unresolvable. The check will be done at runtime instead.
+ */
+ if (!haspolyarg)
+ {
+ tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
+ if (isnull)
+ elog(ERROR, "null prosrc");
- prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
+ prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
- querytree_list = pg_parse_and_rewrite(prosrc, proc->proargtypes, proc->pronargs);
- checkretval(proc->prorettype, functyptype, querytree_list);
+ querytree_list = pg_parse_and_rewrite(prosrc,
+ proc->proargtypes,
+ proc->pronargs);
+ check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
+ }
ReleaseSysCache(tuple);
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index a0e0919fd0b..e0ab9e92d50 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.66 2003/06/12 17:29:26 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.67 2003/07/01 00:04:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,6 +24,7 @@
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
+#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -76,7 +77,8 @@ typedef SQLFunctionCache *SQLFunctionCachePtr;
/* non-export function prototypes */
static execution_state *init_execution_state(char *src,
- Oid *argOidVect, int nargs);
+ Oid *argOidVect, int nargs,
+ Oid rettype, bool haspolyarg);
static void init_sql_fcache(FmgrInfo *finfo);
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
static TupleTableSlot *postquel_getnext(execution_state *es);
@@ -90,7 +92,8 @@ static void ShutdownSQLFunction(Datum arg);
static execution_state *
-init_execution_state(char *src, Oid *argOidVect, int nargs)
+init_execution_state(char *src, Oid *argOidVect, int nargs,
+ Oid rettype, bool haspolyarg)
{
execution_state *firstes;
execution_state *preves;
@@ -99,6 +102,13 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
queryTree_list = pg_parse_and_rewrite(src, argOidVect, nargs);
+ /*
+ * If the function has any arguments declared as polymorphic types,
+ * then it wasn't type-checked at definition time; must do so now.
+ */
+ if (haspolyarg)
+ check_sql_fn_retval(rettype, get_typtype(rettype), queryTree_list);
+
firstes = NULL;
preves = NULL;
@@ -133,17 +143,21 @@ static void
init_sql_fcache(FmgrInfo *finfo)
{
Oid foid = finfo->fn_oid;
+ Oid rettype;
HeapTuple procedureTuple;
HeapTuple typeTuple;
Form_pg_proc procedureStruct;
Form_pg_type typeStruct;
SQLFunctionCachePtr fcache;
Oid *argOidVect;
+ bool haspolyarg;
char *src;
int nargs;
Datum tmp;
bool isNull;
+ fcache = (SQLFunctionCachePtr) palloc0(sizeof(SQLFunctionCache));
+
/*
* get the procedure tuple corresponding to the given function Oid
*/
@@ -153,30 +167,37 @@ init_sql_fcache(FmgrInfo *finfo)
if (!HeapTupleIsValid(procedureTuple))
elog(ERROR, "init_sql_fcache: Cache lookup failed for procedure %u",
foid);
-
procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
/*
- * get the return type from the procedure tuple
+ * get the result type from the procedure tuple, and check for
+ * polymorphic result type; if so, find out the actual result type.
*/
+ rettype = procedureStruct->prorettype;
+
+ if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
+ {
+ rettype = get_fn_expr_rettype(finfo);
+ if (rettype == InvalidOid)
+ elog(ERROR, "could not determine actual result type for function declared %s",
+ format_type_be(procedureStruct->prorettype));
+ }
+
+ /* Now look up the actual result type */
typeTuple = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(procedureStruct->prorettype),
+ ObjectIdGetDatum(rettype),
0, 0, 0);
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "init_sql_fcache: Cache lookup failed for type %u",
- procedureStruct->prorettype);
-
+ rettype);
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
- fcache = (SQLFunctionCachePtr) palloc0(sizeof(SQLFunctionCache));
-
/*
* get the type length and by-value flag from the type tuple
*/
fcache->typlen = typeStruct->typlen;
- if (typeStruct->typtype != 'c' &&
- procedureStruct->prorettype != RECORDOID)
+ if (typeStruct->typtype != 'c' && rettype != RECORDOID)
{
/* The return type is not a composite type, so just use byval */
fcache->typbyval = typeStruct->typbyval;
@@ -205,17 +226,35 @@ init_sql_fcache(FmgrInfo *finfo)
fcache->funcSlot = NULL;
/*
- * Parse and plan the queries. We need the argument info to pass
+ * Parse and plan the queries. We need the argument type info to pass
* to the parser.
*/
nargs = procedureStruct->pronargs;
+ haspolyarg = false;
if (nargs > 0)
{
+ int argnum;
+
argOidVect = (Oid *) palloc(nargs * sizeof(Oid));
memcpy(argOidVect,
procedureStruct->proargtypes,
nargs * sizeof(Oid));
+ /* Resolve any polymorphic argument types */
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ Oid argtype = argOidVect[argnum];
+
+ if (argtype == ANYARRAYOID || argtype == ANYELEMENTOID)
+ {
+ argtype = get_fn_expr_argtype(finfo, argnum);
+ if (argtype == InvalidOid)
+ elog(ERROR, "could not determine actual type of argument declared %s",
+ format_type_be(argOidVect[argnum]));
+ argOidVect[argnum] = argtype;
+ haspolyarg = true;
+ }
+ }
}
else
argOidVect = (Oid *) NULL;
@@ -229,7 +268,8 @@ init_sql_fcache(FmgrInfo *finfo)
foid);
src = DatumGetCString(DirectFunctionCall1(textout, tmp));
- fcache->func_state = init_execution_state(src, argOidVect, nargs);
+ fcache->func_state = init_execution_state(src, argOidVect, nargs,
+ rettype, haspolyarg);
pfree(src);
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 54f2d7bd69b..3da79cc4957 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.142 2003/06/29 00:33:43 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.143 2003/07/01 00:04:37 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -1731,6 +1731,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
int *usecounts;
List *arg;
int i;
+ int j;
/*
* Forget it if the function is not SQL-language or has other
@@ -1742,12 +1743,20 @@ inline_function(Oid funcid, Oid result_type, List *args,
funcform->pronargs != length(args))
return NULL;
- /* Forget it if declared return type is tuple or void */
+ /* Forget it if declared return type is not base or domain */
result_typtype = get_typtype(funcform->prorettype);
if (result_typtype != 'b' &&
result_typtype != 'd')
return NULL;
+ /* Forget it if any declared argument type is polymorphic */
+ for (j = 0; j < funcform->pronargs; j++)
+ {
+ if (funcform->proargtypes[j] == ANYARRAYOID ||
+ funcform->proargtypes[j] == ANYELEMENTOID)
+ return NULL;
+ }
+
/* Check for recursive function, and give up trying to expand if so */
if (oidMember(funcid, active_fns))
return NULL;
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index 3aa70b0d332..6c28b211ceb 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -6,7 +6,7 @@
* Copyright (c) 2003, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.4 2003/06/27 00:33:25 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.5 2003/07/01 00:04:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,8 +37,8 @@ array_push(PG_FUNCTION_ARGS)
int16 typlen;
bool typbyval;
char typalign;
- Oid arg0_typeid = get_fn_expr_argtype(fcinfo, 0);
- Oid arg1_typeid = get_fn_expr_argtype(fcinfo, 1);
+ Oid arg0_typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
+ Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
Oid arg0_elemid;
Oid arg1_elemid;
ArrayMetaState *my_extra;
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 808353a63d4..d0a876a877b 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.92 2003/06/27 00:33:25 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.93 2003/07/01 00:04:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2792,7 +2792,7 @@ array_type_coerce(PG_FUNCTION_ARGS)
if (my_extra->srctype != src_elem_type)
{
- Oid tgt_type = get_fn_expr_rettype(fcinfo);
+ Oid tgt_type = get_fn_expr_rettype(fmgr_info);
Oid tgt_elem_type;
Oid funcId;
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 0d69ac1083e..04e72e53413 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.71 2003/06/29 00:33:44 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.72 2003/07/01 00:04:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1616,16 +1616,19 @@ pg_detoast_datum_slice(struct varlena * datum, int32 first, int32 count)
/*-------------------------------------------------------------------------
* Support routines for extracting info from fn_expr parse tree
+ *
+ * These are needed by polymorphic functions, which accept multiple possible
+ * input types and need help from the parser to know what they've got.
*-------------------------------------------------------------------------
*/
/*
- * Get the OID of the function return type
+ * Get the actual type OID of the function return type
*
* Returns InvalidOid if information is not available
*/
Oid
-get_fn_expr_rettype(FunctionCallInfo fcinfo)
+get_fn_expr_rettype(FmgrInfo *flinfo)
{
Node *expr;
@@ -1633,21 +1636,21 @@ get_fn_expr_rettype(FunctionCallInfo fcinfo)
* can't return anything useful if we have no FmgrInfo or if
* its fn_expr node has not been initialized
*/
- if (!fcinfo || !fcinfo->flinfo || !fcinfo->flinfo->fn_expr)
+ if (!flinfo || !flinfo->fn_expr)
return InvalidOid;
- expr = fcinfo->flinfo->fn_expr;
+ expr = flinfo->fn_expr;
return exprType(expr);
}
/*
- * Get the type OID of a specific function argument (counting from 0)
+ * Get the actual type OID of a specific function argument (counting from 0)
*
* Returns InvalidOid if information is not available
*/
Oid
-get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum)
+get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
{
Node *expr;
List *args;
@@ -1657,10 +1660,10 @@ get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum)
* can't return anything useful if we have no FmgrInfo or if
* its fn_expr node has not been initialized
*/
- if (!fcinfo || !fcinfo->flinfo || !fcinfo->flinfo->fn_expr)
+ if (!flinfo || !flinfo->fn_expr)
return InvalidOid;
- expr = fcinfo->flinfo->fn_expr;
+ expr = flinfo->fn_expr;
if (IsA(expr, FuncExpr))
args = ((FuncExpr *) expr)->args;
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 578a6b7d42a..b1f16c2d421 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_proc.h,v 1.308 2003/06/27 00:33:25 tgl Exp $
+ * $Id: pg_proc.h,v 1.309 2003/07/01 00:04:38 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@@ -3438,4 +3438,7 @@ extern Oid ProcedureCreate(const char *procedureName,
int parameterCount,
const Oid *parameterTypes);
+extern void check_sql_fn_retval(Oid rettype, char fn_typtype,
+ List *queryTreeList);
+
#endif /* PG_PROC_H */
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 51844eac38b..1cc6ed023e4 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: fmgr.h,v 1.29 2003/06/25 21:30:32 momjian Exp $
+ * $Id: fmgr.h,v 1.30 2003/07/01 00:04:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -378,8 +378,8 @@ extern Datum OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
*/
extern Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname);
extern Oid fmgr_internal_function(const char *proname);
-extern Oid get_fn_expr_rettype(FunctionCallInfo fcinfo);
-extern Oid get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum);
+extern Oid get_fn_expr_rettype(FmgrInfo *flinfo);
+extern Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum);
/*
* Routines in dfmgr.c