diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 7027f3c015..91dbd60163 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.33 1999/01/25 18:02:18 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.34 1999/01/26 05:57:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -916,195 +916,195 @@ del_agg_clause(Node *clause) return NULL; } -/***S*H***/ +/***S*H***/ /* check_having_qual_for_vars takes the the havingQual and the actual targetlist as arguments * and recursively scans the havingQual for attributes that are not included in the targetlist * yet. Attributes contained in the havingQual but not in the targetlist show up with queries - * like: - * SELECT sid + * like: + * SELECT sid * FROM part * GROUP BY sid - * HAVING MIN(pid) > 1; (pid is used but never selected for!!!). + * HAVING MIN(pid) > 1; (pid is used but never selected for!!!). * To be able to handle queries like that correctly we have to extend the actual targetlist - * (which will be the one used for the GROUP node later on) by these attributes. */ + * (which will be the one used for the GROUP node later on) by these attributes. */ List * check_having_qual_for_vars(Node *clause, List *targetlist_so_far) { - List *t; + List *t; - if (IsA(clause, Var)) - { - RelOptInfo tmp_rel; - + if (IsA(clause, Var)) + { + RelOptInfo tmp_rel; - tmp_rel.targetlist = targetlist_so_far; - - /* - * Ha! A Var node! - */ - /* Check if the VAR is already contained in the targetlist */ - if (tlist_member((Var *)clause, (List *)targetlist_so_far) == NULL) - { - add_tl_element(&tmp_rel, (Var *)clause); - } - - return tmp_rel.targetlist; - } - - else if (is_funcclause(clause) || not_clause(clause) || - or_clause(clause) || and_clause(clause)) - { - - /* - * This is a function. Recursively call this routine for its - * arguments... - */ - foreach(t, ((Expr *) clause)->args) - { - targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far); + tmp_rel.targetlist = targetlist_so_far; + + /* + * Ha! A Var node! + */ + + /* Check if the VAR is already contained in the targetlist */ + if (tlist_member((Var *) clause, (List *) targetlist_so_far) == NULL) + add_tl_element(&tmp_rel, (Var *) clause); + + return tmp_rel.targetlist; } - return targetlist_so_far; - } - else if (IsA(clause, Aggref)) - { - targetlist_so_far = - check_having_qual_for_vars(((Aggref *) clause)->target, targetlist_so_far); - return targetlist_so_far; - } - else if (IsA(clause, ArrayRef)) - { - ArrayRef *aref = (ArrayRef *) clause; - - /* - * This is an arrayref. Recursively call this routine for its - * expression and its index expression... - */ - foreach(t, aref->refupperindexpr) + + else if (is_funcclause(clause) || not_clause(clause) || + or_clause(clause) || and_clause(clause)) { - targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far); + + /* + * This is a function. Recursively call this routine for its + * arguments... + */ + foreach(t, ((Expr *) clause)->args) + targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far); + return targetlist_so_far; } - foreach(t, aref->reflowerindexpr) + else if (IsA(clause, Aggref)) { - targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far); + targetlist_so_far = + check_having_qual_for_vars(((Aggref *) clause)->target, targetlist_so_far); + return targetlist_so_far; } - targetlist_so_far = check_having_qual_for_vars(aref->refexpr, targetlist_so_far); - targetlist_so_far = check_having_qual_for_vars(aref->refassgnexpr, targetlist_so_far); - - return targetlist_so_far; - } - else if (is_opclause(clause)) - { - - /* - * This is an operator. Recursively call this routine for both its - * left and right operands - */ - Node *left = (Node *) get_leftop((Expr *) clause); - Node *right = (Node *) get_rightop((Expr *) clause); - - if (left != (Node *) NULL) - targetlist_so_far = check_having_qual_for_vars(left, targetlist_so_far); - if (right != (Node *) NULL) - targetlist_so_far = check_having_qual_for_vars(right, targetlist_so_far); - - return targetlist_so_far; - } - else if (IsA(clause, Param) || IsA(clause, Const)) - { - /* do nothing! */ - return targetlist_so_far; - } - /* If we get to a sublink, then we only have to check the lefthand side of the expression - * to see if there are any additional VARs */ - else if (IsA(clause, SubLink)) - { - foreach(t,((List *)((SubLink *)clause)->lefthand)) + else if (IsA(clause, ArrayRef)) { - targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far); + ArrayRef *aref = (ArrayRef *) clause; + + /* + * This is an arrayref. Recursively call this routine for its + * expression and its index expression... + */ + foreach(t, aref->refupperindexpr) + targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far); + foreach(t, aref->reflowerindexpr) + targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far); + targetlist_so_far = check_having_qual_for_vars(aref->refexpr, targetlist_so_far); + targetlist_so_far = check_having_qual_for_vars(aref->refassgnexpr, targetlist_so_far); + + return targetlist_so_far; + } + else if (is_opclause(clause)) + { + + /* + * This is an operator. Recursively call this routine for both its + * left and right operands + */ + Node *left = (Node *) get_leftop((Expr *) clause); + Node *right = (Node *) get_rightop((Expr *) clause); + + if (left != (Node *) NULL) + targetlist_so_far = check_having_qual_for_vars(left, targetlist_so_far); + if (right != (Node *) NULL) + targetlist_so_far = check_having_qual_for_vars(right, targetlist_so_far); + + return targetlist_so_far; + } + else if (IsA(clause, Param) ||IsA(clause, Const)) + { + /* do nothing! */ + return targetlist_so_far; + } + + /* + * If we get to a sublink, then we only have to check the lefthand + * side of the expression to see if there are any additional VARs + */ + else if (IsA(clause, SubLink)) + { + foreach(t, ((List *) ((SubLink *) clause)->lefthand)) + targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far); + return targetlist_so_far; + } + else + { + + /* + * Ooops! we can not handle that! + */ + elog(ERROR, "check_having_qual_for_vars: Can not handle this having_qual! %d\n", + nodeTag(clause)); + return NIL; } - return targetlist_so_far; - } - else - { - /* - * Ooops! we can not handle that! - */ - elog(ERROR, "check_having_qual_for_vars: Can not handle this having_qual! %d\n", - nodeTag(clause)); - return NIL; - } } -/* check_having_qual_for_aggs takes the havingQual, the targetlist and the groupClause +/* check_having_qual_for_aggs takes the havingQual, the targetlist and the groupClause * as arguments and scans the havingQual recursively for aggregates. If an aggregate is - * found it is attached to a list and returned by the function. (All the returned lists + * found it is attached to a list and returned by the function. (All the returned lists * are concenated to result_plan->aggs in planner.c:union_planner() */ List * check_having_qual_for_aggs(Node *clause, List *subplanTargetList, List *groupClause) { - List *t, *l1; + List *t, + *l1; List *agg_list = NIL; - int contained_in_group_clause = 0; - + int contained_in_group_clause = 0; + if (IsA(clause, Var)) { - TargetEntry *subplanVar; - - /* - * Ha! A Var node! - */ - subplanVar = match_varid((Var *) clause, subplanTargetList); - - /* - * Change the varno & varattno fields of the var node to point to the resdom->resno - * fields of the subplan (lefttree) - */ - ((Var *) clause)->varattno = subplanVar->resdom->resno; + TargetEntry *subplanVar; - return NIL; + /* + * Ha! A Var node! + */ + subplanVar = match_varid((Var *) clause, subplanTargetList); + + /* + * Change the varno & varattno fields of the var node to point to + * the resdom->resno fields of the subplan (lefttree) + */ + ((Var *) clause)->varattno = subplanVar->resdom->resno; + + return NIL; } - /***S*H***/ - else if (is_funcclause(clause) || not_clause(clause) || - or_clause(clause) || and_clause(clause)) + /***S*H***/ + else if (is_funcclause(clause) || not_clause(clause) || + or_clause(clause) || and_clause(clause)) { - int new_length=0, old_length=0; - + int new_length = 0, + old_length = 0; + /* * This is a function. Recursively call this routine for its * arguments... (i.e. for AND, OR, ... clauses!) */ foreach(t, ((Expr *) clause)->args) { - old_length=length((List *)agg_list); + old_length = length((List *) agg_list); - agg_list = nconc(agg_list, - check_having_qual_for_aggs(lfirst(t), subplanTargetList, - groupClause)); + agg_list = nconc(agg_list, + check_having_qual_for_aggs(lfirst(t), subplanTargetList, + groupClause)); - /* The arguments of OR or AND clauses are comparisons or relations - * and because we are in the havingQual there must be at least one operand - * using an aggregate function. If so, we will find it and the length of the - * agg_list will be increased after the above call to - * check_having_qual_for_aggs. If there are no aggregates used, the query - * could have been formulated using the 'where' clause */ - if(((new_length=length((List *)agg_list)) == old_length) || (new_length == 0)) - { - elog(ERROR,"This could have been done in a where clause!!"); - return NIL; - } + /* + * The arguments of OR or AND clauses are comparisons or + * relations and because we are in the havingQual there must + * be at least one operand using an aggregate function. If so, + * we will find it and the length of the agg_list will be + * increased after the above call to + * check_having_qual_for_aggs. If there are no aggregates + * used, the query could have been formulated using the + * 'where' clause + */ + if (((new_length = length((List *) agg_list)) == old_length) || (new_length == 0)) + { + elog(ERROR, "This could have been done in a where clause!!"); + return NIL; + } } return agg_list; } else if (IsA(clause, Aggref)) { return lcons(clause, - check_having_qual_for_aggs(((Aggref *) clause)->target, subplanTargetList, - groupClause)); + check_having_qual_for_aggs(((Aggref *) clause)->target, subplanTargetList, + groupClause)); } else if (IsA(clause, ArrayRef)) { @@ -1117,21 +1117,21 @@ check_having_qual_for_aggs(Node *clause, List *subplanTargetList, List *groupCla foreach(t, aref->refupperindexpr) { agg_list = nconc(agg_list, - check_having_qual_for_aggs(lfirst(t), subplanTargetList, - groupClause)); + check_having_qual_for_aggs(lfirst(t), subplanTargetList, + groupClause)); } foreach(t, aref->reflowerindexpr) { agg_list = nconc(agg_list, - check_having_qual_for_aggs(lfirst(t), subplanTargetList, - groupClause)); + check_having_qual_for_aggs(lfirst(t), subplanTargetList, + groupClause)); } agg_list = nconc(agg_list, - check_having_qual_for_aggs(aref->refexpr, subplanTargetList, - groupClause)); + check_having_qual_for_aggs(aref->refexpr, subplanTargetList, + groupClause)); agg_list = nconc(agg_list, - check_having_qual_for_aggs(aref->refassgnexpr, subplanTargetList, - groupClause)); + check_having_qual_for_aggs(aref->refassgnexpr, subplanTargetList, + groupClause)); return agg_list; } @@ -1147,92 +1147,102 @@ check_having_qual_for_aggs(Node *clause, List *subplanTargetList, List *groupCla if (left != (Node *) NULL) agg_list = nconc(agg_list, - check_having_qual_for_aggs(left, subplanTargetList, - groupClause)); + check_having_qual_for_aggs(left, subplanTargetList, + groupClause)); if (right != (Node *) NULL) agg_list = nconc(agg_list, check_having_qual_for_aggs(right, subplanTargetList, - groupClause)); + groupClause)); return agg_list; } - else if (IsA(clause, Param) || IsA(clause, Const)) + else if (IsA(clause, Param) ||IsA(clause, Const)) { /* do nothing! */ return NIL; } - /* This is for Sublinks which show up as EXPR nodes. All the other EXPR nodes - * (funcclauses, and_clauses, or_clauses) were caught above */ + + /* + * This is for Sublinks which show up as EXPR nodes. All the other + * EXPR nodes (funcclauses, and_clauses, or_clauses) were caught above + */ else if (IsA(clause, Expr)) - { - /* Only the lefthand side of the sublink has to be checked for aggregates - * to be attached to result_plan->aggs (see planner.c:union_planner() ) - */ - foreach(t,((List *)((SubLink *)((SubPlan *) - ((Expr *)clause)->oper)->sublink)->lefthand)) - { - agg_list = - nconc(agg_list, - check_having_qual_for_aggs(lfirst(t), - subplanTargetList, groupClause)); - } + { - /* The first argument of ...->oper has also to be checked */ - { - List *tmp_ptr; - - foreach(tmp_ptr, ((SubLink *)((SubPlan *) - ((Expr *)clause)->oper)->sublink)->oper) - { - agg_list = - nconc(agg_list, - check_having_qual_for_aggs((Node *)lfirst(((Expr *) - lfirst(tmp_ptr))->args), - subplanTargetList, groupClause)); + /* + * Only the lefthand side of the sublink has to be checked for + * aggregates to be attached to result_plan->aggs (see + * planner.c:union_planner() ) + */ + foreach(t, ((List *) ((SubLink *) ((SubPlan *) + ((Expr *) clause)->oper)->sublink)->lefthand)) + { + agg_list = + nconc(agg_list, + check_having_qual_for_aggs(lfirst(t), + subplanTargetList, groupClause)); } - } - - /* All arguments to the Sublink node are attributes from outside used within - * the sublink. Here we have to check that only attributes that is grouped for - * are used! */ - foreach(t,((Expr *)clause)->args) - { - contained_in_group_clause = 0; - foreach(l1,groupClause) - { - if (tlist_member(lfirst(t),lcons(((GroupClause *)lfirst(l1))->entry,NIL)) != - NULL) - { - contained_in_group_clause=1; - } - } - - /* If the use of the attribute is allowed (i.e. it is in the groupClause) - * we have to adjust the varnos and varattnos */ - if (contained_in_group_clause) - { - agg_list = - nconc(agg_list, - check_having_qual_for_aggs(lfirst(t), - subplanTargetList, groupClause)); - } - else - { - elog(ERROR,"You must group by the attribute used from outside!"); - return NIL; - } - } - return agg_list; - } + /* The first argument of ...->oper has also to be checked */ + { + List *tmp_ptr; + + foreach(tmp_ptr, ((SubLink *) ((SubPlan *) + ((Expr *) clause)->oper)->sublink)->oper) + { + agg_list = + nconc(agg_list, + check_having_qual_for_aggs((Node *) lfirst(((Expr *) + lfirst(tmp_ptr))->args), + subplanTargetList, groupClause)); + } + } + + /* + * All arguments to the Sublink node are attributes from outside + * used within the sublink. Here we have to check that only + * attributes that is grouped for are used! + */ + foreach(t, ((Expr *) clause)->args) + { + contained_in_group_clause = 0; + + foreach(l1, groupClause) + { + if (tlist_member(lfirst(t), lcons(((GroupClause *) lfirst(l1))->entry, NIL)) != + NULL) + contained_in_group_clause = 1; + } + + /* + * If the use of the attribute is allowed (i.e. it is in the + * groupClause) we have to adjust the varnos and varattnos + */ + if (contained_in_group_clause) + { + agg_list = + nconc(agg_list, + check_having_qual_for_aggs(lfirst(t), + subplanTargetList, groupClause)); + } + else + { + elog(ERROR, "You must group by the attribute used from outside!"); + return NIL; + } + } + return agg_list; + } else - { - /* - * Ooops! we can not handle that! - */ - elog(ERROR, "check_having_qual_for_aggs: Can not handle this having_qual! %d\n", - nodeTag(clause)); - return NIL; - } + { + + /* + * Ooops! we can not handle that! + */ + elog(ERROR, "check_having_qual_for_aggs: Can not handle this having_qual! %d\n", + nodeTag(clause)); + return NIL; + } } -/***S*H***/ /* End */ + + /***S*H***//* End */