gs91.patch
text/x-diff
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/parser/analyze.c | 0 | 0 |
| src/backend/parser/gram.y | 0 | 0 |
| src/backend/parser/Makefile | 0 | 0 |
| src/backend/parser/parse_agg.c | 0 | 0 |
| src/backend/parser/parse_expr.c | 0 | 0 |
| src/backend/parser/parse_target.c | 0 | 0 |
| src/include/nodes/nodes.h | 0 | 0 |
| src/include/nodes/parsenodes.h | 0 | 0 |
| src/include/parser/kwlist.h | 0 | 0 |
| src/include/parser/parse_node.h | 0 | 0 |
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;
/*