diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 84deed9a..d9845358 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -595,6 +595,14 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) 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, UpdateStmt *stmt) 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 index 4bf4aa0d..9aa7ef60 100644 --- 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 index fc41c480..58cdf310 100644 --- a/src/test/regress/expected/generated_virtual.out +++ b/src/test/regress/expected/generated_virtual.out @@ -1723,3 +1723,57 @@ 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; +-- WHERE CURRENT OF via a view on a table with VGC (should fail) +create view gtest_cursor_view as select * from gtest_cursor; +begin; +declare cur3 cursor for select * from gtest_cursor_view for update; +fetch 1 from cur3; + id | a | b +----+----+---- + 2 | 20 | 40 +(1 row) + +update gtest_cursor_view set a = 55 where current of cur3; -- fail +ERROR: WHERE CURRENT OF on a view is not implemented +rollback; +drop view gtest_cursor_view; +drop table gtest_cursor; diff --git a/src/test/regress/sql/generated_virtual.sql b/src/test/regress/sql/generated_virtual.sql index 9b32413e..48daf31a 100644 --- a/src/test/regress/sql/generated_virtual.sql +++ b/src/test/regress/sql/generated_virtual.sql @@ -906,3 +906,33 @@ 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; + +-- WHERE CURRENT OF via a view on a table with VGC (should fail) +create view gtest_cursor_view as select * from gtest_cursor; +begin; +declare cur3 cursor for select * from gtest_cursor_view for update; +fetch 1 from cur3; +update gtest_cursor_view set a = 55 where current of cur3; -- fail +rollback; +drop view gtest_cursor_view; + +drop table gtest_cursor;