Correctly update hasSubLinks while mutating a rule action.
rewriteRuleAction neglected to check for SubLink nodes in the securityQuals of range table entries. This could lead to failing to convert such a SubLink to a SubPlan, resulting in assertion crashes or weird errors later in planning. In passing, fix some poor coding in rewriteTargetView: we should not pass the source parsetree's hasSubLinks field to ReplaceVarsFromTargetList's outer_hasSubLinks. ReplaceVarsFromTargetList knows enough to ignore that when a Query node is passed, but it's still confusing and bad precedent: if we did try to update that flag we'd be updating a stale copy of the parsetree. Per bug #17972 from Alexander Lakhin. This has been broken since we added RangeTblEntry.securityQuals (although the presented test case only fails back to 215b43cdc), so back-patch all the way. Discussion: https://postgr.es/m/17972-f422c094237847d0@postgresql.org
This commit is contained in:
parent
edf1de65e5
commit
b4110bdbfe
@ -472,6 +472,8 @@ rewriteRuleAction(Query *parsetree,
|
||||
/* other RTE types don't contain bare expressions */
|
||||
break;
|
||||
}
|
||||
sub_action->hasSubLinks |=
|
||||
checkExprHasSubLink((Node *) rte->securityQuals);
|
||||
if (sub_action->hasSubLinks)
|
||||
break; /* no need to keep scanning rtable */
|
||||
}
|
||||
@ -3304,7 +3306,7 @@ rewriteTargetView(Query *parsetree, Relation view)
|
||||
view_targetlist,
|
||||
REPLACEVARS_REPORT_ERROR,
|
||||
0,
|
||||
&parsetree->hasSubLinks);
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* Update all other RTI references in the query that point to the view
|
||||
|
@ -2616,6 +2616,38 @@ DROP VIEW v1;
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t1;
|
||||
--
|
||||
-- Test sub-select in nested security barrier views, per bug #17972
|
||||
--
|
||||
CREATE TABLE t1 (a int);
|
||||
CREATE VIEW v1 WITH (security_barrier = true) AS
|
||||
SELECT * FROM t1;
|
||||
CREATE RULE v1_upd_rule AS ON UPDATE TO v1 DO INSTEAD
|
||||
UPDATE t1 SET a = NEW.a WHERE a = OLD.a;
|
||||
CREATE VIEW v2 WITH (security_barrier = true) AS
|
||||
SELECT * FROM v1 WHERE EXISTS (SELECT 1);
|
||||
EXPLAIN (COSTS OFF) UPDATE v2 SET a = 1;
|
||||
QUERY PLAN
|
||||
---------------------------------------------------
|
||||
Update on t1
|
||||
InitPlan 1 (returns $0)
|
||||
-> Result
|
||||
-> Merge Join
|
||||
Merge Cond: (t1.a = v1.a)
|
||||
-> Sort
|
||||
Sort Key: t1.a
|
||||
-> Seq Scan on t1
|
||||
-> Sort
|
||||
Sort Key: v1.a
|
||||
-> Subquery Scan on v1
|
||||
-> Result
|
||||
One-Time Filter: $0
|
||||
-> Seq Scan on t1 t1_1
|
||||
(14 rows)
|
||||
|
||||
DROP VIEW v2;
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
--
|
||||
-- Test CREATE OR REPLACE VIEW turning a non-updatable view into an
|
||||
-- auto-updatable view and adding check options in a single step
|
||||
--
|
||||
|
@ -1243,6 +1243,23 @@ DROP VIEW v1;
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t1;
|
||||
|
||||
--
|
||||
-- Test sub-select in nested security barrier views, per bug #17972
|
||||
--
|
||||
CREATE TABLE t1 (a int);
|
||||
CREATE VIEW v1 WITH (security_barrier = true) AS
|
||||
SELECT * FROM t1;
|
||||
CREATE RULE v1_upd_rule AS ON UPDATE TO v1 DO INSTEAD
|
||||
UPDATE t1 SET a = NEW.a WHERE a = OLD.a;
|
||||
CREATE VIEW v2 WITH (security_barrier = true) AS
|
||||
SELECT * FROM v1 WHERE EXISTS (SELECT 1);
|
||||
|
||||
EXPLAIN (COSTS OFF) UPDATE v2 SET a = 1;
|
||||
|
||||
DROP VIEW v2;
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--
|
||||
-- Test CREATE OR REPLACE VIEW turning a non-updatable view into an
|
||||
-- auto-updatable view and adding check options in a single step
|
||||
|
Loading…
x
Reference in New Issue
Block a user