diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c new file mode 100644 index 84deed9..d984535 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -595,6 +595,14 @@ transformDeleteStmt(ParseState *pstate, ACL_DELETE); nsitem = pstate->p_target_nsitem; + /* disallow DELETE ... WHERE CURRENT OF on a view */ + if (stmt->whereClause && + IsA(stmt->whereClause, CurrentOfExpr) && + pstate->p_target_relation->rd_rel->relkind == RELKIND_VIEW) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("WHERE CURRENT OF on a view is not implemented")); + /* there's no DISTINCT in DELETE */ qry->distinctClause = NIL; @@ -2868,6 +2876,14 @@ transformUpdateStmt(ParseState *pstate, true, ACL_UPDATE); + /* disallow UPDATE ... WHERE CURRENT OF on a view */ + if (stmt->whereClause && + IsA(stmt->whereClause, CurrentOfExpr) && + pstate->p_target_relation->rd_rel->relkind == RELKIND_VIEW) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("WHERE CURRENT OF on a view is not implemented")); + if (stmt->forPortionOf) qry->forPortionOf = transformForPortionOfClause(pstate, qry->resultRelation, diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c new file mode 100644 index 4bf4aa0..9aa7ef6 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -1514,25 +1514,6 @@ replace_rte_variables_mutator(Node *node } /* otherwise fall through to copy the var normally */ } - else if (IsA(node, CurrentOfExpr)) - { - CurrentOfExpr *cexpr = (CurrentOfExpr *) node; - - if (cexpr->cvarno == context->target_varno && - context->sublevels_up == 0) - { - /* - * We get here if a WHERE CURRENT OF expression turns out to apply - * to a view. Someday we might be able to translate the - * expression to apply to an underlying table of the view, but - * right now it's not implemented. - */ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("WHERE CURRENT OF on a view is not implemented"))); - } - /* otherwise fall through to copy the expr normally */ - } else if (IsA(node, Query)) { /* Recurse into RTE subquery or not-yet-planned sublink subquery */ diff --git a/src/test/regress/expected/generated_virtual.out b/src/test/regress/expected/generated_virtual.out new file mode 100644 index fc41c48..c238ef8 --- a/src/test/regress/expected/generated_virtual.out +++ b/src/test/regress/expected/generated_virtual.out @@ -1723,3 +1723,43 @@ select * from gtest33 where b is null; reset constraint_exclusion; drop table gtest33; +create table gtest_cursor (id int primary key, a int, b int generated always as (a * 2) virtual); +insert into gtest_cursor values (1, 10), (2, 20), (3, 30); +-- UPDATE via cursor +begin; +declare cur1 cursor for select * from gtest_cursor order by id for update; +fetch 1 from cur1; + id | a | b +----+----+---- + 1 | 10 | 20 +(1 row) + +update gtest_cursor set a = 99 where current of cur1; +select * from gtest_cursor order by id; + id | a | b +----+----+----- + 1 | 99 | 198 + 2 | 20 | 40 + 3 | 30 | 60 +(3 rows) + +commit; +-- DELETE via cursor +begin; +declare cur2 cursor for select * from gtest_cursor order by id for update; +fetch 1 from cur2; + id | a | b +----+----+----- + 1 | 99 | 198 +(1 row) + +delete from gtest_cursor where current of cur2; +select * from gtest_cursor order by id; + id | a | b +----+----+---- + 2 | 20 | 40 + 3 | 30 | 60 +(2 rows) + +commit; +drop table gtest_cursor; diff --git a/src/test/regress/sql/generated_virtual.sql b/src/test/regress/sql/generated_virtual.sql new file mode 100644 index 9b32413..5bab7d3 --- a/src/test/regress/sql/generated_virtual.sql +++ b/src/test/regress/sql/generated_virtual.sql @@ -906,3 +906,24 @@ select * from gtest33 where b is null; reset constraint_exclusion; drop table gtest33; + +create table gtest_cursor (id int primary key, a int, b int generated always as (a * 2) virtual); +insert into gtest_cursor values (1, 10), (2, 20), (3, 30); + +-- UPDATE via cursor +begin; +declare cur1 cursor for select * from gtest_cursor order by id for update; +fetch 1 from cur1; +update gtest_cursor set a = 99 where current of cur1; +select * from gtest_cursor order by id; +commit; + +-- DELETE via cursor +begin; +declare cur2 cursor for select * from gtest_cursor order by id for update; +fetch 1 from cur2; +delete from gtest_cursor where current of cur2; +select * from gtest_cursor order by id; +commit; + +drop table gtest_cursor;