From dc80b79cc02a464be0bd8f4e5071c6ef74d254c7 Mon Sep 17 00:00:00 2001 From: zhouxiongjia <719216473@qq.com> Date: Wed, 21 Oct 2020 17:45:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=85=B3=E4=BA=8Ero?= =?UTF-8?q?wnum=E7=9A=844=E4=B8=AAbug=E3=80=82=201.=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E5=80=BC=E5=8F=AA=E6=9C=89255=EF=BC=8C=E6=AD=A3=E5=B8=B8?= =?UTF-8?q?=E5=BA=94=E8=AF=A5=E6=98=AF=E6=97=A0=E9=99=90=E5=A4=A7=E3=80=82?= =?UTF-8?q?=202.group=20by=E8=B7=9Fwhere=20rownum=20<=20n=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E5=AD=98=E5=9C=A8=E6=97=B6=EF=BC=8C=E7=A6=81=E6=AD=A2?= =?UTF-8?q?=E5=B0=86rownum=E4=BC=98=E5=8C=96=E6=88=90limit=203.groupy=20by?= =?UTF-8?q?=E5=90=8E=E9=9D=A2=E6=B2=A1=E6=9C=89rownum=EF=BC=8C=E8=80=8Chav?= =?UTF-8?q?ing=E5=90=8E=E9=9D=A2=E6=9C=89rownum=E6=97=B6=EF=BC=8C=E4=BC=9A?= =?UTF-8?q?=E6=AD=A3=E5=B8=B8=E8=BF=90=E8=A1=8C=EF=BC=8C=E6=AD=A3=E5=B8=B8?= =?UTF-8?q?=E5=BA=94=E8=AF=A5=E6=8A=A5=E9=94=99=E3=80=82=204.union?= =?UTF-8?q?=E5=89=8D=E5=90=8E=E7=9A=84=E5=AD=90=E5=8F=A5=E5=A6=82=E6=9E=9C?= =?UTF-8?q?=E6=9C=89where=20rownum=20<=20n=EF=BC=8C=E5=B9=B6=E4=B8=94?= =?UTF-8?q?=E8=BF=98=E6=9C=89=E5=90=AB=E6=9C=89order=20by=E7=9A=84?= =?UTF-8?q?=E5=AD=90=E6=9F=A5=E8=AF=A2=E6=97=B6=EF=BC=8C=E7=A6=81=E6=AD=A2?= =?UTF-8?q?=E5=B0=86order=20by=E4=BC=98=E5=8C=96=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=8E=89=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/parser/parse_agg.cpp | 20 ++++++++ .../optimizer/prep/prepjointree.cpp | 4 +- .../optimizer/prep/prepnonjointree.cpp | 4 ++ src/gausskernel/runtime/executor/execQual.cpp | 2 +- src/test/regress/expected/xc_rownum.out | 51 +++++++++++++++++++ src/test/regress/sql/xc_rownum.sql | 11 ++++ 6 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/common/backend/parser/parse_agg.cpp b/src/common/backend/parser/parse_agg.cpp index c38acd3fe..2a0311f2d 100755 --- a/src/common/backend/parser/parse_agg.cpp +++ b/src/common/backend/parser/parse_agg.cpp @@ -740,6 +740,26 @@ static bool check_ungrouped_columns_walker(Node* node, check_ungrouped_columns_c } } + /* If There is ROWNUM, it must appear in the GROUP BY clause or be used in an aggregate function. */ + if (IsA(node, Rownum)) { + Rownum *rownumVar = (Rownum *)node; + bool haveRownum = false; + if (!context->have_non_var_grouping || context->sublevels_up != 0) { + foreach (gl, context->groupClauses) { + Node *gnode = (Node *)((TargetEntry *)lfirst(gl))->expr; + if (IsA(gnode, Rownum)) { + haveRownum = true; + break; + } + } + + if (haveRownum == false) { + ereport(ERROR, (errcode(ERRCODE_GROUPING_ERROR), + errmsg("ROWNUM must appear in the GROUP BY clause or be used in an aggregate function"), + parser_errposition(context->pstate, rownumVar->location))); + } + } + } /* * If we have an ungrouped Var of the original query level, we have a * failure. Vars below the original query level are not a problem, and diff --git a/src/gausskernel/optimizer/prep/prepjointree.cpp b/src/gausskernel/optimizer/prep/prepjointree.cpp index c17d6c7ca..491665bfd 100755 --- a/src/gausskernel/optimizer/prep/prepjointree.cpp +++ b/src/gausskernel/optimizer/prep/prepjointree.cpp @@ -2963,8 +2963,8 @@ void preprocess_rownum(PlannerInfo *root, Query *parse) if (quals == NULL) { return; } - /* If it includes {order by}, can not be rewrited */ - if (parse->sortClause != NULL) { + /* If it includes {order by} or {group by}, can not be rewrited */ + if ((parse->sortClause != NULL) || (parse->groupClause != NULL)) { return; } if (parse->limitCount != NULL) { diff --git a/src/gausskernel/optimizer/prep/prepnonjointree.cpp b/src/gausskernel/optimizer/prep/prepnonjointree.cpp index 30397cfcd..2a3b99910 100755 --- a/src/gausskernel/optimizer/prep/prepnonjointree.cpp +++ b/src/gausskernel/optimizer/prep/prepnonjointree.cpp @@ -1941,6 +1941,10 @@ static void reduce_orderby_recurse(Query* query, Node* jtnode, bool reduce) /* Reduce orderby clause in subquery for join or from clause of more than one rte */ reduce_orderby_final(rte, reduce); } else if (IsA(jtnode, FromExpr)) { + /* If there is ROWNUM, can not reduce orderby clause in subquery */ + if (contain_rownum_walker(jtnode, NULL)) { + return; + } FromExpr* f = (FromExpr*)jtnode; ListCell* l = NULL; bool flag = false; diff --git a/src/gausskernel/runtime/executor/execQual.cpp b/src/gausskernel/runtime/executor/execQual.cpp index 919cbc7f0..0f64b87a4 100755 --- a/src/gausskernel/runtime/executor/execQual.cpp +++ b/src/gausskernel/runtime/executor/execQual.cpp @@ -979,7 +979,7 @@ static Datum ExecEvalRownum(RownumState* exprstate, ExprContext* econtext, bool* *isDone = ExprSingleResult; *isNull = false; - return Int8GetDatum(exprstate->ps->ps_rownum + 1); + return Int64GetDatum(exprstate->ps->ps_rownum + 1); } /* ---------------------------------------------------------------- diff --git a/src/test/regress/expected/xc_rownum.out b/src/test/regress/expected/xc_rownum.out index 9af4104e2..5f7905f04 100644 --- a/src/test/regress/expected/xc_rownum.out +++ b/src/test/regress/expected/xc_rownum.out @@ -241,7 +241,31 @@ select rownum + 1 rn from dual group by rn; ---- 2 (1 row) + +--test having +select id from distributors group by rownum,id having rownum < 5; + id +---- + 1 + 1 + 1 + 1 +(4 rows) + +select rownum from distributors group by rownum having rownum < 5; + rownum +-------- + 3 + 1 + 2 + 4 +(4 rows) + +select id from distributors group by id having rownum < 5; +ERROR: ROWNUM must appear in the GROUP BY clause or be used in an aggregate function +LINE 1: select id from distributors group by id having rownum < 5; + ^ --test alias name after where select rownum rn, name from distributors where rn<3; ERROR: Alias "rn" reference with ROWNUM included is invalid. @@ -1645,5 +1669,32 @@ explain select * from test where rownum < 5 order by 1; (4 rows) +-- ROWNUM with GROUP BY +explain select id from test where rownum < 5 group by id; + QUERY PLAN +------------------------------------------------------------- + HashAggregate (cost=25.12..25.79 rows=67 width=4) + Group By Key: id + -> Seq Scan on test (cost=0.00..24.18 rows=378 width=4) + Filter: (ROWNUM < 5) +(4 rows) + + +-- ROWNUM with UNION and ORDER BY +explain select id from student where rownum < 3 union select id from (select id from student order by 1) where rownum < 5; + QUERY PLAN +----------------------------------------------------------------------------------- + HashAggregate (cost=79.04..79.10 rows=6 width=4) + Group By Key: public.student.id + -> Append (cost=0.00..79.02 rows=6 width=4) + -> Limit (cost=0.00..0.04 rows=2 width=4) + -> Seq Scan on student (cost=0.00..21.34 rows=1134 width=4) + -> Limit (cost=78.87..78.92 rows=4 width=4) + -> Sort (cost=78.87..81.71 rows=1134 width=4) + Sort Key: public.student.id + -> Seq Scan on student (cost=0.00..21.34 rows=1134 width=4) +(9 rows) + + drop table student; drop table test; diff --git a/src/test/regress/sql/xc_rownum.sql b/src/test/regress/sql/xc_rownum.sql index 86bfc0bf7..789d987ba 100644 --- a/src/test/regress/sql/xc_rownum.sql +++ b/src/test/regress/sql/xc_rownum.sql @@ -85,6 +85,11 @@ select rownum from distributors group by rownum; select rownum rn from distributors group by rn; select rownum + 1 from dual group by rownum; select rownum + 1 rn from dual group by rn; + +--test having +select id from distributors group by rownum,id having rownum < 5; +select rownum from distributors group by rownum having rownum < 5; +select id from distributors group by id having rownum < 5; --test alias name after where select rownum rn, name from distributors where rn<3; select rownum rowno2, * from (select rownum rowno1, * from distributors order by id desc) where rowno2 < 2; @@ -447,5 +452,11 @@ explain select * from student where not(rownum > 3 or id = 1); -- ROWNUM with ORDER BY explain select * from test where rownum < 5 order by 1; +-- ROWNUM with GROUP BY +explain select id from test where rownum < 5 group by id; + +-- ROWNUM with UNION and ORDER BY +explain select id from student where rownum < 3 union select id from (select id from student order by 1) where rownum < 5; + drop table student; drop table test; \ No newline at end of file