88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.123 2003/01/1702:01:16 tgl Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.124 2003/01/1703:25:03 tgl Exp $
1212 *
1313 * HISTORY
1414 * AUTHORDATEMAJOR EVENT
2020#include "postgres.h"
2121
2222#include "catalog/pg_language.h"
23- #include "catalog/pg_operator.h"
2423#include "catalog/pg_proc.h"
2524#include "catalog/pg_type.h"
2625#include "executor/executor.h"
2726#include "miscadmin.h"
2827#include "nodes/makefuncs.h"
2928#include "nodes/nodeFuncs.h"
3029#include "optimizer/clauses.h"
31- #include "optimizer/tlist.h"
3230#include "optimizer/var.h"
3331#include "parser/analyze.h"
34- #include "parser/parsetree.h"
3532#include "tcop/tcopprot.h"
3633#include "utils/acl.h"
3734#include "utils/builtins.h"
4542#define MAKEBOOLCONST (val ,isnull ) \
4643((Node *) makeConst(BOOLOID, 1, (Datum) (val), (isnull), true))
4744
48- typedef struct
49- {
50- Query * query ;
51- List * groupClauses ;
52- }check_subplans_for_ungrouped_vars_context ;
53-
5445typedef struct
5546{
5647int nargs ;
@@ -64,8 +55,6 @@ static bool pull_agg_clause_walker(Node *node, List **listptr);
6455static bool expression_returns_set_walker (Node * node ,void * context );
6556static bool contain_subplans_walker (Node * node ,void * context );
6657static bool pull_subplans_walker (Node * node ,List * * listptr );
67- static bool check_subplans_for_ungrouped_vars_walker (Node * node ,
68- check_subplans_for_ungrouped_vars_context * context );
6958static bool contain_mutable_functions_walker (Node * node ,void * context );
7059static bool contain_volatile_functions_walker (Node * node ,void * context );
7160static bool contain_nonstrict_functions_walker (Node * node ,void * context );
@@ -552,157 +541,6 @@ pull_subplans_walker(Node *node, List **listptr)
552541 (void * )listptr );
553542}
554543
555- /*
556- * check_subplans_for_ungrouped_vars
557- *Check for subplans that are being passed ungrouped variables as
558- *parameters; generate an error message if any are found.
559- *
560- * In most contexts, ungrouped variables will be detected by the parser (see
561- * parse_agg.c, check_ungrouped_columns()). But that routine currently does
562- * not check subplans, because the necessary info is not computed until the
563- * planner runs. So we do it here, after we have processed sublinks into
564- * subplans. This ought to be cleaned up someday.
565- *
566- * A deficiency in this scheme is that any outer reference var must be
567- * grouped by itself; we don't recognize groupable expressions within
568- * subselects.For example, consider
569- *SELECT
570- *(SELECT x FROM bar where y = (foo.a + foo.b))
571- *FROM foo
572- *GROUP BY a + b;
573- * This query will be rejected although it could be allowed.
574- */
575- void
576- check_subplans_for_ungrouped_vars (Query * query )
577- {
578- check_subplans_for_ungrouped_vars_context context ;
579- List * gl ;
580-
581- context .query = query ;
582-
583- /*
584- * Build a list of the acceptable GROUP BY expressions for use in the
585- * walker (to avoid repeated scans of the targetlist within the
586- * recursive routine).
587- */
588- context .groupClauses = NIL ;
589- foreach (gl ,query -> groupClause )
590- {
591- GroupClause * grpcl = lfirst (gl );
592- Node * expr ;
593-
594- expr = get_sortgroupclause_expr (grpcl ,query -> targetList );
595- context .groupClauses = lcons (expr ,context .groupClauses );
596- }
597-
598- /*
599- * Recursively scan the targetlist and the HAVING clause. WHERE and
600- * JOIN/ON conditions are not examined, since they are evaluated
601- * before grouping.
602- */
603- check_subplans_for_ungrouped_vars_walker ((Node * )query -> targetList ,
604- & context );
605- check_subplans_for_ungrouped_vars_walker (query -> havingQual ,
606- & context );
607-
608- freeList (context .groupClauses );
609- }
610-
611- static bool
612- check_subplans_for_ungrouped_vars_walker (Node * node ,
613- check_subplans_for_ungrouped_vars_context * context )
614- {
615- List * gl ;
616-
617- if (node == NULL )
618- return false;
619- if (IsA (node ,Const )||
620- IsA (node ,Param ))
621- return false;/* constants are always acceptable */
622-
623- /*
624- * If we find an aggregate function, do not recurse into its
625- * arguments. Subplans invoked within aggregate calls are allowed to
626- * receive ungrouped variables. (This test and the next one should
627- * match the logic in parse_agg.c's check_ungrouped_columns().)
628- */
629- if (IsA (node ,Aggref ))
630- return false;
631-
632- /*
633- * Check to see if subexpression as a whole matches any GROUP BY item.
634- * We need to do this at every recursion level so that we recognize
635- * GROUPed-BY expressions before reaching variables within them.
636- */
637- foreach (gl ,context -> groupClauses )
638- {
639- if (equal (node ,lfirst (gl )))
640- return false;/* acceptable, do not descend more */
641- }
642-
643- /*
644- * We can ignore Vars other than in subplan args lists, since the
645- * parser already checked 'em.
646- */
647- if (is_subplan (node ))
648- {
649- /*
650- * The args list of the subplan node represents attributes from
651- * outside passed into the sublink.
652- */
653- List * t ;
654-
655- foreach (t , ((SubPlan * )node )-> args )
656- {
657- Node * thisarg = lfirst (t );
658- Var * var ;
659- bool contained_in_group_clause ;
660-
661- /*
662- * We do not care about args that are not local variables;
663- * params or outer-level vars are not our responsibility to
664- * check. (The outer-level query passing them to us needs to
665- * worry, instead.)
666- */
667- if (!IsA (thisarg ,Var ))
668- continue ;
669- var = (Var * )thisarg ;
670- if (var -> varlevelsup > 0 )
671- continue ;
672-
673- /*
674- * Else, see if it is a grouping column.
675- */
676- contained_in_group_clause = false;
677- foreach (gl ,context -> groupClauses )
678- {
679- if (equal (thisarg ,lfirst (gl )))
680- {
681- contained_in_group_clause = true;
682- break ;
683- }
684- }
685-
686- if (!contained_in_group_clause )
687- {
688- /* Found an ungrouped argument. Complain. */
689- RangeTblEntry * rte ;
690- char * attname ;
691-
692- Assert (var -> varno > 0 &&
693- (int )var -> varno <=length (context -> query -> rtable ));
694- rte = rt_fetch (var -> varno ,context -> query -> rtable );
695- attname = get_rte_attribute_name (rte ,var -> varattno );
696- elog (ERROR ,"Sub-SELECT uses un-GROUPed attribute %s.%s from outer query" ,
697- rte -> eref -> aliasname ,attname );
698- }
699- }
700- }
701- return expression_tree_walker (node ,
702- check_subplans_for_ungrouped_vars_walker ,
703- (void * )context );
704- }
705-
706544
707545/*****************************************************************************
708546 *Check clauses for mutable functions