]> granicus.if.org Git - postgresql/commitdiff
I started adding the Having Clause and it works quite fine for
authorBruce Momjian <bruce@momjian.us>
Mon, 30 Mar 1998 16:36:43 +0000 (16:36 +0000)
committerBruce Momjian <bruce@momjian.us>
Mon, 30 Mar 1998 16:36:43 +0000 (16:36 +0000)
sequential scans! (I think it will also work with hash, index, etc
but I did not check it out! I made some High level changes which
should work for all access methods, but maybe I'm wrong. Please
let me know.)

Now it is possible to make queries like:

select s.sname, max(p.pid), min(p.pid) from part p, supplier s
where s.sid=p.sid group by s.sname having max(pid)=6 and min(pid)=1
or avg(pid)=4;

Having does not work yet for queries that contain a subselect
statement in the Having clause, I'll try to fix this in the next
days.

If there are some bugs, please let me know, I'll start to read the
mailinglists now!

Now here is the patch against the original 6.3 version (no snapshot!!):

Stefan

src/backend/executor/execQual.c
src/backend/executor/nodeAgg.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/setrefs.c
src/backend/parser/analyze.c
src/backend/parser/gram.c
src/backend/parser/gram.y
src/backend/parser/parse_agg.c
src/backend/rewrite/rewriteHandler.c

index 55a12bd8317979ea74e0c7fc86e98fd8092625f2..f1ff8bbbb4cbe3dba47075e0e4755e880cd8c170 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.26 1998/02/26 04:31:13 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.27 1998/03/30 16:35:50 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -203,8 +203,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
 static Datum
 ExecEvalAggreg(Aggreg *agg, ExprContext *econtext, bool *isNull)
 {
-
-       *isNull = econtext->ecxt_nulls[agg->aggno];
+       *isNull = econtext->ecxt_nulls[agg->aggno];     
        return econtext->ecxt_values[agg->aggno];
 }
 
@@ -648,6 +647,8 @@ ExecEvalFuncArgs(FunctionCachePtr fcache,
                                                 econtext,
                                                 &argIsNull,
                                                 argIsDone);
+
+
                if (!(*argIsDone))
                {
                        Assert(i == 0);
@@ -1356,8 +1357,11 @@ ExecQual(List *qual, ExprContext *econtext)
         * ----------------
         */
        result = false;
+
        foreach(clause, qual)
        {
+        
+         
                result = ExecQualClause((Node *) lfirst(clause), econtext);
                if (result == true)
                        break;
index 848bd616bf03d0f19e9730bd0d40ac783d0d06a2..c2b77c6e050a28fadb72930b7ea0b4e2b7afcfdf 100644 (file)
@@ -29,6 +29,7 @@
 #include "storage/bufmgr.h"
 #include "utils/palloc.h"
 #include "utils/syscache.h"
+#include "optimizer/clauses.h"
 
 /*
  * AggFuncInfo -
@@ -109,10 +110,16 @@ ExecAgg(Agg *node)
                                isNull1 = FALSE,
                                isNull2 = FALSE;
 
+
+       /***S*H***/
+       do { 
+
+
        /* ---------------------
         *      get state info from node
         * ---------------------
         */
+
        aggstate = node->aggstate;
        if (aggstate->agg_done)
                return NULL;
@@ -229,6 +236,7 @@ ExecAgg(Agg *node)
                        }
                }
        }
+         
 
        /* ----------------
         *       for each tuple from the the outer plan, apply all the aggregates
@@ -477,11 +485,19 @@ ExecAgg(Agg *node)
         *      slot and return it.
         * ----------------
         */
+
+        /***S*H***/
+       }
+       while((ExecQual(fix_opids(node->plan.qual),econtext)!=true) && 
+             (node->plan.qual!=NULL));
+
+        
        ExecStoreTuple(oneTuple,
                                   aggstate->csstate.css_ScanTupleSlot,
                                   InvalidBuffer,
                                   false);
        econtext->ecxt_scantuple = aggstate->csstate.css_ScanTupleSlot;
+
        resultSlot = ExecProject(projInfo, &isDone);
 
        if (oneTuple)
