Index: src/backend/parser/parse_clause.c =================================================================== RCS file: /opt/src/cvs/pgsql/src/backend/parser/parse_clause.c,v retrieving revision 1.92 diff -c -r1.92 parse_clause.c *** src/backend/parser/parse_clause.c 12 May 2002 23:43:03 -0000 1.92 --- src/backend/parser/parse_clause.c 15 May 2002 22:55:37 -0000 *************** *** 61,67 **** static List *addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist, List *opname); static bool exprIsInSortList(Node *expr, List *sortList, List *targetList); ! /* * transformFromClause - --- 61,70 ---- static List *addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist, List *opname); static bool exprIsInSortList(Node *expr, List *sortList, List *targetList); ! static void checkParameterVisibility(ParseState *pstate, ! RangeTblRef *rtr, ! RangeFunction *rangefunc, ! List *containedRels); /* * transformFromClause - *************** *** 545,550 **** --- 548,559 ---- rtr = transformRangeFunction(pstate, (RangeFunction *) n); *containedRels = makeListi1(rtr->rtindex); + + /* + * Make sure we've only been given valid parameters, i.e. + * we should not see vars from sibling FROM nodes. + */ + checkParameterVisibility(pstate, rtr, (RangeFunction *) n, *containedRels); return (Node *) rtr; } else if (IsA(n, JoinExpr)) *************** *** 1377,1380 **** --- 1386,1445 ---- return true; } return false; + } + + /* checkParameterVisibility() + * Make sure we don't try to access vars from + * sibling FROM nodes as RangeFunction parameters. + */ + static void + checkParameterVisibility(ParseState *pstate, RangeTblRef *rtr, RangeFunction *rangefunc, List *containedRels) + { + FuncCall *funccallnode = (FuncCall *) rangefunc->funccallnode; + List *args = funccallnode->args; + List *save_namespace; + List *clause_varnos, + *l; + + /* + * This is a tad tricky, for two reasons. First, the namespace that + * the join expression should see is just the any outer references + * from upper pstate levels. So, temporarily set this pstate's namespace + * accordingly. (We need not check for refname conflicts, because + * transformFromClauseItem() already did.) NOTE: this code is OK only + * because a RangeFunction can't legally alter the namespace by causing + * implicit relation refs to be added. + */ + save_namespace = pstate->p_namespace; + pstate->p_namespace = makeList1(rtr); + + /* transform the list of arguments */ + foreach(args, funccallnode->args) + { + lfirst(args) = transformExpr(pstate, (Node *) lfirst(args)); + + /* + * Second, we need to check that the ON condition doesn't refer to any + * rels outside the input subtrees of the JOIN. It could do that + * despite our hack on the namespace if it uses fully-qualified names. + * So, grovel through the transformed clause and make sure there are + * no bogus references. (Outer references are OK, and are ignored + * here.) + */ + + clause_varnos = pull_varnos(lfirst(args)); + foreach(l, clause_varnos) + { + int varno = lfirsti(l); + + if (!intMember(varno, containedRels)) + { + elog(ERROR, "Function relation in FROM clause may not refer to other relation, \"%s\"", + rt_fetch(varno, pstate->p_rtable)->eref->aliasname); + } + } + freeList(clause_varnos); + + } + pstate->p_namespace = save_namespace; }