aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_func.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2000-08-08 15:43:12 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2000-08-08 15:43:12 +0000
commit62e29fe2e748933bfd8ab1429518ee7b5a8974a7 (patch)
treed9ca32ad908a811854e890c059b46b8ff13fa038 /src/backend/parser/parse_func.c
parent8fc32374beb542380857e2fc0d67df91ad123b1d (diff)
downloadpostgresql-62e29fe2e748933bfd8ab1429518ee7b5a8974a7.tar.gz
postgresql-62e29fe2e748933bfd8ab1429518ee7b5a8974a7.zip
Remove 'func_tlist' from Func expression nodes, likewise 'param_tlist'
from Param nodes, per discussion a few days ago on pghackers. Add new expression node type FieldSelect that implements the functionality where it's actually needed. Clean up some other unused fields in Func nodes as well. NOTE: initdb forced due to change in stored expression trees for rules.
Diffstat (limited to 'src/backend/parser/parse_func.c')
-rw-r--r--src/backend/parser/parse_func.c226
1 files changed, 64 insertions, 162 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index d1a5e44f873..44a750c166e 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.86 2000/08/03 19:19:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.87 2000/08/08 15:42:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -59,7 +59,7 @@ static int match_argtypes(int nargs,
Oid *input_typeids,
CandidateList function_typeids,
CandidateList *candidates);
-static List *setup_tlist(char *attname, Oid relid);
+static FieldSelect *setup_field_select(Node *input, char *attname, Oid relid);
static Oid *func_select_candidate(int nargs, Oid *input_typeids,
CandidateList candidates);
static int agg_get_candidates(char *aggname, Oid typeId, CandidateList *candidates);
@@ -394,10 +394,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
argrelid = typeidTypeRelid(toid);
/*
- * A projection contains either an attribute name or "*".
+ * A projection must match an attribute name of the rel.
*/
- if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
- && strcmp(funcname, "*"))
+ if (get_attnum(argrelid, funcname) == InvalidAttrNumber)
elog(ERROR, "Functions on sets are not yet supported");
}
@@ -670,43 +669,12 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
funcnode = makeNode(Func);
funcnode->funcid = funcid;
funcnode->functype = rettype;
- funcnode->funcisindex = false;
- funcnode->funcsize = 0;
funcnode->func_fcache = NULL;
- funcnode->func_tlist = NIL;
- funcnode->func_planlist = NIL;
- /* perform the necessary typecasting */
+ /* perform the necessary typecasting of arguments */
make_arguments(pstate, nargs, fargs, oid_array, true_oid_array);
/*
- * for functions returning base types, we want to project out the
- * return value. set up a target list to do that. the executor will
- * ignore these for c functions, and do the right thing for postquel
- * functions.
- */
-
- if (typeidTypeRelid(rettype) == InvalidOid)
- funcnode->func_tlist = setup_base_tlist(rettype);
-
- /*
- * For sets, we want to make a targetlist to project out this
- * attribute of the set tuples.
- */
- if (attisset)
- {
- if (!strcmp(funcname, "*"))
- funcnode->func_tlist = expandAll(pstate, relname,
- makeAttr(refname, NULL),
- curr_resno);
- else
- {
- funcnode->func_tlist = setup_tlist(funcname, argrelid);
- rettype = get_atttype(argrelid, get_attnum(argrelid, funcname));
- }
- }
-
- /*
* Special checks to disallow sequence functions with side-effects
* in WHERE clauses. This is pretty much of a hack; why disallow these
* when we have no way to check for side-effects of user-defined fns?
@@ -724,6 +692,18 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
retval = (Node *) expr;
/*
+ * For sets, we want to project out the desired attribute of the tuples.
+ */
+ if (attisset)
+ {
+ FieldSelect *fselect;
+
+ fselect = setup_field_select(retval, funcname, argrelid);
+ rettype = fselect->resulttype;
+ retval = (Node *) fselect;
+ }
+
+ /*
* if the function returns a set of values, then we need to iterate
* over all the returned values in the executor, so we stick an iter
* node here. if it returns a singleton, then we don't need the iter
@@ -1524,66 +1504,30 @@ make_arguments(ParseState *pstate,
}
/*
- ** setup_tlist
- ** Build a tlist that says which attribute to project to.
- ** This routine is called by ParseFuncOrColumn() to set up a target list
- ** on a tuple parameter or return value. Due to a bug in 4.0,
- ** it's not possible to refer to system attributes in this case.
+ ** setup_field_select
+ ** Build a FieldSelect node that says which attribute to project to.
+ ** This routine is called by ParseFuncOrColumn() when we have found
+ ** a projection on a function result or parameter.
*/
-static List *
-setup_tlist(char *attname, Oid relid)
+static FieldSelect *
+setup_field_select(Node *input, char *attname, Oid relid)
{
- TargetEntry *tle;
- Resdom *resnode;
- Var *varnode;
- Oid typeid;
- int32 type_mod;
- int attno;
+ FieldSelect *fselect = makeNode(FieldSelect);
+ AttrNumber attno;
attno = get_attnum(relid, attname);
+
+ /* XXX Is there still a reason for this restriction? */
if (attno < 0)
elog(ERROR, "Cannot reference attribute '%s'"
" of tuple params/return values for functions", attname);
- typeid = get_atttype(relid, attno);
- type_mod = get_atttypmod(relid, attno);
-
- resnode = makeResdom(1,
- typeid,
- type_mod,
- get_attname(relid, attno),
- 0,
- InvalidOid,
- false);
- varnode = makeVar(-1, attno, typeid, type_mod, 0);
+ fselect->arg = input;
+ fselect->fieldnum = attno;
+ fselect->resulttype = get_atttype(relid, attno);
+ fselect->resulttypmod = get_atttypmod(relid, attno);
- tle = makeTargetEntry(resnode, (Node *) varnode);
- return lcons(tle, NIL);
-}
-
-/*
- ** setup_base_tlist
- ** Build a tlist that extracts a base type from the tuple
- ** returned by the executor.
- */
-List *
-setup_base_tlist(Oid typeid)
-{
- TargetEntry *tle;
- Resdom *resnode;
- Var *varnode;
-
- resnode = makeResdom(1,
- typeid,
- -1,
- "<noname>",
- 0,
- InvalidOid,
- false);
- varnode = makeVar(-1, 1, typeid, -1, 0);
- tle = makeTargetEntry(resnode, (Node *) varnode);
-
- return lcons(tle, NIL);
+ return fselect;
}
/*
@@ -1599,51 +1543,32 @@ ParseComplexProjection(ParseState *pstate,
{
Oid argtype;
Oid argrelid;
- Relation rd;
- Oid relid;
- int attnum;
+ FieldSelect *fselect;
switch (nodeTag(first_arg))
{
case T_Iter:
{
- Func *func;
- Iter *iter;
+ Iter *iter = (Iter *) first_arg;
- iter = (Iter *) first_arg;
- func = (Func *) ((Expr *) iter->iterexpr)->oper;
- argtype = get_func_rettype(func->funcid);
+ /*
+ * If the argument of the Iter returns a tuple,
+ * funcname may be a projection. If so, we stick
+ * the FieldSelect *inside* the Iter --- this is
+ * klugy, but necessary because ExecTargetList()
+ * currently does the right thing only when the
+ * Iter node is at the top level of a targetlist item.
+ */
+ argtype = iter->itertype;
argrelid = typeidTypeRelid(argtype);
if (argrelid &&
- ((attnum = get_attnum(argrelid, funcname))
- != InvalidAttrNumber))
+ get_attnum(argrelid, funcname) != InvalidAttrNumber)
{
-
- /*
- * the argument is a function returning a tuple, so
- * funcname may be a projection
- */
-
- /* add a tlist to the func node and return the Iter */
- rd = heap_openr_nofail(typeidTypeName(argtype));
- if (RelationIsValid(rd))
- {
- relid = RelationGetRelid(rd);
- func->func_tlist = setup_tlist(funcname, argrelid);
- iter->itertype = attnumTypeId(rd, attnum);
- heap_close(rd, NoLock);
- return (Node *) iter;
- }
- else
- {
- elog(ERROR, "Function '%s' has bad return type %d",
- funcname, argtype);
- }
- }
- else
- {
- /* drop through */
- ;
+ fselect = setup_field_select(iter->iterexpr,
+ funcname, argrelid);
+ iter->iterexpr = (Node *) fselect;
+ iter->itertype = fselect->resulttype;
+ return (Node *) iter;
}
break;
}
@@ -1665,38 +1590,20 @@ ParseComplexProjection(ParseState *pstate,
if (expr->opType != FUNC_EXPR)
break;
- funcnode = (Func *) expr->oper;
- argtype = get_func_rettype(funcnode->funcid);
- argrelid = typeidTypeRelid(argtype);
-
/*
- * the argument is a function returning a tuple, so
+ * If the argument is a function returning a tuple,
* funcname may be a projection
*/
+ funcnode = (Func *) expr->oper;
+ argtype = funcnode->functype;
+ argrelid = typeidTypeRelid(argtype);
if (argrelid &&
- (attnum = get_attnum(argrelid, funcname))
- != InvalidAttrNumber)
+ get_attnum(argrelid, funcname) != InvalidAttrNumber)
{
- Expr *newexpr;
-
- /* add a tlist to the func node */
- rd = heap_openr(typeidTypeName(argtype), NoLock);
-
- relid = RelationGetRelid(rd);
- funcnode->func_tlist = setup_tlist(funcname, argrelid);
- funcnode->functype = attnumTypeId(rd, attnum);
-
- newexpr = makeNode(Expr);
- newexpr->typeOid = funcnode->functype;
- newexpr->opType = FUNC_EXPR;
- newexpr->oper = (Node *) funcnode;
- newexpr->args = expr->args;
-
- heap_close(rd, NoLock);
-
- return (Node *) newexpr;
+ fselect = setup_field_select((Node *) expr,
+ funcname, argrelid);
+ return (Node *) fselect;
}
-
break;
}
case T_Param:
@@ -1707,19 +1614,14 @@ ParseComplexProjection(ParseState *pstate,
* If the Param is a complex type, this could be a
* projection
*/
- rd = heap_openr_nofail(typeidTypeName(param->paramtype));
- if (RelationIsValid(rd))
+ argtype = param->paramtype;
+ argrelid = typeidTypeRelid(argtype);
+ if (argrelid &&
+ get_attnum(argrelid, funcname) != InvalidAttrNumber)
{
- relid = RelationGetRelid(rd);
- if ((attnum = get_attnum(relid, funcname))
- != InvalidAttrNumber)
- {
- param->paramtype = attnumTypeId(rd, attnum);
- param->param_tlist = setup_tlist(funcname, relid);
- heap_close(rd, NoLock);
- return (Node *) param;
- }
- heap_close(rd, NoLock);
+ fselect = setup_field_select((Node *) param,
+ funcname, argrelid);
+ return (Node *) fselect;
}
break;
}