On Mon, Aug 02, 2010 at 11:50:00PM -0600, Josh Tolley wrote:
> In case anyone's interested, I've taken the CTE-based grouping sets
> patch from [1] and made it apply to 9.1, attached. I haven't yet
> done things like checked it for whitespace consistency, style
> conformity, or anything else, but (tuits permitting) hope to figure
> out how it works and get it closer to commitability in some upcoming
> commitfest.
> 
> I mention it here so that if someone else is working on it, we can
> avoid duplicated effort, and to see if a CTE-based grouping sets
> implementation is really the way we think we want to go.
> 
> [1]
> http://archives.postgresql.org/pgsql-hackers/2009-05/msg00700.php

I've added back one file in the patch enclosed here.  I'm still
getting compile fails from

CC="ccache gcc" ./configure     --prefix=$PG_PREFIX     --with-pgport=$PGPORT   
  --with-perl     --with-libxml     --enable-debug     --enable-cassert
make

Log from that also enclosed.

Cheers,
David.
-- 
David Fetter <da...@fetter.org> http://fetter.org/
Phone: +1 415 235 3778  AIM: dfetter666  Yahoo!: dfetter
Skype: davidfetter      XMPP: david.fet...@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
diff --git a/src/backend/parser/Makefile b/src/backend/parser/Makefile
index a8f4c07..fb248a6 100644
--- a/src/backend/parser/Makefile
+++ b/src/backend/parser/Makefile
@@ -15,7 +15,7 @@ override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
 OBJS= analyze.o gram.o keywords.o kwlookup.o parser.o \
       parse_agg.o parse_clause.o parse_coerce.o parse_cte.o parse_expr.o \
       parse_func.o parse_node.o parse_oper.o parse_param.o parse_relation.o \
-      parse_target.o parse_type.o parse_utilcmd.o scansup.o
+      parse_target.o parse_type.o parse_utilcmd.o scansup.o parse_gsets.o
 
 FLEXFLAGS = -CF
 
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 6b99a10..1b579a8 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -34,6 +34,7 @@
 #include "parser/parse_clause.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_cte.h"
+#include "parser/parse_gsets.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_param.h"
 #include "parser/parse_relation.h"
@@ -150,6 +151,163 @@ parse_sub_analyze(Node *parseTree, ParseState 
*parentParseState,
 }
 
 /*
+ * process GROUPING SETS
+ */
+static SelectStmt *
+makeSelectStmt(List *targetList, List *fromClause)
+{
+       SelectStmt *n = makeNode(SelectStmt);
+       n->distinctClause = NULL;
+       n->intoClause = NULL;
+       n->targetList = targetList;
+       n->fromClause = fromClause;
+       n->whereClause = NULL;
+       n->groupClause = NULL;
+       n->havingClause = NULL;
+       n->windowClause = NIL;
+       n->withClause = NULL;
+       n->valuesLists = NIL;
+       n->sortClause = NIL;
+       n->limitOffset = NULL;
+       n->limitCount = NULL;
+       n->lockingClause = NIL;
+       n->op = SETOP_NONE;
+       n->all = false;
+       n->larg = NULL;
+       n->rarg = NULL;
+       return n;
+}
+
+static List *
+makeStarTargetList(void)
+{
+       ResTarget *rt = makeNode(ResTarget);
+       
+       rt->name = NULL;
+       rt->indirection = NIL;
+       rt->val = (Node *) makeNode(ColumnRef);
+       ((ColumnRef *) rt->val)->fields = list_make1(makeNode(A_Star));
+       rt->location = -1;
+
+       return list_make1(rt);
+}
+ 
+static SelectStmt *
+transformGroupingSets(ParseState *pstate, SelectStmt *stmt)
+{
+       if (stmt->groupClause && IsA(stmt->groupClause, GroupByClause))
+       {
+               GroupingSetsSpec *gss = (GroupingSetsSpec *) 
expandGroupingSets(pstate, 
+                                               (List *)((GroupByClause 
*)stmt->groupClause)->fields);
+       
+               if (pstate->p_hasGroupingSets)
+               {
+                       CommonTableExpr *cte = makeNode(CommonTableExpr);
+                       SelectStmt  *cteedstmt;
+                       int     ngroupingsets = list_length(gss->set_list) + 
(gss->has_empty_set ? 1 : 0);
+                       bool    all = ((GroupByClause *) 
stmt->groupClause)->all;
+               
+                       cteedstmt = makeSelectStmt(NIL, NIL);
+                       cteedstmt->intoClause = stmt->intoClause;
+                       cteedstmt->sortClause = stmt->sortClause;
+                       cteedstmt->limitOffset = stmt->limitOffset;
+                       cteedstmt->limitCount = stmt->limitCount;
+                       cteedstmt->lockingClause = stmt->lockingClause;
+               
+                       cte->ctename = "**g**";
+                       cte->ctequery = (Node *) stmt;
+                       cte->location = -1;
+               
+                       cteedstmt->withClause = makeNode(WithClause);
+                       cteedstmt->withClause->ctes = list_make1(cte);
+                       cteedstmt->withClause->recursive = false;
+                       cteedstmt->withClause->location = -1;
+               
+                       /* when is more than one grouping set, then we should 
generate setop node */
+                       if (ngroupingsets > 1)
+                       {
+                               /* add quuery under union all for every 
grouping set */
+                               SelectStmt      *larg = NULL;
+                               SelectStmt      *rarg;
+                               ListCell    *lc;
+                       
+                               foreach(lc, gss->set_list)
+                               {
+                                       List    *groupClause;
+                               
+                                       Assert(IsA(lfirst(lc), List));
+                                       groupClause = (List *) lfirst(lc);
+                               
+                                       if (larg == NULL)
+                                       {
+                                               larg = 
makeSelectStmt(copyObject(stmt->targetList),
+                                                                       
list_make1(makeRangeVar(NULL, "**g**", -1)));
+                                               larg->groupClause = (Node *) 
groupClause;
+                                               larg->havingClause = 
copyObject(stmt->havingClause);
+                                       }
+                                       else
+                                       {
+                                               SelectStmt      *setop = 
makeSelectStmt(NIL, NIL);
+                                       
+                                               rarg = 
makeSelectStmt(copyObject(stmt->targetList),
+                                                                       
list_make1(makeRangeVar(NULL, "**g**", -1)));
+                                               rarg->groupClause = (Node *) 
groupClause;
+                                               rarg->havingClause = 
copyObject(stmt->havingClause);
+                                       
+                                               setop->op = SETOP_UNION;
+                                               setop->larg = larg;
+                                               setop->rarg = rarg;
+                                               setop->all = all;
+                                       
+                                               larg = setop;
+                                       }
+                               }
+                               if (gss->has_empty_set)
+                               {
+                                       SelectStmt      *setop = 
makeSelectStmt(NIL, NIL);
+                               
+                                       rarg = 
makeSelectStmt(copyObject(stmt->targetList),
+                                                               
list_make1(makeRangeVar(NULL, "**g**", -1)));
+                                       rarg->havingClause = 
copyObject(stmt->havingClause);
+                               
+                                       setop->op = SETOP_UNION;
+                                       setop->larg = larg;
+                                       setop->rarg = rarg;
+                                       setop->all = all;
+                                       
+                                       larg = setop;
+                               }
+                               /* merge larg to result */
+                               cteedstmt->op = larg->op;
+                               cteedstmt->larg = larg->larg;
+                               cteedstmt->rarg = larg->rarg;
+                               cteedstmt->all = larg->all;
+                       }
+                       else
+                       {
+                               /* there isn't used setop node */
+                               cteedstmt->targetList = 
copyObject(stmt->targetList);
+                               cteedstmt->fromClause = 
list_make1(makeRangeVar(NULL, "**g**", -1));
+                       }
+               
+                       ((SelectStmt *)cte->ctequery)->targetList = 
makeStarTargetList();
+                       ((SelectStmt *)cte->ctequery)->groupClause = NULL;
+                       ((SelectStmt *)cte->ctequery)->sortClause = NIL;
+                       ((SelectStmt *)cte->ctequery)->limitOffset = 
stmt->limitOffset;
+                       ((SelectStmt *)cte->ctequery)->limitCount = 
stmt->limitCount;
+                       ((SelectStmt *)cte->ctequery)->lockingClause = 
stmt->lockingClause;
+               
+                       return cteedstmt;
+               }
+               else
+                       /* trim GroupByClause to groupByClause */
+                       stmt->groupClause = (Node *)((GroupByClause 
*)stmt->groupClause)->fields;
+       }
+
+       return stmt;
+}
+
+/*
  * transformStmt -
  *       transform a Parse tree into a Query tree.
  */
@@ -179,6 +337,8 @@ transformStmt(ParseState *pstate, Node *parseTree)
                        {
                                SelectStmt *n = (SelectStmt *) parseTree;
 
+                               n = transformGroupingSets(pstate, n);
+
                                if (n->valuesLists)
                                        result = transformValuesClause(pstate, 
n);
                                else if (n->op == SETOP_NONE)
@@ -827,7 +987,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
                                                                                
  false /* allow SQL92 rules */ );
 
        qry->groupClause = transformGroupClause(pstate,
-                                                                               
        stmt->groupClause,
+                                                                               
        (List *) stmt->groupClause,
                                                                                
        &qry->targetList,
                                                                                
        qry->sortClause,
                                                                                
        false /* allow SQL92 rules */ );
@@ -924,7 +1084,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
        Assert(stmt->targetList == NIL);
        Assert(stmt->fromClause == NIL);
        Assert(stmt->whereClause == NULL);
