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
*************** override CPPFLAGS := -I. -I$(srcdir) $(C
*** 15,21 ****
  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
  
  FLEXFLAGS = -CF
  
--- 15,21 ----
  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_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,39 ****
--- 34,40 ----
  #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"
*************** parse_sub_analyze(Node *parseTree, Parse
*** 150,155 ****
--- 151,313 ----
  }
  
  /*
+  * 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.
   */
*************** transformStmt(ParseState *pstate, Node *
*** 179,184 ****
--- 337,344 ----
  			{
  				SelectStmt *n = (SelectStmt *) parseTree;
  
+   				n = transformGroupingSets(pstate, n);
+ 
  				if (n->valuesLists)
  					result = transformValuesClause(pstate, n);
  				else if (n->op == SETOP_NONE)
*************** transformSelectStmt(ParseState *pstate, 
*** 827,833 ****
  										  false /* allow SQL92 rules */ );
  
  	qry->groupClause = transformGroupClause(pstate,
! 											stmt->groupClause,
  											&qry->targetList,
  											qry->sortClause,
  											false /* allow SQL92 rules */ );
--- 987,993 ----
  										  false /* allow SQL92 rules */ );
  
  	qry->groupClause = transformGroupClause(pstate,
! 											(List *) stmt->groupClause,
  											&qry->targetList,
  											qry->sortClause,
  											false /* allow SQL92 rules */ );
*************** transformValuesClause(ParseState *pstate
*** 924,930 ****
  	Assert(stmt->targetList == NIL);
  	Assert(stmt->fromClause == NIL);
  	Assert(stmt->whereClause == NULL);
! 	Assert(stmt->groupClause == NIL);
  	Assert(stmt->havingClause == NULL);
  	Assert(stmt->windowClause == NIL);
  	Assert(stmt->op == SETOP_NONE);
--- 1084,1090 ----
  	Assert(stmt->targetList == NIL);
  	Assert(stmt->fromClause == NIL);
  	Assert(stmt->whereClause == NULL);
! 	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 3f6eeeb..1d907c5 100644
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** static Node *makeBitStringConst(char *st
*** 111,116 ****
--- 111,118 ----
  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);
*************** static TypeName *TableFuncTypeName(List 
*** 292,298 ****
  				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
  				opt_select_limit opclass_item_list opclass_drop_list
  				opt_opfamily transaction_mode_list_or_empty
  				TableFuncElementList opt_type_modifiers
--- 294,300 ----
  				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 TriggerFuncArgs select_limit
  				opt_select_limit opclass_item_list opclass_drop_list
  				opt_opfamily transaction_mode_list_or_empty
  				TableFuncElementList opt_type_modifiers
*************** static TypeName *TableFuncTypeName(List 
*** 437,442 ****
--- 439,449 ----
  				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.
*************** static TypeName *TableFuncTypeName(List 
*** 472,478 ****
  	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
  	CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
  
  	DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
--- 479,485 ----
  	COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS
  	CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
  	CREATEROLE CREATEUSER CROSS CSV CURRENT_P
! 	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
*************** static TypeName *TableFuncTypeName(List 
*** 485,491 ****
  	FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORWARD
  	FREEZE FROM FULL FUNCTION FUNCTIONS
  
! 	GLOBAL GRANT GRANTED GREATEST GROUP_P
  
  	HANDLER HAVING HEADER_P HOLD HOUR_P
  
--- 492,498 ----
  	FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOLLOWING FOR FORCE FOREIGN FORWARD
  	FREEZE FROM FULL FUNCTION FUNCTIONS
  
! 	GLOBAL GRANT GRANTED GREATEST GROUP_P GROUPING GROUPING_ID
  
  	HANDLER HAVING HEADER_P HOLD HOUR_P
  
*************** static TypeName *TableFuncTypeName(List 
*** 519,528 ****
  
  	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
  
  	SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
! 	SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF 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
--- 526,535 ----
  
  	RANGE READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REINDEX
  	RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART
! 	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 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
*************** first_or_next: FIRST_P								{ $$ = 0; 
*** 7764,7772 ****
  
  
  group_clause:
! 			GROUP_P BY expr_list					{ $$ = $3; }
! 			| /*EMPTY*/								{ $$ = NIL; }
! 		;
  
  having_clause:
  			HAVING a_expr							{ $$ = $2; }
--- 7771,7825 ----
  
  
  group_clause:
!   			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; }
*************** c_expr:		columnref								{ $$ = $1; }
*** 9293,9299 ****
  					r->location = @1;
  					$$ = (Node *)r;
  				}
! 		;
  
  /*
   * func_expr is split out from c_expr just so that we have a classification
--- 9346,9375 ----
  					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
*************** unreserved_keyword:
*** 11010,11015 ****
--- 11086,11092 ----
  			| SERVER
  			| SESSION
  			| SET
+ 			| SETS
  			| SHARE
  			| SHOW
  			| SIMPLE
*************** col_name_keyword:
*** 11087,11092 ****
--- 11164,11170 ----
  			| EXTRACT
  			| FLOAT_P
  			| GREATEST
+             | GROUPING_ID
  			| INOUT
  			| INT_P
  			| INTEGER
*************** reserved_keyword:
*** 11181,11186 ****
--- 11259,11265 ----
  			| COLUMN
  			| CONSTRAINT
  			| CREATE
+             | CUBE
  			| CURRENT_CATALOG
  			| CURRENT_DATE
  			| CURRENT_ROLE
*************** reserved_keyword:
*** 11202,11207 ****
--- 11281,11287 ----
  			| FROM
  			| GRANT
  			| GROUP_P
+             | GROUPING
  			| HAVING
  			| IN_P
  			| INITIALLY
*************** reserved_keyword:
*** 11223,11228 ****
--- 11303,11309 ----
  			| PRIMARY
  			| REFERENCES
  			| RETURNING
+             | ROLLUP
  			| SELECT
  			| SESSION_USER
  			| SOME
*************** makeXmlExpr(XmlExprOp op, char *name, Li
*** 11728,11733 ****
--- 11809,11826 ----
  	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
*************** typedef struct
*** 33,44 ****
--- 33,52 ----
  	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 -
*************** parseCheckAggregates(ParseState *pstate,
*** 405,411 ****
  	 * 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 (hasJoinRTEs)
  		clause = flatten_join_alias_vars(root, clause);
  	check_ungrouped_columns(clause, pstate,
--- 413,428 ----
  	 * WINDOW clauses.	For that matter, it's also going to examine the
  	 * grouping expressions themselves --- but they'll all pass the test ...
  	 */
!   	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,
*************** parseCheckWindowFuncs(ParseState *pstate
*** 514,519 ****
--- 531,613 ----
  }
  
  /*
+  * 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 888b526..72762b1 100644
*** a/src/backend/parser/parse_expr.c
--- b/src/backend/parser/parse_expr.c
*************** transformExpr(ParseState *pstate, Node *
*** 288,293 ****
--- 288,312 ----
  		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);
*************** transformExpr(ParseState *pstate, Node *
*** 324,329 ****
--- 343,349 ----
  		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
*************** FigureColnameInternal(Node *node, char *
*** 1586,1591 ****
--- 1586,1607 ----
  		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
*************** typedef enum NodeTag
*** 385,390 ****
--- 385,394 ----
  	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 b591073..9efa9c7 100644
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef struct SortBy
*** 378,383 ****
--- 378,410 ----
  } 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.
*************** typedef struct WindowDef
*** 431,436 ****
--- 458,483 ----
  	 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
*************** typedef struct SelectStmt
*** 956,962 ****
  	List	   *targetList;		/* the target list (of ResTarget) */
  	List	   *fromClause;		/* the FROM clause */
  	Node	   *whereClause;	/* WHERE qualification */
! 	List	   *groupClause;	/* GROUP BY clauses */
  	Node	   *havingClause;	/* HAVING conditional-expression */
  	List	   *windowClause;	/* WINDOW window_name AS (...), ... */
  	WithClause *withClause;		/* WITH clause */
--- 1003,1009 ----
  	List	   *targetList;		/* the target list (of ResTarget) */
  	List	   *fromClause;		/* the FROM clause */
  	Node	   *whereClause;	/* WHERE qualification */
! 	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
*************** PG_KEYWORD("createrole", CREATEROLE, UNR
*** 99,104 ****
--- 99,105 ----
  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)
*************** PG_KEYWORD("grant", GRANT, RESERVED_KEYW
*** 171,176 ****
--- 172,179 ----
  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)
*************** PG_KEYWORD("revoke", REVOKE, UNRESERVED_
*** 318,323 ****
--- 321,327 ----
  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)
*************** PG_KEYWORD("session", SESSION, UNRESERVE
*** 336,341 ****
--- 340,346 ----
  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_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
*************** struct ParseState
*** 107,112 ****
--- 107,113 ----
  	bool		p_is_update;
  	bool		p_locked_from_parent;
  	Relation	p_target_relation;
+     bool        p_hasGroupingSets;
  	RangeTblEntry *p_target_rangetblentry;
  
  	/*
