From c9738b11d1dc036ba1e64c6154aff02558c82461 Mon Sep 17 00:00:00 2001 From: zhouxiongjia <719216473@qq.com> Date: Fri, 14 Aug 2020 14:24:01 +0800 Subject: [PATCH 1/2] =?UTF-8?q?Ban=20some=20useage=20of=20ROWNUM=201.Ban?= =?UTF-8?q?=20ROWNUM=20in=20INSERT...VALUES=EF=BC=88=EF=BC=89=20STATEMENT?= =?UTF-8?q?=202.Ban=20ROWNUM=20after=20DEFAULT=20when=20creating=20table?= =?UTF-8?q?=203.Ban=20ROWNUM=20in=20VALUES=20clause=20that's=20being=20use?= =?UTF-8?q?d=20as=20a=20standalone=20SELECT=20like=20select=20*=20from=20(?= =?UTF-8?q?values(rownum,1)),=20x(a,b)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/catalog/heap.cpp | 8 +++++++- src/common/backend/nodes/nodeFuncs.cpp | 3 +++ src/common/backend/parser/analyze.cpp | 14 +++++++++++--- src/include/optimizer/clauses.h | 12 ++++++++++++ src/test/regress/expected/xc_rownum.out | 24 +++++++++++++++++++++++- src/test/regress/sql/xc_rownum.sql | 9 +++++++++ 6 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/common/backend/catalog/heap.cpp b/src/common/backend/catalog/heap.cpp index e7bec0ec01..5c49d606bc 100755 --- a/src/common/backend/catalog/heap.cpp +++ b/src/common/backend/catalog/heap.cpp @@ -3442,11 +3442,17 @@ Node* cookDefault(ParseState* pstate, Node* raw_default, Oid atttypid, int32 att ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("cannot use column references in default expression"))); + /* + * Make sure default expr does not refer to rownum. + */ + ExcludeRownumExpr(pstate, expr); + /* * It can't return a set either. */ if (expression_returns_set(expr)) - ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("default expression must not return a set"))); + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("default expression must not return a set"))); /* * No subplans or aggregates, either... diff --git a/src/common/backend/nodes/nodeFuncs.cpp b/src/common/backend/nodes/nodeFuncs.cpp index be725270ec..39eff7a084 100755 --- a/src/common/backend/nodes/nodeFuncs.cpp +++ b/src/common/backend/nodes/nodeFuncs.cpp @@ -1383,6 +1383,9 @@ int exprLocation(const Node* expr) /* just use typename's location */ loc = exprLocation((Node*)((const FunctionParameter*)expr)->argType); break; + case T_Rownum: + loc = ((const Rownum*)expr)->location; + break; default: /* for any other node type it's just unknown... */ loc = -1; diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index efa5a80a12..b0fea17811 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -1536,6 +1536,10 @@ List* transformInsertRow(ParseState* pstate, List* exprlist, List* stmtcols, Lis foreach (lc, exprlist) { Expr* expr = (Expr*)lfirst(lc); ResTarget* col = NULL; + /* + * Rownum is not allowed in exprlist in INSERT statement. + */ + ExcludeRownumExpr(pstate, (Node*)expr); col = (ResTarget*)lfirst(icols); AssertEreport(IsA(col, ResTarget), MOD_OPT, "nodeType inconsistant"); @@ -1802,7 +1806,7 @@ static Query* transformValuesClause(ParseState* pstate, SelectStmt* stmt) /* * For each row of VALUES, transform the raw expressions. This is also a - * handy place to reject DEFAULT nodes, which the grammar allows for + * handy place to reject DEFAULT nodes and Rownum, which the grammar allows for * simplicity. * * Note that the intermediate representation we build is column-organized @@ -1832,7 +1836,7 @@ static Query* transformValuesClause(ParseState* pstate, SelectStmt* stmt) parser_errposition(pstate, exprLocation((Node*)sublist)))); } - /* Check for DEFAULT and build per-column expression lists */ + /* Check for DEFAULT and Rownum, then build per-column expression lists */ i = 0; foreach (lc2, sublist) { Node* col = (Node*)lfirst(lc2); @@ -1842,9 +1846,13 @@ static Query* transformValuesClause(ParseState* pstate, SelectStmt* stmt) (errcode(ERRCODE_SYNTAX_ERROR), errmsg("DEFAULT can only appear in a VALUES list within INSERT"), parser_errposition(pstate, exprLocation(col)))); - } + } + + ExcludeRownumExpr(pstate, col); + colexprs[i] = lappend(colexprs[i], col); i++; + } /* Release sub-list's cells to save memory */ diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index b37449dce1..ce19295b14 100755 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -15,6 +15,8 @@ #define CLAUSES_H #include "nodes/relation.h" +#include "parser/parse_node.h" +#include "nodes/nodeFuncs.h" #define is_opclause(clause) ((clause) != NULL && IsA(clause, OpExpr)) #define is_funcclause(clause) ((clause) != NULL && IsA(clause, FuncExpr)) @@ -112,6 +114,16 @@ static inline bool contain_rownum_expr(Node *node) return contain_rownum_walker(node, NULL); } +/* Check if it includes Rownum */ +static inline void ExcludeRownumExpr(ParseState* pstate, Node* expr) +{ + if (contain_rownum_expr(expr)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("specified ROWNUM is not allowed here."), + parser_errposition(pstate, exprLocation(expr)))); +} + extern List* get_quals_lists(Node *jtnode); #endif /* CLAUSES_H */ diff --git a/src/test/regress/expected/xc_rownum.out b/src/test/regress/expected/xc_rownum.out index ed13b49c4d..2ae97c4022 100644 --- a/src/test/regress/expected/xc_rownum.out +++ b/src/test/regress/expected/xc_rownum.out @@ -251,7 +251,29 @@ select rownum rowno2, * from (select rownum rowno1, * from distributors order by ERROR: Alias "rowno2" reference with ROWNUM included is invalid. LINE 1: ...wno1, * from distributors order by id desc) where rowno2 < 2... ^ - +--test default rownum when creating table +create table student(id int default rownum, stuname varchar(5)); +ERROR: specified ROWNUM is not allowed here. +create table student(id int default rownum+1, stuname varchar(5)); +ERROR: specified ROWNUM is not allowed here. +--test insert when values include rownum +insert into distributors values (rownum, 'qwer'); +ERROR: specified ROWNUM is not allowed here. +LINE 1: insert into distributors values (rownum, 'qwer'); + ^ +insert into distributors(id, name) values (2, 'abcd'), (rownum+1, 'qwer'); +ERROR: specified ROWNUM is not allowed here. +LINE 1: ... into distributors(id, name) values (2, 'abcd'), (rownum+1, ... + ^ +--test VALUES clause that's being used as a standalone SELECT +select * from (values(rownum, 1)) x(a, b); +ERROR: specified ROWNUM is not allowed here. +LINE 1: select * from (values(rownum, 1)) x(a, b); + ^ +select * from (values(rownum+1, 1)) x(a, b); +ERROR: specified ROWNUM is not allowed here. +LINE 1: select * from (values(rownum+1, 1)) x(a, b); + ^ --test except and minus --create test table create table except_table (a int, b int); diff --git a/src/test/regress/sql/xc_rownum.sql b/src/test/regress/sql/xc_rownum.sql index 1494a197f1..dc4d1cd80d 100644 --- a/src/test/regress/sql/xc_rownum.sql +++ b/src/test/regress/sql/xc_rownum.sql @@ -88,6 +88,15 @@ select rownum + 1 rn from dual group by rn; --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; +--test default rownum when creating table +create table student(id int default rownum, stuname varchar(5)); +create table student(id int default rownum+1, stuname varchar(5)); +--test insert when values include rownum +insert into distributors values (rownum, 'qwer'); +insert into distributors(id, name) values (2, 'abcd'), (rownum+1, 'qwer'); +--test VALUES clause that's being used as a standalone SELECT +select * from (values(rownum, 1)) x(a, b); +select * from (values(rownum+1, 1)) x(a, b); --test except and minus --create test table -- Gitee From c43dbab1ce2712e5c28f5711964b14569e2c6ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E9=9B=84=E4=BD=B3?= <719216473@qq.com> Date: Fri, 14 Aug 2020 21:59:53 +0800 Subject: [PATCH 2/2] update src/test/regress/expected/xc_rownum.out. --- src/test/regress/expected/xc_rownum.out | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/regress/expected/xc_rownum.out b/src/test/regress/expected/xc_rownum.out index 2ae97c4022..dd9bf28d3a 100644 --- a/src/test/regress/expected/xc_rownum.out +++ b/src/test/regress/expected/xc_rownum.out @@ -274,6 +274,7 @@ select * from (values(rownum+1, 1)) x(a, b); ERROR: specified ROWNUM is not allowed here. LINE 1: select * from (values(rownum+1, 1)) x(a, b); ^ + --test except and minus --create test table create table except_table (a int, b int); -- Gitee