mirror of
https://github.com/postgres/postgres.git
synced 2026-05-27 12:00:13 -04:00
Fix UPDATE/DELETE ... WHERE CURRENT OF on a table with virtual columns.
Formerly, attempting to use WHERE CURRENT OF to update or delete from
a table with virtual generated columns would fail with the error
"WHERE CURRENT OF on a view is not implemented".
The reason was that the check preventing WHERE CURRENT OF from being
used on a view was in replace_rte_variables_mutator(), which presumed
that the only way it could get there was as part of rewriting a query
on a view. That is no longer the case, since replace_rte_variables()
is now also used to expand the virtual generated columns of a table.
Fix by doing the check for WHERE CURRENT OF on a view at parse time.
This is safe, since it is no longer possible for the relkind to change
after the query is parsed (as of b23cd185f).
Reported-by: Satyanarayana Narlapuram <satyanarlapuram@gmail.com>
Author: Satyanarayana Narlapuram <satyanarlapuram@gmail.com>
Author: Dean Rasheed <dean.a.rasheed@gmail.com>
Discussion: https://postgr.es/m/CAHg+QDc_TwzSgb=B_QgNLt3mvZdmRK23rLb+RkanSQkDF40GjA@mail.gmail.com
Backpatch-through: 18
This commit is contained in:
parent
7834251758
commit
5548a969b6
6 changed files with 77 additions and 19 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -1805,3 +1805,33 @@ insert into gtest34p values (1, 2)
|
|||
(1 row)
|
||||
|
||||
drop table gtest34p;
|
||||
-- Ensure that virtual generated columns work with WHERE CURRENT OF
|
||||
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);
|
||||
begin;
|
||||
declare curs cursor for select * from gtest_cursor order by id for update;
|
||||
fetch 1 from curs;
|
||||
id | a | b
|
||||
----+----+----
|
||||
1 | 10 | 20
|
||||
(1 row)
|
||||
|
||||
update gtest_cursor set a = 99 where current of curs;
|
||||
select * from gtest_cursor order by id;
|
||||
id | a | b
|
||||
----+----+-----
|
||||
1 | 99 | 198
|
||||
2 | 20 | 40
|
||||
3 | 30 | 60
|
||||
(3 rows)
|
||||
|
||||
delete from gtest_cursor where current of curs;
|
||||
select * from gtest_cursor order by id;
|
||||
id | a | b
|
||||
----+----+----
|
||||
2 | 20 | 40
|
||||
3 | 30 | 60
|
||||
(2 rows)
|
||||
|
||||
commit;
|
||||
drop table gtest_cursor;
|
||||
|
|
|
|||
|
|
@ -1336,6 +1336,17 @@ FETCH FROM c1;
|
|||
DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported
|
||||
ERROR: WHERE CURRENT OF on a view is not implemented
|
||||
ROLLBACK;
|
||||
BEGIN;
|
||||
DECLARE c1 CURSOR FOR SELECT * FROM ucview;
|
||||
FETCH FROM c1;
|
||||
f1 | f2
|
||||
----+-------
|
||||
13 | three
|
||||
(1 row)
|
||||
|
||||
UPDATE ucview SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail, views not supported
|
||||
ERROR: WHERE CURRENT OF on a view is not implemented
|
||||
ROLLBACK;
|
||||
-- Check WHERE CURRENT OF with an index-only scan
|
||||
BEGIN;
|
||||
EXPLAIN (costs off)
|
||||
|
|
|
|||
|
|
@ -954,3 +954,18 @@ insert into gtest34p values (1, 7)
|
|||
insert into gtest34p values (1, 2)
|
||||
on conflict (id) do update set a = gtest34p.c + excluded.c returning *;
|
||||
drop table gtest34p;
|
||||
|
||||
-- Ensure that virtual generated columns work with WHERE CURRENT OF
|
||||
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);
|
||||
|
||||
begin;
|
||||
declare curs cursor for select * from gtest_cursor order by id for update;
|
||||
fetch 1 from curs;
|
||||
update gtest_cursor set a = 99 where current of curs;
|
||||
select * from gtest_cursor order by id;
|
||||
delete from gtest_cursor where current of curs;
|
||||
select * from gtest_cursor order by id;
|
||||
commit;
|
||||
|
||||
drop table gtest_cursor;
|
||||
|
|
|
|||
|
|
@ -508,6 +508,11 @@ DECLARE c1 CURSOR FOR SELECT * FROM ucview;
|
|||
FETCH FROM c1;
|
||||
DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported
|
||||
ROLLBACK;
|
||||
BEGIN;
|
||||
DECLARE c1 CURSOR FOR SELECT * FROM ucview;
|
||||
FETCH FROM c1;
|
||||
UPDATE ucview SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail, views not supported
|
||||
ROLLBACK;
|
||||
|
||||
-- Check WHERE CURRENT OF with an index-only scan
|
||||
BEGIN;
|
||||
|
|
|
|||
Loading…
Reference in a new issue