diff --git a/src/common/backend/catalog/heap.cpp b/src/common/backend/catalog/heap.cpp index e7bec0ec01c45f5755e38f4d1493c265e33335ab..5c49d606bc13e700b7533726ec7e62eabada21bf 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 be725270ec5e17025c18beed26d0c4bb9472ffe4..39eff7a084542d27caaa5b9e155471487af02ac0 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 efa5a80a12c753776f692a3c16571434ebeb35c9..b0fea178110727d2efbc8f2dce82cccd2d0b2ac3 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 b37449dce10cd759fdaed2240ab6afee79649ea7..ce19295b142ae2fa76cd5644ac625d810a7eb944 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 ed13b49c4d56f2e96a67ba66f18592cbc4dfbc99..dd9bf28d3a95ac82f85af83c4285c9984a2d389f 100644 --- a/src/test/regress/expected/xc_rownum.out +++ b/src/test/regress/expected/xc_rownum.out @@ -251,7 +251,30 @@ 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 1494a197f1138c99608f0010fec2da006c693c48..dc4d1cd80d15bdc374f8efa0210babb9dc214201 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