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

Commit7fa367d

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 parentecd4dd9 commit7fa367d

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
@@ -2753,13 +2753,22 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
27532753

27542754
if (lockedRels==NIL)
27552755
{
2756-
/* all regular tables used in query */
2756+
/*
2757+
* Lock all regular tables used in query and its subqueries. We
2758+
* examine inFromCl to exclude auto-added RTEs, particularly NEW/OLD
2759+
* in rules. This is a bit of an abuse of a mostly-obsolete flag, but
2760+
* it's convenient. We can't rely on the namespace mechanism that has
2761+
* largely replaced inFromCl, since for example we need to lock
2762+
* base-relation RTEs even if they are masked by upper joins.
2763+
*/
27572764
i=0;
27582765
foreach(rt,qry->rtable)
27592766
{
27602767
RangeTblEntry*rte= (RangeTblEntry*)lfirst(rt);
27612768

27622769
++i;
2770+
if (!rte->inFromCl)
2771+
continue;
27632772
switch (rte->rtekind)
27642773
{
27652774
caseRTE_RELATION:
@@ -2789,7 +2798,11 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
27892798
}
27902799
else
27912800
{
2792-
/* just the named tables */
2801+
/*
2802+
* Lock just the named tables. As above, we allow locking any base
2803+
* relation regardless of alias-visibility rules, so we need to
2804+
* examine inFromCl to exclude OLD/NEW.
2805+
*/
27932806
foreach(l,lockedRels)
27942807
{
27952808
RangeVar*thisrel= (RangeVar*)lfirst(l);
@@ -2810,6 +2823,8 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
28102823
RangeTblEntry*rte= (RangeTblEntry*)lfirst(rt);
28112824

28122825
++i;
2826+
if (!rte->inFromCl)
2827+
continue;
28132828
if (strcmp(rte->eref->aliasname,thisrel->relname)==0)
28142829
{
28152830
switch (rte->rtekind)

‎src/include/nodes/parsenodes.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -915,10 +915,10 @@ typedef struct PartitionCmd
915915
* inFromCl marks those range variables that are listed in the FROM clause.
916916
* It's false for RTEs that are added to a query behind the scenes, such
917917
* as the NEW and OLD variables for a rule, or the subqueries of a UNION.
918-
* This flag is not usedanymoreduring parsing, since the parser now uses
919-
* a separate "namespace" data structure to control visibility, but it is
920-
* needed by ruleutils.c to determine whether RTEs should be shown in
921-
* decompiled queries.
918+
* This flag is not used during parsing (except in transformLockingClause,
919+
*q.v.); the parser now usesa separate "namespace" data structure to
920+
*control visibility. But it isneeded by ruleutils.c to determine
921+
*whether RTEs should be shown indecompiled queries.
922922
*
923923
* requiredPerms and checkAsUser specify run-time access permissions
924924
* 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
@@ -2887,6 +2887,31 @@ select * from only t1_2;
28872887
(10 rows)
28882888

28892889
reset constraint_exclusion;
2890+
-- test FOR UPDATE in rules
2891+
create table rules_base(f1 int, f2 int);
2892+
insert into rules_base values(1,2), (11,12);
2893+
create rule r1 as on update to rules_base do instead
2894+
select * from rules_base where f1 = 1 for update;
2895+
update rules_base set f2 = f2 + 1;
2896+
f1 | f2
2897+
----+----
2898+
1 | 2
2899+
(1 row)
2900+
2901+
create or replace rule r1 as on update to rules_base do instead
2902+
select * from rules_base where f1 = 11 for update of rules_base;
2903+
update rules_base set f2 = f2 + 1;
2904+
f1 | f2
2905+
----+----
2906+
11 | 12
2907+
(1 row)
2908+
2909+
create or replace rule r1 as on update to rules_base do instead
2910+
select * from rules_base where f1 = 11 for update of old; -- error
2911+
ERROR: relation "old" in FOR UPDATE clause not found in FROM clause
2912+
LINE 2: select * from rules_base where f1 = 11 for update of old;
2913+
^
2914+
drop table rules_base;
28902915
-- test various flavors of pg_get_viewdef()
28912916
select pg_get_viewdef('shoe'::regclass) as unpretty;
28922917
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