index 824c0d29b35c8c7bd1f6ca69a6c880a02f3cdb2e..35c19d6c44f845ce274853fb20ff7ab99eddd7ca 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.23 1998/02/26 04:32:51 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.24 1998/03/30 16:36:04 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,6 +59,115 @@ make_groupPlan(List **tlist, bool tuplePerGroup,
  *
  *****************************************************************************/
 
+
+/***S*H***/ /* Anfang */
+
+static List *
+check_having_qual_for_aggs(Node *clause, List *subplanTargetList)
+{
+       List       *t;
+       List       *agg_list = NIL;
+
+       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.
+          *
+          */
+         ((Var *) clause)->varattno = subplanVar->resdom->resno;
+         return NIL;
+       }
+        /***S*H***/
+       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)
+               {
+                       agg_list = nconc(agg_list,
+                                          check_having_qual_for_aggs(lfirst(t), subplanTargetList));
+               }
+               return agg_list;
+       }
+       else if (IsA(clause, Aggreg))
+       {
+               return lcons(clause,
+                   check_having_qual_for_aggs(((Aggreg *) clause)->target, subplanTargetList));
+               
+       }
+       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)
+               {
+                       agg_list = nconc(agg_list,
+                                        check_having_qual_for_aggs(lfirst(t), subplanTargetList));
+               }
+               foreach(t, aref->reflowerindexpr)
+               {
+                       agg_list = nconc(agg_list,
+                                        check_having_qual_for_aggs(lfirst(t), subplanTargetList));
+               }
+               agg_list = nconc(agg_list,
+                                check_having_qual_for_aggs(aref->refexpr, subplanTargetList));
+               agg_list = nconc(agg_list,
+                                check_having_qual_for_aggs(aref->refassgnexpr, subplanTargetList));
+
+               return agg_list;
+       }
+       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)
+                       agg_list = nconc(agg_list,
+                                        check_having_qual_for_aggs(left, subplanTargetList));
+               if (right != (Node *) NULL)
+                       agg_list = nconc(agg_list,
+                                        check_having_qual_for_aggs(right, subplanTargetList));
+
+               return agg_list;
+       }
+       else if (IsA(clause, Param) ||IsA(clause, Const))
+       {
+               /* do nothing! */
+               return NIL;
+       }
+       else
+       {
+
+               /*
+                * Ooops! we can not handle that!
+                */
+               elog(ERROR, "check_having_qual_for_aggs: Can not handle this having_qual!\n");
+               return NIL;
+       }
+}
+/***S*H***/ /* Ende */
+
+
 Plan *
 planner(Query *parse)
 {
@@ -181,7 +290,22 @@ union_planner(Query *parse)
                 * the result tuple of the subplans.
                 */
                ((Agg *) result_plan)->aggs =
-                       set_agg_tlist_references((Agg *) result_plan);
+                       set_agg_tlist_references((Agg *) result_plan); 
+
+               /***S*H***/
+               if(parse->havingQual!=NULL) {
+                 List     *clause;
+
+                 /***S*H***/ /* set qpqual of having clause */
+                 ((Agg *) result_plan)->plan.qual=cnfify((Expr *)parse->havingQual,true);
+
+                 foreach(clause, ((Agg *) result_plan)->plan.qual)
+                   {
+                     ((Agg *) result_plan)->aggs = nconc(((Agg *) result_plan)->aggs,
+                        check_having_qual_for_aggs((Node *) lfirst(clause),
+                                      ((Agg *) result_plan)->plan.lefttree->targetlist));
+                   }
+               }
        }
 
        /*
@@ -429,3 +553,6 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
        /* success */
        return;
 }
+
+
+
index c82a711637ba177dbed9a6916b9894d128c9477f..de4bbf9519807ffa15b79f5adbf917aabef00447 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.19 1998/02/26 04:32:53 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.20 1998/03/30 16:36:14 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -839,6 +839,7 @@ replace_agg_clause(Node *clause, List *subplanTargetList)
        }
 }
 
