v2-0001-add-RangeTblEntry-to-CreatePolicyStmt.patch
text/x-patch
Filename: v2-0001-add-RangeTblEntry-to-CreatePolicyStmt.patch
Type: text/x-patch
Part: 1
From cfe1a262bc5d9ea5b8cd8eba6005c52b56e2ebbf Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Tue, 23 Dec 2025 09:56:30 +0800
Subject: [PATCH v2 1/3] add RangeTblEntry to CreatePolicyStmt
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Currently CreatePolicy is only directly called through parser. But imagine
copying policies from one table to another table (CREATE TABLE LIKE INCLUDING
POLICIES) or changing a column's data type (ALTER COLUMN SET DATA TYPE). In these
case, CreatePolicy will be called indirectly, either via the parser, or by
constructing a CreatePolicyStmt node from catalog metadata.
These indirectly called CreatePolicy may cause repeated lookup CreatePolicyStmt->table
RangeVar. (The relation already exists, but lookup up again via RangeVar).
Generally we should avoid look up the same less-than-fully-qualified name
multiple times, we might get different answers due to concurrent activity, and
that might create a security vulnerability, along the lines of CVE-2014-0062.
To avoid that, Add add a RangeTblEntry Node to CreatePolicyStmt, So we can
record the Relation Oid advance.
discussion: https://postgr.es/m/CACJufxE42vysVEDEmaoBGmGYLZTCgUAwh_h-c9dcSLDtD5jE3g@mail.gmail.com
discussion: https://postgr.es/m/CACJufxFuEOB-i2z2qhyCG=dGwDf7g6Fs_o8cz=BUi76UuUFSOA@mail.gmail.com
---
src/backend/commands/policy.c | 21 ++++++++++++++++-----
src/backend/parser/gram.y | 1 +
src/include/nodes/parsenodes.h | 10 ++++++++++
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 5bd5f8c9968..a47744962e9 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -623,11 +623,22 @@ CreatePolicy(CreatePolicyStmt *stmt)
memset(values, 0, sizeof(values));
memset(isnull, 0, sizeof(isnull));
- /* Get id of table. Also handles permissions checks. */
- table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock,
- 0,
- RangeVarCallbackForPolicy,
- stmt);
+ if (stmt->rte != NULL)
+ table_id = stmt->rte->relid;
+ else
+ {
+ /* Get id of table. Also handles permissions checks. */
+ table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock,
+ 0,
+ RangeVarCallbackForPolicy,
+ stmt);
+
+ /* Create a range table entry. */
+ stmt->rte = makeNode(RangeTblEntry);
+ stmt->rte->rtekind = RTE_RELATION;
+ stmt->rte->relid = table_id;
+ stmt->rte->rellockmode = AccessExclusiveLock;
+ }
/* Open target_table to build quals. No additional lock is necessary. */
target_table = relation_open(table_id, NoLock);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 28f4e11e30f..f6d46f08c22 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -6023,6 +6023,7 @@ CreatePolicyStmt:
n->policy_name = $3;
n->table = $5;
+ n->rte = NULL;
n->permissive = $6;
n->cmd_name = $7;
n->roles = $8;
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index bc7adba4a0f..7acbd2bf72c 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3094,6 +3094,16 @@ typedef struct CreatePolicyStmt
NodeTag type;
char *policy_name; /* Policy's name */
RangeVar *table; /* the table name the policy applies to */
+
+ /*
+ * RangeTblEntry for the table. This is useful for avoid repeated name
+ * lookups issue. If CreatePolicyStmt.table has been looked up, we should
+ * not rely on it to resolve the relation again, use this rte field
+ * instead. This is useful when calling CreatePolicy not directly from
+ * parser.
+ */
+ RangeTblEntry *rte;
+
char *cmd_name; /* the command name the policy applies to */
bool permissive; /* restrictive or permissive policy */
List *roles; /* the roles associated with the policy */
--
2.34.1