-       Assert(stmt->groupClause == NIL);
+       Assert(stmt->groupClause == NULL);
        Assert(stmt->havingClause == NULL);
        Assert(stmt->windowClause == NIL);
        Assert(stmt->op == SETOP_NONE);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 1722036..0c9eff1 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -111,6 +111,8 @@ static Node *makeBitStringConst(char *str, int location);
 static Node *makeNullAConst(int location);
 static Node *makeAConst(Value *v, int location);
 static Node *makeBoolAConst(bool state, int location);
+static Node *makeGroupingSetsFunc(GroupingSetsFuncIdentity identity, Node 
*expr, 
+                                                       List *expr_list, int 
location);
 static FuncCall *makeOverlaps(List *largs, List *rargs,
                                                          int location, 
core_yyscan_t yyscanner);
 static void check_qualified_name(List *names, core_yyscan_t yyscanner);
@@ -292,7 +294,7 @@ static TypeName *TableFuncTypeName(List *columns);
                                target_list insert_column_list set_target_list
                                set_clause_list set_clause multiple_set_clause
                                ctext_expr_list ctext_row def_list indirection 
opt_indirection
-                               reloption_list group_clause TriggerFuncArgs 
select_limit
+                               reloption_list TriggerFuncArgs select_limit
                                opt_select_limit opclass_item_list 
opclass_drop_list
                                opt_opfamily transaction_mode_list_or_empty
                                TableFuncElementList opt_type_modifiers
@@ -437,6 +439,11 @@ static TypeName *TableFuncTypeName(List *columns);
                                opt_frame_clause frame_extent frame_bound
 %type <str>            opt_existing_window_name
 
+%type <node>   grouping_element empty_grouping_set grouping_sets_spec
+                               group_clause
+%type <list>   grouping_element_list
+%type <boolean>        opt_grouping_set_quantifier
+  
 
 /*
  * Non-keyword token types.  These are hard-wired into the "flex" lexer.
@@ -472,7 +479,7 @@ static TypeName *TableFuncTypeName(List *columns);
        COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS
        CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
        CREATEROLE CREATEUSER CROSS CSV CURRENT_P
-       CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA
+       CUBE CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA
        CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
 
        DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
@@ -485,7 +492,7 @@ static TypeName *TableFuncTypeName(List *columns);
        FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORWARD
        FREEZE FROM FULL FUNCTION FUNCTIONS
 
-       GLOBAL GRANT GRANTED GREATEST GROUP_P
+       GLOBAL GRANT GRANTED GREATEST GROUP_P GROUPING GROUPING_ID
 
        HANDLER HAVING HEADER_P HOLD HOUR_P
 
@@ -519,10 +526,10 @@ static TypeName *TableFuncTypeName(List *columns);
 
        RANGE READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REINDEX
        RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART
-       RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
+       RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP ROW ROWS 
RULE
 
        SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE 
SEQUENCES
-       SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF SHARE
+       SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF SETS SHARE
        SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE_P START STATEMENT
        STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
        SYMMETRIC SYSID SYSTEM_P
@@ -7797,9 +7804,55 @@ first_or_next: FIRST_P                                   
                        { $$ = 0; }
 
 
 group_clause:
-                       GROUP_P BY expr_list                                    
{ $$ = $3; }
-                       | /*EMPTY*/                                             
                { $$ = NIL; }
-               ;
+                       GROUP_P BY opt_grouping_set_quantifier 
grouping_element_list            
+                                       { 
+                                               GroupByClause *clause = 
makeNode(GroupByClause);
+                                               clause->all = $3;
+                                               clause->fields = $4;
+                                               clause->location = @1;
+                                               $$ = (Node *) clause; 
+                                       }
+                       | /*EMPTY*/
+                                       {
+                                               $$ = NULL; 
+                                       }
+               ;
+  
+grouping_sets_spec:
+                       GROUPING SETS '(' grouping_element_list ')'
+                               {
+                                       /* We cannot identify and drop empty 
sets yet. */
+                                       GroupingSetsSpec *gss = 
makeNode(GroupingSetsSpec);
+                                       gss->set_list = $4;
+                                       gss->has_empty_set = false;
+                                       gss->location = @1;
+                                       $$ = (Node *) gss;
+                               }
+               ;
+               
+grouping_element_list:
+                       grouping_element                                        
                { $$ = list_make1($1); }
+                       | grouping_element_list ',' grouping_element            
        { $$ = lappend($1, $3); }
+               ;
+               
+grouping_element:
+                       a_expr                                                  
{ $$ = $1; }
+                       | grouping_sets_spec                                    
{ $$ = $1; }
+                       | empty_grouping_set                                    
{ $$ = $1; }
+               ;
+  
+empty_grouping_set:
+                       '(' ')'
+                               {
+                                       $$ = makeNode(EmptySet);
+                               }
+               ;
+  
+opt_grouping_set_quantifier:
+                       ALL                     { $$ = true; }
+                       | DISTINCT              { $$ = false; }
+                       | /*EMPTY*/             { $$ = true; }
+               ;
 
 having_clause:
                        HAVING a_expr                                           
        { $$ = $2; }
@@ -9326,7 +9379,30 @@ c_expr:          columnref                               
                                { $$ = $1; }
                                        r->location = @1;
                                        $$ = (Node *)r;
                                }
-               ;
+                       | GROUPING '(' a_expr ')'
+                               {
+                                       $$ = 
makeGroupingSetsFunc(FUNCTION_GROUPING, $3, NIL, @1);
+                               }
+                       | GROUPING_ID '(' expr_list ')'
+                               {
+                                       $$ = 
makeGroupingSetsFunc(FUNCTION_GROUPING_ID, NULL, $3, @1);
+                               }
+                       | CUBE '(' expr_list ')'
+                               {
+                                       /* 
+                                        * Cube should be used in two different 
contexts. First,
+                                        * as part of Grouping Sets 
specification. Second, as
+                                        * normal UDF function from contrib 
cube module. When isnot 
+                                        * grouping sets context, then node is 
transformated to 
+                                        * FuncCall node later.
+                                        */
+                                        $$ = 
makeGroupingSetsFunc(FUNCTION_CUBE, NULL, $3, @1);
+                               }
+                       | ROLLUP '(' expr_list ')'
+                               {
+                                       $$ = 
makeGroupingSetsFunc(FUNCTION_ROLLUP, NULL, $3, @1);
+                               }
+               ;
 
 /*
  * func_expr is split out from c_expr just so that we have a classification
@@ -11043,6 +11119,7 @@ unreserved_keyword:
                        | SERVER
                        | SESSION
                        | SET
+                       | SETS
                        | SHARE
                        | SHOW
                        | SIMPLE
@@ -11120,6 +11197,7 @@ col_name_keyword:
                        | EXTRACT
                        | FLOAT_P
                        | GREATEST
+            | GROUPING_ID
                        | INOUT
                        | INT_P
                        | INTEGER
@@ -11214,6 +11292,7 @@ reserved_keyword:
                        | COLUMN
                        | CONSTRAINT
                        | CREATE
+            | CUBE
                        | CURRENT_CATALOG
                        | CURRENT_DATE
                        | CURRENT_ROLE
@@ -11235,6 +11314,7 @@ reserved_keyword:
                        | FROM
                        | GRANT
                        | GROUP_P
+            | GROUPING
                        | HAVING
                        | IN_P
                        | INITIALLY
@@ -11256,6 +11336,7 @@ reserved_keyword:
                        | PRIMARY
                        | REFERENCES
                        | RETURNING
+            | ROLLUP
                        | SELECT
                        | SESSION_USER
                        | SOME
@@ -11761,6 +11842,18 @@ makeXmlExpr(XmlExprOp op, char *name, List 
*named_args, List *args,
        return (Node *) x;
 }
 
+static Node *
+makeGroupingSetsFunc(GroupingSetsFuncIdentity identity, Node *expr, List 
*expr_list, int location)
+{
+       GroupingSetsFunc *gsfunc = makeNode(GroupingSetsFunc);
+       
+       gsfunc->identity = identity;
+       gsfunc->expr = expr;
+       gsfunc->expr_list = expr_list;
+       gsfunc->location = location;
+       return (Node *) gsfunc;
+}
+
 /* parser_init()
  * Initialize to parse one query string
  */
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 0a69bde..3aeea45 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -33,12 +33,20 @@ typedef struct
        bool            have_non_var_grouping;
        int                     sublevels_up;
 } check_ungrouped_columns_context;
+  
+typedef struct
+{
+       ParseState *pstate;
+       List            *groupClause;
+} transform_ungrouped_target_context;
 
 static void check_ungrouped_columns(Node *node, ParseState *pstate,
                                                List *groupClauses, bool 
have_non_var_grouping);
 static bool check_ungrouped_columns_walker(Node *node,
                                                           
check_ungrouped_columns_context *context);
 
+static Node * transform_ungrouped_target(Node *node, ParseState *pstate,
+                                                       List *groupClauses);
 
 /*
  * transformAggregateCall -
@@ -405,7 +413,16 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
         * WINDOW clauses.      For that matter, it's also going to examine the
         * grouping expressions themselves --- but they'll all pass the test ...
         */
-       clause = (Node *) qry->targetList;
+       if (pstate->parentParseState && 
pstate->parentParseState->p_hasGroupingSets)
+       {
+               clause = (Node *) transform_ungrouped_target((Node *) 
qry->targetList, 
+                                                                               
    pstate, 
+                                                                               
    groupClauses);
+               /* HACK!!! - move to transform part*/
+               qry->targetList = clause;
+       }
+       else
+               clause = (Node *) qry->targetList;
        if (hasJoinRTEs)
                clause = flatten_join_alias_vars(root, clause);
        check_ungrouped_columns(clause, pstate,
@@ -514,6 +531,83 @@ parseCheckWindowFuncs(ParseState *pstate, Query *qry)
 }
 
 /*
+ * transform_ungrouped_cols_mutator -
+ *   All non aggregates non constatnt columns are replaced by NULL,
+ *   grouping and grouping_id functions are replaced by constatnts.
+ */
+static Node *
+transform_ungrouped_target_mutator(Node *node,
+                                            transform_ungrouped_target_context 
*context)
+{
+       if (node == NULL)
+               return NULL;
+       if (IsA(node, Aggref))
+               return node;
+
+       if (IsA(node, GroupingSetsFunc))
+       {
+               GroupingSetsFunc *gsf = (GroupingSetsFunc *) node;
+               int     result = 0;
+               
+               if (gsf->identity == FUNCTION_GROUPING)
+               {
+                       result = list_member(context->groupClause, gsf->expr) ? 
0 : 1;
+                       return (Node *) make_const(context->pstate, 
makeInteger(result), gsf->location);
+               }
+               else if (gsf->identity == FUNCTION_GROUPING_ID)
+               {
+                       ListCell        *el;
+                       
+                       foreach(el, gsf->expr_list)
+                       {
+                               result = result << 1;
+                               if (!list_member(context->groupClause, 
lfirst(el)))
+                                       result = result | 0x01;
+                       }
+                       return (Node *) make_const(context->pstate, 
makeInteger(result), gsf->location);
+               }
+               else /* replace Cube and Rollup by FuncCall node */
+               {
+                       /* ToDo: Support cube function */
+               }
+       }
+       
+       if (IsA(node, Var))
+       {
+               Var *var = (Var *) node;
+
+               if (list_member(context->groupClause, node))
+                       return node;
+               else
+                       return (Node *) makeNullConst(var->vartype, 
var->vartypmod);
+       }
+       else if (IsA(node, FuncExpr))
+       {
+               FuncExpr *fexpr = (FuncExpr *) node;
+               
+               if (list_member(context->groupClause, node))
+                       return node;
+               else
+                       return (Node *) makeNullConst(fexpr->funcresulttype, 
-1);
+       }
+       
+       return expression_tree_mutator(node, 
+                                           transform_ungrouped_target_mutator, 
context);
+}
+
+static Node *
+transform_ungrouped_target(Node *node, ParseState *pstate,
+                                                       List *groupClauses)
+{
+       transform_ungrouped_target_context context;
+       
+       context.pstate = pstate;
+       context.groupClause = groupClauses;
+       
+       return transform_ungrouped_target_mutator(node, &context);
+}
+
+/*
  * check_ungrouped_columns -
  *       Scan the given expression tree for ungrouped variables (variables
  *       that are not listed in the groupClauses list and are not within
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 5e60374..609be1d 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -284,6 +284,25 @@ transformExpr(ParseState *pstate, Node *expr)
                case T_BooleanTest:
                        result = transformBooleanTest(pstate, (BooleanTest *) 
expr);
                        break;
+               
+               case T_GroupingSetsFunc:
+                       {
+                               GroupingSetsFunc *gsf = (GroupingSetsFunc *) 
expr;
+                               ListCell        *lc;
+                               List            *expr_list = NIL;
+                               
+                               gsf->expr = (Node *) transformExpr(pstate, 
(Node *) gsf->expr);
+ 
+                               foreach(lc, gsf->expr_list)
+                               {
+                                       expr_list = lappend(expr_list, 
transformExpr(pstate,
+                                                                               
         (Node *) lfirst(lc)));
+                               }
+                               gsf->expr_list = expr_list;
+                               result = expr;
+                               break;
+                       }
+  
 
                case T_CurrentOfExpr:
                        result = transformCurrentOfExpr(pstate, (CurrentOfExpr 
*) expr);
@@ -320,6 +339,7 @@ transformExpr(ParseState *pstate, Node *expr)
                case T_CoerceToDomain:
                case T_CoerceToDomainValue:
                case T_SetToDefault:
+        case T_EmptySet:
                        {
                                result = (Node *) expr;
                                break;
diff --git a/src/backend/parser/parse_target.c 
b/src/backend/parser/parse_target.c
index e542dc0..1a3e969 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1586,6 +1586,22 @@ FigureColnameInternal(Node *node, char **name)
                case T_XmlSerialize:
                        *name = "xmlserialize";
                        return 2;
+               case T_GroupingSetsFunc:
+                       switch (((GroupingSetsFunc *) node)->identity)
+                       {
+                               case FUNCTION_GROUPING:
+                                       *name = "grouping";
+                                       return 2;
+                               case FUNCTION_GROUPING_ID:
+                                       *name = "grouping_id";
+                                       return 2;
+                               case FUNCTION_CUBE:             /* by compiler 
quite */
+                               case FUNCTION_ROLLUP:
+                                       /* nothing */
+                                       break;
+                       }
+                       break;
+                       
                default:
                        break;
        }
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index a5f5df5..836e38d 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -385,6 +385,10 @@ typedef enum NodeTag
        T_XmlSerialize,
        T_WithClause,
        T_CommonTableExpr,
+       T_GroupingSetsFunc,
+       T_GroupingSetsSpec,
+       T_EmptySet,
+       T_GroupByClause,
 
        /*
         * TAGS FOR RANDOM OTHER STUFF
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index fec8d3c..904cb4a 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -378,6 +378,33 @@ typedef struct SortBy
 } SortBy;
 
 /*
+ * GroupingSetsSpec - for GROUP BY GROUPING SETS clause
+ */
+typedef struct GroupingSetsSpec
+{
+       NodeTag         type;
+       List        *set_list;
+       bool            has_empty_set; /* true when grouping sets contains 
empty set */
+       int                     location;
+} GroupingSetsSpec;
+
+typedef struct EmptySet
+{
+       NodeTag         type;
+} EmptySet;
+
+/*
+ * GroupByClause for GROUP BY clause
+ */
+typedef struct GroupByClause
+{
+       NodeTag         type;
+       bool    all;
+       List            *fields;
+       int                     location;
+} GroupByClause;
+
+/*
  * WindowDef - raw representation of WINDOW and OVER clauses
  *
  * For entries in a WINDOW list, "name" is the window name being defined.
@@ -431,6 +458,26 @@ typedef struct WindowDef
         FRAMEOPTION_END_CURRENT_ROW)
 
 /*
+ * GroupingSetsFunc - parser node for Grouping, Grouping_id, Cube and Rollup 
quasy functions
+ */
+typedef enum GroupingSetsFuncIdentity
+{
+       FUNCTION_GROUPING,
+       FUNCTION_GROUPING_ID,
+       FUNCTION_CUBE,
+       FUNCTION_ROLLUP
+} GroupingSetsFuncIdentity;
+
+typedef struct GroupingSetsFunc
+{
+       NodeTag         type;
+       GroupingSetsFuncIdentity        identity;
+       Node                    *expr;
+       List                    *expr_list;
+       int             location;
+} GroupingSetsFunc;
+
+/*
  * RangeSubselect - subquery appearing in a FROM clause
  */
 typedef struct RangeSubselect
@@ -956,7 +1003,7 @@ typedef struct SelectStmt
        List       *targetList;         /* the target list (of ResTarget) */
        List       *fromClause;         /* the FROM clause */
        Node       *whereClause;        /* WHERE qualification */
-       List       *groupClause;        /* GROUP BY clauses */
+       Node       *groupClause;        /* GROUP BY clauses */
        Node       *havingClause;       /* HAVING conditional-expression */
        List       *windowClause;       /* WINDOW window_name AS (...), ... */
        WithClause *withClause;         /* WITH clause */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 49d4b6c..d0dcfe7 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -99,6 +99,7 @@ PG_KEYWORD("createrole", CREATEROLE, UNRESERVED_KEYWORD)
 PG_KEYWORD("createuser", CREATEUSER, UNRESERVED_KEYWORD)
 PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD)
 PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD)
+PG_KEYWORD("cube", CUBE, RESERVED_KEYWORD)
 PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD)
 PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD)
 PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD)
@@ -171,6 +172,8 @@ PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD)
 PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD)
 PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD)
 PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD)
+PG_KEYWORD("grouping", GROUPING, RESERVED_KEYWORD)
+PG_KEYWORD("grouping_id", GROUPING_ID, COL_NAME_KEYWORD)
 PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD)
 PG_KEYWORD("having", HAVING, RESERVED_KEYWORD)
 PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD)
@@ -318,6 +321,7 @@ PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD)
 PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD)
 PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD)
 PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD)
+PG_KEYWORD("rollup", ROLLUP, RESERVED_KEYWORD)
 PG_KEYWORD("row", ROW, COL_NAME_KEYWORD)
 PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD)
 PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD)
@@ -336,6 +340,7 @@ PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD)
 PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD)
 PG_KEYWORD("set", SET, UNRESERVED_KEYWORD)
 PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD)
+PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD)
 PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD)
 PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD)
 PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD)
diff --git a/src/include/parser/parse_gsets.h b/src/include/parser/parse_gsets.h
new file mode 100644
index 0000000..98a9161
--- /dev/null
+++ b/src/include/parser/parse_gsets.h
@@ -0,0 +1,12 @@
+#include "parser/parse_node.h"
+#include "nodes/pg_list.h"
+
+#ifndef PARSE_GETS_H
+#define PARSE_GETS_H
+
+Node *expandGroupingSets(ParseState *pstate, List *grouplist);
+List *transformGroupingSetsSpec(ParseState *pstate, List *groupClause,
+                                                               List 
**GroupClauses, List **targetLists,
+                                                               List 
**targetList, List *sortClause);
+
+#endif         /* PARSE_GETS_H */
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 1c1383b..f2b80bd 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -107,6 +107,7 @@ struct ParseState
        bool            p_is_update;
        bool            p_locked_from_parent;
        Relation        p_target_relation;
