Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4649003

Browse files
committed
Avoid trying to lock OLD/NEW in a rule with FOR UPDATE.
transformLockingClause neglected to exclude the pseudo-RTEs forOLD/NEW when processing a rule's query. This led to odd errorsor even crashes later on. This bug is very ancient, but it'snot terribly surprising that nobody noticed, since the use-casefor SELECT FOR UPDATE in a non-view rule is somewhere betweenthin and non-existent. Still, crashing is not OK.Per bug #17151 from Zhiyong Wu. Thanks to Masahiko Sawadafor analysis of the problem.Discussion:https://postgr.es/m/17151-c03a3e6e4ec9aadb@postgresql.org
1 parent18914f2 commit4649003

File tree

4 files changed

+60
-6
lines changed

4 files changed

+60
-6
lines changed

‎src/backend/parser/analyze.c‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3170,13 +3170,22 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
31703170

31713171
if (lockedRels==NIL)
31723172
{
3173-
/* all regular tables used in query */
3173+
/*
3174+
* Lock all regular tables used in query and its subqueries. We
3175+
* examine inFromCl to exclude auto-added RTEs, particularly NEW/OLD
3176+
* in rules. This is a bit of an abuse of a mostly-obsolete flag, but
3177+
* it's convenient. We can't rely on the namespace mechanism that has
3178+
* largely replaced inFromCl, since for example we need to lock
3179+
* base-relation RTEs even if they are masked by upper joins.
3180+
*/
31743181
i=0;
31753182
foreach(rt,qry->rtable)
31763183
{
31773184
RangeTblEntry*rte= (RangeTblEntry*)lfirst(rt);
31783185

31793186
++i;
3187+
if (!rte->inFromCl)
3188+
continue;
31803189
switch (rte->rtekind)
31813190
{
31823191
caseRTE_RELATION:
@@ -3206,7 +3215,11 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
32063215
}
32073216
else
32083217
{
3209-
/* just the named tables */
3218+
/*
3219+
* Lock just the named tables. As above, we allow locking any base
3220+
* relation regardless of alias-visibility rules, so we need to
3221+
* examine inFromCl to exclude OLD/NEW.
3222+
*/
32103223
foreach(l,lockedRels)
32113224
{
32123225
RangeVar*thisrel= (RangeVar*)lfirst(l);
@@ -3227,6 +3240,8 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
32273240
RangeTblEntry*rte= (RangeTblEntry*)lfirst(rt);
32283241

32293242
++i;
3243+
if (!rte->inFromCl)
3244+
continue;
32303245
if (strcmp(rte->eref->aliasname,thisrel->relname)==0)
32313246
{
32323247
switch (rte->rtekind)

‎src/include/nodes/parsenodes.h‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -929,10 +929,10 @@ typedef struct PartitionCmd
929929
* inFromCl marks those range variables that are listed in the FROM clause.
930930
* It's false for RTEs that are added to a query behind the scenes, such
931931
* as the NEW and OLD variables for a rule, or the subqueries of a UNION.
932-
* This flag is not usedanymoreduring parsing, since the parser now uses
933-
* a separate "namespace" data structure to control visibility, but it is
934-
* needed by ruleutils.c to determine whether RTEs should be shown in
935-
* decompiled queries.
932+
* This flag is not used during parsing (except in transformLockingClause,
933+
*q.v.); the parser now usesa separate "namespace" data structure to
934+
*control visibility. But it isneeded by ruleutils.c to determine
935+
*whether RTEs should be shown indecompiled queries.
936936
*
937937
* requiredPerms and checkAsUser specify run-time access permissions
938938
* checks to be performed at query startup. The user must have *all*

‎src/test/regress/expected/rules.out‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3026,6 +3026,31 @@ select * from only t1_2;
30263026
(10 rows)
30273027

30283028
reset constraint_exclusion;
3029+
-- test FOR UPDATE in rules
3030+
create table rules_base(f1 int, f2 int);
3031+
insert into rules_base values(1,2), (11,12);
3032+
create rule r1 as on update to rules_base do instead
3033+
select * from rules_base where f1 = 1 for update;
3034+
update rules_base set f2 = f2 + 1;
3035+
f1 | f2
3036+
----+----
3037+
1 | 2
3038+
(1 row)
3039+
3040+
create or replace rule r1 as on update to rules_base do instead
3041+
select * from rules_base where f1 = 11 for update of rules_base;
3042+
update rules_base set f2 = f2 + 1;
3043+
f1 | f2
3044+
----+----
3045+
11 | 12
3046+
(1 row)
3047+
3048+
create or replace rule r1 as on update to rules_base do instead
3049+
select * from rules_base where f1 = 11 for update of old; -- error
3050+
ERROR: relation "old" in FOR UPDATE clause not found in FROM clause
3051+
LINE 2: select * from rules_base where f1 = 11 for update of old;
3052+
^
3053+
drop table rules_base;
30293054
-- test various flavors of pg_get_viewdef()
30303055
select pg_get_viewdef('shoe'::regclass) as unpretty;
30313056
unpretty

‎src/test/regress/sql/rules.sql‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,20 @@ select * from only t1_2;
992992

993993
reset constraint_exclusion;
994994

995+
-- test FOR UPDATE in rules
996+
997+
createtablerules_base(f1int, f2int);
998+
insert into rules_basevalues(1,2), (11,12);
999+
createruler1asonupdate to rules_base do instead
1000+
select*from rules_basewhere f1=1 forupdate;
1001+
update rules_baseset f2= f2+1;
1002+
create or replaceruler1asonupdate to rules_base do instead
1003+
select*from rules_basewhere f1=11 forupdate of rules_base;
1004+
update rules_baseset f2= f2+1;
1005+
create or replaceruler1asonupdate to rules_base do instead
1006+
select*from rules_basewhere f1=11 forupdate of old;-- error
1007+
droptable rules_base;
1008+
9951009
-- test various flavors of pg_get_viewdef()
9961010

9971011
select pg_get_viewdef('shoe'::regclass)as unpretty;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp