aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/prep/prepsecurity.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/prep/prepsecurity.c')
-rw-r--r--src/backend/optimizer/prep/prepsecurity.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/src/backend/optimizer/prep/prepsecurity.c b/src/backend/optimizer/prep/prepsecurity.c
index af3ee61bef1..08309538ffa 100644
--- a/src/backend/optimizer/prep/prepsecurity.c
+++ b/src/backend/optimizer/prep/prepsecurity.c
@@ -37,7 +37,7 @@ typedef struct
} security_barrier_replace_vars_context;
static void expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
- RangeTblEntry *rte, Node *qual);
+ RangeTblEntry *rte, Node *qual, bool targetRelation);
static void security_barrier_replace_vars(Node *node,
security_barrier_replace_vars_context *context);
@@ -63,6 +63,7 @@ expand_security_quals(PlannerInfo *root, List *tlist)
Query *parse = root->parse;
int rt_index;
ListCell *cell;
+ bool targetRelation = false;
/*
* Process each RTE in the rtable list.
@@ -98,6 +99,15 @@ expand_security_quals(PlannerInfo *root, List *tlist)
{
RangeTblEntry *newrte = copyObject(rte);
+ /*
+ * We need to let expand_security_qual know if this is the target
+ * relation, as it has additional work to do in that case.
+ *
+ * Capture that information here as we're about to replace
+ * parse->resultRelation.
+ */
+ targetRelation = true;
+
parse->rtable = lappend(parse->rtable, newrte);
parse->resultRelation = list_length(parse->rtable);
@@ -147,7 +157,8 @@ expand_security_quals(PlannerInfo *root, List *tlist)
rte->securityQuals = list_delete_first(rte->securityQuals);
ChangeVarNodes(qual, rt_index, 1, 0);
- expand_security_qual(root, tlist, rt_index, rte, qual);
+ expand_security_qual(root, tlist, rt_index, rte, qual,
+ targetRelation);
}
}
}
@@ -160,7 +171,7 @@ expand_security_quals(PlannerInfo *root, List *tlist)
*/
static void
expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
- RangeTblEntry *rte, Node *qual)
+ RangeTblEntry *rte, Node *qual, bool targetRelation)
{
Query *parse = root->parse;
Oid relid = rte->relid;
@@ -219,10 +230,11 @@ expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
* Now deal with any PlanRowMark on this RTE by requesting a lock
* of the same strength on the RTE copied down to the subquery.
*
- * Note that we can't push the user-defined quals down since they
- * may included untrusted functions and that means that we will
- * end up locking all rows which pass the securityQuals, even if
- * those rows don't pass the user-defined quals. This is
+ * Note that we can only push down user-defined quals if they are
+ * only using leakproof (and therefore trusted) functions and
+ * operators. As a result, we may end up locking more rows than
+ * strictly necessary (and, in the worst case, we could end up
+ * locking all rows which pass the securityQuals). This is
* currently documented behavior, but it'd be nice to come up with
* a better solution some day.
*/
@@ -256,6 +268,15 @@ expand_security_qual(PlannerInfo *root, List *tlist, int rt_index,
}
/*
+ * When we are replacing the target relation with a subquery, we
+ * need to make sure to add a locking clause explicitly to the
+ * generated subquery since there won't be any row marks against
+ * the target relation itself.
+ */
+ if (targetRelation)
+ applyLockingClause(subquery, 1, LCS_FORUPDATE,
+ LockWaitBlock, false);
+ /*
* Replace any variables in the outer query that refer to the
* original relation RTE with references to columns that we will
* expose in the new subquery, building the subquery's targetlist