+    bool        p_hasGroupingSets;
        RangeTblEntry *p_target_rangetblentry;
 
        /*
make -C src all
make[1]: Entering directory `/home/shackle/pggit/postgresql/src'
make -C port all
make[2]: Entering directory `/home/shackle/pggit/postgresql/src/port'
echo "#define PGBINDIR \"/home/shackle/tip/bin\"" >pg_config_paths.h
echo "#define PGSHAREDIR \"/home/shackle/tip/share/postgresql\"" 
>>pg_config_paths.h
echo "#define SYSCONFDIR \"/home/shackle/tip/etc/postgresql\"" 
>>pg_config_paths.h
echo "#define INCLUDEDIR \"/home/shackle/tip/include\"" >>pg_config_paths.h
echo "#define PKGINCLUDEDIR \"/home/shackle/tip/include/postgresql\"" 
>>pg_config_paths.h
echo "#define INCLUDEDIRSERVER \"/home/shackle/tip/include/postgresql/server\"" 
>>pg_config_paths.h
echo "#define LIBDIR \"/home/shackle/tip/lib\"" >>pg_config_paths.h
echo "#define PKGLIBDIR \"/home/shackle/tip/lib/postgresql\"" 
>>pg_config_paths.h
echo "#define LOCALEDIR \"/home/shackle/tip/share/locale\"" >>pg_config_paths.h
echo "#define DOCDIR \"/home/shackle/tip/share/doc//postgresql\"" 
>>pg_config_paths.h
echo "#define HTMLDIR \"/home/shackle/tip/share/doc//postgresql\"" 
>>pg_config_paths.h
echo "#define MANDIR \"/home/shackle/tip/share/man\"" >>pg_config_paths.h
ccache gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith 
-Wdeclaration-after-statement -Wendif-labels -fno-strict-aliasing -fwrapv -g 
-I../../src/port -DFRONTEND -I../../src/include -D_GNU_SOURCE 
-I/usr/include/libxml2   -c -o path.o path.c
ar crs libpgport.a strlcat.o strlcpy.o chklocale.o dirmod.o exec.o noblock.o 
path.o pgsleep.o pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o
ccache gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith 
-Wdeclaration-after-statement -Wendif-labels -fno-strict-aliasing -fwrapv -g  
-I../../src/port  -I../../src/include -D_GNU_SOURCE -I/usr/include/libxml2  -c 
path.c -o path_srv.o
ar crs libpgport_srv.a strlcat_srv.o strlcpy_srv.o chklocale_srv.o dirmod_srv.o 
exec_srv.o noblock_srv.o path_srv.o pgsleep_srv.o pgstrcasecmp_srv.o 
qsort_srv.o qsort_arg_srv.o sprompt_srv.o thread_srv.o
make[2]: Leaving directory `/home/shackle/pggit/postgresql/src/port'
make -C timezone all
make[2]: Entering directory `/home/shackle/pggit/postgresql/src/timezone'
make -C ../../src/port all
make[3]: Entering directory `/home/shackle/pggit/postgresql/src/port'
make[3]: Nothing to be done for `all'.
make[3]: Leaving directory `/home/shackle/pggit/postgresql/src/port'
make[2]: Leaving directory `/home/shackle/pggit/postgresql/src/timezone'
make -C backend all
make[2]: Entering directory `/home/shackle/pggit/postgresql/src/backend'
make -C ../../src/port all
make[3]: Entering directory `/home/shackle/pggit/postgresql/src/port'
make[3]: Nothing to be done for `all'.
make[3]: Leaving directory `/home/shackle/pggit/postgresql/src/port'
make -C catalog schemapg.h
make[3]: Entering directory `/home/shackle/pggit/postgresql/src/backend/catalog'
make[3]: `schemapg.h' is up to date.
make[3]: Leaving directory `/home/shackle/pggit/postgresql/src/backend/catalog'
make -C parser gram.h
make[3]: Entering directory `/home/shackle/pggit/postgresql/src/backend/parser'
/usr/bin/bison -d  -o gram.c gram.y
make[3]: Leaving directory `/home/shackle/pggit/postgresql/src/backend/parser'
prereqdir=`cd parser/ >/dev/null && pwd` && \
          cd ../../src/include/parser/ && rm -f gram.h && \
          ln -s "$prereqdir/gram.h" .
make -C access all
make[3]: Entering directory `/home/shackle/pggit/postgresql/src/backend/access'
make -C common all
make[4]: Entering directory 
`/home/shackle/pggit/postgresql/src/backend/access/common'
make[4]: Nothing to be done for `all'.
make[4]: Leaving directory 
`/home/shackle/pggit/postgresql/src/backend/access/common'
make -C gist all
make[4]: Entering directory 
`/home/shackle/pggit/postgresql/src/backend/access/gist'
make[4]: Nothing to be done for `all'.
make[4]: Leaving directory 
`/home/shackle/pggit/postgresql/src/backend/access/gist'
make -C hash all
make[4]: Entering directory 
`/home/shackle/pggit/postgresql/src/backend/access/hash'
make[4]: Nothing to be done for `all'.
make[4]: Leaving directory 
`/home/shackle/pggit/postgresql/src/backend/access/hash'
make -C heap all
make[4]: Entering directory 
`/home/shackle/pggit/postgresql/src/backend/access/heap'
make[4]: Nothing to be done for `all'.
make[4]: Leaving directory 
`/home/shackle/pggit/postgresql/src/backend/access/heap'
make -C index all
make[4]: Entering directory 
`/home/shackle/pggit/postgresql/src/backend/access/index'
make[4]: Nothing to be done for `all'.
make[4]: Leaving directory 
`/home/shackle/pggit/postgresql/src/backend/access/index'
make -C nbtree all
make[4]: Entering directory 
`/home/shackle/pggit/postgresql/src/backend/access/nbtree'
make[4]: Nothing to be done for `all'.
make[4]: Leaving directory 
`/home/shackle/pggit/postgresql/src/backend/access/nbtree'
make -C transam all
make[4]: Entering directory 
`/home/shackle/pggit/postgresql/src/backend/access/transam'
make[4]: Nothing to be done for `all'.
make[4]: Leaving directory 
`/home/shackle/pggit/postgresql/src/backend/access/transam'
make -C gin all
make[4]: Entering directory 
`/home/shackle/pggit/postgresql/src/backend/access/gin'
make[4]: Nothing to be done for `all'.
make[4]: Leaving directory 
`/home/shackle/pggit/postgresql/src/backend/access/gin'
make[3]: Leaving directory `/home/shackle/pggit/postgresql/src/backend/access'
make -C bootstrap all
make[3]: Entering directory 
`/home/shackle/pggit/postgresql/src/backend/bootstrap'
make[3]: Nothing to be done for `all'.
make[3]: Leaving directory 
`/home/shackle/pggit/postgresql/src/backend/bootstrap'
make -C catalog all
make[3]: Entering directory `/home/shackle/pggit/postgresql/src/backend/catalog'
make[3]: Nothing to be done for `all'.
make[3]: Leaving directory `/home/shackle/pggit/postgresql/src/backend/catalog'
make -C parser all
make[3]: Entering directory `/home/shackle/pggit/postgresql/src/backend/parser'
ccache gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith 
-Wdeclaration-after-statement -Wendif-labels -fno-strict-aliasing -fwrapv -g 
-I. -I. -I../../../src/include -D_GNU_SOURCE -I/usr/include/libxml2   -c -o 
analyze.o analyze.c
ccache gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith 
-Wdeclaration-after-statement -Wendif-labels -fno-strict-aliasing -fwrapv -g 
-Wno-error -I. -I. -I../../../src/include -D_GNU_SOURCE -I/usr/include/libxml2  
 -c -o gram.o gram.c
gram.y: In function ‘base_yyparse’:
gram.y:7847: warning: assignment from incompatible pointer type
In file included from gram.y:11920:
scan.c: In function ‘yy_try_NUL_trans’:
scan.c:16246: warning: unused variable ‘yyg’
ccache gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith 
-Wdeclaration-after-statement -Wendif-labels -fno-strict-aliasing -fwrapv -g 
-I. -I. -I../../../src/include -D_GNU_SOURCE -I/usr/include/libxml2   -c -o 
keywords.o keywords.c
ccache gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith 
-Wdeclaration-after-statement -Wendif-labels -fno-strict-aliasing -fwrapv -g 
-I. -I. -I../../../src/include -D_GNU_SOURCE -I/usr/include/libxml2   -c -o 
parser.o parser.c
ccache gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith 
-Wdeclaration-after-statement -Wendif-labels -fno-strict-aliasing -fwrapv -g 
-I. -I. -I../../../src/include -D_GNU_SOURCE -I/usr/include/libxml2   -c -o 
parse_agg.o parse_agg.c
parse_agg.c: In function ‘parseCheckAggregates’:
parse_agg.c:422: warning: assignment from incompatible pointer type
ccache gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith 
-Wdeclaration-after-statement -Wendif-labels -fno-strict-aliasing -fwrapv -g 
-I. -I. -I../../../src/include -D_GNU_SOURCE -I/usr/include/libxml2   -c -o 
parse_expr.o parse_expr.c
ccache gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith 
-Wdeclaration-after-statement -Wendif-labels -fno-strict-aliasing -fwrapv -g 
-I. -I. -I../../../src/include -D_GNU_SOURCE -I/usr/include/libxml2   -c -o 
parse_target.o parse_target.c
make[3]: *** No rule to make target `parse_gsets.o', needed by `objfiles.txt'.  
Stop.
make[3]: Leaving directory `/home/shackle/pggit/postgresql/src/backend/parser'
make[2]: *** [parser-recursive] Error 2
make[2]: Leaving directory `/home/shackle/pggit/postgresql/src/backend'
make[1]: *** [all] Error 2
make[1]: Leaving directory `/home/shackle/pggit/postgresql/src'
make: *** [all] Error 2
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to