diff options
Diffstat (limited to 'src/backend/parser/parse_func.c')
-rw-r--r-- | src/backend/parser/parse_func.c | 226 |
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; } |