+
 /*
  * del_agg_tlist_references
  *       Remove the Agg nodes from the target list
index 64ec5fa37d944489b00f871ed95cc7ae22df68e2..6dfdd8c26fe57b1a1b865f75d0189b460328c184 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.71 1998/02/26 04:33:26 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.72 1998/03/30 16:36:23 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -781,6 +781,10 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
        qry->targetList = transformTargetList(pstate, stmt->targetList);
 
        qry->qual = transformWhereClause(pstate, stmt->whereClause);
+
+        /***S*H***/
+       qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
+
        qry->hasSubLinks = pstate->p_hasSubLinks;
 
        qry->sortClause = transformSortClause(pstate,
index 9c4cca1a40f9fc887f0ec71234009fbacedcf324..298852387dd92951e981ae1fd2fc91163af3852a 100644 (file)
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/Attic/gram.c,v 2.4 1998/03/18 16:50:15 thomas Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/Attic/gram.c,v 2.5 1998/03/30 16:36:32 momjian Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -6700,7 +6700,7 @@ case 463:
 case 464:
 #line 2529 "gram.y"
 {
-                                       elog(NOTICE, "HAVING not yet supported; ignore clause");
+                                       /***S*H***/ /* elog(NOTICE, "HAVING not yet supported; ignore clause");*/
                                        yyval.node = yyvsp[0].node;
                                ;
     break;}
index e9808c9102757b821cbbda5b29a40289af5fc9f6..71812de58b43bd62d29016dcc62e59743528170c 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.7 1998/03/18 16:50:19 thomas Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.8 1998/03/30 16:36:35 momjian Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -2527,7 +2527,7 @@ groupby:  ColId
 
 having_clause:  HAVING a_expr
                                {
-                                       elog(NOTICE, "HAVING not yet supported; ignore clause");
+                                       /***S*H***/ /* elog(NOTICE, "HAVING not yet supported; ignore clause");*/
                                        $$ = $2;
                                }
                | /*EMPTY*/                                                             { $$ = NULL; }
index e7a88101960133ecfa0d87c67011857a357e6db0..083d4ee15dfd074ceef4f0807f27b6542628ac91 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.9 1998/02/26 04:33:28 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.10 1998/03/30 16:36:36 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -331,7 +331,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
        aggreg->target = lfirst(target);
        if (usenulls)
                aggreg->usenulls = true;
-
+       
        pstate->p_hasAggs = true;
 
        return aggreg;
index f3ccf54c23e48fba40b2755e6780dc09f7348833..5bb24720f8f59cdcd4276516e58eb6eee97717f4 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.14 1998/02/26 04:35:16 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.15 1998/03/30 16:36:43 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -195,7 +195,7 @@ FireRetrieveRulesAtQuery(Query *parsetree,
        if ((rt_entry_locks = relation->rd_rules) == NULL)
                return NIL;
 
-       locks = matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree);
+       locks = matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree);    
 
        /* find all retrieve instead */
        foreach(i, locks)
@@ -375,6 +375,7 @@ ProcessRetrieveQuery(Query *parsetree,
        List       *product_queries = NIL;
        int                     rt_index = 0;
 
+
        foreach(rt, rtable)
        {
                RangeTblEntry *rt_entry = lfirst(rt);
@@ -384,6 +385,8 @@ ProcessRetrieveQuery(Query *parsetree,
                rt_index++;
                rt_entry_relation = heap_openr(rt_entry->relname);
 
+
+
                if (rt_entry_relation->rd_rules != NULL)
                {
                        result =
@@ -414,6 +417,7 @@ ProcessRetrieveQuery(Query *parsetree,
                rt_entry_locks = rt_entry_relation->rd_rules;
                heap_close(rt_entry_relation);
 
+
                if (rt_entry_locks)
                {
                        locks =
@@ -683,7 +687,6 @@ static int  numQueryRewriteInvoked = 0;
 List *
 QueryRewrite(Query *parsetree)
 {
-
        QueryRewriteSubLink(parsetree->qual);
        return QueryRewriteOne(parsetree);
 }
@@ -780,6 +783,8 @@ deepRewriteQuery(Query *parsetree)
        bool            instead;
        List       *qual_products = NIL;
 
+
+
        if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX)
        {
                elog(ERROR, "query rewritten %d times, may contain cycles",