agora inbox for pgsql-hackers@postgresql.org  
help / color / mirror / Atom feed
[PATCH] Asymmetric partitionwise join.
327+ messages / 3 participants
[nested] [flat]

* [PATCH] Asymmetric partitionwise join.
@ 2021-04-02 06:02  Andrey Lepikhov <a.lepikhov@postgrespro.ru>
  0 siblings, 0 replies; 327+ messages in thread

From: Andrey Lepikhov @ 2021-04-02 06:02 UTC (permalink / raw)

Teach optimizer to consider partitionwise join of non-partitioned
table with each partition of partitioned table.

Disallow asymmetric machinery for joining of two partitioned (or appended)
relations because it could cause huge consumption of CPU and memory
during reparameterization of NestLoop path.

Change logic of the multilevel child relids adjustment, because this
feature allows the optimizer to plan in new way.
---
 src/backend/optimizer/path/joinpath.c        |   9 +
 src/backend/optimizer/path/joinrels.c        | 187 +++++++++
 src/backend/optimizer/plan/setrefs.c         |  17 +-
 src/backend/optimizer/util/appendinfo.c      |  51 ++-
 src/backend/optimizer/util/pathnode.c        |   9 +-
 src/backend/optimizer/util/relnode.c         |  19 +-
 src/include/optimizer/paths.h                |   7 +-
 src/test/regress/expected/partition_join.out | 378 +++++++++++++++++++
 src/test/regress/sql/partition_join.sql      | 167 ++++++++
 9 files changed, 808 insertions(+), 36 deletions(-)

diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 6407ede12a..32618ebbd5 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -335,6 +335,15 @@ add_paths_to_joinrel(PlannerInfo *root,
 	if (set_join_pathlist_hook)
 		set_join_pathlist_hook(root, joinrel, outerrel, innerrel,
 							   jointype, &extra);
+
+	/*
+	 * 7. If outer relation is delivered from partition-tables, consider
+	 * distributing inner relation to every partition-leaf prior to
+	 * append these leafs.
+	 */
+	try_asymmetric_partitionwise_join(root, joinrel,
+									  outerrel, innerrel,
+									  jointype, &extra);
 }
 
 /*
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 8b69870cf4..9453258f83 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -16,6 +16,7 @@
 
 #include "miscadmin.h"
 #include "optimizer/appendinfo.h"
+#include "optimizer/cost.h"
 #include "optimizer/joininfo.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
@@ -1552,6 +1553,192 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
 	}
 }
 
+/*
+ * Build RelOptInfo on JOIN of each partition of the outer relation and the inner
+ * relation. Return List of such RelOptInfo's. Return NIL, if at least one of
+ * these JOINs is impossible to build.
+ */
+static List *
+extract_asymmetric_partitionwise_subjoin(PlannerInfo *root,
+										 RelOptInfo *joinrel,
+										 AppendPath *append_path,
+										 RelOptInfo *inner_rel,
+										 JoinType jointype,
+										 JoinPathExtraData *extra)
+{
+	List		*result = NIL;
+	ListCell	*lc;
+
+	foreach (lc, append_path->subpaths)
+	{
+		Path			*child_path = lfirst(lc);
+		RelOptInfo		*child_rel = child_path->parent;
+		Relids			child_joinrelids;
+		Relids			parent_relids;
+		RelOptInfo		*child_joinrel;
+		SpecialJoinInfo	*child_sjinfo;
+		List			*child_restrictlist;
+
+		child_joinrelids = bms_union(child_rel->relids, inner_rel->relids);
+		parent_relids = bms_union(append_path->path.parent->relids,
+								  inner_rel->relids);
+
+		child_sjinfo = build_child_join_sjinfo(root, extra->sjinfo,
+											   child_rel->relids,
+											   inner_rel->relids);
+		child_restrictlist = (List *)
+			adjust_appendrel_attrs_multilevel(root, (Node *)extra->restrictlist,
+											  child_joinrelids, parent_relids);
+
+		child_joinrel = find_join_rel(root, child_joinrelids);
+		if (!child_joinrel)
+			child_joinrel = build_child_join_rel(root,
+												 child_rel,
+												 inner_rel,
+												 joinrel,
+												 child_restrictlist,
+												 child_sjinfo,
+												 jointype);
+		else
+		{
+			/*
+			 * The join relation already exists. For example, it could happen if
+			 * we join two plane tables with partitioned table(s).
+			 * Populating this join with additional paths could push out some
+			 * previously added paths which could be pointed in a subplans list
+			 * of an higher level append.
+			 * Of course, we could save such paths before generating new. But it
+			 * can increase too much the number of paths in complex queries. It
+			 * can be a task for future work.
+			 */
+			return NIL;
+		}
+
+		populate_joinrel_with_paths(root,
+									child_rel,
+									inner_rel,
+									child_joinrel,
+									child_sjinfo,
+									child_restrictlist);
+
+		/* Give up if asymmetric partition-wise join is not available */
+		if (child_joinrel->pathlist == NIL)
+			return NIL;
+
+		set_cheapest(child_joinrel);
+		result = lappend(result, child_joinrel);
+	}
+	return result;
+}
+
+static bool
+is_asymmetric_join_feasible(PlannerInfo *root,
+						   RelOptInfo *outer_rel,
+						   RelOptInfo *inner_rel,
+						   JoinType jointype)
+{
+	ListCell *lc;
+
+	if (jointype != JOIN_INNER && jointype != JOIN_LEFT)
+		return false;
+
+	if (IS_OTHER_REL(outer_rel) || IS_OTHER_REL(inner_rel))
+		return false;
+
+	/* Disallow recursive usage of asymmertic join machinery */
+	if (root->join_rel_level == NULL)
+		return false;
+
+	/*
+	 * Don't allow asymmetric JOIN of two append subplans.
+	 * In the case of a parameterized NL join, a reparameterization procedure
+	 * will lead to large memory allocations and a CPU consumption:
+	 * each reparameterization will induce subpath duplication, creating new
+	 * ParamPathInfo instance and increasing of ppilist up to number of
+	 * partitions in the inner. Also, if we have many partitions, each bitmapset
+	 * variable will be large and many leaks of such variable (caused by relid
+	 * replacement) will highly increase memory consumption.
+	 * So, we deny such paths for now.
+	 */
+	foreach(lc, inner_rel->pathlist)
+	{
+		if (IsA(lfirst(lc), AppendPath))
+			return false;
+	}
+
+	return true;
+}
+
+void
+try_asymmetric_partitionwise_join(PlannerInfo *root,
+								  RelOptInfo *joinrel,
+								  RelOptInfo *outer_rel,
+								  RelOptInfo *inner_rel,
+								  JoinType jointype,
+								  JoinPathExtraData *extra)
+{
+	ListCell *lc;
+
+	/*
+	 * Try this kind of paths if we allow complex partitionwise joins and we know
+	 * we can build this join safely.
+	 */
+	if (!enable_partitionwise_join ||
+		!is_asymmetric_join_feasible(root, outer_rel, inner_rel, jointype))
+		return;
+
+	foreach (lc, outer_rel->pathlist)
+	{
+		AppendPath *append_path = lfirst(lc);
+
+		/*
+		 * We assume this pathlist keeps at least one AppendPath that
+		 * represents partitioned table-scan, symmetric or asymmetric
+		 * partition-wise join. Asymmetric join isn't needed if the append node
+		 * has only one child.
+		 */
+		if (IsA(append_path, AppendPath) &&
+			list_length(append_path->subpaths) > 1)
+		{
+			List **join_rel_level_saved;
+			List *live_childrels = NIL;
+
+			join_rel_level_saved = root->join_rel_level;
+			PG_TRY();
+			{
+				/* temporary disables "dynamic programming" algorithm */
+				root->join_rel_level = NULL;
+
+				live_childrels =
+					extract_asymmetric_partitionwise_subjoin(root,
+															 joinrel,
+															 append_path,
+															 inner_rel,
+															 jointype,
+															 extra);
+			}
+			PG_FINALLY();
+			{
+				root->join_rel_level = join_rel_level_saved;
+			}
+			PG_END_TRY();
+
+			if (live_childrels != NIL)
+			{
+				/*
+				 * Add new append relation. We must choose cheapest paths after
+				 * this operation because the pathlist possibly contains
+				 * joinrels and appendrels that can be suboptimal.
+				 */
+				add_paths_to_append_rel(root, joinrel, live_childrels);
+				set_cheapest(joinrel);
+			}
+
+			break;
+		}
+	}
+}
+
 /*
  * Construct the SpecialJoinInfo for a child-join by translating
  * SpecialJoinInfo for the join between parents. left_relids and right_relids
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index e50624c465..fccc0685d7 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -281,24 +281,29 @@ set_plan_references(PlannerInfo *root, Plan *plan)
 
 	/*
 	 * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
-	 * We assume the AppendRelInfos were built during planning and don't need
-	 * to be copied.
+	 * The AppendRelInfos are copied, because as a part of a subplan they could
+	 * be visited many times in the case of asymmetric join.
 	 */
 	foreach(lc, root->append_rel_list)
 	{
 		AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
+		AppendRelInfo *newappinfo;
+
+		/* flat copy is enough since all valuable fields are scalars */
+		newappinfo = (AppendRelInfo *) palloc(sizeof(AppendRelInfo));
+		memcpy(newappinfo, appinfo, sizeof(AppendRelInfo));
 
 		/* adjust RT indexes */
-		appinfo->parent_relid += rtoffset;
-		appinfo->child_relid += rtoffset;
+		newappinfo->parent_relid += rtoffset;
+		newappinfo->child_relid += rtoffset;
 
 		/*
 		 * Rather than adjust the translated_vars entries, just drop 'em.
 		 * Neither the executor nor EXPLAIN currently need that data.
 		 */
-		appinfo->translated_vars = NIL;
+		newappinfo->translated_vars = NIL;
 
-		glob->appendRelations = lappend(glob->appendRelations, appinfo);
+		glob->appendRelations = lappend(glob->appendRelations, newappinfo);
 	}
 
 	/* Now fix the Plan tree */
diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c
index af46f581ac..3ae25f3444 100644
--- a/src/backend/optimizer/util/appendinfo.c
+++ b/src/backend/optimizer/util/appendinfo.c
@@ -202,7 +202,9 @@ adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos,
 	context.appinfos = appinfos;
 
 	/* If there's nothing to adjust, don't call this function. */
-	Assert(nappinfos >= 1 && appinfos != NULL);
+	/* If there's nothing to adjust, just return a duplication */
+	if (nappinfos == 0)
+		return copyObject(node);
 
 	/* Should never be translating a Query tree. */
 	Assert(node == NULL || !IsA(node, Query));
@@ -489,12 +491,10 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
 								  Relids child_relids,
 								  Relids top_parent_relids)
 {
-	AppendRelInfo **appinfos;
-	Bitmapset  *parent_relids = NULL;
-	int			nappinfos;
-	int			cnt;
-
-	Assert(bms_num_members(child_relids) == bms_num_members(top_parent_relids));
+	AppendRelInfo	**appinfos;
+	Relids			parent_relids = NULL;
+	int				nappinfos;
+	int				cnt;
 
 	appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
 
@@ -506,8 +506,13 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
 		parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
 	}
 
-	/* Recurse if immediate parent is not the top parent. */
-	if (!bms_equal(parent_relids, top_parent_relids))
+	/*
+	 * Recurse if immediate parent is not the top parent. Keep in mind that in a
+	 * case of asymmetric JOIN top_parent_relids can contain relids which aren't
+	 * part of an append node.
+	 */
+	if (!bms_equal(parent_relids, top_parent_relids) &&
+		!bms_is_subset(parent_relids, top_parent_relids))
 		node = adjust_appendrel_attrs_multilevel(root, node, parent_relids,
 												 top_parent_relids);
 
@@ -515,12 +520,13 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
 	node = adjust_appendrel_attrs(root, node, nappinfos, appinfos);
 
 	pfree(appinfos);
+	pfree(parent_relids);
 
 	return node;
 }
 
 /*
- * Substitute child relids for parent relids in a Relid set.  The array of
+ * Substitute child relids for parent relids in a Relid set. The array of
  * appinfos specifies the substitutions to be performed.
  */
 Relids
@@ -565,8 +571,9 @@ adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
 	AppendRelInfo **appinfos;
 	int			nappinfos;
 	Relids		parent_relids = NULL;
+	Relids		normal_relids = NULL;
 	Relids		result;
-	Relids		tmp_result = NULL;
+	Relids		tmp_result = relids;
 	int			cnt;
 
 	/*
@@ -579,12 +586,17 @@ adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
 	appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
 
 	/* Construct relids set for the immediate parent of the given child. */
+	normal_relids = bms_copy(child_relids);
 	for (cnt = 0; cnt < nappinfos; cnt++)
 	{
 		AppendRelInfo *appinfo = appinfos[cnt];
 
 		parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
+		normal_relids = bms_del_member(normal_relids, appinfo->child_relid);
 	}
+	parent_relids = bms_union(parent_relids, normal_relids);
+	if (normal_relids)
+		bms_free(normal_relids);
 
 	/* Recurse if immediate parent is not the top parent. */
 	if (!bms_equal(parent_relids, top_parent_relids))
@@ -592,13 +604,15 @@ adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
 		tmp_result = adjust_child_relids_multilevel(root, relids,
 													parent_relids,
 													top_parent_relids);
-		relids = tmp_result;
 	}
 
-	result = adjust_child_relids(relids, nappinfos, appinfos);
+	result = adjust_child_relids(tmp_result, nappinfos, appinfos);
 
-	/* Free memory consumed by any intermediate result. */
-	if (tmp_result)
+	/*
+	 * Free memory consumed by any intermediate result. If recursive pass did't
+	 * replace any relids, tmp_result point to the original set, not a copy.
+	 */
+	if (tmp_result != relids)
 		bms_free(tmp_result);
 	bms_free(parent_relids);
 	pfree(appinfos);
@@ -715,11 +729,11 @@ AppendRelInfo **
 find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
 {
 	AppendRelInfo **appinfos;
+	int			nrooms = bms_num_members(relids);
 	int			cnt = 0;
 	int			i;
 
-	*nappinfos = bms_num_members(relids);
-	appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
+	appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * nrooms);
 
 	i = -1;
 	while ((i = bms_next_member(relids, i)) >= 0)
@@ -727,10 +741,11 @@ find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
 		AppendRelInfo *appinfo = root->append_rel_array[i];
 
 		if (!appinfo)
-			elog(ERROR, "child rel %d not found in append_rel_array", i);
+			continue;
 
 		appinfos[cnt++] = appinfo;
 	}
+	*nappinfos = cnt;
 	return appinfos;
 }
 
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index cedb3848dd..17e215b72d 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -4225,7 +4225,14 @@ do { \
 
 		MemoryContextSwitchTo(oldcontext);
 	}
-	bms_free(required_outer);
+
+	/*
+	 * If adjust_child_relids_multilevel don't do replacements it returns
+	 * the original set, not a copy. It is possible in the case of asymmetric
+	 * JOIN and child_rel->relids contains relids only of plane relations.
+	 */
+	if (required_outer != old_ppi->ppi_req_outer)
+		bms_free(required_outer);
 
 	new_path->param_info = new_ppi;
 
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 47769cea45..ddf0f5a876 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -792,11 +792,8 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
 	AppendRelInfo **appinfos;
 	int			nappinfos;
 
-	/* Only joins between "other" relations land here. */
-	Assert(IS_OTHER_REL(outer_rel) && IS_OTHER_REL(inner_rel));
-
-	/* The parent joinrel should have consider_partitionwise_join set. */
-	Assert(parent_joinrel->consider_partitionwise_join);
+	/* Either of relations must be "other" relation at least. */
+	Assert(IS_OTHER_REL(outer_rel) || IS_OTHER_REL(inner_rel));
 
 	joinrel->reloptkind = RELOPT_OTHER_JOINREL;
 	joinrel->relids = bms_union(outer_rel->relids, inner_rel->relids);
@@ -854,8 +851,11 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
 	joinrel->partexprs = NULL;
 	joinrel->nullable_partexprs = NULL;
 
-	joinrel->top_parent_relids = bms_union(outer_rel->top_parent_relids,
-										   inner_rel->top_parent_relids);
+	joinrel->top_parent_relids =
+		bms_union(IS_OTHER_REL(outer_rel) ?
+				  outer_rel->top_parent_relids : outer_rel->relids,
+				  IS_OTHER_REL(inner_rel) ?
+				  inner_rel->top_parent_relids : inner_rel->relids);
 
 	/* Compute information relevant to foreign relations. */
 	set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
@@ -2036,9 +2036,8 @@ build_child_join_reltarget(PlannerInfo *root,
 {
 	/* Build the targetlist */
 	childrel->reltarget->exprs = (List *)
-		adjust_appendrel_attrs(root,
-							   (Node *) parentrel->reltarget->exprs,
-							   nappinfos, appinfos);
+		adjust_appendrel_attrs_multilevel(root, (Node *)parentrel->reltarget->exprs,
+										childrel->relids, parentrel->relids);
 
 	/* Set the cost and width fields */
 	childrel->reltarget->cost.startup = parentrel->reltarget->cost.startup;
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index f1d111063c..a0106dc539 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -109,7 +109,12 @@ extern bool have_join_order_restriction(PlannerInfo *root,
 extern bool have_dangerous_phv(PlannerInfo *root,
 							   Relids outer_relids, Relids inner_params);
 extern void mark_dummy_rel(RelOptInfo *rel);
-
+extern void try_asymmetric_partitionwise_join(PlannerInfo *root,
+											  RelOptInfo *joinrel,
+											  RelOptInfo *outer_rel,
+											  RelOptInfo *inner_rel,
+											  JoinType jointype,
+											  JoinPathExtraData *extra);
 /*
  * equivclass.c
  *	  routines for managing EquivalenceClasses
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index 27f7525b3e..327505676c 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -2320,6 +2320,384 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a =
  375 | 0375 | 375 | 0375
 (8 rows)
 
+--
+-- For asymmetric partition-wise join
+--
+CREATE TABLE prt5 (hkey int, a int, b int) PARTITION BY HASH(hkey);
+CREATE TABLE prt5_p0 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 0);
+CREATE TABLE prt5_p1 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 1);
+CREATE TABLE prt5_p2 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 2);
+CREATE TABLE prt6 (aid int, alabel text) PARTITION BY HASH(aid);
+CREATE TABLE prt6_p0 PARTITION OF prt6
+                     FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prt6_p1 PARTITION OF prt6
+                     FOR VALUES WITH (modulus 2, remainder 1);
+CREATE TABLE t5_1 (aid int, alabel text);
+CREATE TABLE t5_2 (bid int, blabel text);
+INSERT INTO prt5 (SELECT x, (x % 1000)::int,
+                            ((x+1) % 1000)::int
+                    FROM generate_series(1,1000000) x);
+INSERT INTO t5_1 (SELECT x, md5(x::text) FROM generate_series(-200, 1500) x);
+INSERT INTO t5_2 (SELECT x, md5(x::text) FROM generate_series(-200, 1500) x);
+INSERT INTO prt6 (SELECT * FROM t5_1);
+VACUUM ANALYZE prt5,prt6,t5_1,t5_2;
+SET max_parallel_workers_per_gather = 0;
+-- Trivial asymmetric JOIN of partitioned table with a relation
+EXPLAIN (COSTS OFF)
+SELECT *
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                      QUERY PLAN                       
+-------------------------------------------------------
+ Append
+   ->  Hash Join
+         Hash Cond: (prt5_1.a = t5_1.aid)
+         ->  Seq Scan on prt5_p0 prt5_1
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_2.a = t5_1.aid)
+         ->  Seq Scan on prt5_p1 prt5_2
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_3.a = t5_1.aid)
+         ->  Seq Scan on prt5_p2 prt5_3
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+(19 rows)
+
+-- The same, but appended with UNION ALL
+EXPLAIN (COSTS OFF)
+SELECT * FROM (
+	(SELECT * FROM prt5_p0)
+	UNION ALL
+	(SELECT * FROM prt5_p1)
+	UNION ALL
+	(SELECT * FROM prt5_p2)
+	) AS sq1
+JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                      QUERY PLAN                       
+-------------------------------------------------------
+ Append
+   ->  Hash Join
+         Hash Cond: (prt5_p0.a = t5_1.aid)
+         ->  Seq Scan on prt5_p0
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_p1.a = t5_1.aid)
+         ->  Seq Scan on prt5_p1
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_p2.a = t5_1.aid)
+         ->  Seq Scan on prt5_p2
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+(19 rows)
+
+-- Don't allow asymmetric JOIN of two partitioned tables.
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM prt5 JOIN prt6 ON a = aid AND alabel like '%abc%';
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Aggregate
+   ->  Hash Join
+         Hash Cond: (prt5.a = prt6.aid)
+         ->  Append
+               ->  Seq Scan on prt5_p0 prt5_1
+               ->  Seq Scan on prt5_p1 prt5_2
+               ->  Seq Scan on prt5_p2 prt5_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt6_p0 prt6_1
+                           Filter: (alabel ~~ '%abc%'::text)
+                     ->  Seq Scan on prt6_p1 prt6_2
+                           Filter: (alabel ~~ '%abc%'::text)
+(13 rows)
+
+SELECT count(*) FROM prt5 JOIN prt6 ON a = aid AND alabel like '%abc%';
+ count 
+-------
+  4000
+(1 row)
+
+-- Check asymmetric JOIN with Subquery
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM prt5 JOIN (
+	SELECT * FROM prt6 LIMIT 1000
+) AS sq1 ON a = aid AND alabel like '%abc%';
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ Aggregate
+   ->  Append
+         ->  Hash Join
+               Hash Cond: (prt5_1.a = sq1.aid)
+               ->  Seq Scan on prt5_p0 prt5_1
+               ->  Hash
+                     ->  Subquery Scan on sq1
+                           Filter: (sq1.alabel ~~ '%abc%'::text)
+                           ->  Limit
+                                 ->  Append
+                                       ->  Seq Scan on prt6_p0 prt6_1
+                                       ->  Seq Scan on prt6_p1 prt6_2
+         ->  Hash Join
+               Hash Cond: (prt5_2.a = sq1.aid)
+               ->  Seq Scan on prt5_p1 prt5_2
+               ->  Hash
+                     ->  Subquery Scan on sq1
+                           Filter: (sq1.alabel ~~ '%abc%'::text)
+                           ->  Limit
+                                 ->  Append
+                                       ->  Seq Scan on prt6_p0 prt6_4
+                                       ->  Seq Scan on prt6_p1 prt6_5
+         ->  Hash Join
+               Hash Cond: (prt5_3.a = sq1.aid)
+               ->  Seq Scan on prt5_p2 prt5_3
+               ->  Hash
+                     ->  Subquery Scan on sq1
+                           Filter: (sq1.alabel ~~ '%abc%'::text)
+                           ->  Limit
+                                 ->  Append
+                                       ->  Seq Scan on prt6_p0 prt6_7
+                                       ->  Seq Scan on prt6_p1 prt6_8
+(32 rows)
+
+SELECT count(*) FROM prt5 JOIN (SELECT * FROM prt6 LIMIT 1000) AS sq1
+	ON a = aid AND alabel like '%abc%';
+ count 
+-------
+  2000
+(1 row)
+
+-- Asymmetric JOIN of two plane tables and one partitioned
+EXPLAIN (COSTS OFF)
+SELECT count(*)
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Aggregate
+   ->  Append
+         ->  Hash Join
+               Hash Cond: (prt5_1.b = t5_2.bid)
+               ->  Hash Join
+                     Hash Cond: (prt5_1.a = t5_1.aid)
+                     ->  Seq Scan on prt5_p0 prt5_1
+                     ->  Hash
+                           ->  Seq Scan on t5_1
+                                 Filter: (alabel ~~ '%ab%'::text)
+               ->  Hash
+                     ->  Seq Scan on t5_2
+                           Filter: (blabel ~~ '%cd%'::text)
+         ->  Hash Join
+               Hash Cond: (prt5_2.b = t5_2.bid)
+               ->  Hash Join
+                     Hash Cond: (prt5_2.a = t5_1.aid)
+                     ->  Seq Scan on prt5_p1 prt5_2
+                     ->  Hash
+                           ->  Seq Scan on t5_1
+                                 Filter: (alabel ~~ '%ab%'::text)
+               ->  Hash
+                     ->  Seq Scan on t5_2
+                           Filter: (blabel ~~ '%cd%'::text)
+         ->  Hash Join
+               Hash Cond: (prt5_3.b = t5_2.bid)
+               ->  Hash Join
+                     Hash Cond: (prt5_3.a = t5_1.aid)
+                     ->  Seq Scan on prt5_p2 prt5_3
+                     ->  Hash
+                           ->  Seq Scan on t5_1
+                                 Filter: (alabel ~~ '%ab%'::text)
+               ->  Hash
+                     ->  Seq Scan on t5_2
+                           Filter: (blabel ~~ '%cd%'::text)
+(35 rows)
+
+SELECT count(*)
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+ count 
+-------
+ 11000
+(1 row)
+
+-- unable to extract non-partitioned right relation
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 RIGHT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                  QUERY PLAN                   
+-----------------------------------------------
+ Hash Right Join
+   Hash Cond: (prt5.a = t5_1.aid)
+   Join Filter: (t5_1.alabel ~~ '%abc%'::text)
+   ->  Append
+         ->  Seq Scan on prt5_p0 prt5_1
+         ->  Seq Scan on prt5_p1 prt5_2
+         ->  Seq Scan on prt5_p2 prt5_3
+   ->  Hash
+         ->  Seq Scan on t5_1
+(9 rows)
+
+-- left side can be extracted, but no cost benefit
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 LEFT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Hash Left Join
+   Hash Cond: (prt5.a = t5_1.aid)
+   ->  Append
+         ->  Seq Scan on prt5_p0 prt5_1
+         ->  Seq Scan on prt5_p1 prt5_2
+         ->  Seq Scan on prt5_p2 prt5_3
+   ->  Hash
+         ->  Seq Scan on t5_1
+               Filter: (alabel ~~ '%abc%'::text)
+(9 rows)
+
+-- validation of the results with/without asymmetric partition-wise join
+SELECT * INTO pg_temp.result01a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+SELECT * INTO pg_temp.result02a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+SET enable_partitionwise_join = off;
+SELECT * INTO pg_temp.result01b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+SELECT * INTO pg_temp.result02b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+SELECT * FROM pg_temp.result01a EXCEPT SELECT * FROM pg_temp.result01b;
+ hkey | a | b | aid | alabel 
+------+---+---+-----+--------
+(0 rows)
+
+SELECT * FROM pg_temp.result02a EXCEPT SELECT * FROM pg_temp.result02b;
+ hkey | a | b | aid | alabel | bid | blabel 
+------+---+---+-----+--------+-----+--------
+(0 rows)
+
+SET enable_partitionwise_join = on;
+-- Check reparameterization code when required_outer set contains relid of plain
+-- relation entry, not 'other' entry.
+SET enable_hashjoin = 'off';
+SET enable_mergejoin = 'off';
+SET enable_material = 'off';
+CREATE TABLE big AS SELECT x AS x FROM generate_series(1,1E4) x;
+CREATE INDEX ON big(x);
+CREATE TABLE small AS SELECT x, -x AS y FROM generate_series(1,100) x;
+CREATE TABLE part_l0 (x int, y int, z int) PARTITION BY HASH (y);
+CREATE TABLE part0_l1 PARTITION OF part_l0 (y)
+	FOR VALUES WITH (modulus 2, remainder 0) PARTITION BY HASH (z);
+CREATE TABLE part0_l2 PARTITION OF part0_l1 (z)
+	FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE part1_l2 PARTITION OF part0_l1 (z)
+	FOR VALUES WITH (modulus 2, remainder 1);
+CREATE TABLE part1_l1 PARTITION OF part_l0 (y)
+	FOR VALUES WITH (modulus 2, remainder 1);
+INSERT INTO part_l0 (x, y, z) (SELECT x,x,x FROM generate_series(1,1E4) x);
+ANALYZE big,small,part_l0;
+EXPLAIN
+SELECT small.* FROM small
+	JOIN part_l0 ON small.y = part_l0.y AND small.y + part_l0.y < 10
+	LEFT JOIN big ON big.x = small.x;
+                                       QUERY PLAN                                        
+-----------------------------------------------------------------------------------------
+ Nested Loop Left Join  (cost=0.29..33230.19 rows=33 width=8)
+   ->  Append  (cost=0.00..33008.08 rows=67 width=8)
+         ->  Nested Loop  (cost=0.00..16604.25 rows=33 width=8)
+               Join Filter: ((small.y = part_l0_1.y) AND ((small.y + part_l0_1.y) < 10))
+               ->  Seq Scan on small  (cost=0.00..2.00 rows=100 width=8)
+               ->  Seq Scan on part0_l2 part_l0_1  (cost=0.00..78.19 rows=5019 width=4)
+         ->  Nested Loop  (cost=0.00..3.75 rows=1 width=8)
+               Join Filter: ((small.y = part_l0_2.y) AND ((small.y + part_l0_2.y) < 10))
+               ->  Seq Scan on part1_l2 part_l0_2  (cost=0.00..0.00 rows=1 width=4)
+               ->  Seq Scan on small  (cost=0.00..2.00 rows=100 width=8)
+         ->  Nested Loop  (cost=0.00..16399.75 rows=33 width=8)
+               Join Filter: ((small.y = part_l0_3.y) AND ((small.y + part_l0_3.y) < 10))
+               ->  Seq Scan on small  (cost=0.00..2.00 rows=100 width=8)
+               ->  Seq Scan on part1_l1 part_l0_3  (cost=0.00..76.81 rows=4981 width=4)
+   ->  Index Only Scan using big_x_idx on big  (cost=0.29..3.31 rows=1 width=5)
+         Index Cond: (x = (small.x)::numeric)
+(16 rows)
+
+DROP TABLE IF EXISTS big,small,part_l0 CASCADE;
+RESET enable_hashjoin;
+RESET enable_mergejoin;
+RESET enable_material;
+RESET max_parallel_workers_per_gather;
+-- Parameterized path examples.
+CREATE TABLE prta (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prta1 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prta2 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prta1 (id);
+CREATE UNIQUE INDEX ON prta2 (id);
+INSERT INTO prta (id, payload)
+	(SELECT *, ('abc' || id)::text AS payload
+		FROM generate_series(1,1) AS id);
+CREATE TABLE prtb (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prtb1 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prtb2 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prtb1 (id);
+CREATE UNIQUE INDEX ON prtb2 (id);
+INSERT INTO prtb (id, payload)
+    (SELECT *, ('def' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+CREATE TABLE e (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE e1 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE e2 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 1);
+INSERT INTO e (id, payload)
+	(SELECT *, ('ghi' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+CREATE UNIQUE INDEX ON e1 (id);
+CREATE UNIQUE INDEX ON e2 (id);
+ANALYZE prta,prtb,e;
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb WHERE prta.id=prtb.id;
+                        QUERY PLAN                         
+-----------------------------------------------------------
+ Append
+   ->  Nested Loop
+         ->  Seq Scan on prta1 prta_1
+         ->  Index Scan using prtb1_id_idx on prtb1 prtb_1
+               Index Cond: (id = prta_1.id)
+   ->  Nested Loop
+         ->  Seq Scan on prta2 prta_2
+         ->  Index Scan using prtb2_id_idx on prtb2 prtb_2
+               Index Cond: (id = prta_2.id)
+(9 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb,e WHERE prta.id=prtb.id AND prta.id=e.id;
+                           QUERY PLAN                            
+-----------------------------------------------------------------
+ Append
+   ->  Nested Loop
+         Join Filter: (prta_1.id = e_1.id)
+         ->  Nested Loop
+               ->  Seq Scan on prta1 prta_1
+               ->  Index Scan using prtb1_id_idx on prtb1 prtb_1
+                     Index Cond: (id = prta_1.id)
+         ->  Index Scan using e1_id_idx on e1 e_1
+               Index Cond: (id = prtb_1.id)
+   ->  Nested Loop
+         Join Filter: (prta_2.id = e_2.id)
+         ->  Nested Loop
+               ->  Seq Scan on prta2 prta_2
+               ->  Index Scan using prtb2_id_idx on prtb2 prtb_2
+                     Index Cond: (id = prta_2.id)
+         ->  Index Scan using e2_id_idx on e2 e_2
+               Index Cond: (id = prtb_2.id)
+(17 rows)
+
 -- semi join
 EXPLAIN (COSTS OFF)
 SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
diff --git a/src/test/regress/sql/partition_join.sql b/src/test/regress/sql/partition_join.sql
index d97b5b69ff..364b3216f8 100644
--- a/src/test/regress/sql/partition_join.sql
+++ b/src/test/regress/sql/partition_join.sql
@@ -536,6 +536,173 @@ EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
 
+--
+-- For asymmetric partition-wise join
+--
+CREATE TABLE prt5 (hkey int, a int, b int) PARTITION BY HASH(hkey);
+CREATE TABLE prt5_p0 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 0);
+CREATE TABLE prt5_p1 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 1);
+CREATE TABLE prt5_p2 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 2);
+CREATE TABLE prt6 (aid int, alabel text) PARTITION BY HASH(aid);
+CREATE TABLE prt6_p0 PARTITION OF prt6
+                     FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prt6_p1 PARTITION OF prt6
+                     FOR VALUES WITH (modulus 2, remainder 1);
+CREATE TABLE t5_1 (aid int, alabel text);
+CREATE TABLE t5_2 (bid int, blabel text);
+
+INSERT INTO prt5 (SELECT x, (x % 1000)::int,
+                            ((x+1) % 1000)::int
+                    FROM generate_series(1,1000000) x);
+INSERT INTO t5_1 (SELECT x, md5(x::text) FROM generate_series(-200, 1500) x);
+INSERT INTO t5_2 (SELECT x, md5(x::text) FROM generate_series(-200, 1500) x);
+INSERT INTO prt6 (SELECT * FROM t5_1);
+
+VACUUM ANALYZE prt5,prt6,t5_1,t5_2;
+
+SET max_parallel_workers_per_gather = 0;
+
+-- Trivial asymmetric JOIN of partitioned table with a relation
+EXPLAIN (COSTS OFF)
+SELECT *
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+-- The same, but appended with UNION ALL
+EXPLAIN (COSTS OFF)
+SELECT * FROM (
+	(SELECT * FROM prt5_p0)
+	UNION ALL
+	(SELECT * FROM prt5_p1)
+	UNION ALL
+	(SELECT * FROM prt5_p2)
+	) AS sq1
+JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+-- Don't allow asymmetric JOIN of two partitioned tables.
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM prt5 JOIN prt6 ON a = aid AND alabel like '%abc%';
+SELECT count(*) FROM prt5 JOIN prt6 ON a = aid AND alabel like '%abc%';
+
+-- Check asymmetric JOIN with Subquery
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM prt5 JOIN (
+	SELECT * FROM prt6 LIMIT 1000
+) AS sq1 ON a = aid AND alabel like '%abc%';
+SELECT count(*) FROM prt5 JOIN (SELECT * FROM prt6 LIMIT 1000) AS sq1
+	ON a = aid AND alabel like '%abc%';
+
+-- Asymmetric JOIN of two plane tables and one partitioned
+EXPLAIN (COSTS OFF)
+SELECT count(*)
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+SELECT count(*)
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+
+-- unable to extract non-partitioned right relation
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 RIGHT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+-- left side can be extracted, but no cost benefit
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 LEFT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+-- validation of the results with/without asymmetric partition-wise join
+SELECT * INTO pg_temp.result01a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+SELECT * INTO pg_temp.result02a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+
+SET enable_partitionwise_join = off;
+
+SELECT * INTO pg_temp.result01b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+SELECT * INTO pg_temp.result02b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+
+SELECT * FROM pg_temp.result01a EXCEPT SELECT * FROM pg_temp.result01b;
+SELECT * FROM pg_temp.result02a EXCEPT SELECT * FROM pg_temp.result02b;
+
+SET enable_partitionwise_join = on;
+
+-- Check reparameterization code when required_outer set contains relid of plain
+-- relation entry, not 'other' entry.
+
+SET enable_hashjoin = 'off';
+SET enable_mergejoin = 'off';
+SET enable_material = 'off';
+
+CREATE TABLE big AS SELECT x AS x FROM generate_series(1,1E4) x;
+CREATE INDEX ON big(x);
+CREATE TABLE small AS SELECT x, -x AS y FROM generate_series(1,100) x;
+
+CREATE TABLE part_l0 (x int, y int, z int) PARTITION BY HASH (y);
+CREATE TABLE part0_l1 PARTITION OF part_l0 (y)
+	FOR VALUES WITH (modulus 2, remainder 0) PARTITION BY HASH (z);
+CREATE TABLE part0_l2 PARTITION OF part0_l1 (z)
+	FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE part1_l2 PARTITION OF part0_l1 (z)
+	FOR VALUES WITH (modulus 2, remainder 1);
+CREATE TABLE part1_l1 PARTITION OF part_l0 (y)
+	FOR VALUES WITH (modulus 2, remainder 1);
+INSERT INTO part_l0 (x, y, z) (SELECT x,x,x FROM generate_series(1,1E4) x);
+
+ANALYZE big,small,part_l0;
+
+EXPLAIN
+SELECT small.* FROM small
+	JOIN part_l0 ON small.y = part_l0.y AND small.y + part_l0.y < 10
+	LEFT JOIN big ON big.x = small.x;
+
+DROP TABLE IF EXISTS big,small,part_l0 CASCADE;
+RESET enable_hashjoin;
+RESET enable_mergejoin;
+RESET enable_material;
+RESET max_parallel_workers_per_gather;
+
+-- Parameterized path examples.
+CREATE TABLE prta (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prta1 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prta2 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prta1 (id);
+CREATE UNIQUE INDEX ON prta2 (id);
+INSERT INTO prta (id, payload)
+	(SELECT *, ('abc' || id)::text AS payload
+		FROM generate_series(1,1) AS id);
+
+CREATE TABLE prtb (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prtb1 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prtb2 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prtb1 (id);
+CREATE UNIQUE INDEX ON prtb2 (id);
+INSERT INTO prtb (id, payload)
+    (SELECT *, ('def' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+
+CREATE TABLE e (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE e1 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE e2 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 1);
+INSERT INTO e (id, payload)
+	(SELECT *, ('ghi' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+CREATE UNIQUE INDEX ON e1 (id);
+CREATE UNIQUE INDEX ON e2 (id);
+
+ANALYZE prta,prtb,e;
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb WHERE prta.id=prtb.id;
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb,e WHERE prta.id=prtb.id AND prta.id=e.id;
+
 -- semi join
 EXPLAIN (COSTS OFF)
 SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
-- 
2.25.1


--------------3592BFA68FFAC61CCE0AF115--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Asymmetric partitionwise join.
@ 2021-04-02 06:02  Andrey Lepikhov <a.lepikhov@postgrespro.ru>
  0 siblings, 0 replies; 327+ messages in thread

From: Andrey Lepikhov @ 2021-04-02 06:02 UTC (permalink / raw)

Teach optimizer to consider partitionwise join of non-partitioned
table with each partition of partitioned table.

Disallow asymmetric machinery for joining of two partitioned (or appended)
relations because it could cause huge consumption of CPU and memory
during reparameterization of NestLoop path.

Change logic of the multilevel child relids adjustment, because this
feature allows the optimizer to plan in new way.
---
 src/backend/optimizer/path/joinpath.c        |   9 +
 src/backend/optimizer/path/joinrels.c        | 187 ++++++++
 src/backend/optimizer/plan/setrefs.c         |  17 +-
 src/backend/optimizer/util/appendinfo.c      |  44 +-
 src/backend/optimizer/util/pathnode.c        |   9 +-
 src/backend/optimizer/util/relnode.c         |  19 +-
 src/include/optimizer/paths.h                |   7 +-
 src/test/regress/expected/partition_join.out | 425 +++++++++++++++++++
 src/test/regress/sql/partition_join.sql      | 180 ++++++++
 9 files changed, 867 insertions(+), 30 deletions(-)

diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 6407ede12a..32618ebbd5 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -335,6 +335,15 @@ add_paths_to_joinrel(PlannerInfo *root,
 	if (set_join_pathlist_hook)
 		set_join_pathlist_hook(root, joinrel, outerrel, innerrel,
 							   jointype, &extra);
+
+	/*
+	 * 7. If outer relation is delivered from partition-tables, consider
+	 * distributing inner relation to every partition-leaf prior to
+	 * append these leafs.
+	 */
+	try_asymmetric_partitionwise_join(root, joinrel,
+									  outerrel, innerrel,
+									  jointype, &extra);
 }
 
 /*
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 8b69870cf4..9453258f83 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -16,6 +16,7 @@
 
 #include "miscadmin.h"
 #include "optimizer/appendinfo.h"
+#include "optimizer/cost.h"
 #include "optimizer/joininfo.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
@@ -1552,6 +1553,192 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
 	}
 }
 
+/*
+ * Build RelOptInfo on JOIN of each partition of the outer relation and the inner
+ * relation. Return List of such RelOptInfo's. Return NIL, if at least one of
+ * these JOINs is impossible to build.
+ */
+static List *
+extract_asymmetric_partitionwise_subjoin(PlannerInfo *root,
+										 RelOptInfo *joinrel,
+										 AppendPath *append_path,
+										 RelOptInfo *inner_rel,
+										 JoinType jointype,
+										 JoinPathExtraData *extra)
+{
+	List		*result = NIL;
+	ListCell	*lc;
+
+	foreach (lc, append_path->subpaths)
+	{
+		Path			*child_path = lfirst(lc);
+		RelOptInfo		*child_rel = child_path->parent;
+		Relids			child_joinrelids;
+		Relids			parent_relids;
+		RelOptInfo		*child_joinrel;
+		SpecialJoinInfo	*child_sjinfo;
+		List			*child_restrictlist;
+
+		child_joinrelids = bms_union(child_rel->relids, inner_rel->relids);
+		parent_relids = bms_union(append_path->path.parent->relids,
+								  inner_rel->relids);
+
+		child_sjinfo = build_child_join_sjinfo(root, extra->sjinfo,
+											   child_rel->relids,
+											   inner_rel->relids);
+		child_restrictlist = (List *)
+			adjust_appendrel_attrs_multilevel(root, (Node *)extra->restrictlist,
+											  child_joinrelids, parent_relids);
+
+		child_joinrel = find_join_rel(root, child_joinrelids);
+		if (!child_joinrel)
+			child_joinrel = build_child_join_rel(root,
+												 child_rel,
+												 inner_rel,
+												 joinrel,
+												 child_restrictlist,
+												 child_sjinfo,
+												 jointype);
+		else
+		{
+			/*
+			 * The join relation already exists. For example, it could happen if
+			 * we join two plane tables with partitioned table(s).
+			 * Populating this join with additional paths could push out some
+			 * previously added paths which could be pointed in a subplans list
+			 * of an higher level append.
+			 * Of course, we could save such paths before generating new. But it
+			 * can increase too much the number of paths in complex queries. It
+			 * can be a task for future work.
+			 */
+			return NIL;
+		}
+
+		populate_joinrel_with_paths(root,
+									child_rel,
+									inner_rel,
+									child_joinrel,
+									child_sjinfo,
+									child_restrictlist);
+
+		/* Give up if asymmetric partition-wise join is not available */
+		if (child_joinrel->pathlist == NIL)
+			return NIL;
+
+		set_cheapest(child_joinrel);
+		result = lappend(result, child_joinrel);
+	}
+	return result;
+}
+
+static bool
+is_asymmetric_join_feasible(PlannerInfo *root,
+						   RelOptInfo *outer_rel,
+						   RelOptInfo *inner_rel,
+						   JoinType jointype)
+{
+	ListCell *lc;
+
+	if (jointype != JOIN_INNER && jointype != JOIN_LEFT)
+		return false;
+
+	if (IS_OTHER_REL(outer_rel) || IS_OTHER_REL(inner_rel))
+		return false;
+
+	/* Disallow recursive usage of asymmertic join machinery */
+	if (root->join_rel_level == NULL)
+		return false;
+
+	/*
+	 * Don't allow asymmetric JOIN of two append subplans.
+	 * In the case of a parameterized NL join, a reparameterization procedure
+	 * will lead to large memory allocations and a CPU consumption:
+	 * each reparameterization will induce subpath duplication, creating new
+	 * ParamPathInfo instance and increasing of ppilist up to number of
+	 * partitions in the inner. Also, if we have many partitions, each bitmapset
+	 * variable will be large and many leaks of such variable (caused by relid
+	 * replacement) will highly increase memory consumption.
+	 * So, we deny such paths for now.
+	 */
+	foreach(lc, inner_rel->pathlist)
+	{
+		if (IsA(lfirst(lc), AppendPath))
+			return false;
+	}
+
+	return true;
+}
+
+void
+try_asymmetric_partitionwise_join(PlannerInfo *root,
+								  RelOptInfo *joinrel,
+								  RelOptInfo *outer_rel,
+								  RelOptInfo *inner_rel,
+								  JoinType jointype,
+								  JoinPathExtraData *extra)
+{
+	ListCell *lc;
+
+	/*
+	 * Try this kind of paths if we allow complex partitionwise joins and we know
+	 * we can build this join safely.
+	 */
+	if (!enable_partitionwise_join ||
+		!is_asymmetric_join_feasible(root, outer_rel, inner_rel, jointype))
+		return;
+
+	foreach (lc, outer_rel->pathlist)
+	{
+		AppendPath *append_path = lfirst(lc);
+
+		/*
+		 * We assume this pathlist keeps at least one AppendPath that
+		 * represents partitioned table-scan, symmetric or asymmetric
+		 * partition-wise join. Asymmetric join isn't needed if the append node
+		 * has only one child.
+		 */
+		if (IsA(append_path, AppendPath) &&
+			list_length(append_path->subpaths) > 1)
+		{
+			List **join_rel_level_saved;
+			List *live_childrels = NIL;
+
+			join_rel_level_saved = root->join_rel_level;
+			PG_TRY();
+			{
+				/* temporary disables "dynamic programming" algorithm */
+				root->join_rel_level = NULL;
+
+				live_childrels =
+					extract_asymmetric_partitionwise_subjoin(root,
+															 joinrel,
+															 append_path,
+															 inner_rel,
+															 jointype,
+															 extra);
+			}
+			PG_FINALLY();
+			{
+				root->join_rel_level = join_rel_level_saved;
+			}
+			PG_END_TRY();
+
+			if (live_childrels != NIL)
+			{
+				/*
+				 * Add new append relation. We must choose cheapest paths after
+				 * this operation because the pathlist possibly contains
+				 * joinrels and appendrels that can be suboptimal.
+				 */
+				add_paths_to_append_rel(root, joinrel, live_childrels);
+				set_cheapest(joinrel);
+			}
+
+			break;
+		}
+	}
+}
+
 /*
  * Construct the SpecialJoinInfo for a child-join by translating
  * SpecialJoinInfo for the join between parents. left_relids and right_relids
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index e50624c465..fccc0685d7 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -281,24 +281,29 @@ set_plan_references(PlannerInfo *root, Plan *plan)
 
 	/*
 	 * Adjust RT indexes of AppendRelInfos and add to final appendrels list.
-	 * We assume the AppendRelInfos were built during planning and don't need
-	 * to be copied.
+	 * The AppendRelInfos are copied, because as a part of a subplan they could
+	 * be visited many times in the case of asymmetric join.
 	 */
 	foreach(lc, root->append_rel_list)
 	{
 		AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
+		AppendRelInfo *newappinfo;
+
+		/* flat copy is enough since all valuable fields are scalars */
+		newappinfo = (AppendRelInfo *) palloc(sizeof(AppendRelInfo));
+		memcpy(newappinfo, appinfo, sizeof(AppendRelInfo));
 
 		/* adjust RT indexes */
-		appinfo->parent_relid += rtoffset;
-		appinfo->child_relid += rtoffset;
+		newappinfo->parent_relid += rtoffset;
+		newappinfo->child_relid += rtoffset;
 
 		/*
 		 * Rather than adjust the translated_vars entries, just drop 'em.
 		 * Neither the executor nor EXPLAIN currently need that data.
 		 */
-		appinfo->translated_vars = NIL;
+		newappinfo->translated_vars = NIL;
 
-		glob->appendRelations = lappend(glob->appendRelations, appinfo);
+		glob->appendRelations = lappend(glob->appendRelations, newappinfo);
 	}
 
 	/* Now fix the Plan tree */
diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c
index af46f581ac..f4d12f76e1 100644
--- a/src/backend/optimizer/util/appendinfo.c
+++ b/src/backend/optimizer/util/appendinfo.c
@@ -202,7 +202,9 @@ adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos,
 	context.appinfos = appinfos;
 
 	/* If there's nothing to adjust, don't call this function. */
-	Assert(nappinfos >= 1 && appinfos != NULL);
+	/* If there's nothing to adjust, just return a duplication */
+	if (nappinfos == 0)
+		return copyObject(node);
 
 	/* Should never be translating a Query tree. */
 	Assert(node == NULL || !IsA(node, Query));
@@ -490,12 +492,10 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
 								  Relids top_parent_relids)
 {
 	AppendRelInfo **appinfos;
-	Bitmapset  *parent_relids = NULL;
+	Relids		parent_relids = NULL;
 	int			nappinfos;
 	int			cnt;
 
-	Assert(bms_num_members(child_relids) == bms_num_members(top_parent_relids));
-
 	appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
 
 	/* Construct relids set for the immediate parent of given child. */
@@ -506,8 +506,13 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
 		parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
 	}
 
-	/* Recurse if immediate parent is not the top parent. */
-	if (!bms_equal(parent_relids, top_parent_relids))
+	/*
+	 * Recurse if immediate parent is not the top parent. Keep in mind that in a
+	 * case of asymmetric JOIN top_parent_relids can contain relids which aren't
+	 * part of an append node.
+	 */
+	if (!bms_equal(parent_relids, top_parent_relids) &&
+		!bms_is_subset(parent_relids, top_parent_relids))
 		node = adjust_appendrel_attrs_multilevel(root, node, parent_relids,
 												 top_parent_relids);
 
@@ -515,12 +520,13 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
 	node = adjust_appendrel_attrs(root, node, nappinfos, appinfos);
 
 	pfree(appinfos);
+	pfree(parent_relids);
 
 	return node;
 }
 
 /*
- * Substitute child relids for parent relids in a Relid set.  The array of
+ * Substitute child relids for parent relids in a Relid set. The array of
  * appinfos specifies the substitutions to be performed.
  */
 Relids
@@ -565,6 +571,7 @@ adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
 	AppendRelInfo **appinfos;
 	int			nappinfos;
 	Relids		parent_relids = NULL;
+	Relids		normal_relids = NULL;
 	Relids		result;
 	Relids		tmp_result = NULL;
 	int			cnt;
@@ -579,13 +586,24 @@ adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
 	appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
 
 	/* Construct relids set for the immediate parent of the given child. */
+	normal_relids = bms_copy(child_relids);
 	for (cnt = 0; cnt < nappinfos; cnt++)
 	{
 		AppendRelInfo *appinfo = appinfos[cnt];
 
 		parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
+		normal_relids = bms_del_member(normal_relids, appinfo->child_relid);
 	}
 
+	if (bms_is_subset(relids, normal_relids))
+	{
+		/* Nothing to do. Parameters set points to plain relations only. */
+		result = relids;
+		goto cleanup;
+	}
+
+	parent_relids = bms_union(parent_relids, normal_relids);
+
 	/* Recurse if immediate parent is not the top parent. */
 	if (!bms_equal(parent_relids, top_parent_relids))
 	{
@@ -597,10 +615,11 @@ adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
 
 	result = adjust_child_relids(relids, nappinfos, appinfos);
 
+cleanup:
 	/* Free memory consumed by any intermediate result. */
-	if (tmp_result)
-		bms_free(tmp_result);
+	bms_free(tmp_result);
 	bms_free(parent_relids);
+	bms_free(normal_relids);
 	pfree(appinfos);
 
 	return result;
@@ -715,11 +734,11 @@ AppendRelInfo **
 find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
 {
 	AppendRelInfo **appinfos;
+	int			nrooms = bms_num_members(relids);
 	int			cnt = 0;
 	int			i;
 
-	*nappinfos = bms_num_members(relids);
-	appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
+	appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * nrooms);
 
 	i = -1;
 	while ((i = bms_next_member(relids, i)) >= 0)
@@ -727,10 +746,11 @@ find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
 		AppendRelInfo *appinfo = root->append_rel_array[i];
 
 		if (!appinfo)
-			elog(ERROR, "child rel %d not found in append_rel_array", i);
+			continue;
 
 		appinfos[cnt++] = appinfo;
 	}
+	*nappinfos = cnt;
 	return appinfos;
 }
 
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index cedb3848dd..17e215b72d 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -4225,7 +4225,14 @@ do { \
 
 		MemoryContextSwitchTo(oldcontext);
 	}
-	bms_free(required_outer);
+
+	/*
+	 * If adjust_child_relids_multilevel don't do replacements it returns
+	 * the original set, not a copy. It is possible in the case of asymmetric
+	 * JOIN and child_rel->relids contains relids only of plane relations.
+	 */
+	if (required_outer != old_ppi->ppi_req_outer)
+		bms_free(required_outer);
 
 	new_path->param_info = new_ppi;
 
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 47769cea45..ddf0f5a876 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -792,11 +792,8 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
 	AppendRelInfo **appinfos;
 	int			nappinfos;
 
-	/* Only joins between "other" relations land here. */
-	Assert(IS_OTHER_REL(outer_rel) && IS_OTHER_REL(inner_rel));
-
-	/* The parent joinrel should have consider_partitionwise_join set. */
-	Assert(parent_joinrel->consider_partitionwise_join);
+	/* Either of relations must be "other" relation at least. */
+	Assert(IS_OTHER_REL(outer_rel) || IS_OTHER_REL(inner_rel));
 
 	joinrel->reloptkind = RELOPT_OTHER_JOINREL;
 	joinrel->relids = bms_union(outer_rel->relids, inner_rel->relids);
@@ -854,8 +851,11 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
 	joinrel->partexprs = NULL;
 	joinrel->nullable_partexprs = NULL;
 
-	joinrel->top_parent_relids = bms_union(outer_rel->top_parent_relids,
-										   inner_rel->top_parent_relids);
+	joinrel->top_parent_relids =
+		bms_union(IS_OTHER_REL(outer_rel) ?
+				  outer_rel->top_parent_relids : outer_rel->relids,
+				  IS_OTHER_REL(inner_rel) ?
+				  inner_rel->top_parent_relids : inner_rel->relids);
 
 	/* Compute information relevant to foreign relations. */
 	set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
@@ -2036,9 +2036,8 @@ build_child_join_reltarget(PlannerInfo *root,
 {
 	/* Build the targetlist */
 	childrel->reltarget->exprs = (List *)
-		adjust_appendrel_attrs(root,
-							   (Node *) parentrel->reltarget->exprs,
-							   nappinfos, appinfos);
+		adjust_appendrel_attrs_multilevel(root, (Node *)parentrel->reltarget->exprs,
+										childrel->relids, parentrel->relids);
 
 	/* Set the cost and width fields */
 	childrel->reltarget->cost.startup = parentrel->reltarget->cost.startup;
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index f1d111063c..a0106dc539 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -109,7 +109,12 @@ extern bool have_join_order_restriction(PlannerInfo *root,
 extern bool have_dangerous_phv(PlannerInfo *root,
 							   Relids outer_relids, Relids inner_params);
 extern void mark_dummy_rel(RelOptInfo *rel);
-
+extern void try_asymmetric_partitionwise_join(PlannerInfo *root,
+											  RelOptInfo *joinrel,
+											  RelOptInfo *outer_rel,
+											  RelOptInfo *inner_rel,
+											  JoinType jointype,
+											  JoinPathExtraData *extra);
 /*
  * equivclass.c
  *	  routines for managing EquivalenceClasses
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index 27f7525b3e..3eddd9bec3 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -2320,6 +2320,431 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a =
  375 | 0375 | 375 | 0375
 (8 rows)
 
+--
+-- For asymmetric partition-wise join
+--
+CREATE TABLE prt5 (hkey int, a int, b int) PARTITION BY HASH(hkey);
+CREATE TABLE prt5_p0 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 0);
+CREATE TABLE prt5_p1 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 1);
+CREATE TABLE prt5_p2 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 2);
+CREATE TABLE prt6 (aid int, alabel text) PARTITION BY HASH(aid);
+CREATE TABLE prt6_p0 PARTITION OF prt6
+                     FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prt6_p1 PARTITION OF prt6
+                     FOR VALUES WITH (modulus 2, remainder 1);
+CREATE TABLE t5_1 (aid int, alabel text);
+CREATE TABLE t5_2 (bid int, blabel text);
+INSERT INTO prt5 (SELECT x, (x % 1000)::int,
+                            ((x+1) % 1000)::int
+                    FROM generate_series(1,1000000) x);
+INSERT INTO t5_1 (SELECT x, md5(x::text) FROM generate_series(-200, 1500) x);
+INSERT INTO t5_2 (SELECT x, md5(x::text) FROM generate_series(-200, 1500) x);
+INSERT INTO prt6 (SELECT * FROM t5_1);
+VACUUM ANALYZE prt5,prt6,t5_1,t5_2;
+SET max_parallel_workers_per_gather = 0;
+-- Trivial asymmetric JOIN of partitioned table with a relation
+EXPLAIN (COSTS OFF)
+SELECT *
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                      QUERY PLAN                       
+-------------------------------------------------------
+ Append
+   ->  Hash Join
+         Hash Cond: (prt5_1.a = t5_1.aid)
+         ->  Seq Scan on prt5_p0 prt5_1
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_2.a = t5_1.aid)
+         ->  Seq Scan on prt5_p1 prt5_2
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_3.a = t5_1.aid)
+         ->  Seq Scan on prt5_p2 prt5_3
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+(19 rows)
+
+-- The same, but appended with UNION ALL
+EXPLAIN (COSTS OFF)
+SELECT * FROM (
+	(SELECT * FROM prt5_p0)
+	UNION ALL
+	(SELECT * FROM prt5_p1)
+	UNION ALL
+	(SELECT * FROM prt5_p2)
+	) AS sq1
+JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                      QUERY PLAN                       
+-------------------------------------------------------
+ Append
+   ->  Hash Join
+         Hash Cond: (prt5_p0.a = t5_1.aid)
+         ->  Seq Scan on prt5_p0
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_p1.a = t5_1.aid)
+         ->  Seq Scan on prt5_p1
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_p2.a = t5_1.aid)
+         ->  Seq Scan on prt5_p2
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+(19 rows)
+
+-- Don't allow asymmetric JOIN of two partitioned tables.
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM prt5 JOIN prt6 ON a = aid AND alabel like '%abc%';
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Aggregate
+   ->  Hash Join
+         Hash Cond: (prt5.a = prt6.aid)
+         ->  Append
+               ->  Seq Scan on prt5_p0 prt5_1
+               ->  Seq Scan on prt5_p1 prt5_2
+               ->  Seq Scan on prt5_p2 prt5_3
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on prt6_p0 prt6_1
+                           Filter: (alabel ~~ '%abc%'::text)
+                     ->  Seq Scan on prt6_p1 prt6_2
+                           Filter: (alabel ~~ '%abc%'::text)
+(13 rows)
+
+SELECT count(*) FROM prt5 JOIN prt6 ON a = aid AND alabel like '%abc%';
+ count 
+-------
+  4000
+(1 row)
+
+-- Check asymmetric JOIN with Subquery
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM prt5 JOIN (
+	SELECT * FROM prt6 LIMIT 1000
+) AS sq1 ON a = aid AND alabel like '%abc%';
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ Aggregate
+   ->  Append
+         ->  Hash Join
+               Hash Cond: (prt5_1.a = sq1.aid)
+               ->  Seq Scan on prt5_p0 prt5_1
+               ->  Hash
+                     ->  Subquery Scan on sq1
+                           Filter: (sq1.alabel ~~ '%abc%'::text)
+                           ->  Limit
+                                 ->  Append
+                                       ->  Seq Scan on prt6_p0 prt6_1
+                                       ->  Seq Scan on prt6_p1 prt6_2
+         ->  Hash Join
+               Hash Cond: (prt5_2.a = sq1.aid)
+               ->  Seq Scan on prt5_p1 prt5_2
+               ->  Hash
+                     ->  Subquery Scan on sq1
+                           Filter: (sq1.alabel ~~ '%abc%'::text)
+                           ->  Limit
+                                 ->  Append
+                                       ->  Seq Scan on prt6_p0 prt6_4
+                                       ->  Seq Scan on prt6_p1 prt6_5
+         ->  Hash Join
+               Hash Cond: (prt5_3.a = sq1.aid)
+               ->  Seq Scan on prt5_p2 prt5_3
+               ->  Hash
+                     ->  Subquery Scan on sq1
+                           Filter: (sq1.alabel ~~ '%abc%'::text)
+                           ->  Limit
+                                 ->  Append
+                                       ->  Seq Scan on prt6_p0 prt6_7
+                                       ->  Seq Scan on prt6_p1 prt6_8
+(32 rows)
+
+SELECT count(*) FROM prt5 JOIN (SELECT * FROM prt6 LIMIT 1000) AS sq1
+	ON a = aid AND alabel like '%abc%';
+ count 
+-------
+  2000
+(1 row)
+
+-- Asymmetric JOIN of two plane tables and one partitioned
+EXPLAIN (COSTS OFF)
+SELECT count(*)
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Aggregate
+   ->  Append
+         ->  Hash Join
+               Hash Cond: (prt5_1.b = t5_2.bid)
+               ->  Hash Join
+                     Hash Cond: (prt5_1.a = t5_1.aid)
+                     ->  Seq Scan on prt5_p0 prt5_1
+                     ->  Hash
+                           ->  Seq Scan on t5_1
+                                 Filter: (alabel ~~ '%ab%'::text)
+               ->  Hash
+                     ->  Seq Scan on t5_2
+                           Filter: (blabel ~~ '%cd%'::text)
+         ->  Hash Join
+               Hash Cond: (prt5_2.b = t5_2.bid)
+               ->  Hash Join
+                     Hash Cond: (prt5_2.a = t5_1.aid)
+                     ->  Seq Scan on prt5_p1 prt5_2
+                     ->  Hash
+                           ->  Seq Scan on t5_1
+                                 Filter: (alabel ~~ '%ab%'::text)
+               ->  Hash
+                     ->  Seq Scan on t5_2
+                           Filter: (blabel ~~ '%cd%'::text)
+         ->  Hash Join
+               Hash Cond: (prt5_3.b = t5_2.bid)
+               ->  Hash Join
+                     Hash Cond: (prt5_3.a = t5_1.aid)
+                     ->  Seq Scan on prt5_p2 prt5_3
+                     ->  Hash
+                           ->  Seq Scan on t5_1
+                                 Filter: (alabel ~~ '%ab%'::text)
+               ->  Hash
+                     ->  Seq Scan on t5_2
+                           Filter: (blabel ~~ '%cd%'::text)
+(35 rows)
+
+SELECT count(*)
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+ count 
+-------
+ 11000
+(1 row)
+
+-- unable to extract non-partitioned right relation
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 RIGHT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                  QUERY PLAN                   
+-----------------------------------------------
+ Hash Right Join
+   Hash Cond: (prt5.a = t5_1.aid)
+   Join Filter: (t5_1.alabel ~~ '%abc%'::text)
+   ->  Append
+         ->  Seq Scan on prt5_p0 prt5_1
+         ->  Seq Scan on prt5_p1 prt5_2
+         ->  Seq Scan on prt5_p2 prt5_3
+   ->  Hash
+         ->  Seq Scan on t5_1
+(9 rows)
+
+-- left side can be extracted, but no cost benefit
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 LEFT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Hash Left Join
+   Hash Cond: (prt5.a = t5_1.aid)
+   ->  Append
+         ->  Seq Scan on prt5_p0 prt5_1
+         ->  Seq Scan on prt5_p1 prt5_2
+         ->  Seq Scan on prt5_p2 prt5_3
+   ->  Hash
+         ->  Seq Scan on t5_1
+               Filter: (alabel ~~ '%abc%'::text)
+(9 rows)
+
+-- validation of the results with/without asymmetric partition-wise join
+SELECT * INTO pg_temp.result01a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+SELECT * INTO pg_temp.result02a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+SET enable_partitionwise_join = off;
+SELECT * INTO pg_temp.result01b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+SELECT * INTO pg_temp.result02b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+SELECT * FROM pg_temp.result01a EXCEPT SELECT * FROM pg_temp.result01b;
+ hkey | a | b | aid | alabel 
+------+---+---+-----+--------
+(0 rows)
+
+SELECT * FROM pg_temp.result02a EXCEPT SELECT * FROM pg_temp.result02b;
+ hkey | a | b | aid | alabel | bid | blabel 
+------+---+---+-----+--------+-----+--------
+(0 rows)
+
+SET enable_partitionwise_join = on;
+-- Check reparameterization code when an optimizer have to make two level relids
+-- adjustment.
+SET enable_hashjoin = 'off';
+SET enable_mergejoin = 'off';
+SET enable_material = 'off';
+CREATE TABLE big AS SELECT x AS x FROM generate_series(1,1E4) x;
+CREATE INDEX ON big(x);
+CREATE TABLE small AS SELECT x, -x AS y FROM generate_series(1,100) x;
+CREATE TABLE part_l0 (x int, y int, z int) PARTITION BY HASH (y);
+CREATE TABLE part0_l1 PARTITION OF part_l0 (y)
+	FOR VALUES WITH (modulus 2, remainder 0) PARTITION BY HASH (z);
+CREATE TABLE part0_l2 PARTITION OF part0_l1 (z)
+	FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE part1_l2 PARTITION OF part0_l1 (z)
+	FOR VALUES WITH (modulus 2, remainder 1);
+CREATE TABLE part1_l1 PARTITION OF part_l0 (y)
+	FOR VALUES WITH (modulus 2, remainder 1);
+INSERT INTO part_l0 (x, y, z) (SELECT x,x,x FROM generate_series(1,1E4) x);
+ANALYZE big,small,part_l0;
+-- Parameter have to be reparameterized by a plane relation.
+EXPLAIN (COSTS OFF)
+SELECT small.* FROM small
+	JOIN part_l0 ON small.y = part_l0.y AND small.y + part_l0.y < 10
+	LEFT JOIN big ON big.x = small.x;
+                                       QUERY PLAN                                        
+-----------------------------------------------------------------------------------------
+ Nested Loop Left Join
+   ->  Append
+         ->  Nested Loop
+               Join Filter: ((small.y = part_l0_1.y) AND ((small.y + part_l0_1.y) < 10))
+               ->  Seq Scan on small
+               ->  Seq Scan on part0_l2 part_l0_1
+         ->  Nested Loop
+               Join Filter: ((small.y = part_l0_2.y) AND ((small.y + part_l0_2.y) < 10))
+               ->  Seq Scan on part1_l2 part_l0_2
+               ->  Seq Scan on small
+         ->  Nested Loop
+               Join Filter: ((small.y = part_l0_3.y) AND ((small.y + part_l0_3.y) < 10))
+               ->  Seq Scan on small
+               ->  Seq Scan on part1_l1 part_l0_3
+   ->  Index Only Scan using big_x_idx on big
+         Index Cond: (x = (small.x)::numeric)
+(16 rows)
+
+SELECT small.* FROM small
+	JOIN part_l0 ON small.y = part_l0.y AND small.y + part_l0.y < 10
+	LEFT JOIN big ON big.x = small.x;
+ x | y 
+---+---
+(0 rows)
+
+-- Parameters have to be reparameterized by plane and partitioned relations.
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM small
+	JOIN part_l0 ON small.y = part_l0.y AND small.y + part_l0.y < 10
+	LEFT JOIN big ON big.x = small.x OR big.x = part_l0.x;
+                                          QUERY PLAN                                           
+-----------------------------------------------------------------------------------------------
+ Aggregate
+   ->  Nested Loop Left Join
+         ->  Append
+               ->  Nested Loop
+                     Join Filter: ((small.y = part_l0_1.y) AND ((small.y + part_l0_1.y) < 10))
+                     ->  Seq Scan on small
+                     ->  Seq Scan on part0_l2 part_l0_1
+               ->  Nested Loop
+                     Join Filter: ((small.y = part_l0_2.y) AND ((small.y + part_l0_2.y) < 10))
+                     ->  Seq Scan on part1_l2 part_l0_2
+                     ->  Seq Scan on small
+               ->  Nested Loop
+                     Join Filter: ((small.y = part_l0_3.y) AND ((small.y + part_l0_3.y) < 10))
+                     ->  Seq Scan on small
+                     ->  Seq Scan on part1_l1 part_l0_3
+         ->  Bitmap Heap Scan on big
+               Recheck Cond: ((x = (small.x)::numeric) OR (x = (part_l0.x)::numeric))
+               ->  BitmapOr
+                     ->  Bitmap Index Scan on big_x_idx
+                           Index Cond: (x = (small.x)::numeric)
+                     ->  Bitmap Index Scan on big_x_idx
+                           Index Cond: (x = (part_l0.x)::numeric)
+(22 rows)
+
+SELECT count(*) FROM small
+	JOIN part_l0 ON small.y = part_l0.y AND small.y + part_l0.y < 10
+	LEFT JOIN big ON big.x = small.x OR big.x = part_l0.x;
+ count 
+-------
+     0
+(1 row)
+
+DROP TABLE IF EXISTS big,small,part_l0 CASCADE;
+RESET enable_hashjoin;
+RESET enable_mergejoin;
+RESET enable_material;
+RESET max_parallel_workers_per_gather;
+-- Parameterized path examples.
+CREATE TABLE prta (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prta1 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prta2 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prta1 (id);
+CREATE UNIQUE INDEX ON prta2 (id);
+INSERT INTO prta (id, payload)
+	(SELECT *, ('abc' || id)::text AS payload
+		FROM generate_series(1,1) AS id);
+CREATE TABLE prtb (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prtb1 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prtb2 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prtb1 (id);
+CREATE UNIQUE INDEX ON prtb2 (id);
+INSERT INTO prtb (id, payload)
+    (SELECT *, ('def' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+CREATE TABLE e (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE e1 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE e2 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 1);
+INSERT INTO e (id, payload)
+	(SELECT *, ('ghi' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+CREATE UNIQUE INDEX ON e1 (id);
+CREATE UNIQUE INDEX ON e2 (id);
+ANALYZE prta,prtb,e;
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb WHERE prta.id=prtb.id;
+                        QUERY PLAN                         
+-----------------------------------------------------------
+ Append
+   ->  Nested Loop
+         ->  Seq Scan on prta1 prta_1
+         ->  Index Scan using prtb1_id_idx on prtb1 prtb_1
+               Index Cond: (id = prta_1.id)
+   ->  Nested Loop
+         ->  Seq Scan on prta2 prta_2
+         ->  Index Scan using prtb2_id_idx on prtb2 prtb_2
+               Index Cond: (id = prta_2.id)
+(9 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb,e WHERE prta.id=prtb.id AND prta.id=e.id;
+                           QUERY PLAN                            
+-----------------------------------------------------------------
+ Append
+   ->  Nested Loop
+         Join Filter: (prta_1.id = e_1.id)
+         ->  Nested Loop
+               ->  Seq Scan on prta1 prta_1
+               ->  Index Scan using prtb1_id_idx on prtb1 prtb_1
+                     Index Cond: (id = prta_1.id)
+         ->  Index Scan using e1_id_idx on e1 e_1
+               Index Cond: (id = prtb_1.id)
+   ->  Nested Loop
+         Join Filter: (prta_2.id = e_2.id)
+         ->  Nested Loop
+               ->  Seq Scan on prta2 prta_2
+               ->  Index Scan using prtb2_id_idx on prtb2 prtb_2
+                     Index Cond: (id = prta_2.id)
+         ->  Index Scan using e2_id_idx on e2 e_2
+               Index Cond: (id = prtb_2.id)
+(17 rows)
+
 -- semi join
 EXPLAIN (COSTS OFF)
 SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
diff --git a/src/test/regress/sql/partition_join.sql b/src/test/regress/sql/partition_join.sql
index d97b5b69ff..4d1dd5bec1 100644
--- a/src/test/regress/sql/partition_join.sql
+++ b/src/test/regress/sql/partition_join.sql
@@ -536,6 +536,186 @@ EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
 
+--
+-- For asymmetric partition-wise join
+--
+CREATE TABLE prt5 (hkey int, a int, b int) PARTITION BY HASH(hkey);
+CREATE TABLE prt5_p0 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 0);
+CREATE TABLE prt5_p1 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 1);
+CREATE TABLE prt5_p2 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 2);
+CREATE TABLE prt6 (aid int, alabel text) PARTITION BY HASH(aid);
+CREATE TABLE prt6_p0 PARTITION OF prt6
+                     FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prt6_p1 PARTITION OF prt6
+                     FOR VALUES WITH (modulus 2, remainder 1);
+CREATE TABLE t5_1 (aid int, alabel text);
+CREATE TABLE t5_2 (bid int, blabel text);
+
+INSERT INTO prt5 (SELECT x, (x % 1000)::int,
+                            ((x+1) % 1000)::int
+                    FROM generate_series(1,1000000) x);
+INSERT INTO t5_1 (SELECT x, md5(x::text) FROM generate_series(-200, 1500) x);
+INSERT INTO t5_2 (SELECT x, md5(x::text) FROM generate_series(-200, 1500) x);
+INSERT INTO prt6 (SELECT * FROM t5_1);
+
+VACUUM ANALYZE prt5,prt6,t5_1,t5_2;
+
+SET max_parallel_workers_per_gather = 0;
+
+-- Trivial asymmetric JOIN of partitioned table with a relation
+EXPLAIN (COSTS OFF)
+SELECT *
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+-- The same, but appended with UNION ALL
+EXPLAIN (COSTS OFF)
+SELECT * FROM (
+	(SELECT * FROM prt5_p0)
+	UNION ALL
+	(SELECT * FROM prt5_p1)
+	UNION ALL
+	(SELECT * FROM prt5_p2)
+	) AS sq1
+JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+-- Don't allow asymmetric JOIN of two partitioned tables.
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM prt5 JOIN prt6 ON a = aid AND alabel like '%abc%';
+SELECT count(*) FROM prt5 JOIN prt6 ON a = aid AND alabel like '%abc%';
+
+-- Check asymmetric JOIN with Subquery
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM prt5 JOIN (
+	SELECT * FROM prt6 LIMIT 1000
+) AS sq1 ON a = aid AND alabel like '%abc%';
+SELECT count(*) FROM prt5 JOIN (SELECT * FROM prt6 LIMIT 1000) AS sq1
+	ON a = aid AND alabel like '%abc%';
+
+-- Asymmetric JOIN of two plane tables and one partitioned
+EXPLAIN (COSTS OFF)
+SELECT count(*)
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+SELECT count(*)
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+
+-- unable to extract non-partitioned right relation
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 RIGHT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+-- left side can be extracted, but no cost benefit
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 LEFT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+-- validation of the results with/without asymmetric partition-wise join
+SELECT * INTO pg_temp.result01a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+SELECT * INTO pg_temp.result02a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+
+SET enable_partitionwise_join = off;
+
+SELECT * INTO pg_temp.result01b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+SELECT * INTO pg_temp.result02b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+
+SELECT * FROM pg_temp.result01a EXCEPT SELECT * FROM pg_temp.result01b;
+SELECT * FROM pg_temp.result02a EXCEPT SELECT * FROM pg_temp.result02b;
+
+SET enable_partitionwise_join = on;
+
+-- Check reparameterization code when an optimizer have to make two level relids
+-- adjustment.
+
+SET enable_hashjoin = 'off';
+SET enable_mergejoin = 'off';
+SET enable_material = 'off';
+
+CREATE TABLE big AS SELECT x AS x FROM generate_series(1,1E4) x;
+CREATE INDEX ON big(x);
+CREATE TABLE small AS SELECT x, -x AS y FROM generate_series(1,100) x;
+
+CREATE TABLE part_l0 (x int, y int, z int) PARTITION BY HASH (y);
+CREATE TABLE part0_l1 PARTITION OF part_l0 (y)
+	FOR VALUES WITH (modulus 2, remainder 0) PARTITION BY HASH (z);
+CREATE TABLE part0_l2 PARTITION OF part0_l1 (z)
+	FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE part1_l2 PARTITION OF part0_l1 (z)
+	FOR VALUES WITH (modulus 2, remainder 1);
+CREATE TABLE part1_l1 PARTITION OF part_l0 (y)
+	FOR VALUES WITH (modulus 2, remainder 1);
+INSERT INTO part_l0 (x, y, z) (SELECT x,x,x FROM generate_series(1,1E4) x);
+
+ANALYZE big,small,part_l0;
+
+-- Parameter have to be reparameterized by a plane relation.
+EXPLAIN (COSTS OFF)
+SELECT small.* FROM small
+	JOIN part_l0 ON small.y = part_l0.y AND small.y + part_l0.y < 10
+	LEFT JOIN big ON big.x = small.x;
+SELECT small.* FROM small
+	JOIN part_l0 ON small.y = part_l0.y AND small.y + part_l0.y < 10
+	LEFT JOIN big ON big.x = small.x;
+
+-- Parameters have to be reparameterized by plane and partitioned relations.
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM small
+	JOIN part_l0 ON small.y = part_l0.y AND small.y + part_l0.y < 10
+	LEFT JOIN big ON big.x = small.x OR big.x = part_l0.x;
+SELECT count(*) FROM small
+	JOIN part_l0 ON small.y = part_l0.y AND small.y + part_l0.y < 10
+	LEFT JOIN big ON big.x = small.x OR big.x = part_l0.x;
+
+DROP TABLE IF EXISTS big,small,part_l0 CASCADE;
+RESET enable_hashjoin;
+RESET enable_mergejoin;
+RESET enable_material;
+RESET max_parallel_workers_per_gather;
+
+-- Parameterized path examples.
+CREATE TABLE prta (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prta1 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prta2 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prta1 (id);
+CREATE UNIQUE INDEX ON prta2 (id);
+INSERT INTO prta (id, payload)
+	(SELECT *, ('abc' || id)::text AS payload
+		FROM generate_series(1,1) AS id);
+
+CREATE TABLE prtb (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prtb1 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prtb2 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prtb1 (id);
+CREATE UNIQUE INDEX ON prtb2 (id);
+INSERT INTO prtb (id, payload)
+    (SELECT *, ('def' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+
+CREATE TABLE e (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE e1 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE e2 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 1);
+INSERT INTO e (id, payload)
+	(SELECT *, ('ghi' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+CREATE UNIQUE INDEX ON e1 (id);
+CREATE UNIQUE INDEX ON e2 (id);
+
+ANALYZE prta,prtb,e;
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb WHERE prta.id=prtb.id;
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb,e WHERE prta.id=prtb.id AND prta.id=e.id;
+
 -- semi join
 EXPLAIN (COSTS OFF)
 SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
-- 
2.33.0


--------------9DCA5E9A07F91111D4169DAB--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Asymmetric partitionwise join.
@ 2021-04-02 06:02  Andrey Lepikhov <a.lepikhov@postgrespro.ru>
  0 siblings, 0 replies; 327+ messages in thread

From: Andrey Lepikhov @ 2021-04-02 06:02 UTC (permalink / raw)

Teach optimizer to consider partitionwise join of non-partitioned
table with each partition of partitioned table.
This technique cause changes of 'reparameterize by child' machinery.
---
 src/backend/optimizer/path/joinpath.c        |   9 +
 src/backend/optimizer/path/joinrels.c        | 151 ++++++++++++++
 src/backend/optimizer/util/appendinfo.c      |  28 ++-
 src/backend/optimizer/util/pathnode.c        |   9 +-
 src/backend/optimizer/util/relnode.c         |  14 +-
 src/include/optimizer/paths.h                |   7 +-
 src/test/regress/expected/partition_join.out | 209 +++++++++++++++++++
 src/test/regress/sql/partition_join.sql      |  99 +++++++++
 8 files changed, 509 insertions(+), 17 deletions(-)

diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index e9b6968b1d..6ba6d32ae4 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -335,6 +335,15 @@ add_paths_to_joinrel(PlannerInfo *root,
 	if (set_join_pathlist_hook)
 		set_join_pathlist_hook(root, joinrel, outerrel, innerrel,
 							   jointype, &extra);
+
+	/*
+	 * 7. If outer relation is delivered from partition-tables, consider
+	 * distributing inner relation to every partition-leaf prior to
+	 * append these leafs.
+	 */
+	try_asymmetric_partitionwise_join(root, joinrel,
+									  outerrel, innerrel,
+									  jointype, &extra);
 }
 
 /*
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 0dbe2ac726..6f900475bb 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -16,6 +16,7 @@
 
 #include "miscadmin.h"
 #include "optimizer/appendinfo.h"
+#include "optimizer/cost.h"
 #include "optimizer/joininfo.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
@@ -1551,6 +1552,156 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
 	}
 }
 
+/*
+ * Build RelOptInfo on JOIN of each partition of the outer relation and the inner
+ * relation. Return List of such RelOptInfo's. Return NIL, if at least one of
+ * these JOINs are impossible to build.
+ */
+static List *
+extract_asymmetric_partitionwise_subjoin(PlannerInfo *root,
+										 RelOptInfo *joinrel,
+										 AppendPath *append_path,
+										 RelOptInfo *inner_rel,
+										 JoinType jointype,
+										 JoinPathExtraData *extra)
+{
+	List		*result = NIL;
+	ListCell	*lc;
+
+	foreach (lc, append_path->subpaths)
+	{
+		Path			*child_path = lfirst(lc);
+		RelOptInfo		*child_rel = child_path->parent;
+		Relids			child_join_relids;
+		RelOptInfo		*child_join_rel;
+		SpecialJoinInfo	*child_sjinfo;
+		List			*child_restrictlist;
+		AppendRelInfo	**appinfos;
+		int				nappinfos;
+
+		child_join_relids = bms_union(child_rel->relids,
+									  inner_rel->relids);
+		appinfos = find_appinfos_by_relids(root, child_join_relids,
+										   &nappinfos);
+		child_sjinfo = build_child_join_sjinfo(root, extra->sjinfo,
+											   child_rel->relids,
+											   inner_rel->relids);
+		child_restrictlist = (List *)
+			adjust_appendrel_attrs(root, (Node *)extra->restrictlist,
+								   nappinfos, appinfos);
+		pfree(appinfos);
+
+		child_join_rel = find_join_rel(root, child_join_relids);
+		if (!child_join_rel)
+		{
+			child_join_rel = build_child_join_rel(root,
+												  child_rel,
+												  inner_rel,
+												  joinrel,
+												  child_restrictlist,
+												  child_sjinfo,
+												  jointype);
+			if (!child_join_rel)
+			{
+				/*
+				 * If can't build JOIN between inner relation and one of the outer
+				 * partitions - return immediately.
+				 */
+				return NIL;
+			}
+		}
+		else
+		{
+			/*
+			 * TODO:
+			 * Can't imagine situation when join relation already exists. But in
+			 * the 'partition_join' regression test it happens.
+			 * It may be an indicator of possible problems.
+			 */
+		}
+
+		populate_joinrel_with_paths(root,
+									child_rel,
+									inner_rel,
+									child_join_rel,
+									child_sjinfo,
+									child_restrictlist);
+
+		/* Give up if asymmetric partition-wise join is not available */
+		if (child_join_rel->pathlist == NIL)
+			return NIL;
+
+		set_cheapest(child_join_rel);
+		result = lappend(result, child_join_rel);
+	}
+	return result;
+}
+
+void
+try_asymmetric_partitionwise_join(PlannerInfo *root,
+								  RelOptInfo *joinrel,
+								  RelOptInfo *outer_rel,
+								  RelOptInfo *inner_rel,
+								  JoinType jointype,
+								  JoinPathExtraData *extra)
+{
+	ListCell *lc;
+
+	if (!enable_partitionwise_join)
+		return;
+
+	if (IS_OTHER_REL(outer_rel) || IS_OTHER_REL(inner_rel))
+		return;
+
+	if (jointype != JOIN_INNER && jointype != JOIN_LEFT)
+		return;
+
+	foreach (lc, outer_rel->pathlist)
+	{
+		AppendPath *append_path = lfirst(lc);
+
+		/*
+		 * MEMO: We assume this pathlist keeps at least one AppendPath that
+		 * represents partitioned table-scan, symmetric or asymmetric
+		 * partition-wise join. It is not correct right now, however, a hook
+		 * on add_path() to give additional decision for path removel allows
+		 * to retain this kind of AppendPath, regardless of its cost.
+		 */
+		if (IsA(append_path, AppendPath))
+		{
+			List **join_rel_level_saved;
+			List *live_childrels = NIL;
+
+			join_rel_level_saved = root->join_rel_level;
+			PG_TRY();
+			{
+				/* temporary disables "dynamic programming" algorithm */
+				root->join_rel_level = NULL;
+
+				live_childrels =
+					extract_asymmetric_partitionwise_subjoin(root,
+															 joinrel,
+															 append_path,
+															 inner_rel,
+															 jointype,
+															 extra);
+			}
+			PG_CATCH();
+			{
+				root->join_rel_level = join_rel_level_saved;
+				PG_RE_THROW();
+			}
+			PG_END_TRY();
+			root->join_rel_level = join_rel_level_saved;
+
+			if (live_childrels != NIL)
+				add_paths_to_append_rel(root, joinrel, live_childrels);
+
+			break;
+		}
+	}
+}
+
 /*
  * Construct the SpecialJoinInfo for a child-join by translating
  * SpecialJoinInfo for the join between parents. left_relids and right_relids
diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c
index af46f581ac..be4624b619 100644
--- a/src/backend/optimizer/util/appendinfo.c
+++ b/src/backend/optimizer/util/appendinfo.c
@@ -202,7 +202,9 @@ adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos,
 	context.appinfos = appinfos;
 
 	/* If there's nothing to adjust, don't call this function. */
-	Assert(nappinfos >= 1 && appinfos != NULL);
+	/* If there's nothing to adjust, just return a duplication */
+	if (nappinfos == 0)
+		return copyObject(node);
 
 	/* Should never be translating a Query tree. */
 	Assert(node == NULL || !IsA(node, Query));
@@ -494,8 +496,6 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
 	int			nappinfos;
 	int			cnt;
 
-	Assert(bms_num_members(child_relids) == bms_num_members(top_parent_relids));
-
 	appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
 
 	/* Construct relids set for the immediate parent of given child. */
@@ -506,8 +506,13 @@ adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
 		parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
 	}
 
-	/* Recurse if immediate parent is not the top parent. */
-	if (!bms_equal(parent_relids, top_parent_relids))
+	/*
+	 * Recurse if immediate parent is not the top parent. Keep in mind that in a
+	 * case of asymmetric JOIN top_parent_relids can contain relids which aren't
+	 * part of an append node.
+	 */
+	if (!bms_equal(parent_relids, top_parent_relids) &&
+		!bms_is_subset(parent_relids, top_parent_relids))
 		node = adjust_appendrel_attrs_multilevel(root, node, parent_relids,
 												 top_parent_relids);
 
@@ -565,6 +570,7 @@ adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
 	AppendRelInfo **appinfos;
 	int			nappinfos;
 	Relids		parent_relids = NULL;
+	Relids		normal_relids = NULL;
 	Relids		result;
 	Relids		tmp_result = NULL;
 	int			cnt;
@@ -579,12 +585,17 @@ adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
 	appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
 
 	/* Construct relids set for the immediate parent of the given child. */
+	normal_relids = bms_copy(child_relids);
 	for (cnt = 0; cnt < nappinfos; cnt++)
 	{
 		AppendRelInfo *appinfo = appinfos[cnt];
 
 		parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
+		normal_relids = bms_del_member(normal_relids, appinfo->child_relid);
 	}
+	parent_relids = bms_union(parent_relids, normal_relids);
+	if (normal_relids)
+		bms_free(normal_relids);
 
 	/* Recurse if immediate parent is not the top parent. */
 	if (!bms_equal(parent_relids, top_parent_relids))
@@ -715,11 +726,11 @@ AppendRelInfo **
 find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
 {
 	AppendRelInfo **appinfos;
+	int			nrooms = bms_num_members(relids);
 	int			cnt = 0;
 	int			i;
 
-	*nappinfos = bms_num_members(relids);
-	appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
+	appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * nrooms);
 
 	i = -1;
 	while ((i = bms_next_member(relids, i)) >= 0)
@@ -727,10 +738,11 @@ find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
 		AppendRelInfo *appinfo = root->append_rel_array[i];
 
 		if (!appinfo)
-			elog(ERROR, "child rel %d not found in append_rel_array", i);
+			continue;
 
 		appinfos[cnt++] = appinfo;
 	}
+	*nappinfos = cnt;
 	return appinfos;
 }
 
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index b248b038e0..73cfb4748d 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -4209,7 +4209,14 @@ do { \
 
 		MemoryContextSwitchTo(oldcontext);
 	}
-	bms_free(required_outer);
+
+	/*
+	 * If adjust_child_relids_multilevel don't do replacements it returns
+	 * the original set, not a copy. It is possible in the case of asymmetric
+	 * JOIN and child_rel->relids contains relids only of plane relations.
+	 */
+	if (required_outer != old_ppi->ppi_req_outer)
+		bms_free(required_outer);
 
 	new_path->param_info = new_ppi;
 
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index e105a4d5f1..f98a82e725 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -790,11 +790,8 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
 	AppendRelInfo **appinfos;
 	int			nappinfos;
 
-	/* Only joins between "other" relations land here. */
-	Assert(IS_OTHER_REL(outer_rel) && IS_OTHER_REL(inner_rel));
-
-	/* The parent joinrel should have consider_partitionwise_join set. */
-	Assert(parent_joinrel->consider_partitionwise_join);
+	/* Either of relations must be "other" relation at least. */
+	Assert(IS_OTHER_REL(outer_rel) || IS_OTHER_REL(inner_rel));
 
 	joinrel->reloptkind = RELOPT_OTHER_JOINREL;
 	joinrel->relids = bms_union(outer_rel->relids, inner_rel->relids);
@@ -851,8 +848,11 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
 	joinrel->partexprs = NULL;
 	joinrel->nullable_partexprs = NULL;
 
-	joinrel->top_parent_relids = bms_union(outer_rel->top_parent_relids,
-										   inner_rel->top_parent_relids);
+	joinrel->top_parent_relids =
+		bms_union(IS_OTHER_REL(outer_rel) ?
+				  outer_rel->top_parent_relids : outer_rel->relids,
+				  IS_OTHER_REL(inner_rel) ?
+				  inner_rel->top_parent_relids : inner_rel->relids);
 
 	/* Compute information relevant to foreign relations. */
 	set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 035d3e1206..d64aa37f80 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -109,7 +109,12 @@ extern bool have_join_order_restriction(PlannerInfo *root,
 extern bool have_dangerous_phv(PlannerInfo *root,
 							   Relids outer_relids, Relids inner_params);
 extern void mark_dummy_rel(RelOptInfo *rel);
-
+extern void try_asymmetric_partitionwise_join(PlannerInfo *root,
+											  RelOptInfo *joinrel,
+											  RelOptInfo *outer_rel,
+											  RelOptInfo *inner_rel,
+											  JoinType jointype,
+											  JoinPathExtraData *extra);
 /*
  * equivclass.c
  *	  routines for managing EquivalenceClasses
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index 27f7525b3e..2bc7ad70d9 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -2320,6 +2320,215 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a =
  375 | 0375 | 375 | 0375
 (8 rows)
 
+--
+-- For asymmetric partition-wise join
+--
+CREATE TABLE prt5 (hkey int, a int, b int) PARTITION BY HASH(hkey);
+CREATE TABLE prt5_p0 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 0);
+CREATE TABLE prt5_p1 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 1);
+CREATE TABLE prt5_p2 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 2);
+CREATE TABLE t5_1 (aid int, alabel text);
+CREATE TABLE t5_2 (bid int, blabel text);
+INSERT INTO prt5 (SELECT x, (1000.0 * random())::int,
+                            (1000.0 * random())::int
+                    FROM generate_series(1,1000000) x);
+INSERT INTO t5_1 (SELECT x, md5(x::text) FROM generate_series(-200, 800) x);
+INSERT INTO t5_2 (SELECT x, md5(x::text) FROM generate_series(-200, 800) x);
+VACUUM ANALYZE prt5;
+VACUUM ANALYZE t5_1;
+VACUUM ANALYZE t5_2;
+SET max_parallel_workers_per_gather = 0;
+EXPLAIN (COSTS OFF)
+SELECT *
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                      QUERY PLAN                       
+-------------------------------------------------------
+ Append
+   ->  Hash Join
+         Hash Cond: (prt5_1.a = t5_1.aid)
+         ->  Seq Scan on prt5_p0 prt5_1
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_2.a = t5_1.aid)
+         ->  Seq Scan on prt5_p1 prt5_2
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_3.a = t5_1.aid)
+         ->  Seq Scan on prt5_p2 prt5_3
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%abc%'::text)
+(19 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT *
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Append
+   ->  Hash Join
+         Hash Cond: (prt5_1.a = t5_1.aid)
+         ->  Hash Join
+               Hash Cond: (prt5_1.b = t5_2.bid)
+               ->  Seq Scan on prt5_p0 prt5_1
+               ->  Hash
+                     ->  Seq Scan on t5_2
+                           Filter: (blabel ~~ '%cd%'::text)
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%ab%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_2.a = t5_1.aid)
+         ->  Hash Join
+               Hash Cond: (prt5_2.b = t5_2.bid)
+               ->  Seq Scan on prt5_p1 prt5_2
+               ->  Hash
+                     ->  Seq Scan on t5_2
+                           Filter: (blabel ~~ '%cd%'::text)
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%ab%'::text)
+   ->  Hash Join
+         Hash Cond: (prt5_3.a = t5_1.aid)
+         ->  Hash Join
+               Hash Cond: (prt5_3.b = t5_2.bid)
+               ->  Seq Scan on prt5_p2 prt5_3
+               ->  Hash
+                     ->  Seq Scan on t5_2
+                           Filter: (blabel ~~ '%cd%'::text)
+         ->  Hash
+               ->  Seq Scan on t5_1
+                     Filter: (alabel ~~ '%ab%'::text)
+(34 rows)
+
+-- unable to extract non-partitioned right relation
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 RIGHT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                  QUERY PLAN                   
+-----------------------------------------------
+ Hash Right Join
+   Hash Cond: (prt5.a = t5_1.aid)
+   Join Filter: (t5_1.alabel ~~ '%abc%'::text)
+   ->  Append
+         ->  Seq Scan on prt5_p0 prt5_1
+         ->  Seq Scan on prt5_p1 prt5_2
+         ->  Seq Scan on prt5_p2 prt5_3
+   ->  Hash
+         ->  Seq Scan on t5_1
+(9 rows)
+
+-- left side can be extracted, but no cost benefit
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 LEFT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+                   QUERY PLAN                    
+-------------------------------------------------
+ Hash Left Join
+   Hash Cond: (prt5.a = t5_1.aid)
+   ->  Append
+         ->  Seq Scan on prt5_p0 prt5_1
+         ->  Seq Scan on prt5_p1 prt5_2
+         ->  Seq Scan on prt5_p2 prt5_3
+   ->  Hash
+         ->  Seq Scan on t5_1
+               Filter: (alabel ~~ '%abc%'::text)
+(9 rows)
+
+-- validation of the results with/without asymmetric partition-wise join
+SELECT * INTO pg_temp.result01a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+SELECT * INTO pg_temp.result02a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+SET enable_partitionwise_join = off;
+SELECT * INTO pg_temp.result01b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+SELECT * INTO pg_temp.result02b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+SELECT * FROM pg_temp.result01a EXCEPT SELECT * FROM pg_temp.result01b;
+ hkey | a | b | aid | alabel 
+------+---+---+-----+--------
+(0 rows)
+
+SELECT * FROM pg_temp.result02a EXCEPT SELECT * FROM pg_temp.result02b;
+ hkey | a | b | aid | alabel | bid | blabel 
+------+---+---+-----+--------+-----+--------
+(0 rows)
+
+RESET max_parallel_workers_per_gather;
+SET enable_partitionwise_join = true;
+-- Parameterized path examples.
+CREATE TABLE prta (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prta1 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prta2 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prta1 (id);
+CREATE UNIQUE INDEX ON prta2 (id);
+INSERT INTO prta (id, payload)
+	(SELECT *, ('abc' || id)::text AS payload
+		FROM generate_series(1,1) AS id);
+CREATE TABLE prtb (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prtb1 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prtb2 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prtb1 (id);
+CREATE UNIQUE INDEX ON prtb2 (id);
+INSERT INTO prtb (id, payload)
+    (SELECT *, ('def' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+CREATE TABLE e (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE e1 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE e2 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 1);
+INSERT INTO e (id, payload)
+	(SELECT *, ('ghi' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+CREATE UNIQUE INDEX ON e1 (id);
+CREATE UNIQUE INDEX ON e2 (id);
+ANALYZE prta,prtb,e;
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb WHERE prta.id=prtb.id;
+                        QUERY PLAN                         
+-----------------------------------------------------------
+ Append
+   ->  Nested Loop
+         ->  Seq Scan on prta1 prta_1
+         ->  Index Scan using prtb1_id_idx on prtb1 prtb_1
+               Index Cond: (id = prta_1.id)
+   ->  Nested Loop
+         ->  Seq Scan on prta2 prta_2
+         ->  Index Scan using prtb2_id_idx on prtb2 prtb_2
+               Index Cond: (id = prta_2.id)
+(9 rows)
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb,e WHERE prta.id=prtb.id AND prta.id=e.id;
+                           QUERY PLAN                            
+-----------------------------------------------------------------
+ Append
+   ->  Nested Loop
+         Join Filter: (prta_1.id = e_1.id)
+         ->  Nested Loop
+               ->  Seq Scan on prta1 prta_1
+               ->  Index Scan using prtb1_id_idx on prtb1 prtb_1
+                     Index Cond: (id = prta_1.id)
+         ->  Index Scan using e1_id_idx on e1 e_1
+               Index Cond: (id = prtb_1.id)
+   ->  Nested Loop
+         Join Filter: (prta_2.id = e_2.id)
+         ->  Nested Loop
+               ->  Seq Scan on prta2 prta_2
+               ->  Index Scan using prtb2_id_idx on prtb2 prtb_2
+                     Index Cond: (id = prta_2.id)
+         ->  Index Scan using e2_id_idx on e2 e_2
+               Index Cond: (id = prtb_2.id)
+(17 rows)
+
 -- semi join
 EXPLAIN (COSTS OFF)
 SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
diff --git a/src/test/regress/sql/partition_join.sql b/src/test/regress/sql/partition_join.sql
index d97b5b69ff..c206fd736a 100644
--- a/src/test/regress/sql/partition_join.sql
+++ b/src/test/regress/sql/partition_join.sql
@@ -536,6 +536,105 @@ EXPLAIN (COSTS OFF)
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
 SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = t2.b) WHERE t1.b = 0 ORDER BY t1.a, t2.b;
 
+--
+-- For asymmetric partition-wise join
+--
+CREATE TABLE prt5 (hkey int, a int, b int) PARTITION BY HASH(hkey);
+CREATE TABLE prt5_p0 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 0);
+CREATE TABLE prt5_p1 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 1);
+CREATE TABLE prt5_p2 PARTITION OF prt5
+                     FOR VALUES WITH (modulus 3, remainder 2);
+CREATE TABLE t5_1 (aid int, alabel text);
+CREATE TABLE t5_2 (bid int, blabel text);
+
+INSERT INTO prt5 (SELECT x, (1000.0 * random())::int,
+                            (1000.0 * random())::int
+                    FROM generate_series(1,1000000) x);
+INSERT INTO t5_1 (SELECT x, md5(x::text) FROM generate_series(-200, 800) x);
+INSERT INTO t5_2 (SELECT x, md5(x::text) FROM generate_series(-200, 800) x);
+
+VACUUM ANALYZE prt5;
+VACUUM ANALYZE t5_1;
+VACUUM ANALYZE t5_2;
+
+SET max_parallel_workers_per_gather = 0;
+EXPLAIN (COSTS OFF)
+SELECT *
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+EXPLAIN (COSTS OFF)
+SELECT *
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+
+-- unable to extract non-partitioned right relation
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 RIGHT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+-- left side can be extracted, but no cost benefit
+EXPLAIN (COSTS OFF)
+SELECT * FROM prt5 LEFT JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+-- validation of the results with/without asymmetric partition-wise join
+SELECT * INTO pg_temp.result01a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+SELECT * INTO pg_temp.result02a
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+
+SET enable_partitionwise_join = off;
+
+SELECT * INTO pg_temp.result01b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%abc%';
+
+SELECT * INTO pg_temp.result02b
+  FROM prt5 JOIN t5_1 ON a = aid AND alabel like '%ab%'
+            JOIN t5_2 ON b = bid AND blabel like '%cd%';
+
+SELECT * FROM pg_temp.result01a EXCEPT SELECT * FROM pg_temp.result01b;
+SELECT * FROM pg_temp.result02a EXCEPT SELECT * FROM pg_temp.result02b;
+
+RESET max_parallel_workers_per_gather;
+SET enable_partitionwise_join = true;
+
+-- Parameterized path examples.
+CREATE TABLE prta (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prta1 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prta2 PARTITION OF prta FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prta1 (id);
+CREATE UNIQUE INDEX ON prta2 (id);
+INSERT INTO prta (id, payload)
+	(SELECT *, ('abc' || id)::text AS payload
+		FROM generate_series(1,1) AS id);
+
+CREATE TABLE prtb (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE prtb1 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE prtb2 PARTITION OF prtb FOR VALUES WITH (modulus 2, remainder 1);
+CREATE UNIQUE INDEX ON prtb1 (id);
+CREATE UNIQUE INDEX ON prtb2 (id);
+INSERT INTO prtb (id, payload)
+    (SELECT *, ('def' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+
+CREATE TABLE e (id integer, payload text) PARTITION BY HASH (id);
+CREATE TABLE e1 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 0);
+CREATE TABLE e2 PARTITION OF e FOR VALUES WITH (modulus 2, remainder 1);
+INSERT INTO e (id, payload)
+	(SELECT *, ('ghi' || id)::text AS payload
+		FROM generate_series(1,1000) AS id);
+CREATE UNIQUE INDEX ON e1 (id);
+CREATE UNIQUE INDEX ON e2 (id);
+
+ANALYZE prta,prtb,e;
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb WHERE prta.id=prtb.id;
+
+EXPLAIN (COSTS OFF)
+SELECT * FROM prta,prtb,e WHERE prta.id=prtb.id AND prta.id=e.id;
+
 -- semi join
 EXPLAIN (COSTS OFF)
 SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a;
-- 
2.25.1


--------------8EB2F9A6243C623F4024291E--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH 1/3] Schema variables - new implementation for Postgres 15
@ 2021-10-30 06:35  Pavel Stehule <pavel.stehule@gmail.com>
  0 siblings, 0 replies; 327+ messages in thread

From: Pavel Stehule @ 2021-10-30 06:35 UTC (permalink / raw)

Hi

only rebase

Regards

Pavel
---
 doc/src/sgml/advanced.sgml                    |  50 +
 doc/src/sgml/catalogs.sgml                    | 144 +++
 doc/src/sgml/plpgsql.sgml                     |  13 +
 doc/src/sgml/ref/allfiles.sgml                |   4 +
 .../sgml/ref/alter_default_privileges.sgml    |  14 +-
 doc/src/sgml/ref/alter_variable.sgml          | 179 ++++
 doc/src/sgml/ref/create_variable.sgml         | 190 ++++
 doc/src/sgml/ref/discard.sgml                 |  14 +-
 doc/src/sgml/ref/drop_variable.sgml           | 120 +++
 doc/src/sgml/ref/grant.sgml                   |  23 +
 doc/src/sgml/ref/let.sgml                     | 107 +++
 doc/src/sgml/ref/pg_restore.sgml              |  11 +
 doc/src/sgml/ref/revoke.sgml                  |   6 +
 doc/src/sgml/reference.sgml                   |   4 +
 src/backend/access/transam/xact.c             |   9 +
 src/backend/catalog/Makefile                  |   4 +-
 src/backend/catalog/aclchk.c                  | 307 ++++++
 src/backend/catalog/dependency.c              |  18 +-
 src/backend/catalog/namespace.c               | 341 +++++++
 src/backend/catalog/objectaddress.c           | 126 ++-
 src/backend/catalog/pg_shdepend.c             |   2 +
 src/backend/catalog/pg_variable.c             | 388 ++++++++
 src/backend/commands/Makefile                 |   1 +
 src/backend/commands/alter.c                  |   9 +
 src/backend/commands/discard.c                |   6 +
 src/backend/commands/dropcmds.c               |   4 +
 src/backend/commands/event_trigger.c          |   6 +
 src/backend/commands/explain.c                |  16 +
 src/backend/commands/schemavariable.c         | 881 ++++++++++++++++++
 src/backend/commands/seclabel.c               |   1 +
 src/backend/commands/tablecmds.c              |   1 +
 src/backend/executor/Makefile                 |   1 +
 src/backend/executor/execExpr.c               |  55 ++
 src/backend/executor/execExprInterp.c         |  12 +
 src/backend/executor/execMain.c               |  49 +
 src/backend/executor/execParallel.c           | 148 ++-
 src/backend/executor/spi.c                    |   3 +
 src/backend/executor/svariableReceiver.c      | 145 +++
 src/backend/jit/llvm/llvmjit_expr.c           |   6 +
 src/backend/nodes/copyfuncs.c                 |  42 +-
 src/backend/nodes/equalfuncs.c                |  35 +
 src/backend/nodes/outfuncs.c                  |  21 +
 src/backend/nodes/readfuncs.c                 |   4 +
 src/backend/optimizer/plan/planner.c          |   8 +
 src/backend/optimizer/plan/setrefs.c          | 104 ++-
 src/backend/optimizer/util/clauses.c          |  31 +-
 src/backend/parser/analyze.c                  | 287 +++++-
 src/backend/parser/gram.y                     | 202 +++-
 src/backend/parser/parse_agg.c                |   6 +
 src/backend/parser/parse_expr.c               | 167 +++-
 src/backend/parser/parse_func.c               |   4 +
 src/backend/parser/parse_target.c             |   4 +-
 src/backend/parser/parser.c                   |   3 +-
 src/backend/rewrite/rewriteHandler.c          |  34 +
 src/backend/rewrite/rowsecurity.c             |   8 +-
 src/backend/tcop/dest.c                       |   7 +
 src/backend/tcop/pquery.c                     |   3 +
 src/backend/tcop/utility.c                    |  34 +
 src/backend/utils/adt/acl.c                   |  21 +
 src/backend/utils/adt/ruleutils.c             |   9 +
 src/backend/utils/cache/lsyscache.c           |  13 +
 src/backend/utils/cache/syscache.c            |  23 +
 src/backend/utils/fmgr/fmgr.c                 |  16 +-
 src/bin/pg_dump/common.c                      |   3 +-
 src/bin/pg_dump/pg_backup.h                   |   2 +
 src/bin/pg_dump/pg_backup_archiver.c          |  12 +-
 src/bin/pg_dump/pg_dump.c                     | 231 +++++
 src/bin/pg_dump/pg_dump.h                     |  22 +
 src/bin/pg_dump/pg_dump_sort.c                |   6 +
 src/bin/pg_dump/pg_restore.c                  |   9 +-
 src/bin/pg_dump/t/002_pg_dump.pl              |  24 +
 src/bin/psql/command.c                        |   3 +
 src/bin/psql/describe.c                       |  82 ++
 src/bin/psql/describe.h                       |   2 +
 src/bin/psql/help.c                           |   1 +
 src/bin/psql/tab-complete.c                   |  56 +-
 src/include/catalog/dependency.h              |   5 +-
 src/include/catalog/namespace.h               |   6 +
 src/include/catalog/pg_default_acl.h          |   1 +
 src/include/catalog/pg_proc.dat               |   3 +
 src/include/catalog/pg_variable.h             | 117 +++
 src/include/commands/schema_variable.h        |  44 +
 src/include/executor/execExpr.h               |  10 +
 src/include/executor/execdesc.h               |   4 +
 src/include/executor/svariableReceiver.h      |  25 +
 src/include/nodes/execnodes.h                 |  19 +
 src/include/nodes/nodes.h                     |   2 +
 src/include/nodes/parsenodes.h                |  42 +-
 src/include/nodes/pathnodes.h                 |   3 +
 src/include/nodes/plannodes.h                 |   4 +-
 src/include/nodes/primnodes.h                 |  19 +-
 src/include/optimizer/planmain.h              |   2 +
 src/include/parser/kwlist.h                   |   3 +
 src/include/parser/parse_node.h               |   3 +
 src/include/parser/parser.h                   |   6 +-
 src/include/tcop/cmdtaglist.h                 |   5 +
 src/include/tcop/dest.h                       |   3 +-
 src/include/utils/acl.h                       |  10 +-
 src/include/utils/lsyscache.h                 |   1 +
 src/include/utils/syscache.h                  |   6 +-
 src/pl/plpgsql/src/pl_exec.c                  |  55 ++
 src/pl/plpgsql/src/pl_funcs.c                 |  24 +
 src/pl/plpgsql/src/pl_gram.y                  |  28 +-
 src/pl/plpgsql/src/pl_reserved_kwlist.h       |   1 +
 src/pl/plpgsql/src/plpgsql.h                  |  14 +-
 src/test/regress/expected/misc_sanity.out     |   4 +-
 src/test/regress/expected/sanity_check.out    |   1 +
 .../regress/expected/schema_variables.out     | 655 +++++++++++++
 src/test/regress/parallel_schedule            |   2 +-
 src/test/regress/sql/schema_variables.sql     | 438 +++++++++
 110 files changed, 6455 insertions(+), 67 deletions(-)
 create mode 100644 doc/src/sgml/ref/alter_variable.sgml
 create mode 100644 doc/src/sgml/ref/create_variable.sgml
 create mode 100644 doc/src/sgml/ref/drop_variable.sgml
 create mode 100644 doc/src/sgml/ref/let.sgml
 create mode 100644 src/backend/catalog/pg_variable.c
 create mode 100644 src/backend/commands/schemavariable.c
 create mode 100644 src/backend/executor/svariableReceiver.c
 create mode 100644 src/include/catalog/pg_variable.h
 create mode 100644 src/include/commands/schema_variable.h
 create mode 100644 src/include/executor/svariableReceiver.h
 create mode 100644 src/test/regress/expected/schema_variables.out
 create mode 100644 src/test/regress/sql/schema_variables.sql

diff --git a/doc/src/sgml/advanced.sgml b/doc/src/sgml/advanced.sgml
index 71ae423f63..2d6555497c 100644
--- a/doc/src/sgml/advanced.sgml
+++ b/doc/src/sgml/advanced.sgml
@@ -700,6 +700,56 @@ SELECT name, elevation
   </sect1>
 
 
+  <sect1 id="tutorial-schema-variables">
+   <title>Schema Variables</title>
+
+   <indexterm zone="tutorial-schema-variables">
+    <primary>Schema variables</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>schema variable</primary>
+    <secondary>introduction</secondary>
+   </indexterm>
+
+   <para>
+    Schema variables are database objects that can hold a value.
+    Schema variables, like relations, exist within a schema and their access is
+    controlled via <command>GRANT</command> and <command>REVOKE</command> commands.
+    The schema variable can be created by the <command>CREATE VARIABLE</command> command.
+   </para>
+
+   <para>
+    The value of a schema variable is local to the current session. Retrieving
+    a variable's value returns either a NULL or a default value, unless its value
+    is set to something else in the current session with a LET command. The content
+    of a variable is not transactional. This is the same as in regular variables
+    in PL languages.
+   </para>
+
+   <para>
+    Schema variables are retrieved by the <command>SELECT</command> SQL command.
+    Their value is set with the <command>LET</command> SQL command.
+    While schema variables share properties with tables, their value cannot be updated
+    with an <command>UPDATE</command> command.
+<programlisting>
+CREATE VARIABLE var1 AS date;
+LET var1 = current_date;
+SELECT var1;
+</programlisting>
+
+    or
+
+<programlisting>
+CREATE VARIABLE public.current_user_id AS integer;
+GRANT READ ON VARIABLE public.current_user_id TO PUBLIC;
+LET current_user_id = (SELECT id FROM users WHERE usename = session_user);
+SELECT current_user_id;
+</programlisting>
+   </para>
+  </sect1>
+
+
   <sect1 id="tutorial-conclusion">
    <title>Conclusion</title>
 
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 720e83e523..db0d2fe859 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -364,6 +364,11 @@
       <entry><link linkend="catalog-pg-user-mapping"><structname>pg_user_mapping</structname></link></entry>
       <entry>mappings of users to foreign servers</entry>
      </row>
+
+     <row>
+      <entry><link linkend="catalog-pg-variable"><structname>pg_variable</structname></link></entry>
+      <entry>schema variables</entry>
+     </row>
     </tbody>
    </tgroup>
   </table>
@@ -13982,4 +13987,143 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
 
  </sect1>
 
+ <sect1 id="catalog-pg-variable">
+  <title><structname>pg_variable</structname></title>
+
+  <indexterm zone="catalog-pg-variable">
+   <primary>pg_variable</primary>
+  </indexterm>
+
+  <para>
+   The table <structname>pg_variable</structname> holds metadata
+   of schema variables.
+  </para>
+
+  <table>
+   <title><structname>pg_variable</structname> Columns</title>
+
+   <tgroup cols="4">
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+    <tbody>
+     <row>
+      <entry><structfield>oid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry></entry>
+      <entry>Row identifier</entry>
+     </row>
+
+     <row>
+      <entry><structfield>varname</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry></entry>
+      <entry>Name of the schema variable</entry>
+     </row>
+
+     <row>
+      <entry><structfield>varnamespace</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-namespace"><structname>pg_namespace</structname></link>.oid</literal></entry>
+      <entry>
+       The OID of the namespace that contains this variable
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>vartype</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
+      <entry>
+       The OID of the variable's data type.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>vartypmod</structfield></entry>
+      <entry><type>int4</type></entry>
+      <entry></entry>
+      <entry>
+       <structfield>vartypmod</structfield> records type-specific data
+       supplied at variable creation time (for example, the maximum
+       length of a <type>varchar</type> column).  It is passed to
+       type-specific input 
+       functions and length coercion functions.
+       The value will generally be -1 for types that do not need <structfield>vartypmod</structfield>.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>varowner</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+      <entry>Owner of the variable</entry>
+     </row>
+
+     <row>
+      <entry><structfield>varcollation</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-collation"><structname>pg_collation</structname></link>.oid</literal></entry>
+      <entry>
+       The defined collation of the variable, or zero if the variable is
+       not of a collatable data type.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>varisnotnull</structfield></entry>
+      <entry><type>boolean</type></entry>
+      <entry></entry>
+      <entry>
+       True if the schema variable doesn't allow null value. The default value is false.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>varisimmutable</structfield></entry>
+      <entry><type>boolean</type></entry>
+      <entry></entry>
+      <entry>
+       True if the variable is immutable (cannot be modified). The default value is false.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>vareoxaction</structfield></entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>
+       <literal>n</literal> = no action, <literal>d</literal> = drop the variable,
+       <literal>r</literal> = reset the variable to its default value.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>vardefexpr</structfield></entry>
+      <entry><type>pg_node_tree</type></entry>
+      <entry></entry>
+      <entry>The internal representation of the variable default value.</entry>
+     </row>
+
+     <row>
+      <entry><structfield>varacl</structfield></entry>
+      <entry><type>aclitem[]</type></entry>
+      <entry></entry>
+      <entry>
+       Access privileges; see
+       <xref linkend="sql-grant"/> and
+       <xref linkend="sql-revoke"/>
+       for details
+      </entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+ </sect1>
+
 </chapter>
diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index e5c1356d8c..e494161741 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -5952,6 +5952,19 @@ $$ LANGUAGE plpgsql STRICT IMMUTABLE;
 </programlisting>
     </para>
    </sect3>
+
+   <sect3>
+    <title><command>Global variables and constants</command></title>
+
+    <para>
+     The <application>PL/pgSQL</application> language has no packages,
+     and therefore no package variables or package constants.
+     <productname>PostgreSQL</productname> has schema variables and
+     immutable schema variables. Schema variables can be created
+     by <command>CREATE VARIABLE</command> described in <xref
+     linkend="sql-createvariable"/>.
+    </para>
+   </sect3>
   </sect2>
 
   <sect2 id="plpgsql-porting-appendix">
diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index d67270ccc3..8458cad752 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -47,6 +47,7 @@ Complete list of usable sgml source files in this directory.
 <!ENTITY alterType          SYSTEM "alter_type.sgml">
 <!ENTITY alterUser          SYSTEM "alter_user.sgml">
 <!ENTITY alterUserMapping   SYSTEM "alter_user_mapping.sgml">
+<!ENTITY alterVariable      SYSTEM "alter_variable.sgml">
 <!ENTITY alterView          SYSTEM "alter_view.sgml">
 <!ENTITY analyze            SYSTEM "analyze.sgml">
 <!ENTITY begin              SYSTEM "begin.sgml">
@@ -99,6 +100,7 @@ Complete list of usable sgml source files in this directory.
 <!ENTITY createType         SYSTEM "create_type.sgml">
 <!ENTITY createUser         SYSTEM "create_user.sgml">
 <!ENTITY createUserMapping  SYSTEM "create_user_mapping.sgml">
+<!ENTITY createVariable     SYSTEM "create_variable.sgml">
 <!ENTITY createView         SYSTEM "create_view.sgml">
 <!ENTITY deallocate         SYSTEM "deallocate.sgml">
 <!ENTITY declare            SYSTEM "declare.sgml">
@@ -148,6 +150,7 @@ Complete list of usable sgml source files in this directory.
 <!ENTITY dropUser           SYSTEM "drop_user.sgml">
 <!ENTITY dropUserMapping    SYSTEM "drop_user_mapping.sgml">
 <!ENTITY dropView           SYSTEM "drop_view.sgml">
+<!ENTITY dropVariable       SYSTEM "drop_variable.sgml">
 <!ENTITY end                SYSTEM "end.sgml">
 <!ENTITY execute            SYSTEM "execute.sgml">
 <!ENTITY explain            SYSTEM "explain.sgml">
@@ -155,6 +158,7 @@ Complete list of usable sgml source files in this directory.
 <!ENTITY grant              SYSTEM "grant.sgml">
 <!ENTITY importForeignSchema SYSTEM "import_foreign_schema.sgml">
 <!ENTITY insert             SYSTEM "insert.sgml">
+<!ENTITY let                SYSTEM "let.sgml">
 <!ENTITY listen             SYSTEM "listen.sgml">
 <!ENTITY load               SYSTEM "load.sgml">
 <!ENTITY lock               SYSTEM "lock.sgml">
diff --git a/doc/src/sgml/ref/alter_default_privileges.sgml b/doc/src/sgml/ref/alter_default_privileges.sgml
index f1d54f5aa3..95e8352167 100644
--- a/doc/src/sgml/ref/alter_default_privileges.sgml
+++ b/doc/src/sgml/ref/alter_default_privileges.sgml
@@ -50,6 +50,10 @@ GRANT { USAGE | CREATE | ALL [ PRIVILEGES ] }
     ON SCHEMAS
     TO { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
 
+GRANT { READ | WRITE | ALL [ PRIVILEGES ] }
+    ON VARIABLES
+    TO { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
 REVOKE [ GRANT OPTION FOR ]
     { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
     [, ...] | ALL [ PRIVILEGES ] }
@@ -81,6 +85,12 @@ REVOKE [ GRANT OPTION FOR ]
     ON SCHEMAS
     FROM { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...]
     [ CASCADE | RESTRICT ]
+
+REVOKE [ GRANT OPTION FOR ]
+    { { READ | WRITE } [, ...] | ALL [ PRIVILEGES ] }
+    ON VARIABLES
+    FROM { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...]
+    [ CASCADE | RESTRICT ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -92,8 +102,8 @@ REVOKE [ GRANT OPTION FOR ]
    that will be applied to objects created in the future.  (It does not
    affect privileges assigned to already-existing objects.)  Currently,
    only the privileges for schemas, tables (including views and foreign
-   tables), sequences, functions, and types (including domains) can be
-   altered.  For this command, functions include aggregates and procedures.
+   tables), sequences, functions, types (including domains) and schema variables
+   can be altered.  For this command, functions include aggregates and procedures.
    The words <literal>FUNCTIONS</literal> and <literal>ROUTINES</literal> are
    equivalent in this command.  (<literal>ROUTINES</literal> is preferred
    going forward as the standard term for functions and procedures taken
diff --git a/doc/src/sgml/ref/alter_variable.sgml b/doc/src/sgml/ref/alter_variable.sgml
new file mode 100644
index 0000000000..85a38fb9d5
--- /dev/null
+++ b/doc/src/sgml/ref/alter_variable.sgml
@@ -0,0 +1,179 @@
+<!--
+doc/src/sgml/ref/alter_variable.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="sql-altervariable">
+ <indexterm zone="sql-altervariable">
+  <primary>ALTER VARIABLE</primary>
+ </indexterm>
+
+ <indexterm>
+  <primary>schema variable</primary>
+  <secondary>altering</secondary>
+ </indexterm>
+
+ <refmeta>
+  <refentrytitle>ALTER VARIABLE</refentrytitle>
+  <manvolnum>7</manvolnum>
+  <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+  <refname>ALTER VARIABLE</refname>
+  <refpurpose>
+   change the definition of a variable
+  </refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+<synopsis>
+ALTER VARIABLE <replaceable class="parameter">name</replaceable> OWNER TO { <replaceable class="parameter">new_owner</replaceable> | CURRENT_USER | SESSION_USER }
+ALTER VARIABLE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable class="parameter">new_name</replaceable>
+ALTER VARIABLE <replaceable class="parameter">name</replaceable> SET SCHEMA <replaceable class="parameter">new_schema</replaceable>
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+  <title>Description</title>
+
+  <para>
+   The <command>ALTER VARIABLE</command> command changes the definition of an existing
+   variable. There are several subforms:
+
+  <variablelist>
+   <varlistentry>
+    <term><literal>OWNER</literal></term>
+    <listitem>
+     <para>
+      This form changes the owner of the variable.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>RENAME</literal></term>
+    <listitem>
+     <para>
+      This form changes the name of the variable.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>SET SCHEMA</literal></term>
+    <listitem>
+     <para>
+      This form moves the variable into another schema.
+     </para>
+    </listitem>
+   </varlistentry>
+
+  </variablelist>
+  </para>
+
+  <para>
+   Only the owner or a superuser is allowed to alter a schema variable.
+   In order to move a schema variable from one schema to another, the user must
+   also have the <literal>CREATE</literal> privilege on the new schema (or be
+   a superuser).
+
+   In order to move the schema variable ownership from one role to another,
+   the user must also be a direct or indirect member of the new
+   owning role, and that role must have the <literal>CREATE</literal> privilege
+   on the variable's schema (or be a superuser). These restrictions enforce that
+   altering the owner doesn't do anything you couldn't do by dropping and
+   recreating the variable.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Parameters</title>
+
+   <para>
+    <variablelist>
+     <varlistentry>
+      <term><replaceable class="parameter">name</replaceable></term>
+      <listitem>
+       <para>
+        The name (possibly schema-qualified) of the existing variable to
+        alter.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><replaceable class="parameter">new_name</replaceable></term>
+      <listitem>
+       <para>
+        The new name for the variable.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><replaceable class="parameter">new_owner</replaceable></term>
+      <listitem>
+       <para>
+        The user name of the new owner of the variable.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><replaceable class="parameter">new_schema</replaceable></term>
+      <listitem>
+       <para>
+        The new schema for the variable.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+  </refsect1>
+
+ <refsect1>
+  <title>Examples</title>
+
+  <para>
+   To rename a variable:
+<programlisting>
+ALTER VARIABLE foo RENAME TO boo;
+</programlisting>
+  </para>
+
+  <para>
+   To change the owner of the variable <literal>boo</literal>
+   to <literal>joe</literal>:
+<programlisting>
+ALTER VARIABLE boo OWNER TO joe;
+</programlisting>
+  </para>
+
+  <para>
+   To change the schema of the variable <literal>boo</literal>
+   to <literal>private</literal>:
+<programlisting>
+ALTER VARIABLE boo SET SCHEMA private;
+</programlisting>
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Compatibility</title>
+
+  <para>
+   Schema variables and this command in particular are a PostgreSQL extension.
+  </para>
+ </refsect1>
+
+ <refsect1 id="sql-altervariable-see-also">
+  <title>See Also</title>
+
+  <simplelist type="inline">
+   <member><xref linkend="sql-createvariable"/></member>
+   <member><xref linkend="sql-dropvariable"/></member>
+   <member><xref linkend="sql-let"/></member>
+  </simplelist>
+ </refsect1>
+</refentry>
diff --git a/doc/src/sgml/ref/create_variable.sgml b/doc/src/sgml/ref/create_variable.sgml
new file mode 100644
index 0000000000..859c0bc2f1
--- /dev/null
+++ b/doc/src/sgml/ref/create_variable.sgml
@@ -0,0 +1,190 @@
+<!--
+doc/src/sgml/ref/create_variable.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="sql-createvariable">
+ <indexterm zone="sql-createvariable">
+  <primary>CREATE VARIABLE</primary>
+ </indexterm>
+
+ <indexterm>
+  <primary>schema variable</primary>
+  <secondary>defining</secondary>
+ </indexterm>
+
+ <refmeta>
+  <refentrytitle>CREATE VARIABLE</refentrytitle>
+  <manvolnum>7</manvolnum>
+  <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+  <refname>CREATE VARIABLE</refname>
+  <refpurpose>define a schema variable</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+<synopsis>
+CREATE [ { TEMPORARY | TEMP } ] [ IMMUTABLE ] VARIABLE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> [ AS ] <replaceable class="parameter">data_type</replaceable> ] [ COLLATE <replaceable class="parameter">collation</replaceable> ]
+    [ NOT NULL ] [ DEFAULT <replaceable class="parameter">default_expr</replaceable> ] [ { ON COMMIT DROP | ON TRANSACTION END RESET } ]
+</synopsis>
+ </refsynopsisdiv>
+ <refsect1>
+  <title>Description</title>
+
+  <para>
+   The <command>CREATE VARIABLE</command> command creates a schema variable.
+   Schema variables, like relations, exist within a schema and their access is
+   controlled via <command>GRANT</command> and <command>REVOKE</command> commands.
+   Changing a schema variable is non-transactional.
+  </para>
+
+  <para>
+   The value of a schema variable is local to the current session. Retrieving
+   a variable's value returns either a NULL or a default value, unless its value
+   is set to something else in the current session with a LET command. The content
+   of a variable is not transactional. This is the same as in regular variables in PL languages.
+  </para>
+
+  <para>
+   Schema variables are retrieved by the <command>SELECT</command> SQL command.
+   Their value is set with the <command>LET</command> SQL command.
+   While schema variables share properties with tables, their value cannot be updated
+   with an <command>UPDATE</command> command.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Parameters</title>
+
+  <variablelist>
+   <varlistentry>
+    <term><literal>IMMUTABLE</literal></term>
+    <listitem>
+     <para>
+      The value of the variable cannot be changed.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do not throw an error if the name already exists. A notice is issued in this case.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="parameter">name</replaceable></term>
+    <listitem>
+     <para>
+      The name, optionally schema-qualified, of the variable.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="parameter">data_type</replaceable></term>
+    <listitem>
+     <para>
+      The name, optionally schema-qualified, of the data type of the variable.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>COLLATE <replaceable>collation</replaceable></literal></term>
+    <listitem>
+     <para>
+      The <literal>COLLATE</literal> clause assigns a collation to
+      the variable (which must be of a collatable data type).
+      If not specified, the variable data type's default collation is used.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>NOT NULL</literal></term>
+    <listitem>
+     <para>
+      The <literal>NOT NULL</literal> clause forbids to set the variable to
+      a null value. A variable created as NOT NULL and without an explicitly
+      declared default value cannot be read until it is initialized by a LET
+      command. This obliges the user to explicitly initialize the variable
+      content before reading it.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>DEFAULT <replaceable>default_expr</replaceable></literal></term>
+    <listitem>
+     <para>
+      The <literal>DEFAULT</literal> clause can be used to assign a default value to
+      a schema variable.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>ON COMMIT DROP</literal>, <literal>ON TRANSACTION END RESET</literal></term>
+    <listitem>
+     <para>
+      The <literal>ON COMMIT DROP</literal> clause specifies the behaviour
+      of a temporary schema variable at transaction commit. With this clause the
+      variable is dropped at commit time. The clause is only allowed
+      for temporary variables. The <literal>ON TRANSACTION END RESET</literal>
+      clause enforces the variable to be reset to its default value when
+      the transaction is committed or rolled back.
+     </para>
+    </listitem>
+   </varlistentry>
+
+  </variablelist>
+ </refsect1>
+
+ <refsect1>
+  <title>Notes</title>
+
+  <para>
+   Use the <command>DROP VARIABLE</command> command to remove a variable.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Examples</title>
+
+  <para>
+   Create an integer variable <literal>var1</literal>:
+<programlisting>
+CREATE VARIABLE var1 AS date;
+LET var1 = current_date;
+SELECT var1;
+</programlisting>
+  </para>
+
+ </refsect1>
+
+ <refsect1>
+  <title>Compatibility</title>
+
+  <para>
+   The <command>CREATE VARIABLE</command> command is a PostgreSQL extension.
+   <!-- The choice of wording here seems to be left to personal preference... -->
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simplelist type="inline">
+   <member><xref linkend="sql-altervariable"/></member>
+   <member><xref linkend="sql-dropvariable"/></member>
+   <member><xref linkend="sql-let"/></member>
+  </simplelist>
+ </refsect1>
+
+</refentry>
diff --git a/doc/src/sgml/ref/discard.sgml b/doc/src/sgml/ref/discard.sgml
index bf44c523ca..698b2c07fd 100644
--- a/doc/src/sgml/ref/discard.sgml
+++ b/doc/src/sgml/ref/discard.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-DISCARD { ALL | PLANS | SEQUENCES | TEMPORARY | TEMP }
+DISCARD { ALL | PLANS | SEQUENCES | TEMPORARY | TEMP | VARIABLES }
 </synopsis>
  </refsynopsisdiv>
 
@@ -75,6 +75,17 @@ DISCARD { ALL | PLANS | SEQUENCES | TEMPORARY | TEMP }
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><literal>VARIABLES</literal></term>
+    <listitem>
+     <para>
+      Resets the value of all schema variables. If a variable
+      is later reused, it is re-initialized to either
+      NULL or its default value.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><literal>ALL</literal></term>
     <listitem>
@@ -93,6 +104,7 @@ SELECT pg_advisory_unlock_all();
 DISCARD PLANS;
 DISCARD TEMP;
 DISCARD SEQUENCES;
+DISCARD VARIABLES;
 </programlisting></para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/ref/drop_variable.sgml b/doc/src/sgml/ref/drop_variable.sgml
new file mode 100644
index 0000000000..da3632e780
--- /dev/null
+++ b/doc/src/sgml/ref/drop_variable.sgml
@@ -0,0 +1,120 @@
+<!--
+doc/src/sgml/ref/drop_variable.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="sql-dropvariable">
+ <indexterm zone="sql-dropvariable">
+  <primary>DROP VARIABLE</primary>
+ </indexterm>
+
+ <indexterm>
+  <primary>schema variable</primary>
+  <secondary>removing</secondary>
+ </indexterm>
+
+ <refmeta>
+  <refentrytitle>DROP VARIABLE</refentrytitle>
+  <manvolnum>7</manvolnum>
+  <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+  <refname>DROP VARIABLE</refname>
+  <refpurpose>remove a schema variable</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+<synopsis>
+DROP VARIABLE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> [, ...] [ CASCADE | RESTRICT ]
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+  <title>Description</title>
+
+  <para>
+   <command>DROP VARIABLE</command> removes a schema variable.
+   A variable can only be dropped by its owner or a superuser.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Parameters</title>
+
+  <variablelist>
+   <varlistentry>
+    <term><literal>IF EXISTS</literal></term>
+    <listitem>
+     <para>
+      Do not throw an error if the variable does not exist. A notice is issued
+      in this case.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="parameter">name</replaceable></term>
+    <listitem>
+     <para>
+      The name, optionally schema-qualified, of a schema variable.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>CASCADE</literal></term>
+    <listitem>
+     <para>
+      Automatically drop objects that depend on the variable (such as
+      views),
+      and in turn all objects that depend on those objects
+      (see <xref linkend="ddl-depend"/>).
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>RESTRICT</literal></term>
+    <listitem>
+     <para>
+      Refuse to drop the variable if any objects depend on it.  This is
+      the default.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </refsect1>
+
+ <refsect1>
+  <title>Examples</title>
+
+  <para>
+   To remove the schema variable <literal>var1</literal>:
+
+<programlisting>
+DROP VARIABLE var1;
+</programlisting></para>
+ </refsect1>
+
+ <refsect1>
+  <title>Compatibility</title>
+
+  <para>
+   The <command>DROP VARIABLE</command> command is a PostgreSQL extension.
+   <!-- create variable is a "PostgreSQL feature",
+        this is a "proprietary PostgreSQL command" ... -->
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simplelist type="inline">
+   <member><xref linkend="sql-altervariable"/></member>
+   <member><xref linkend="sql-createvariable"/></member>
+   <member><xref linkend="sql-let"/></member>
+  </simplelist>
+ </refsect1>
+
+</refentry>
diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index a897712de2..6586e412c1 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -103,6 +103,11 @@ GRANT <replaceable class="parameter">role_name</replaceable> [, ...] TO <replace
   | CURRENT_ROLE
   | CURRENT_USER
   | SESSION_USER
+
+GRANT { READ | WRITE | ALL [ PRIVILEGES ] }
+    ON VARIABLE <replaceable>variable_name</replaceable> [, ...]
+    TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
+
 </synopsis>
  </refsynopsisdiv>
 
@@ -201,6 +206,24 @@ GRANT <replaceable class="parameter">role_name</replaceable> [, ...] TO <replace
      </listitem>
     </varlistentry>
 
+    <varlistentry>
+     <term><literal>READ</literal></term>
+     <listitem>
+      <para>
+       Allows to read a schema variable.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>WRITE</literal></term>
+     <listitem>
+      <para>
+       Allows to set a schema variable's content.
+      </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry>
      <term><literal>ALL PRIVILEGES</literal></term>
      <listitem>
diff --git a/doc/src/sgml/ref/let.sgml b/doc/src/sgml/ref/let.sgml
new file mode 100644
index 0000000000..d4396cad3c
--- /dev/null
+++ b/doc/src/sgml/ref/let.sgml
@@ -0,0 +1,107 @@
+<!--
+doc/src/sgml/ref/let.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="sql-let">
+ <indexterm zone="sql-let">
+  <primary>LET</primary>
+ </indexterm>
+
+ <indexterm>
+  <primary>schema variable</primary>
+  <secondary>changing</secondary>
+ </indexterm>
+
+ <refmeta>
+  <refentrytitle>LET</refentrytitle>
+  <manvolnum>7</manvolnum>
+  <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+  <refname>LET</refname>
+  <refpurpose>change a schema variable's value</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+<synopsis>
+LET <replaceable class="parameter">schema_variable</replaceable> = <replaceable class="parameter">sql_expression</replaceable>
+LET <replaceable class="parameter">schema_variable</replaceable> = DEFAULT
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+  <title>Description</title>
+
+  <para>
+   The <command>LET</command> command updates the specified schema variable value.
+  </para>
+
+ </refsect1>
+
+ <refsect1>
+  <title>Parameters</title>
+
+  <variablelist>
+   <varlistentry>
+    <term><literal>schema_variable</literal></term>
+    <listitem>
+     <para>
+      The name of the schema variable.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>sql_expression</literal></term>
+    <listitem>
+     <para>
+      An SQL expression. The result is cast into the schema variable's type.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>DEFAULT</literal></term>
+    <listitem>
+     <para>
+      Reset the schema variable to its default value, if that is defined.
+      If no explicit default value has been assigned, the schema variable
+      is set to NULL.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+
+  <para>
+   Example:
+<programlisting>
+CREATE VARIABLE myvar AS integer;
+LET myvar = 10;
+LET myvar = (SELECT sum(val) FROM tab);
+LET myvar = DEFAULT;
+</programlisting>
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Compatibility</title>
+
+  <para>
+   <literal>LET</literal> extends the syntax defined in the SQL
+   standard. The <literal>SET</literal> command from the SQL standard
+   is used for different purposes in PostgreSQL.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simplelist type="inline">
+   <member><xref linkend="sql-altervariable"/></member>
+   <member><xref linkend="sql-createvariable"/></member>
+   <member><xref linkend="sql-dropvariable"/></member>
+  </simplelist>
+ </refsect1>
+</refentry>
diff --git a/doc/src/sgml/ref/pg_restore.sgml b/doc/src/sgml/ref/pg_restore.sgml
index 93ea937ac8..0d86239eb4 100644
--- a/doc/src/sgml/ref/pg_restore.sgml
+++ b/doc/src/sgml/ref/pg_restore.sgml
@@ -106,6 +106,17 @@ PostgreSQL documentation
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><option>-A <replaceable class="parameter">schema_variable</replaceable></option></term>
+      <term><option>--variable=<replaceable class="parameter">schema_variable</replaceable></option></term>
+      <listitem>
+       <para>
+        Restore a named schema variable only.  Multiple schema variables may be specified with
+        multiple <option>-A</option> switches.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><option>-c</option></term>
       <term><option>--clean</option></term>
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index 3014c864ea..3e9f9804be 100644
--- a/doc/src/sgml/ref/revoke.sgml
+++ b/doc/src/sgml/ref/revoke.sgml
@@ -130,6 +130,12 @@ REVOKE [ ADMIN OPTION FOR ]
   | CURRENT_ROLE
   | CURRENT_USER
   | SESSION_USER
+
+REVOKE [ GRANT OPTION FOR ]
+    { { READ | WRITE } [, ...] | ALL [ PRIVILEGES ] }
+    ON VARIABLE <replaceable>variable_name</replaceable> [, ...]
+    FROM { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...]
+    [ CASCADE | RESTRICT ]
 </synopsis>
  </refsynopsisdiv>
 
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index da421ff24e..f9e42443b6 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -75,6 +75,7 @@
    &alterType;
    &alterUser;
    &alterUserMapping;
+   &alterVariable;
    &alterView;
    &analyze;
    &begin;
@@ -127,6 +128,7 @@
    &createType;
    &createUser;
    &createUserMapping;
+   &createVariable;
    &createView;
    &deallocate;
    &declare;
@@ -175,6 +177,7 @@
    &dropType;
    &dropUser;
    &dropUserMapping;
+   &dropVariable;
    &dropView;
    &end;
    &execute;
@@ -183,6 +186,7 @@
    &grant;
    &importForeignSchema;
    &insert;
+   &let;
    &listen;
    &load;
    &lock;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 8e35c432f5..87e2662c4a 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -35,6 +35,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/schema_variable.h"
 #include "commands/tablecmds.h"
 #include "commands/trigger.h"
 #include "executor/spi.h"
@@ -2196,6 +2197,9 @@ CommitTransaction(void)
 	 */
 	smgrDoPendingSyncs(true, is_parallel_worker);
 
+	/* Let ON COMMIT DROP or ON TRANSACTION END */
+	AtPreEOXact_SchemaVariable_on_commit_actions(true);
+
 	/* close large objects before lower-level cleanup */
 	AtEOXact_LargeObject(true);
 
@@ -2335,6 +2339,7 @@ CommitTransaction(void)
 	AtEOXact_SPI(true);
 	AtEOXact_Enum();
 	AtEOXact_on_commit_actions(true);
+	AtEOXact_SchemaVariable_on_commit_actions(true);
 	AtEOXact_Namespace(true, is_parallel_worker);
 	AtEOXact_SMgr();
 	AtEOXact_Files(true);
@@ -2772,6 +2777,9 @@ AbortTransaction(void)
 	AtAbort_Portals();
 	smgrDoPendingSyncs(false, is_parallel_worker);
 	AtEOXact_LargeObject(false);
+
+	/* 'false' means it's abort */
+	AtPreEOXact_SchemaVariable_on_commit_actions(false);
 	AtAbort_Notify();
 	AtEOXact_RelationMap(false, is_parallel_worker);
 	AtAbort_Twophase();
@@ -2836,6 +2844,7 @@ AbortTransaction(void)
 		AtEOXact_SPI(false);
 		AtEOXact_Enum();
 		AtEOXact_on_commit_actions(false);
+		AtEOXact_SchemaVariable_on_commit_actions(false);
 		AtEOXact_Namespace(false, is_parallel_worker);
 		AtEOXact_SMgr();
 		AtEOXact_Files(false);
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 4e6efda97f..5c402a5ed8 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -43,6 +43,7 @@ OBJS = \
 	pg_shdepend.o \
 	pg_subscription.o \
 	pg_type.o \
+	pg_variable.o \
 	storage.o \
 	toasting.o
 
@@ -69,7 +70,8 @@ CATALOG_HEADERS := \
 	pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \
 	pg_collation.h pg_partitioned_table.h pg_range.h pg_transform.h \
 	pg_sequence.h pg_publication.h pg_publication_namespace.h \
-	pg_publication_rel.h pg_subscription.h pg_subscription_rel.h
+	pg_publication_rel.h pg_subscription.h pg_subscription_rel.h \
+	pg_variable.h
 
 GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) schemapg.h system_fk_info.h
 
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index ce0a4ff14e..8d1c02b871 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -58,6 +58,7 @@
 #include "catalog/pg_ts_parser.h"
 #include "catalog/pg_ts_template.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_variable.h"
 #include "commands/dbcommands.h"
 #include "commands/defrem.h"
 #include "commands/event_trigger.h"
@@ -112,6 +113,7 @@ static void ExecGrant_Largeobject(InternalGrant *grantStmt);
 static void ExecGrant_Namespace(InternalGrant *grantStmt);
 static void ExecGrant_Tablespace(InternalGrant *grantStmt);
 static void ExecGrant_Type(InternalGrant *grantStmt);
+static void ExecGrant_Variable(InternalGrant *grantStmt);
 
 static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
 static void SetDefaultACL(InternalDefaultACL *iacls);
@@ -259,6 +261,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
 		case OBJECT_TYPE:
 			whole_mask = ACL_ALL_RIGHTS_TYPE;
 			break;
+		case OBJECT_VARIABLE:
+			whole_mask = ACL_ALL_RIGHTS_VARIABLE;
+			break;
 		default:
 			elog(ERROR, "unrecognized object type: %d", objtype);
 			/* not reached, but keep compiler quiet */
@@ -498,6 +503,10 @@ ExecuteGrantStmt(GrantStmt *stmt)
 			all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
 			errormsg = gettext_noop("invalid privilege type %s for foreign server");
 			break;
+		case OBJECT_VARIABLE:
+			all_privileges = ACL_ALL_RIGHTS_VARIABLE;
+			errormsg = gettext_noop("invalid privilege type %s for schema variable");
+			break;
 		default:
 			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
 				 (int) stmt->objtype);
@@ -600,6 +609,9 @@ ExecGrantStmt_oids(InternalGrant *istmt)
 		case OBJECT_TABLESPACE:
 			ExecGrant_Tablespace(istmt);
 			break;
+		case OBJECT_VARIABLE:
+			ExecGrant_Variable(istmt);
+			break;
 		default:
 			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
 				 (int) istmt->objtype);
@@ -759,6 +771,16 @@ objectNamesToOids(ObjectType objtype, List *objnames)
 				objects = lappend_oid(objects, srvid);
 			}
 			break;
+		case OBJECT_VARIABLE:
+			foreach(cell, objnames)
+			{
+				RangeVar   *varvar = (RangeVar *) lfirst(cell);
+				Oid			relOid;
+
+				relOid = LookupVariable(varvar->schemaname, varvar->relname, false);
+				objects = lappend_oid(objects, relOid);
+			}
+			break;
 		default:
 			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
 				 (int) objtype);
@@ -848,6 +870,33 @@ objectsInSchemaToOids(ObjectType objtype, List *nspnames)
 					table_close(rel, AccessShareLock);
 				}
 				break;
+			case OBJECT_VARIABLE:
+				{
+					ScanKeyData key;
+					Relation	rel;
+					TableScanDesc scan;
+					HeapTuple	tuple;
+
+					ScanKeyInit(&key,
+								Anum_pg_variable_varnamespace,
+								BTEqualStrategyNumber, F_OIDEQ,
+								ObjectIdGetDatum(namespaceId));
+
+					rel = table_open(VariableRelationId, AccessShareLock);
+					scan = table_beginscan_catalog(rel, 1, &key);
+
+					while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+					{
+						Oid			oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
+
+						objects = lappend_oid(objects, oid);
+					}
+
+					table_endscan(scan);
+					table_close(rel, AccessShareLock);
+				}
+				break;
+
 			default:
 				/* should not happen */
 				elog(ERROR, "unrecognized GrantStmt.objtype: %d",
@@ -1007,6 +1056,10 @@ ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *s
 			all_privileges = ACL_ALL_RIGHTS_SCHEMA;
 			errormsg = gettext_noop("invalid privilege type %s for schema");
 			break;
+		case OBJECT_VARIABLE:
+			all_privileges = ACL_ALL_RIGHTS_VARIABLE;
+			errormsg = gettext_noop("invalid privilege type %s for schema variable");
+			break;
 		default:
 			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
 				 (int) action->objtype);
@@ -1204,6 +1257,12 @@ SetDefaultACL(InternalDefaultACL *iacls)
 				this_privileges = ACL_ALL_RIGHTS_SCHEMA;
 			break;
 
+		case OBJECT_VARIABLE:
+			objtype = DEFACLOBJ_VARIABLE;
+			if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
+				this_privileges = ACL_ALL_RIGHTS_VARIABLE;
+			break;
+
 		default:
 			elog(ERROR, "unrecognized objtype: %d",
 				 (int) iacls->objtype);
@@ -1437,6 +1496,9 @@ RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
 			case DEFACLOBJ_NAMESPACE:
 				iacls.objtype = OBJECT_SCHEMA;
 				break;
+			case DEFACLOBJ_VARIABLE:
+				iacls.objtype = OBJECT_VARIABLE;
+				break;
 			default:
 				/* Shouldn't get here */
 				elog(ERROR, "unexpected default ACL type: %d",
@@ -1494,6 +1556,9 @@ RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
 			case ForeignDataWrapperRelationId:
 				istmt.objtype = OBJECT_FDW;
 				break;
+			case VariableRelationId:
+				istmt.objtype = OBJECT_VARIABLE;
+				break;
 			default:
 				elog(ERROR, "unexpected object class %u", classid);
 				break;
@@ -3225,6 +3290,129 @@ ExecGrant_Type(InternalGrant *istmt)
 	table_close(relation, RowExclusiveLock);
 }
 
+static void
+ExecGrant_Variable(InternalGrant *istmt)
+{
+	Relation	relation;
+	ListCell   *cell;
+
+	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
+		istmt->privileges = ACL_ALL_RIGHTS_VARIABLE;
+
+	relation = table_open(VariableRelationId, RowExclusiveLock);
+
+	foreach(cell, istmt->objects)
+	{
+		Oid			varId = lfirst_oid(cell);
+		Form_pg_variable pg_variable_tuple;
+		Datum		aclDatum;
+		bool		isNull;
+		AclMode		avail_goptions;
+		AclMode		this_privileges;
+		Acl		   *old_acl;
+		Acl		   *new_acl;
+		Oid			grantorId;
+		Oid			ownerId;
+		HeapTuple	tuple;
+		HeapTuple	newtuple;
+		Datum		values[Natts_pg_variable];
+		bool		nulls[Natts_pg_variable];
+		bool		replaces[Natts_pg_variable];
+		int			noldmembers;
+		int			nnewmembers;
+		Oid		   *oldmembers;
+		Oid		   *newmembers;
+
+		tuple = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(varId));
+		if (!HeapTupleIsValid(tuple))
+			elog(ERROR, "cache lookup failed for schema variables %u", varId);
+
+		pg_variable_tuple = (Form_pg_variable) GETSTRUCT(tuple);
+
+		/*
+		 * Get owner ID and working copy of existing ACL. If there's no ACL,
+		 * substitute the proper default.
+		 */
+		ownerId = pg_variable_tuple->varowner;
+		aclDatum = SysCacheGetAttr(VARIABLEOID, tuple, Anum_pg_variable_varacl,
+								   &isNull);
+		if (isNull)
+		{
+			old_acl = acldefault(OBJECT_VARIABLE, ownerId);
+			/* There are no old member roles according to the catalogs */
+			noldmembers = 0;
+			oldmembers = NULL;
+		}
+		else
+		{
+			old_acl = DatumGetAclPCopy(aclDatum);
+			/* Get the roles mentioned in the existing ACL */
+			noldmembers = aclmembers(old_acl, &oldmembers);
+		}
+
+		/* Determine ID to do the grant as, and available grant options */
+		select_best_grantor(GetUserId(), istmt->privileges,
+							old_acl, ownerId,
+							&grantorId, &avail_goptions);
+
+		/*
+		 * Restrict the privileges to what we can actually grant, and emit the
+		 * standards-mandated warning and error messages.
+		 */
+		this_privileges =
+			restrict_and_check_grant(istmt->is_grant, avail_goptions,
+									 istmt->all_privs, istmt->privileges,
+									 varId, grantorId, OBJECT_VARIABLE,
+									 NameStr(pg_variable_tuple->varname),
+									 0, NULL);
+
+		/*
+		 * Generate new ACL.
+		 */
+		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
+									   istmt->grant_option, istmt->behavior,
+									   istmt->grantees, this_privileges,
+									   grantorId, ownerId);
+
+		/*
+		 * We need the members of both old and new ACLs so we can correct the
+		 * shared dependency information.
+		 */
+		nnewmembers = aclmembers(new_acl, &newmembers);
+
+		/* finished building new ACL value, now insert it */
+		MemSet(values, 0, sizeof(values));
+		MemSet(nulls, false, sizeof(nulls));
+		MemSet(replaces, false, sizeof(replaces));
+
+		replaces[Anum_pg_variable_varacl - 1] = true;
+		values[Anum_pg_variable_varacl - 1] = PointerGetDatum(new_acl);
+
+		newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
+									 nulls, replaces);
+
+		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
+
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(varId, VariableRelationId, 0, new_acl);
+
+		/* Update the shared dependency ACL info */
+		updateAclDependencies(VariableRelationId, varId, 0,
+							  ownerId,
+							  noldmembers, oldmembers,
+							  nnewmembers, newmembers);
+
+		ReleaseSysCache(tuple);
+
+		pfree(new_acl);
+
+		/* prevent error when processing duplicate objects */
+		CommandCounterIncrement();
+	}
+
+	table_close(relation, RowExclusiveLock);
+}
+
 
 static AclMode
 string_to_privilege(const char *privname)
@@ -3257,6 +3445,10 @@ string_to_privilege(const char *privname)
 		return ACL_CONNECT;
 	if (strcmp(privname, "rule") == 0)
 		return 0;				/* ignore old RULE privileges */
+	if (strcmp(privname, "read") == 0)
+		return ACL_READ;
+	if (strcmp(privname, "write") == 0)
+		return ACL_WRITE;
 	ereport(ERROR,
 			(errcode(ERRCODE_SYNTAX_ERROR),
 			 errmsg("unrecognized privilege type \"%s\"", privname)));
@@ -3292,6 +3484,10 @@ privilege_to_string(AclMode privilege)
 			return "TEMP";
 		case ACL_CONNECT:
 			return "CONNECT";
+		case ACL_READ:
+			return "READ";
+		case ACL_WRITE:
+			return "WRITE";
 		default:
 			elog(ERROR, "unrecognized privilege: %d", (int) privilege);
 	}
@@ -3415,6 +3611,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
 					case OBJECT_TYPE:
 						msg = gettext_noop("permission denied for type %s");
 						break;
+					case OBJECT_VARIABLE:
+						msg = gettext_noop("permission denied for schema variable %s");
+						break;
 					case OBJECT_VIEW:
 						msg = gettext_noop("permission denied for view %s");
 						break;
@@ -3526,6 +3725,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
 					case OBJECT_TYPE:
 						msg = gettext_noop("must be owner of type %s");
 						break;
+					case OBJECT_VARIABLE:
+						msg = gettext_noop("must be owner of schema variable %s");
+						break;
 					case OBJECT_VIEW:
 						msg = gettext_noop("must be owner of view %s");
 						break;
@@ -3671,6 +3873,8 @@ pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid,
 			return ACL_NO_RIGHTS;
 		case OBJECT_TYPE:
 			return pg_type_aclmask(table_oid, roleid, mask, how);
+		case OBJECT_VARIABLE:
+			return pg_variable_aclmask(table_oid, roleid, mask, how);
 		default:
 			elog(ERROR, "unrecognized objtype: %d",
 				 (int) objtype);
@@ -4539,6 +4743,66 @@ pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
 	return result;
 }
 
+/*
+ * Exported routine for examining a user's privileges for a variable.
+ */
+AclMode
+pg_variable_aclmask(Oid var_oid, Oid roleid, AclMode mask, AclMaskHow how)
+{
+	AclMode		result;
+	HeapTuple	tuple;
+	Datum		aclDatum;
+	bool		isNull;
+	Acl		   *acl;
+	Oid			ownerId;
+
+	Form_pg_variable varForm;
+
+	/* Bypass permission checks for superusers */
+	if (superuser_arg(roleid))
+		return mask;
+
+	/*
+	 * Must get the type's tuple from pg_type
+	 */
+	tuple = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(var_oid));
+	if (!HeapTupleIsValid(tuple))
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("variable with OID %u does not exist",
+						var_oid)));
+	varForm = (Form_pg_variable) GETSTRUCT(tuple);
+
+	/*
+	 * Now get the type's owner and ACL from the tuple
+	 */
+	ownerId = varForm->varowner;
+
+	aclDatum = SysCacheGetAttr(VARIABLEOID, tuple,
+							   Anum_pg_variable_varacl, &isNull);
+	if (isNull)
+	{
+		/* No ACL, so build default ACL */
+		acl = acldefault(OBJECT_VARIABLE, ownerId);
+		aclDatum = (Datum) 0;
+	}
+	else
+	{
+		/* detoast rel's ACL if necessary */
+		acl = DatumGetAclP(aclDatum);
+	}
+
+	result = aclmask(acl, roleid, ownerId, mask, how);
+
+	/* if we have a detoasted copy, free it */
+	if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
+		pfree(acl);
+
+	ReleaseSysCache(tuple);
+
+	return result;
+}
+
 /*
  * Exported routine for checking a user's access privileges to a column
  *
@@ -4813,6 +5077,18 @@ pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
 		return ACLCHECK_NO_PRIV;
 }
 
+/*
+ * Exported routine for checking a user's access privileges to a variable
+ */
+AclResult
+pg_variable_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
+{
+	if (pg_variable_aclmask(type_oid, roleid, mode, ACLMASK_ANY) != 0)
+		return ACLCHECK_OK;
+	else
+		return ACLCHECK_NO_PRIV;
+}
+
 /*
  * Ownership check for a relation (specified by OID).
  */
@@ -5430,6 +5706,33 @@ pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid)
 	return has_privs_of_role(roleid, ownerId);
 }
 
+/*
+ * Ownership check for a schema variables (specified by OID).
+ */
+bool
+pg_variable_ownercheck(Oid db_oid, Oid roleid)
+{
+	HeapTuple	tuple;
+	Oid			ownerId;
+
+	/* Superusers bypass all permission checking. */
+	if (superuser_arg(roleid))
+		return true;
+
+	tuple = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(db_oid));
+	if (!HeapTupleIsValid(tuple))
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_DATABASE),
+				 errmsg("variable with OID %u does not exist", db_oid)));
+
+	ownerId = ((Form_pg_variable) GETSTRUCT(tuple))->varowner;
+
+	ReleaseSysCache(tuple);
+
+	return has_privs_of_role(roleid, ownerId);
+}
+
+
 /*
  * Check whether specified role has CREATEROLE privilege (or is a superuser)
  *
@@ -5558,6 +5861,10 @@ get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
 			defaclobjtype = DEFACLOBJ_NAMESPACE;
 			break;
 
+		case OBJECT_VARIABLE:
+			defaclobjtype = DEFACLOBJ_VARIABLE;
+			break;
+
 		default:
 			return NULL;
 	}
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 9f8eb1a37f..4ec76d4e03 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -63,12 +63,15 @@
 #include "catalog/pg_ts_template.h"
 #include "catalog/pg_type.h"
 #include "catalog/pg_user_mapping.h"
+#include "catalog/pg_variable.h"
 #include "commands/comment.h"
 #include "commands/defrem.h"
 #include "commands/event_trigger.h"
 #include "commands/extension.h"
 #include "commands/policy.h"
 #include "commands/publicationcmds.h"
+#include "commands/schemacmds.h"
+#include "commands/schema_variable.h"
 #include "commands/seclabel.h"
 #include "commands/sequence.h"
 #include "commands/trigger.h"
@@ -183,7 +186,8 @@ static const Oid object_classes[] = {
 	PublicationRelationId,		/* OCLASS_PUBLICATION */
 	PublicationRelRelationId,	/* OCLASS_PUBLICATION_REL */
 	SubscriptionRelationId,		/* OCLASS_SUBSCRIPTION */
-	TransformRelationId			/* OCLASS_TRANSFORM */
+	TransformRelationId,		/* OCLASS_TRANSFORM */
+	VariableRelationId			/* OCLASS_VARIABLE */
 };
 
 
@@ -1492,6 +1496,10 @@ doDeletion(const ObjectAddress *object, int flags)
 			DropObjectById(object);
 			break;
 
+		case OCLASS_VARIABLE:
+			RemoveSchemaVariable(object->objectId);
+			break;
+
 			/*
 			 * These global object types are not supported here.
 			 */
@@ -1870,6 +1878,11 @@ find_expr_references_walker(Node *node,
 	{
 		Param	   *param = (Param *) node;
 
+		if (param->paramkind == PARAM_VARIABLE)
+			/* A variable parameter depends on the schema variable */
+			add_object_address(OCLASS_VARIABLE, param->paramvarid, 0,
+							   context->addrs);
+
 		/* A parameter must depend on the parameter's datatype */
 		add_object_address(OCLASS_TYPE, param->paramtype, 0,
 						   context->addrs);
@@ -2870,6 +2883,9 @@ getObjectClass(const ObjectAddress *object)
 
 		case TransformRelationId:
 			return OCLASS_TRANSFORM;
+
+		case VariableRelationId:
+			return OCLASS_VARIABLE;
 	}
 
 	/* shouldn't get here */
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 4de8400fd0..02c5de7f73 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -39,6 +39,7 @@
 #include "catalog/pg_ts_parser.h"
 #include "catalog/pg_ts_template.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_variable.h"
 #include "commands/dbcommands.h"
 #include "funcapi.h"
 #include "mb/pg_wchar.h"
@@ -763,6 +764,70 @@ RelationIsVisible(Oid relid)
 	return visible;
 }
 
+/*
+ * VariableIsVisible
+ *		Determine whether a variable (identified by OID) is visible in the
+ *		current search path.  Visible means "would be found by searching
+ *		for the unqualified variable name".
+ */
+bool
+VariableIsVisible(Oid varid)
+{
+	HeapTuple	vartup;
+	Form_pg_variable varform;
+	Oid			varnamespace;
+	bool		visible;
+
+	vartup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(varid));
+	if (!HeapTupleIsValid(vartup))
+		elog(ERROR, "cache lookup failed for schema variable %u", varid);
+	varform = (Form_pg_variable) GETSTRUCT(vartup);
+
+	recomputeNamespacePath();
+
+	/*
+	 * Quick check: if it ain't in the path at all, it ain't visible. Items in
+	 * the system namespace are surely in the path and so we needn't even do
+	 * list_member_oid() for them.
+	 */
+	varnamespace = varform->varnamespace;
+	if (varnamespace != PG_CATALOG_NAMESPACE &&
+		!list_member_oid(activeSearchPath, varnamespace))
+		visible = false;
+	else
+	{
+		/*
+		 * If it is in the path, it might still not be visible; it could be
+		 * hidden by another relation of the same name earlier in the path. So
+		 * we must do a slow check for conflicting relations.
+		 */
+		char	   *varname = NameStr(varform->varname);
+		ListCell   *l;
+
+		visible = false;
+		foreach(l, activeSearchPath)
+		{
+			Oid			namespaceId = lfirst_oid(l);
+
+			if (namespaceId == varnamespace)
+			{
+				/* Found it first in path */
+				visible = true;
+				break;
+			}
+			if (OidIsValid(get_varname_varid(varname, namespaceId)))
+			{
+				/* Found something else first in path */
+				break;
+			}
+		}
+	}
+
+	ReleaseSysCache(vartup);
+
+	return visible;
+}
+
 
 /*
  * TypenameGetTypid
@@ -2842,6 +2907,271 @@ TSConfigIsVisible(Oid cfgid)
 	return visible;
 }
 
+/*
+ * When we know a variable name, then we can find variable simply
+ */
+Oid
+LookupVariable(const char *nspname, const char *varname, bool missing_ok)
+{
+	Oid			namespaceId;
+	Oid			varoid = InvalidOid;
+	ListCell   *l;
+
+	if (nspname)
+	{
+		namespaceId = LookupExplicitNamespace(nspname, missing_ok);
+		if (!OidIsValid(namespaceId))
+			return InvalidOid;
+
+		varoid = GetSysCacheOid2(VARIABLENAMENSP, Anum_pg_variable_oid,
+								 PointerGetDatum(varname),
+								 ObjectIdGetDatum(namespaceId));
+	}
+	else
+	{
+		/* search for it in search path */
+		recomputeNamespacePath();
+
+		foreach(l, activeSearchPath)
+		{
+			namespaceId = lfirst_oid(l);
+
+			varoid = GetSysCacheOid2(VARIABLENAMENSP, Anum_pg_variable_oid,
+									 PointerGetDatum(varname),
+									 ObjectIdGetDatum(namespaceId));
+
+			if (OidIsValid(varoid))
+				break;
+		}
+	}
+
+	if (!OidIsValid(varoid) && !missing_ok)
+	{
+		if (nspname)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("variable \"%s\".\"%s\" does not exist",
+							nspname, varname)));
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("variable \"%s\" does not exist",
+							varname)));
+	}
+
+	return varoid;
+}
+
+/*
+ * The source list holds names with indirection expressions used
+ * as left part of LET statement. Following routine makes new
+ * list with only initial strings (names) - without indirection
+ * expressions.
+ */
+List *
+NamesFromList(List *names)
+{
+	ListCell   *l;
+	List	   *result = NIL;
+
+	foreach(l, names)
+	{
+		Node	   *n = lfirst(l);
+
+		if (IsA(n, String))
+		{
+			result = lappend(result, n);
+		}
+		else
+			break;
+	}
+
+	return result;
+}
+
+/*
+ * IdentifyVariable
+ *
+ * Returns oid of not ambigonuous variable specified by qualified path
+ * or InvalidOid. When the path is ambigonuous, then not_uniq flag is
+ * is true.
+ */
+Oid
+IdentifyVariable(List *names, char **attrname, bool *not_uniq)
+{
+	Node	   *field1 = NULL;
+	Node	   *field2 = NULL;
+	Node	   *field3 = NULL;
+	Node	   *field4 = NULL;
+	char	   *a = NULL;
+	char	   *b = NULL;
+	char	   *c = NULL;
+	char	   *d = NULL;
+	Oid			varoid_without_attr = InvalidOid;
+	Oid			varoid_with_attr = InvalidOid;
+
+	*not_uniq = false;
+
+	switch (list_length(names))
+	{
+		case 1:
+			field1 = linitial(names);
+
+			Assert(IsA(field1, String));
+
+			return LookupVariable(NULL, strVal(field1), true);
+
+		case 2:
+			field1 = linitial(names);
+			field2 = lsecond(names);
+
+			Assert(IsA(field1, String));
+			a = strVal(field1);
+
+			if (IsA(field2, String))
+			{
+				b = strVal(field2);
+
+				/*
+				 * a.b can mean "schema"."variable" or "variable"."field", Check
+				 * both variants, and returns InvalidOid with not_uniq flag, when
+				 * both interpretations are possible. Second node can be star. In
+				 * this case, the only allowed possibility is "variable"."*".
+				 */
+				varoid_without_attr = LookupVariable(a, b, true);
+				varoid_with_attr = LookupVariable(NULL, a, true);
+			}
+			else
+			{
+				Assert(IsA(field2, A_Star));
+
+				/*
+				 * Schema variables doesn't support unboxing by star syntax. But
+				 * this syntax have to be calculated here, because can come from
+				 * non schema variables related expressions.
+				 */
+				return InvalidOid;
+			}
+
+			if (OidIsValid(varoid_without_attr) && OidIsValid(varoid_with_attr))
+			{
+				*not_uniq = true;
+				return InvalidOid;
+			}
+			else if (OidIsValid(varoid_without_attr))
+			{
+				*attrname = NULL;
+				return varoid_without_attr;
+			}
+			else
+			{
+				*attrname = b;
+				return varoid_with_attr;
+			}
+			break;
+
+		case 3:
+			field1 = linitial(names);
+			field2 = lsecond(names);
+			field3 = lthird(names);
+
+			Assert(IsA(field1, String));
+			Assert(IsA(field2, String));
+
+			a = strVal(field1);
+			b = strVal(field2);
+
+			if (IsA(field3, String))
+			{
+				c = strVal(field3);
+
+				/*
+				 * a.b.c can mean "catalog"."schema"."variable" or
+				 * "schema"."variable"."field", Check both variants, and returns
+				 * InvalidOid with not_uniq flag, when both interpretations are
+				 * possible. When third node is star, then only possible
+				 * interpretation is "schema"."variable"."*".
+				 */
+				varoid_without_attr = LookupVariable(b, c, true);
+				varoid_with_attr = LookupVariable(a, b, true);
+			}
+			else
+			{
+				Assert(IsA(field3, A_Star));
+				return InvalidOid;
+			}
+
+			if (OidIsValid(varoid_without_attr) && OidIsValid(varoid_with_attr))
+			{
+				*not_uniq = true;
+				return InvalidOid;
+			}
+			else if (OidIsValid(varoid_without_attr))
+			{
+				*attrname = NULL;
+
+				/*
+				 * We in this case a "a" is used as catalog name, check it.
+				 */
+				if (strcmp(a, get_database_name(MyDatabaseId)) != 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("cross-database references are not implemented: %s",
+									NameListToString(names))));
+
+				return varoid_without_attr;
+			}
+			else
+			{
+				*attrname = c;
+				return varoid_with_attr;
+			}
+			break;
+
+		case 4:
+			field1 = linitial(names);
+			field2 = lsecond(names);
+			field3 = lthird(names);
+			field4 = lfourth(names);
+
+			Assert(IsA(field1, String));
+			Assert(IsA(field2, String));
+			Assert(IsA(field3, String));
+
+			a = strVal(field1);
+			b = strVal(field2);
+			c = strVal(field3);
+
+			/*
+			 * We in this case a "a" is used as catalog name, check it.
+			 */
+			if (strcmp(a, get_database_name(MyDatabaseId)) != 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cross-database references are not implemented: %s",
+								NameListToString(names))));
+
+			if (IsA(field4, String))
+			{
+				d = strVal(field4);
+			}
+			else
+			{
+				Assert(IsA(field4, A_Star));
+				return InvalidOid;
+			}
+
+			*attrname = d;
+			return LookupVariable(b, c, true);
+
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_SYNTAX_ERROR),
+					 errmsg("improper qualified name (too many dotted names): %s",
+							NameListToString(names))));
+			break;
+	}
+}
 
 /*
  * DeconstructQualifiedName
@@ -4657,3 +4987,14 @@ pg_is_other_temp_schema(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(isOtherTempNamespace(oid));
 }
+
+Datum
+pg_variable_is_visible(PG_FUNCTION_ARGS)
+{
+	Oid			oid = PG_GETARG_OID(0);
+
+	if (!SearchSysCacheExists1(VARIABLEOID, ObjectIdGetDatum(oid)))
+		PG_RETURN_NULL();
+
+	PG_RETURN_BOOL(VariableIsVisible(oid));
+}
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 2bae3fbb17..182ffa142d 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -62,6 +62,7 @@
 #include "catalog/pg_ts_template.h"
 #include "catalog/pg_type.h"
 #include "catalog/pg_user_mapping.h"
+#include "catalog/pg_variable.h"
 #include "commands/dbcommands.h"
 #include "commands/defrem.h"
 #include "commands/event_trigger.h"
@@ -617,6 +618,20 @@ static const ObjectPropertyType ObjectProperty[] =
 		OBJECT_USER_MAPPING,
 		false
 	},
+	{
+		"schema variable",
+		VariableRelationId,
+		VariableObjectIndexId,
+		VARIABLEOID,
+		VARIABLENAMENSP,
+		Anum_pg_variable_oid,
+		Anum_pg_variable_varname,
+		Anum_pg_variable_varnamespace,
+		Anum_pg_variable_varowner,
+		Anum_pg_variable_varacl,
+		OBJECT_VARIABLE,
+		true
+	}
 };
 
 /*
@@ -845,6 +860,10 @@ static const struct object_type_map
 	/* OCLASS_STATISTIC_EXT */
 	{
 		"statistics object", OBJECT_STATISTIC_EXT
+	},
+	/* OCLASS_VARIABLE */
+	{
+		"schema variable", OBJECT_VARIABLE
 	}
 };
 
@@ -870,6 +889,7 @@ static ObjectAddress get_object_address_attrdef(ObjectType objtype,
 												bool missing_ok);
 static ObjectAddress get_object_address_type(ObjectType objtype,
 											 TypeName *typename, bool missing_ok);
+static ObjectAddress get_object_address_variable(List *object, bool missing_ok);
 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *object,
 											 bool missing_ok);
 static ObjectAddress get_object_address_opf_member(ObjectType objtype,
@@ -1139,6 +1159,9 @@ get_object_address(ObjectType objtype, Node *object,
 															 missing_ok);
 				address.objectSubId = 0;
 				break;
+			case OBJECT_VARIABLE:
+				address = get_object_address_variable(castNode(List, object), missing_ok);
+				break;
 			default:
 				elog(ERROR, "unrecognized objtype: %d", (int) objtype);
 				/* placate compiler, in case it thinks elog might return */
@@ -2038,16 +2061,20 @@ get_object_address_defacl(List *object, bool missing_ok)
 		case DEFACLOBJ_NAMESPACE:
 			objtype_str = "schemas";
 			break;
+		case DEFACLOBJ_VARIABLE:
+			objtype_str = "variables";
+			break;
 		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("unrecognized default ACL object type \"%c\"", objtype),
-					 errhint("Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".",
+					 errhint("Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".",
 							 DEFACLOBJ_RELATION,
 							 DEFACLOBJ_SEQUENCE,
 							 DEFACLOBJ_FUNCTION,
 							 DEFACLOBJ_TYPE,
-							 DEFACLOBJ_NAMESPACE)));
+							 DEFACLOBJ_NAMESPACE,
+							 DEFACLOBJ_VARIABLE)));
 	}
 
 	/*
@@ -2132,6 +2159,24 @@ textarray_to_strvaluelist(ArrayType *arr)
 	return list;
 }
 
+/*
+ * Find the ObjectAddress for a schema variable
+ */
+static ObjectAddress
+get_object_address_variable(List *object, bool missing_ok)
+{
+	ObjectAddress address;
+	char	   *nspname = NULL;
+	char	   *varname = NULL;
+
+	ObjectAddressSet(address, VariableRelationId, InvalidOid);
+
+	DeconstructQualifiedName(object, &nspname, &varname);
+	address.objectId = LookupVariable(nspname, varname, missing_ok);
+
+	return address;
+}
+
 /*
  * SQL-callable version of get_object_address
  */
@@ -2322,6 +2367,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 		case OBJECT_TABCONSTRAINT:
 		case OBJECT_OPCLASS:
 		case OBJECT_OPFAMILY:
+		case OBJECT_VARIABLE:
 			objnode = (Node *) name;
 			break;
 		case OBJECT_ACCESS_METHOD:
@@ -2630,6 +2676,11 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
 							   NameListToString(castNode(List, object)));
 			break;
+		case OBJECT_VARIABLE:
+			if (!pg_variable_ownercheck(address.objectId, roleid))
+				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
+							   NameListToString(castNode(List, object)));
+			break;
 		default:
 			elog(ERROR, "unrecognized object type: %d",
 				 (int) objtype);
@@ -3558,6 +3609,32 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok)
 				break;
 			}
 
+		case OCLASS_VARIABLE:
+			{
+				char	   *nspname;
+				HeapTuple	tup;
+				Form_pg_variable varform;
+
+				tup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(object->objectId));
+				if (!HeapTupleIsValid(tup))
+					elog(ERROR, "cache lookup failed for schema variable %u",
+						 object->objectId);
+
+				varform = (Form_pg_variable) GETSTRUCT(tup);
+
+				if (VariableIsVisible(object->objectId))
+					nspname = NULL;
+				else
+					nspname = get_namespace_name(varform->varnamespace);
+
+				appendStringInfo(&buffer, _("schema variable %s"),
+								 quote_qualified_identifier(nspname,
+															NameStr(varform->varname)));
+
+				ReleaseSysCache(tup);
+				break;
+			}
+
 		case OCLASS_TSPARSER:
 			{
 				HeapTuple	tup;
@@ -3868,6 +3945,16 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok)
 										 _("default privileges on new schemas belonging to role %s"),
 										 rolename);
 						break;
+					case DEFACLOBJ_VARIABLE:
+						if (nspname)
+							appendStringInfo(&buffer,
+											 _("default privileges on new variables belonging to role %s in schema %s"),
+											 rolename, nspname);
+						else
+							appendStringInfo(&buffer,
+											 _("default privileges on new variables belonging to role %s"),
+											 rolename);
+						break;
 					default:
 						/* shouldn't get here */
 						if (nspname)
@@ -4610,6 +4697,10 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
 			appendStringInfoString(&buffer, "transform");
 			break;
 
+		case OCLASS_VARIABLE:
+			appendStringInfoString(&buffer, "schema variable");
+			break;
+
 			/*
 			 * There's intentionally no default: case here; we want the
 			 * compiler to warn if a new OCLASS hasn't been handled above.
@@ -5703,6 +5794,10 @@ getObjectIdentityParts(const ObjectAddress *object,
 						appendStringInfoString(&buffer,
 											   " on schemas");
 						break;
+					case DEFACLOBJ_VARIABLE:
+						appendStringInfoString(&buffer,
+											   " on schema variables");
+						break;
 				}
 
 				if (objname)
@@ -5918,6 +6013,33 @@ getObjectIdentityParts(const ObjectAddress *object,
 			}
 			break;
 
+		case OCLASS_VARIABLE:
+			{
+				char	   *schema;
+				char	   *varname;
+				HeapTuple	tup;
+				Form_pg_variable varform;
+
+				tup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(object->objectId));
+				if (!HeapTupleIsValid(tup))
+					elog(ERROR, "cache lookup failed for schema variable %u",
+						 object->objectId);
+
+				varform = (Form_pg_variable) GETSTRUCT(tup);
+
+				schema = get_namespace_name_or_temp(varform->varnamespace);
+				varname = NameStr(varform->varname);
+
+				appendStringInfo(&buffer, "%s",
+								 quote_qualified_identifier(schema, varname));
+
+				if (objname)
+					*objname = list_make2(schema, varname);
+
+				ReleaseSysCache(tup);
+				break;
+			}
+
 			/*
 			 * There's intentionally no default: case here; we want the
 			 * compiler to warn if a new OCLASS hasn't been handled above.
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 8453d8fefd..bbf7e9413a 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -46,6 +46,7 @@
 #include "catalog/pg_ts_dict.h"
 #include "catalog/pg_type.h"
 #include "catalog/pg_user_mapping.h"
+#include "catalog/pg_variable.h"
 #include "commands/alter.h"
 #include "commands/collationcmds.h"
 #include "commands/conversioncmds.h"
@@ -1572,6 +1573,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
 				case DatabaseRelationId:
 				case TSConfigRelationId:
 				case TSDictionaryRelationId:
+				case VariableRelationId:
 					{
 						Oid			classId = sdepForm->classid;
 						Relation	catalog;
diff --git a/src/backend/catalog/pg_variable.c b/src/backend/catalog/pg_variable.c
new file mode 100644
index 0000000000..451b57a0b7
--- /dev/null
+++ b/src/backend/catalog/pg_variable.c
@@ -0,0 +1,388 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_variable.c
+ *		schema variables
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *		src/backend/catalog/pg_variable.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "access/htup_details.h"
+
+#include "catalog/catalog.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
+#include "catalog/pg_namespace.h"
+#include "catalog/pg_type.h"
+#include "catalog/pg_variable.h"
+
+#include "commands/schema_variable.h"
+
+#include "storage/lmgr.h"
+
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+
+static VariableEOXActionCodes
+to_eoxaction_code(VariableEOXAction action)
+{
+	switch (action)
+	{
+		case VARIABLE_EOX_NOOP:
+			return VARIABLE_EOX_CODE_NOOP;
+
+		case VARIABLE_EOX_DROP:
+			return VARIABLE_EOX_CODE_DROP;
+
+		case VARIABLE_EOX_RESET:
+			return VARIABLE_EOX_CODE_RESET;
+
+		default:
+			elog(ERROR, "unexpected action");
+	}
+
+}
+
+static VariableEOXAction
+to_eoxaction(VariableEOXActionCodes code)
+{
+	switch (code)
+	{
+		case VARIABLE_EOX_CODE_NOOP:
+			return VARIABLE_EOX_NOOP;
+
+		case VARIABLE_EOX_CODE_DROP:
+			return VARIABLE_EOX_DROP;
+
+		case VARIABLE_EOX_CODE_RESET:
+			return VARIABLE_EOX_RESET;
+
+		default:
+			elog(ERROR, "unexpected code");
+	}
+}
+
+/*
+ * Returns name of schema variable. When variable is not on path,
+ * then the name is qualified.
+ */
+char *
+schema_variable_get_name(Oid varid)
+{
+	HeapTuple	tup;
+	Form_pg_variable varform;
+	char	   *varname;
+	char	   *nspname;
+	char	   *result;
+
+	tup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(varid));
+
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "cache lookup failed for variable %u", varid);
+
+	varform = (Form_pg_variable) GETSTRUCT(tup);
+
+	varname = NameStr(varform->varname);
+
+	if (VariableIsVisible(varid))
+		nspname = NULL;
+	else
+		nspname = get_namespace_name(varform->varnamespace);
+
+	result = quote_qualified_identifier(nspname, varname);
+
+	ReleaseSysCache(tup);
+
+	return result;
+}
+
+/*
+ * Returns varname field of pg_variable
+ */
+char *
+get_schema_variable_name(Oid varid)
+{
+	HeapTuple	tup;
+	Form_pg_variable varform;
+	char	   *varname;
+
+	tup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(varid));
+
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "cache lookup failed for variable %u", varid);
+
+	varform = (Form_pg_variable) GETSTRUCT(tup);
+
+	varname = NameStr(varform->varname);
+
+	ReleaseSysCache(tup);
+
+	return varname;
+}
+
+/*
+ * Returns type, typmod of schema variable
+ */
+void
+get_schema_variable_type_typmod_collid(Oid varid, Oid *typid, int32 *typmod, Oid *collid)
+{
+	HeapTuple	tup;
+	Form_pg_variable varform;
+
+	tup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(varid));
+
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "cache lookup failed for variable %u", varid);
+
+	varform = (Form_pg_variable) GETSTRUCT(tup);
+
+	*typid = varform->vartype;
+	*typmod = varform->vartypmod;
+	*collid = varform->varcollation;
+
+	ReleaseSysCache(tup);
+
+	return;
+}
+
+/*
+ * Fetch all fields of schema variable from the syscache.
+ */
+void
+initVariable(Variable *var, Oid varid, bool missing_ok, bool fast_only)
+{
+	HeapTuple	tup;
+	Form_pg_variable varform;
+	Datum		defexpr_datum;
+	bool		defexpr_isnull;
+
+	tup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(varid));
+
+	if (!HeapTupleIsValid(tup))
+	{
+		if (missing_ok)
+		{
+			var->oid = InvalidOid;
+			return;
+		}
+
+		elog(ERROR, "cache lookup failed for variable %u", varid);
+	}
+
+	varform = (Form_pg_variable) GETSTRUCT(tup);
+
+	var->oid = varid;
+	var->name = pstrdup(NameStr(varform->varname));
+	var->namespace = varform->varnamespace;
+	var->typid = varform->vartype;
+	var->typmod = varform->vartypmod;
+	var->owner = varform->varowner;
+	var->collation = varform->varcollation;
+	var->eoxaction = to_eoxaction(varform->vareoxaction);
+	var->is_not_null = varform->varisnotnull;
+	var->is_immutable = varform->varisimmutable;
+
+	/* Get defexpr */
+	defexpr_datum = SysCacheGetAttr(VARIABLEOID,
+									tup,
+									Anum_pg_variable_vardefexpr,
+									&defexpr_isnull);
+
+	var->has_defexpr = !defexpr_isnull;
+
+	/*
+	 * Sometimes we don't need deserialized defexpr, but we need info about
+	 * existence of defexpr.
+	 */
+
+	if (!fast_only)
+	{
+		Datum		aclDatum;
+		bool		isnull;
+
+		/* name */
+		var->name = pstrdup(NameStr(varform->varname));
+
+		if (!defexpr_isnull)
+			var->defexpr = stringToNode(TextDatumGetCString(defexpr_datum));
+		else
+			var->defexpr = NULL;
+
+		/* Get varacl */
+		aclDatum = SysCacheGetAttr(VARIABLEOID,
+								   tup,
+								   Anum_pg_variable_varacl,
+								   &isnull);
+		if (!isnull)
+			var->acl = DatumGetAclPCopy(aclDatum);
+		else
+			var->acl = NULL;
+	}
+	else
+	{
+		var->name = NULL;
+		var->defexpr = NULL;
+		var->acl = NULL;
+	}
+
+	ReleaseSysCache(tup);
+
+	return;
+}
+
+/*
+ * Create entry in pg_variable table
+ */
+ObjectAddress
+VariableCreate(const char *varName,
+			   Oid varNamespace,
+			   Oid varType,
+			   int32 varTypmod,
+			   Oid varOwner,
+			   Oid varCollation,
+			   Node *varDefexpr,
+			   VariableEOXAction eoxaction,
+			   bool is_not_null,
+			   bool if_not_exists,
+			   bool is_immutable)
+{
+	Acl		   *varacl;
+	NameData	varname;
+	bool		nulls[Natts_pg_variable];
+	Datum		values[Natts_pg_variable];
+	Relation	rel;
+	HeapTuple	tup,
+				oldtup;
+	TupleDesc	tupdesc;
+	ObjectAddress myself,
+				referenced;
+	Oid			varid;
+	int			i;
+
+	for (i = 0; i < Natts_pg_variable; i++)
+	{
+		nulls[i] = false;
+		values[i] = (Datum) 0;
+	}
+
+	namestrcpy(&varname, varName);
+
+	rel = table_open(VariableRelationId, RowExclusiveLock);
+
+	varid = GetNewOidWithIndex(rel, VariableObjectIndexId, Anum_pg_variable_oid);
+	values[Anum_pg_variable_oid - 1] = ObjectIdGetDatum(varid);
+	values[Anum_pg_variable_varname - 1] = NameGetDatum(&varname);
+	values[Anum_pg_variable_varnamespace - 1] = ObjectIdGetDatum(varNamespace);
+	values[Anum_pg_variable_vartype - 1] = ObjectIdGetDatum(varType);
+	values[Anum_pg_variable_vartypmod - 1] = Int32GetDatum(varTypmod);
+	values[Anum_pg_variable_varowner - 1] = ObjectIdGetDatum(varOwner);
+	values[Anum_pg_variable_varcollation - 1] = ObjectIdGetDatum(varCollation);
+	values[Anum_pg_variable_vareoxaction - 1] = CharGetDatum((char) to_eoxaction_code(eoxaction));
+	values[Anum_pg_variable_varisnotnull - 1] = BoolGetDatum(is_not_null);
+	values[Anum_pg_variable_varisimmutable - 1] = BoolGetDatum(is_immutable);
+	/* proacl will be determined later */
+
+	if (varDefexpr)
+		values[Anum_pg_variable_vardefexpr - 1] = CStringGetTextDatum(nodeToString(varDefexpr));
+	else
+		nulls[Anum_pg_variable_vardefexpr - 1] = true;
+
+	tupdesc = RelationGetDescr(rel);
+
+	oldtup = SearchSysCache2(VARIABLENAMENSP,
+							 PointerGetDatum(varName),
+							 ObjectIdGetDatum(varNamespace));
+
+	if (HeapTupleIsValid(oldtup))
+	{
+		if (if_not_exists)
+			ereport(NOTICE,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("schema variable \"%s\" already exists, skipping",
+							varName)));
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("schema variable \"%s\" already exists",
+							varName)));
+
+		ReleaseSysCache(oldtup);
+		table_close(rel, RowExclusiveLock);
+
+		return InvalidObjectAddress;
+	}
+
+	varacl = get_user_default_acl(OBJECT_VARIABLE, varOwner,
+								  varNamespace);
+
+	if (varacl != NULL)
+		values[Anum_pg_variable_varacl - 1] = PointerGetDatum(varacl);
+	else
+		nulls[Anum_pg_variable_varacl - 1] = true;
+
+	tup = heap_form_tuple(tupdesc, values, nulls);
+	CatalogTupleInsert(rel, tup);
+
+	myself.classId = VariableRelationId;
+	myself.objectId = varid;
+	myself.objectSubId = 0;
+
+	/* dependency on namespace */
+	referenced.classId = NamespaceRelationId;
+	referenced.objectId = varNamespace;
+	referenced.objectSubId = 0;
+	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+	/* dependency on used type */
+	referenced.classId = TypeRelationId;
+	referenced.objectId = varType;
+	referenced.objectSubId = 0;
+	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+	/* dependency on default expr */
+	if (varDefexpr)
+		recordDependencyOnExpr(&myself, (Node *) varDefexpr,
+							   NIL, DEPENDENCY_NORMAL);
+
+	/* dependency on any roles mentioned in ACL */
+	if (varacl != NULL)
+	{
+		int			nnewmembers;
+		Oid		   *newmembers;
+
+		nnewmembers = aclmembers(varacl, &newmembers);
+		updateAclDependencies(VariableRelationId, varid, 0,
+							  varOwner,
+							  0, NULL,
+							  nnewmembers, newmembers);
+	}
+
+	/* dependency on extension */
+	recordDependencyOnCurrentExtension(&myself, false);
+
+	/*
+	 * register on commit action if it is necessary. This moment, the variable
+	 * has not any value, so we don't need to solve content transactionality.
+	 */
+	register_variable_on_commit_action(myself.objectId, eoxaction);
+
+	heap_freetuple(tup);
+
+	/* Post creation hook for new function */
+	InvokeObjectPostCreateHook(VariableRelationId, varid, 0);
+
+	table_close(rel, RowExclusiveLock);
+
+	return myself;
+}
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index e8504f0ae4..0b785be2ce 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -48,6 +48,7 @@ OBJS = \
 	proclang.o \
 	publicationcmds.o \
 	schemacmds.o \
+	schemavariable.o \
 	seclabel.o \
 	sequence.o \
 	statscmds.o \
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 40044070cf..c559449f1a 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -40,6 +40,7 @@
 #include "catalog/pg_ts_dict.h"
 #include "catalog/pg_ts_parser.h"
 #include "catalog/pg_ts_template.h"
+#include "catalog/pg_variable.h"
 #include "commands/alter.h"
 #include "commands/collationcmds.h"
 #include "commands/conversioncmds.h"
@@ -141,6 +142,10 @@ report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
 			Assert(OidIsValid(nspOid));
 			msgfmt = gettext_noop("text search configuration \"%s\" already exists in schema \"%s\"");
 			break;
+		case VariableRelationId:
+			Assert(OidIsValid(nspOid));
+			msgfmt = gettext_noop("schema variable \"%s\" already exists in schema \"%s\"");
+			break;
 		default:
 			elog(ERROR, "unsupported object class %u", classId);
 			break;
@@ -393,6 +398,7 @@ ExecRenameStmt(RenameStmt *stmt)
 		case OBJECT_TSTEMPLATE:
 		case OBJECT_PUBLICATION:
 		case OBJECT_SUBSCRIPTION:
+		case OBJECT_VARIABLE:
 			{
 				ObjectAddress address;
 				Relation	catalog;
@@ -536,6 +542,7 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt,
 		case OBJECT_TSDICTIONARY:
 		case OBJECT_TSPARSER:
 		case OBJECT_TSTEMPLATE:
+		case OBJECT_VARIABLE:
 			{
 				Relation	catalog;
 				Relation	relation;
@@ -626,6 +633,7 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
 		case OCLASS_TSDICT:
 		case OCLASS_TSTEMPLATE:
 		case OCLASS_TSCONFIG:
+		case OCLASS_VARIABLE:
 			{
 				Relation	catalog;
 
@@ -884,6 +892,7 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
 		case OBJECT_TABLESPACE:
 		case OBJECT_TSDICTIONARY:
 		case OBJECT_TSCONFIGURATION:
+		case OBJECT_VARIABLE:
 			{
 				Relation	catalog;
 				Relation	relation;
diff --git a/src/backend/commands/discard.c b/src/backend/commands/discard.c
index 57d3d7dd9b..a712bf44b6 100644
--- a/src/backend/commands/discard.c
+++ b/src/backend/commands/discard.c
@@ -19,6 +19,7 @@
 #include "commands/discard.h"
 #include "commands/prepare.h"
 #include "commands/sequence.h"
+#include "commands/schema_variable.h"
 #include "utils/guc.h"
 #include "utils/portal.h"
 
@@ -48,6 +49,10 @@ DiscardCommand(DiscardStmt *stmt, bool isTopLevel)
 			ResetTempTableNamespace();
 			break;
 
+		case DISCARD_VARIABLES:
+			ResetSchemaVariableCache();
+			break;
+
 		default:
 			elog(ERROR, "unrecognized DISCARD target: %d", stmt->target);
 	}
@@ -75,4 +80,5 @@ DiscardAll(bool isTopLevel)
 	ResetPlanCache();
 	ResetTempTableNamespace();
 	ResetSequenceCaches();
+	ResetSchemaVariableCache();
 }
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index 4e545adf95..1d14951e8c 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -481,6 +481,10 @@ does_not_exist_skipping(ObjectType objtype, Node *object)
 			msg = gettext_noop("publication \"%s\" does not exist, skipping");
 			name = strVal(object);
 			break;
+		case OBJECT_VARIABLE:
+			msg = gettext_noop("schema variable \"%s\" does not exist, skipping");
+			name = NameListToString(castNode(List, object));
+			break;
 		default:
 			elog(ERROR, "unrecognized object type: %d", (int) objtype);
 			break;
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index df264329d8..98d0e2ec25 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -991,6 +991,7 @@ EventTriggerSupportsObjectType(ObjectType obtype)
 		case OBJECT_TSTEMPLATE:
 		case OBJECT_TYPE:
 		case OBJECT_USER_MAPPING:
+		case OBJECT_VARIABLE:
 		case OBJECT_VIEW:
 			return true;
 
@@ -1055,6 +1056,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass)
 		case OCLASS_PUBLICATION_REL:
 		case OCLASS_SUBSCRIPTION:
 		case OCLASS_TRANSFORM:
+		case OCLASS_VARIABLE:
 			return true;
 
 			/*
@@ -2106,6 +2108,8 @@ stringify_grant_objtype(ObjectType objtype)
 			return "TABLESPACE";
 		case OBJECT_TYPE:
 			return "TYPE";
+		case OBJECT_VARIABLE:
+			return "VARIABLE";
 			/* these currently aren't used */
 		case OBJECT_ACCESS_METHOD:
 		case OBJECT_AGGREGATE:
@@ -2189,6 +2193,8 @@ stringify_adefprivs_objtype(ObjectType objtype)
 			return "TABLESPACES";
 		case OBJECT_TYPE:
 			return "TYPES";
+		case OBJECT_VARIABLE:
+			return "VARIABLES";
 			/* these currently aren't used */
 		case OBJECT_ACCESS_METHOD:
 		case OBJECT_AGGREGATE:
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 10644dfac4..77d18cb9ac 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -492,6 +492,22 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es,
 		else
 			ExplainDummyGroup("Notify", NULL, es);
 	}
+	else if (IsA(utilityStmt, LetStmt))
+	{
+		LetStmt	   *letstmt = (LetStmt *) utilityStmt;
+		List	   *rewritten;
+
+		if (es->format == EXPLAIN_FORMAT_TEXT)
+			appendStringInfoString(es->str, "SET SCHEMA VARIABLE\n");
+		else
+			ExplainDummyGroup("Set Schema Variable", NULL, es);
+
+		rewritten = QueryRewrite(castNode(Query, copyObject(letstmt->query)));
+		Assert(list_length(rewritten) == 1);
+		ExplainOneQuery(linitial_node(Query, rewritten),
+						CURSOR_OPT_PARALLEL_OK, NULL, es,
+						queryString, params, queryEnv);
+	}
 	else
 	{
 		if (es->format == EXPLAIN_FORMAT_TEXT)
diff --git a/src/backend/commands/schemavariable.c b/src/backend/commands/schemavariable.c
new file mode 100644
index 0000000000..15e0567199
--- /dev/null
+++ b/src/backend/commands/schemavariable.c
@@ -0,0 +1,881 @@
+/*-------------------------------------------------------------------------
+ *
+ * schemavariable.c
+ *	  schema variable creation/manipulation commands
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/commands/schemavariable.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+#include "miscadmin.h"
+#include "access/heapam.h"
+#include "access/htup_details.h"
+#include "access/xact.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_variable.h"
+#include "commands/schema_variable.h"
+#include "executor/executor.h"
+#include "executor/svariableReceiver.h"
+#include "optimizer/optimizer.h"
+#include "parser/parse_coerce.h"
+#include "parser/parse_collate.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_type.h"
+#include "rewrite/rewriteHandler.h"
+#include "tcop/tcopprot.h"
+#include "utils/builtins.h"
+#include "utils/datum.h"
+#include "utils/inval.h"
+#include "utils/lsyscache.h"
+#include "utils/snapmgr.h"
+#include "utils/syscache.h"
+
+/*
+ * ON COMMIT action list
+ */
+typedef struct OnCommitItem
+{
+	Oid			varid;			/* relid of relation */
+	VariableEOXAction eoxaction;	/* what to do at end of xact */
+
+	/*
+	 * If this entry was created during the current transaction,
+	 * creating_subid is the ID of the creating subxact; if created in a prior
+	 * transaction, creating_subid is zero.  If deleted during the current
+	 * transaction, deleting_subid is the ID of the deleting subxact; if no
+	 * deletion request is pending, deleting_subid is zero.
+	 */
+	SubTransactionId creating_subid;
+	SubTransactionId deleting_subid;
+} OnCommitItem;
+
+static List *on_commits = NIL;
+
+/*
+ * The content of variables is not transactional. Due this fact the
+ * implementation of DROP can be simple, because although DROP VARIABLE
+ * can be reverted, the content of variable can be lost. In this example,
+ * DROP VARIABLE is same like reset variable.
+ */
+
+typedef struct SchemaVariableData
+{
+	Oid			varid;			/* pg_variable OID of this sequence (hash key) */
+	Oid			typid;			/* OID of the data type */
+	int16		typlen;
+	bool		typbyval;
+	bool		isnull;
+	bool		freeval;
+	Datum		value;
+	bool		is_rowtype;		/* true when variable is composite */
+	bool		is_valid;		/* true when variable was successfuly
+								 * initialized */
+	bool		reset_auto;		/* next read fix invalidate value by self */
+
+	bool		is_not_null;	/* don't allow null values */
+	bool		has_defexpr;	/* true when there are default value */
+	bool		is_immutable;	/* true when variable is immutable */
+
+	SubTransactionId creating_subid;
+}			SchemaVariableData;
+
+typedef SchemaVariableData * SchemaVariable;
+
+static HTAB *schemavarhashtab = NULL;	/* hash table for session variables */
+static MemoryContext SchemaVariableMemoryContext = NULL;
+
+static bool first_time = true;
+static bool clean_cache_req = false;
+
+static void create_schema_variable_hashtable(void);
+static void clean_cache_callback(XactEvent event, void *arg);
+static void free_schema_variable(SchemaVariable svar, bool force);
+static void set_schema_variable(SchemaVariable svar, Datum value, bool isnull, Oid typid);
+static void init_schema_variable(SchemaVariable svar, Variable *var);
+static SchemaVariable prepare_variable_for_reading(Oid varid, bool reset);
+static void remove_variable_on_commit_actions(Oid varid, VariableEOXAction eoxaction);
+static void clean_cache_variable(Oid varid);
+
+/*
+ * Save info about necessity to clean hash table, because some
+ * schema variable was dropped. Don't do here more, recheck
+ * needs to be in transaction state.
+ */
+static void
+InvalidateSchemaVariableCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
+{
+	if (cacheid != VARIABLEOID)
+		return;
+
+	clean_cache_req = true;
+}
+
+/*
+ * Recheck values of all schema variables stored in local memory.
+ * Remove the value from local memory, when related schema variable
+ * was dropped (and removed from system catalogue).
+ */
+static void
+clean_cache_callback(XactEvent event, void *arg)
+{
+	/*
+	 * should continue only in transaction time, when syscache is available.
+	 */
+	if (clean_cache_req && IsTransactionState())
+	{
+		HASH_SEQ_STATUS status;
+		SchemaVariable svar;
+
+		if (!schemavarhashtab)
+			return;
+
+		hash_seq_init(&status, schemavarhashtab);
+
+		while ((svar = (SchemaVariable) hash_seq_search(&status)) != NULL)
+		{
+			HeapTuple	tp;
+
+			tp = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(svar->varid));
+			if (!HeapTupleIsValid(tp))
+			{
+				elog(DEBUG1, "variable %d is removed from cache", svar->varid);
+
+				free_schema_variable(svar, true);
+
+				remove_variable_on_commit_actions(svar->varid, VARIABLE_EOX_DROP);
+
+				(void) hash_search(schemavarhashtab, (void *) &svar->varid,
+								   HASH_REMOVE, NULL);
+			}
+			else
+				ReleaseSysCache(tp);
+		}
+
+		clean_cache_req = false;
+	}
+}
+
+/*
+ * Create the hash table for storing schema variables
+ */
+static void
+create_schema_variable_hashtable(void)
+{
+	HASHCTL		ctl;
+
+	/* set callbacks */
+	if (first_time)
+	{
+		CacheRegisterSyscacheCallback(VARIABLEOID,
+									  InvalidateSchemaVariableCacheCallback,
+									  (Datum) 0);
+
+		RegisterXactCallback(clean_cache_callback, NULL);
+
+		first_time = false;
+	}
+
+	/* needs own long life memory context */
+	if (SchemaVariableMemoryContext == NULL)
+	{
+		SchemaVariableMemoryContext =
+			AllocSetContextCreate(TopMemoryContext,
+								  "schema variables",
+								  ALLOCSET_START_SMALL_SIZES);
+	}
+
+	memset(&ctl, 0, sizeof(ctl));
+	ctl.keysize = sizeof(Oid);
+	ctl.entrysize = sizeof(SchemaVariableData);
+	ctl.hcxt = SchemaVariableMemoryContext;
+
+	schemavarhashtab = hash_create("Schema variables", 64, &ctl,
+								   HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
+}
+
+/*
+ * Fast drop complete content of schema variables
+ */
+void
+ResetSchemaVariableCache(void)
+{
+	/* Remove temporal schema variables */
+	AtPreEOXact_SchemaVariable_on_commit_actions(true);
+
+	/* Destroy hash table and reset related memory context */
+	if (schemavarhashtab)
+	{
+		hash_destroy(schemavarhashtab);
+		schemavarhashtab = NULL;
+	}
+
+	/* Release memory allocated by schema variables */
+	if (SchemaVariableMemoryContext != NULL)
+		MemoryContextReset(SchemaVariableMemoryContext);
+}
+
+/*
+ * Release data stored inside svar. When a variable is transactional,
+ * and was not modified already in this transaction, then it archives
+ * current value for possible future usage on rollback.
+ *
+ * When force is true, then release current and possibly archived value.
+ */
+static void
+free_schema_variable(SchemaVariable svar, bool force)
+{
+	if (svar->freeval)
+		pfree(DatumGetPointer(svar->value));
+
+	/* Clean current value, and mark it as invalid */
+	svar->value = (Datum) 0;
+	svar->isnull = true;
+	svar->freeval = false;
+
+	svar->is_valid = false;
+}
+
+/*
+ * Assign some content to the schema variable. It does copy to
+ * SchemaVariableMemoryContext if it is necessary.
+ */
+static void
+set_schema_variable(SchemaVariable svar, Datum value, bool isnull, Oid typid)
+{
+	MemoryContext oldcxt;
+	Datum		newval = value;
+
+	/* Don't allow assign null to NOT NULL variable */
+	if (isnull && svar->is_not_null)
+		ereport(ERROR,
+				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+				 errmsg("null value is not allowed for NOT NULL schema variable \"%s\"",
+						schema_variable_get_name(svar->varid))));
+
+	if (!isnull && svar->typid != typid)
+		ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+				 errmsg("type \"%s\" of assigned value is different than type \"%s\" of schema variable \"%s\"",
+						format_type_be(typid),
+						format_type_be(svar->typid),
+						schema_variable_get_name(svar->varid))));
+
+	/* copy value to session persistent context */
+	oldcxt = MemoryContextSwitchTo(SchemaVariableMemoryContext);
+	if (!isnull)
+		newval = datumCopy(value, svar->typbyval, svar->typlen);
+	MemoryContextSwitchTo(oldcxt);
+
+	free_schema_variable(svar, false);
+
+	svar->value = newval;
+	svar->isnull = isnull;
+	svar->freeval = newval != value;
+	svar->is_valid = true;
+	svar->reset_auto = false;
+}
+
+/*
+ * Initialize svar from var
+ * svar - SchemaVariable - holds data
+ * var  - Variable - holds metadata
+ */
+static void
+init_schema_variable(SchemaVariable svar, Variable *var)
+{
+	Assert(OidIsValid(var->oid));
+
+	svar->varid = var->oid;
+	svar->typid = var->typid;
+
+	get_typlenbyval(var->typid,
+					&svar->typlen,
+					&svar->typbyval);
+
+	svar->isnull = true;
+	svar->freeval = false;
+	svar->value = (Datum) 0;
+
+	svar->is_rowtype = type_is_rowtype(var->typid);
+	svar->is_not_null = var->is_not_null;
+	svar->is_immutable = var->is_immutable;
+	svar->has_defexpr = var->has_defexpr;
+
+	/* the variable initialization was not complete here */
+	svar->is_valid = false;
+	svar->reset_auto = false;
+
+	svar->creating_subid = InvalidSubTransactionId;
+}
+
+/*
+ * Try to search value in hash table. If doesn't
+ * exists insert it (and calculate defexpr if exists.
+ * When reset is true, we would to enforce calculate
+ * defexpr. When some is wrong, then this function try
+ * don't break previous value.
+ */
+static SchemaVariable
+prepare_variable_for_reading(Oid varid, bool reset)
+{
+	SchemaVariable svar;
+	Variable	var;
+	bool		found;
+
+	var.oid = InvalidOid;
+
+	if (schemavarhashtab == NULL)
+		create_schema_variable_hashtable();
+
+	svar = (SchemaVariable) hash_search(schemavarhashtab, &varid,
+										HASH_ENTER, &found);
+
+	/* Return content if it is available, and reset is not required */
+	if (found && !reset && !svar->reset_auto)
+	{
+		/* raise exception when content is not valid */
+		if (!svar->is_valid)
+			ereport(ERROR,
+					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+					 errmsg("variable \"%s\" has not valid content",
+							schema_variable_get_name(varid)),
+					 errhint("Overwrite the content of variable or assign DEFAULT again.")));
+
+		return svar;
+	}
+
+	/* We need to load defexpr. */
+	initVariable(&var, varid, false, false);
+
+	if (!found)
+		init_schema_variable(svar, &var);
+
+	/* Raise a error when we cannot to initialize variable correctly */
+	if (var.is_not_null && !var.defexpr)
+		ereport(ERROR,
+				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+				 errmsg("null value is not allowed for NOT NULL schema variable \"%s\"",
+						schema_variable_get_name(varid)),
+				 errdetail("The schema variable was not initialized yet.")));
+
+	if (!found)
+		register_variable_on_commit_action(varid, var.eoxaction);
+
+	if (svar->has_defexpr)
+	{
+		Datum		value = (Datum) 0;
+		bool		isnull;
+		EState	   *estate = NULL;
+		Expr	   *defexpr;
+		ExprState  *defexprs;
+		MemoryContext oldcxt;
+
+		/* Prepare default expr */
+		estate = CreateExecutorState();
+
+		oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
+
+		defexpr = expression_planner((Expr *) var.defexpr);
+		defexprs = ExecInitExpr(defexpr, NULL);
+		value = ExecEvalExprSwitchContext(defexprs,
+										  GetPerTupleExprContext(estate),
+										  &isnull);
+
+
+		/* Store result before releasing Executor memory */
+		set_schema_variable(svar, value, isnull, svar->typid);
+
+		MemoryContextSwitchTo(oldcxt);
+
+		FreeExecutorState(estate);
+	}
+	else
+		set_schema_variable(svar, (Datum) 0, true, svar->typid);
+
+	return svar;
+}
+
+/*
+ * Write value to variable. We expect secured access in this moment.
+ * We try to don't break previous value, if some is wrong.
+ */
+void
+SetSchemaVariable(Oid varid, Datum value, bool isNull, Oid typid)
+{
+	SchemaVariable svar;
+	bool		found;
+
+	if (schemavarhashtab == NULL)
+		create_schema_variable_hashtable();
+
+	svar = (SchemaVariable) hash_search(schemavarhashtab, &varid,
+										HASH_ENTER, &found);
+
+	/* Initialize svar when was not initialized or when stored value is null */
+	if (!found)
+	{
+		Variable	var;
+
+		/* don't need defexpr and acl here */
+		initVariable(&var, varid, false, true);
+		init_schema_variable(svar, &var);
+		register_variable_on_commit_action(varid, var.eoxaction);
+	}
+
+	/* don't allow a update on immutable variable */
+	if (svar->is_immutable)
+		ereport(ERROR,
+				(errcode(ERRCODE_ERROR_IN_ASSIGNMENT),
+				 errmsg("schema variable \"%s\" is declared IMMUTABLE",
+						schema_variable_get_name(svar->varid))));
+
+	set_schema_variable(svar, value, isNull, typid);
+}
+
+
+/*
+ * Write value to variable with security check.
+ * We try to don't break previous value, if some is wrong.
+ */
+void
+SetSchemaVariableWithSecurityCheck(Oid varid, Datum value, bool isNull, Oid typid)
+{
+	AclResult	aclresult;
+
+	/*
+	 * Is possible to write to schema variable?
+	 */
+	aclresult = pg_variable_aclcheck(varid, GetUserId(), ACL_WRITE);
+	if (aclresult != ACLCHECK_OK)
+		aclcheck_error(aclresult, OBJECT_VARIABLE, schema_variable_get_name(varid));
+
+	SetSchemaVariable(varid, value, isNull, typid);
+}
+
+/*
+ * Returns copy of value of schema variable spcified by varid
+ */
+Datum
+CopySchemaVariable(Oid varid, bool *isNull, Oid *typid)
+{
+	SchemaVariable svar;
+
+	svar = prepare_variable_for_reading(varid, false);
+	Assert(svar != NULL && svar->is_valid);
+
+	*isNull = svar->isnull;
+	*typid = svar->typid;
+
+	if (!svar->isnull)
+		return datumCopy(svar->value, svar->typbyval, svar->typlen);
+
+	return (Datum) 0;
+}
+
+/*
+ * Returns value of schema variable specified by varid. Check correct
+ * result type. Optionaly the result can be copy.
+ */
+Datum
+GetSchemaVariable(Oid varid, bool *isNull, Oid expected_typid, bool copy)
+{
+	SchemaVariable svar;
+	Datum		value;
+	bool		isnull;
+
+	svar = prepare_variable_for_reading(varid, false);
+	Assert(svar != NULL);
+
+	if (expected_typid != svar->typid)
+		elog(ERROR, "type of variable \"%s\" is different than expected",
+			 schema_variable_get_name(varid));
+
+	value = svar->value;
+	isnull = svar->isnull;
+
+	*isNull = isnull;
+
+	if (!isnull && copy)
+		return datumCopy(value, svar->typbyval, svar->typlen);
+
+	return value;
+}
+
+/*
+ * Clean variable defined by varid
+ */
+static void
+clean_cache_variable(Oid varid)
+{
+	SchemaVariable svar;
+	bool		found;
+
+	if (schemavarhashtab == NULL)
+		return;
+
+	svar = (SchemaVariable) hash_search(schemavarhashtab, &varid,
+										HASH_FIND, &found);
+	if (found)
+	{
+		/* clean content, if it is necessary */
+		free_schema_variable(svar, true);
+
+		if (hash_search(schemavarhashtab,
+						(void *) &svar->varid,
+						HASH_REMOVE,
+						NULL) == NULL)
+			elog(DEBUG1, "hash table corrupted");
+	}
+}
+
+/*
+ * Drop variable by OID
+ */
+void
+RemoveSchemaVariable(Oid varid)
+{
+	Relation	rel;
+	HeapTuple	tup;
+
+	rel = table_open(VariableRelationId, RowExclusiveLock);
+
+	tup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(varid));
+
+	if (!HeapTupleIsValid(tup))
+		elog(ERROR, "cache lookup failed for variable %u", varid);
+
+	CatalogTupleDelete(rel, &tup->t_self);
+
+	ReleaseSysCache(tup);
+
+	table_close(rel, RowExclusiveLock);
+
+	clean_cache_variable(varid);
+
+	/* remove variable from on_commits list */
+	remove_variable_on_commit_actions(varid, VARIABLE_EOX_DROP);
+}
+
+/*
+ * Assign result of evaluated expression to schema variable
+ */
+void
+ExecuteLetStmt(ParseState *pstate,
+			   LetStmt *stmt,
+			   ParamListInfo params,
+			   QueryEnvironment *queryEnv,
+			   QueryCompletion *qc)
+{
+	Query	   *query = castNode(Query, stmt->query);
+	List	   *rewritten;
+	DestReceiver *dest;
+	AclResult	aclresult;
+	PlannedStmt *plan;
+	QueryDesc  *queryDesc;
+	Oid			varid = query->resultVariable;
+
+	Assert(OidIsValid(varid));
+
+	/*
+	 * Is possible to write to schema variable?
+	 */
+	aclresult = pg_variable_aclcheck(varid, GetUserId(), ACL_WRITE);
+	if (aclresult != ACLCHECK_OK)
+		aclcheck_error(aclresult, OBJECT_VARIABLE, schema_variable_get_name(varid));
+
+	/* Create dest receiver for LET */
+	dest = CreateDestReceiver(DestVariable);
+	SetVariableDestReceiverParams(dest, varid);
+
+	/* run rewriter - there can be used for replacement of DEFAULT node */
+	query = copyObject(query);
+
+	rewritten = QueryRewrite(query);
+
+	Assert(list_length(rewritten) == 1);
+
+	query = linitial_node(Query, rewritten);
+	Assert(query->commandType == CMD_SELECT);
+
+	/* plan the query */
+	plan = pg_plan_query(query, pstate->p_sourcetext,
+						 CURSOR_OPT_PARALLEL_OK, params);
+
+	/*
+	 * Use a snapshot with an updated command ID to ensure this query sees
+	 * results of any previously executed queries.  (This could only
+	 * matter if the planner executed an allegedly-stable function that
+	 * changed the database contents, but let's do it anyway to be
+	 * parallel to the EXPLAIN code path.)
+	 */
+	PushCopiedSnapshot(GetActiveSnapshot());
+	UpdateActiveSnapshotCommandId();
+
+	/* Create a QueryDesc, redirecting output to our tuple receiver */
+	queryDesc = CreateQueryDesc(plan, pstate->p_sourcetext,
+								GetActiveSnapshot(), InvalidSnapshot,
+								dest, params, queryEnv, 0);
+
+	/* call ExecutorStart to prepare the plan for execution */
+	ExecutorStart(queryDesc, 0);
+
+	/* run the plan to completion */
+	ExecutorRun(queryDesc, ForwardScanDirection, 2L, true);
+
+	/* save the rowcount if we're given a qc to fill */
+	if (qc)
+		SetQueryCompletion(qc, CMDTAG_LET, queryDesc->estate->es_processed);
+
+	/* and clean up */
+	ExecutorFinish(queryDesc);
+	ExecutorEnd(queryDesc);
+
+	FreeQueryDesc(queryDesc);
+
+	PopActiveSnapshot();
+}
+
+/*
+ * Creates new variable - entry in pg_catalog.pg_variable table
+ *
+ * Used by CREATE VARIABLE command
+ */
+ObjectAddress
+DefineSchemaVariable(ParseState *pstate, CreateSchemaVarStmt *stmt)
+{
+	Oid			namespaceid;
+	AclResult	aclresult;
+	Oid			typid;
+	int32		typmod;
+	Oid			varowner = GetUserId();
+	Oid			collation;
+	Oid			typcollation;
+	ObjectAddress variable;
+
+	Node	   *cooked_default = NULL;
+
+	/*
+	 * Check consistency of arguments
+	 */
+	if (stmt->eoxaction == VARIABLE_EOX_DROP
+		&& stmt->variable->relpersistence != RELPERSISTENCE_TEMP)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+				 errmsg("ON COMMIT DROP can only be used on temporary variables")));
+
+	if (stmt->is_not_null && stmt->is_immutable && !stmt->defexpr)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+				 errmsg("IMMUTABLE NOT NULL variable requires default expression")));
+
+	namespaceid =
+		RangeVarGetAndCheckCreationNamespace(stmt->variable, NoLock, NULL);
+
+	typenameTypeIdAndMod(pstate, stmt->typeName, &typid, &typmod);
+	typcollation = get_typcollation(typid);
+
+	aclresult = pg_type_aclcheck(typid, GetUserId(), ACL_USAGE);
+	if (aclresult != ACLCHECK_OK)
+		aclcheck_error_type(aclresult, typid);
+
+	if (stmt->collClause)
+		collation = LookupCollation(pstate,
+									stmt->collClause->collname,
+									stmt->collClause->location);
+	else
+		collation = typcollation;;
+
+	/* Complain if COLLATE is applied to an uncollatable type */
+	if (OidIsValid(collation) && !OidIsValid(typcollation))
+		ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+				 errmsg("collations are not supported by type %s",
+						format_type_be(typid)),
+				 parser_errposition(pstate, stmt->collClause->location)));
+
+	if (stmt->defexpr)
+	{
+		cooked_default = transformExpr(pstate, stmt->defexpr,
+									   EXPR_KIND_VARIABLE_DEFAULT);
+
+		cooked_default = coerce_to_specific_type(pstate,
+												 cooked_default, typid, "DEFAULT");
+		assign_expr_collations(pstate, cooked_default);
+	}
+
+	variable = VariableCreate(stmt->variable->relname,
+							  namespaceid,
+							  typid,
+							  typmod,
+							  varowner,
+							  collation,
+							  cooked_default,
+							  stmt->eoxaction,
+							  stmt->is_not_null,
+							  stmt->if_not_exists,
+							  stmt->is_immutable);
+
+	/*
+	 * We must bump the command counter to make the newly-created variable
+	 * tuple visible for any other operations.
+	 */
+	CommandCounterIncrement();
+
+	return variable;
+}
+
+/*
+ * Register a newly-created variable ON COMMIT action.
+ */
+void
+register_variable_on_commit_action(Oid varid,
+								   VariableEOXAction action)
+{
+	OnCommitItem *oc;
+	MemoryContext oldcxt;
+
+	/*
+	 * We needn't bother registering the relation unless there is an ON COMMIT
+	 * action we need to take.
+	 */
+	if (action == VARIABLE_EOX_NOOP)
+		return;
+
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+
+	oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
+	oc->varid = varid;
+	oc->eoxaction = action;
+
+	oc->creating_subid = GetCurrentSubTransactionId();
+	oc->deleting_subid = InvalidSubTransactionId;
+
+	on_commits = lcons(oc, on_commits);
+
+	MemoryContextSwitchTo(oldcxt);
+}
+
+/*
+ * Remove variable from on_commits action
+ */
+static void
+remove_variable_on_commit_actions(Oid varid,
+								  VariableEOXAction eoxaction)
+{
+	ListCell   *l;
+
+	foreach(l, on_commits)
+	{
+		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
+
+		if (oc->varid == varid)
+		{
+			if (eoxaction == VARIABLE_EOX_DROP ||
+				(oc->eoxaction == VARIABLE_EOX_RESET &&
+				 eoxaction == VARIABLE_EOX_RESET))
+				oc->deleting_subid = GetCurrentSubTransactionId();
+		}
+	}
+}
+
+/*
+ * Perform ON TRANSACTION END RESET, ON COMMIT DROP
+ * and COMMIT/ROLLBACK of transaction schema variables.
+ */
+void
+AtPreEOXact_SchemaVariable_on_commit_actions(bool isCommit)
+{
+	ListCell   *l;
+
+	foreach(l, on_commits)
+	{
+		OnCommitItem *oc = (OnCommitItem *) lfirst(l);
+
+		/* Ignore entry if already dropped in this xact */
+		if (oc->deleting_subid != InvalidSubTransactionId)
+			continue;
+
+		switch (oc->eoxaction)
+		{
+			case VARIABLE_EOX_NOOP:
+				/* Do nothing */
+				break;
+			case VARIABLE_EOX_RESET:
+				clean_cache_variable(oc->varid);
+				remove_variable_on_commit_actions(oc->varid,
+												  VARIABLE_EOX_RESET);
+				break;
+			case VARIABLE_EOX_DROP:
+				{
+					/*
+					 * ON COMMIT DROP is allowed only for temp schema
+					 * variables. So we should explicit delete only when
+					 * current transaction was committed. When is rollback,
+					 * then schema variable is removed automatically.
+					 */
+					if (isCommit)
+					{
+						ObjectAddress object;
+
+						object.classId = VariableRelationId;
+						object.objectId = oc->varid;
+						object.objectSubId = 0;
+
+						/*
+						 * Since this is an automatic drop, rather than one
+						 * directly initiated by the user, we pass the
+						 * PERFORM_DELETION_INTERNAL flag.
+						 */
+						performDeletion(&object,
+										DROP_CASCADE, PERFORM_DELETION_INTERNAL);
+					}
+				}
+				break;
+		}
+	}
+}
+
+/*
+ * Post-commit or post-abort cleanup for ON COMMIT management.
+ *
+ * All we do here is remove no-longer-needed OnCommitItem entries.
+ *
+ */
+void
+AtEOXact_SchemaVariable_on_commit_actions(bool isCommit)
+{
+	ListCell   *cur_item;
+
+	foreach(cur_item, on_commits)
+	{
+		OnCommitItem *oc = (OnCommitItem *) lfirst(cur_item);
+
+		/*
+		 * During commit, remove entries that were deleted during this
+		 * transaction; during abort, remove those created during this
+		 * transaction.
+		 *
+		 * The transact variable event is removed every time.
+		 */
+
+		if ((isCommit ? oc->deleting_subid != InvalidSubTransactionId :
+			 oc->creating_subid != InvalidSubTransactionId))
+		{
+			on_commits = foreach_delete_current(on_commits, cur_item);
+			pfree(oc);
+		}
+		else
+		{
+			oc->creating_subid = InvalidSubTransactionId;
+			oc->deleting_subid = InvalidSubTransactionId;
+		}
+	}
+}
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index 53c18628a7..c094a3871c 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -91,6 +91,7 @@ SecLabelSupportsObjectType(ObjectType objtype)
 		case OBJECT_TSPARSER:
 		case OBJECT_TSTEMPLATE:
 		case OBJECT_USER_MAPPING:
+		case OBJECT_VARIABLE:
 			return false;
 
 			/*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 857cc5ce6e..011534270f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -12290,6 +12290,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 			case OCLASS_PUBLICATION_REL:
 			case OCLASS_SUBSCRIPTION:
 			case OCLASS_TRANSFORM:
+			case OCLASS_VARIABLE:
 
 				/*
 				 * We don't expect any of these sorts of objects to depend on
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index 11118d0ce0..71248a34f2 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -76,6 +76,7 @@ OBJS = \
 	nodeWindowAgg.o \
 	nodeWorktablescan.o \
 	spi.o \
+	svariableReceiver.o \
 	tqueue.o \
 	tstoreReceiver.o
 
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 892b4e17e0..35a8523f98 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -33,6 +33,7 @@
 #include "access/nbtree.h"
 #include "catalog/objectaccess.h"
 #include "catalog/pg_type.h"
+#include "commands/schema_variable.h"
 #include "executor/execExpr.h"
 #include "executor/nodeSubplan.h"
 #include "funcapi.h"
@@ -994,6 +995,60 @@ ExecInitExprRec(Expr *node, ExprState *state,
 						scratch.d.param.paramtype = param->paramtype;
 						ExprEvalPushStep(state, &scratch);
 						break;
+
+					case PARAM_VARIABLE:
+						{
+							int			es_num_schema_variables = 0;
+							SchemaVariableValue *es_schema_variables = NULL;
+
+							if (state->parent && state->parent->state)
+							{
+								es_schema_variables = state->parent->state->es_schema_variables;
+								es_num_schema_variables = state->parent->state->es_num_schema_variables;
+							}
+
+							/*
+							 * We should use schema variable buffer, when
+							 * it is available.
+							 */
+							if (es_schema_variables)
+							{
+								SchemaVariableValue *var;
+
+								/* check params, unexpected */
+								if (param->paramid >= es_num_schema_variables)
+									elog(ERROR, "paramid of PARAM_VARIABLE param is out of range");
+
+								var = &es_schema_variables[param->paramid];
+
+								/* unexpected */
+								if (var->typid != param->paramtype)
+									elog(ERROR, "type of buffered value is different than PARAM_VARIABLE type");
+
+								/*
+								 * In this case, the parameter is like a
+								 * constant
+								 */
+								scratch.opcode = EEOP_CONST;
+								scratch.d.constval.value = var->value;
+								scratch.d.constval.isnull = var->isnull;
+								ExprEvalPushStep(state, &scratch);
+							}
+							else
+							{
+								/*
+								 * When we have not a full PlanState (plpgsql
+								 * simple expr evaluation, then we should to
+								 * use direct access.
+								 */
+								scratch.opcode = EEOP_PARAM_VARIABLE;
+								scratch.d.vparam.varid = param->paramvarid;
+								scratch.d.vparam.vartype = param->paramtype;
+								ExprEvalPushStep(state, &scratch);
+							}
+						}
+						break;
+
 					case PARAM_EXTERN:
 
 						/*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index eb49817cee..ce34f7ff0c 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -59,6 +59,7 @@
 #include "access/heaptoast.h"
 #include "catalog/pg_type.h"
 #include "commands/sequence.h"
+#include "commands/schema_variable.h"
 #include "executor/execExpr.h"
 #include "executor/nodeSubplan.h"
 #include "funcapi.h"
@@ -444,6 +445,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 		&&CASE_EEOP_PARAM_EXEC,
 		&&CASE_EEOP_PARAM_EXTERN,
 		&&CASE_EEOP_PARAM_CALLBACK,
+		&&CASE_EEOP_PARAM_VARIABLE,
 		&&CASE_EEOP_CASE_TESTVAL,
 		&&CASE_EEOP_MAKE_READONLY,
 		&&CASE_EEOP_IOCOERCE,
@@ -1078,6 +1080,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 			EEO_NEXT();
 		}
 
+		EEO_CASE(EEOP_PARAM_VARIABLE)
+		{
+			/* direct access to schema variable (without buffering) */
+			*op->resvalue = GetSchemaVariable(op->d.vparam.varid,
+											  op->resnull,
+											  op->d.vparam.vartype,
+											  true);
+			EEO_NEXT();
+		}
+
 		EEO_CASE(EEOP_CASE_TESTVAL)
 		{
 			/*
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index b3ce4bae53..95dac87ca7 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -45,10 +45,13 @@
 #include "access/xact.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_publication.h"
+#include "catalog/pg_variable.h"
 #include "commands/matview.h"
 #include "commands/trigger.h"
+#include "commands/schema_variable.h"
 #include "executor/execdebug.h"
 #include "executor/nodeSubplan.h"
+#include "executor/svariableReceiver.h"
 #include "foreign/fdwapi.h"
 #include "jit/jit.h"
 #include "mb/pg_wchar.h"
@@ -199,6 +202,52 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
 	Assert(queryDesc->sourceText != NULL);
 	estate->es_sourceText = queryDesc->sourceText;
 
+	/*
+	 * Prepare schema variables, if are not prepared in queryDesc
+	 */
+	if (queryDesc->num_schema_variables > 0)
+	{
+		/*
+		 * link shared memory with working copy of schema variable's values
+		 * used in this query. This access is used by parallel query executor's
+		 * workers.
+		 */
+		estate->es_schema_variables = queryDesc->schema_variables;
+		estate->es_num_schema_variables = queryDesc->num_schema_variables;
+	}
+	else if (queryDesc->plannedstmt->schemaVariables)
+	{
+		ListCell   *lc;
+		int			nSchemaVariables;
+		int			i = 0;
+
+		nSchemaVariables = list_length(queryDesc->plannedstmt->schemaVariables);
+
+		/* Create buffer for used schema variables */
+		estate->es_schema_variables = (SchemaVariableValue *)
+			palloc(nSchemaVariables * sizeof(SchemaVariableValue));
+
+		foreach(lc, queryDesc->plannedstmt->schemaVariables)
+		{
+			AclResult	aclresult;
+			Oid			varid = lfirst_oid(lc);
+
+			aclresult = pg_variable_aclcheck(varid, GetUserId(), ACL_READ);
+			if (aclresult != ACLCHECK_OK)
+				aclcheck_error(aclresult, OBJECT_VARIABLE,
+							   schema_variable_get_name(varid));
+
+			estate->es_schema_variables[i].varid = varid;
+			estate->es_schema_variables[i].value = CopySchemaVariable(varid,
+																	  &estate->es_schema_variables[i].isnull,
+																	  &estate->es_schema_variables[i].typid);
+
+			i++;
+		}
+
+		estate->es_num_schema_variables = nSchemaVariables;
+	}
+
 	/*
 	 * Fill in the query environment, if any, from queryDesc.
 	 */
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index f8a4a40e7b..341c817371 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -12,8 +12,9 @@
  * workers and ensuring that their state generally matches that of the
  * leader; see src/backend/access/transam/README.parallel for details.
  * However, we must save and restore relevant executor state, such as
- * any ParamListInfo associated with the query, buffer/WAL usage info, and
- * the actual plan to be passed down to the worker.
+ * any ParamListInfo associated with the query, buffer/WAL usage info,
+ * used schema variables buffer, and the actual plan to be passed down
+ * to the worker.
  *
  * IDENTIFICATION
  *	  src/backend/executor/execParallel.c
@@ -66,6 +67,7 @@
 #define PARALLEL_KEY_QUERY_TEXT		UINT64CONST(0xE000000000000008)
 #define PARALLEL_KEY_JIT_INSTRUMENTATION UINT64CONST(0xE000000000000009)
 #define PARALLEL_KEY_WAL_USAGE			UINT64CONST(0xE00000000000000A)
+#define PARALLEL_KEY_SCHEMA_VARIABLES	UINT64CONST(0xE00000000000000B)
 
 #define PARALLEL_TUPLE_QUEUE_SIZE		65536
 
@@ -140,6 +142,12 @@ static bool ExecParallelRetrieveInstrumentation(PlanState *planstate,
 /* Helper function that runs in the parallel worker. */
 static DestReceiver *ExecParallelGetReceiver(dsm_segment *seg, shm_toc *toc);
 
+/* Helper functions that can pass values of used schema variables */
+static Size EstimateSchemaVariables(EState *estate);
+static void SerializeSchemaVariables(EState *estate, char **start_address);
+static SchemaVariableValue * RestoreSchemaVariables(char **start_address,
+													int *num_schema_variables);
+
 /*
  * Create a serialized representation of the plan to be sent to each worker.
  */
@@ -597,6 +605,7 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
 	char	   *pstmt_data;
 	char	   *pstmt_space;
 	char	   *paramlistinfo_space;
+	char	   *schema_variables_space;
 	BufferUsage *bufusage_space;
 	WalUsage   *walusage_space;
 	SharedExecutorInstrumentation *instrumentation = NULL;
@@ -606,6 +615,7 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
 	int			instrumentation_len = 0;
 	int			jit_instrumentation_len = 0;
 	int			instrument_offset = 0;
+	int			schema_variables_len = 0;
 	Size		dsa_minsize = dsa_minimum_size();
 	char	   *query_string;
 	int			query_len;
@@ -661,6 +671,11 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
 	shm_toc_estimate_chunk(&pcxt->estimator, paramlistinfo_len);
 	shm_toc_estimate_keys(&pcxt->estimator, 1);
 
+	/* Estimate space for serialized schema variables. */
+	schema_variables_len = EstimateSchemaVariables(estate);
+	shm_toc_estimate_chunk(&pcxt->estimator, schema_variables_len);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
 	/*
 	 * Estimate space for BufferUsage.
 	 *
@@ -755,6 +770,11 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
 	shm_toc_insert(pcxt->toc, PARALLEL_KEY_PARAMLISTINFO, paramlistinfo_space);
 	SerializeParamList(estate->es_param_list_info, &paramlistinfo_space);
 
+	/* Store serialized schema variables. */
+	schema_variables_space = shm_toc_allocate(pcxt->toc, schema_variables_len);
+	shm_toc_insert(pcxt->toc, PARALLEL_KEY_SCHEMA_VARIABLES, schema_variables_space);
+	SerializeSchemaVariables(estate, &schema_variables_space);
+
 	/* Allocate space for each worker's BufferUsage; no need to initialize. */
 	bufusage_space = shm_toc_allocate(pcxt->toc,
 									  mul_size(sizeof(BufferUsage), pcxt->nworkers));
@@ -1402,6 +1422,7 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
 	SharedJitInstrumentation *jit_instrumentation;
 	int			instrument_options = 0;
 	void	   *area_space;
+	char	   *schemavariable_space;
 	dsa_area   *area;
 	ParallelWorkerContext pwcxt;
 
@@ -1427,6 +1448,14 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
 	area_space = shm_toc_lookup(toc, PARALLEL_KEY_DSA, false);
 	area = dsa_attach_in_place(area_space, seg);
 
+	/* Reconstruct schema variables. */
+	schemavariable_space = shm_toc_lookup(toc,
+										  PARALLEL_KEY_SCHEMA_VARIABLES,
+										  false);
+	queryDesc->schema_variables =
+		RestoreSchemaVariables(&schemavariable_space,
+							   &queryDesc->num_schema_variables);
+
 	/* Start up the executor */
 	queryDesc->plannedstmt->jitFlags = fpes->jit_flags;
 	ExecutorStart(queryDesc, fpes->eflags);
@@ -1496,3 +1525,118 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
 	FreeQueryDesc(queryDesc);
 	receiver->rDestroy(receiver);
 }
+
+/*
+ * Estimate the amount of space required to serialize a used
+ * schema variables.
+ */
+static Size
+EstimateSchemaVariables(EState *estate)
+{
+	int			i;
+	Size		sz = sizeof(int);
+
+	if (estate->es_schema_variables == NULL)
+		return sz;
+
+	for (i = 0; i < estate->es_num_schema_variables; i++)
+	{
+		SchemaVariableValue *svarval;
+		Oid			typeOid;
+		int16		typLen;
+		bool		typByVal;
+
+		svarval = &estate->es_schema_variables[i];
+
+		typeOid = svarval->typid;
+
+		sz = add_size(sz, sizeof(Oid)); /* space for type OID */
+
+		/* space for datum/isnull */
+		Assert(OidIsValid(typeOid));
+		get_typlenbyval(typeOid, &typLen, &typByVal);
+
+		sz = add_size(sz,
+					  datumEstimateSpace(svarval->value, svarval->isnull, typByVal, typLen));
+	}
+
+	return sz;
+}
+
+/*
+ * Serialize a schema variables buffer into caller-provided storage.
+ *
+ * We write the number of parameters first, as a 4-byte integer, and then
+ * write details for each parameter in turn.  The details for each parameter
+ * consist of a 4-byte type OID, and then the datum as serialized by
+ * datumSerialize().  The caller is responsible for ensuring that there is
+ * enough storage to store the number of bytes that will be written; use
+ * EstimateSchemaVariables to find out how many will be needed.
+ * *start_address is updated to point to the byte immediately following those
+ * written.
+ *
+ * RestoreSchemaVariables can be used to recreate a schema variable buffer
+ * based on the serialized representation;
+ */
+static void
+SerializeSchemaVariables(EState *estate, char **start_address)
+{
+	int			nparams;
+	int			i;
+
+	/* Write number of parameters. */
+	nparams = estate->es_num_schema_variables;
+	memcpy(*start_address, &nparams, sizeof(int));
+	*start_address += sizeof(int);
+
+	/* Write each parameter in turn. */
+	for (i = 0; i < nparams; i++)
+	{
+		SchemaVariableValue *svarval;
+		Oid			typeOid;
+		int16		typLen;
+		bool		typByVal;
+
+		svarval = &estate->es_schema_variables[i];
+		typeOid = svarval->typid;
+
+		/* Write type OID. */
+		memcpy(*start_address, &typeOid, sizeof(Oid));
+		*start_address += sizeof(Oid);
+
+		Assert(OidIsValid(typeOid));
+		get_typlenbyval(typeOid, &typLen, &typByVal);
+
+		datumSerialize(svarval->value, svarval->isnull, typByVal, typLen,
+					   start_address);
+	}
+}
+
+static SchemaVariableValue *
+RestoreSchemaVariables(char **start_address, int *num_schema_variables)
+{
+	SchemaVariableValue *schema_variables;
+	int			i;
+	int			nparams;
+
+	memcpy(&nparams, *start_address, sizeof(int));
+	*start_address += sizeof(int);
+
+	*num_schema_variables = nparams;
+	schema_variables = (SchemaVariableValue *)
+		palloc(nparams * sizeof(SchemaVariableValue));
+
+	for (i = 0; i < nparams; i++)
+	{
+		SchemaVariableValue *svarval = &schema_variables[i];
+
+		/* Read type OID. */
+		memcpy(&svarval->typid, *start_address, sizeof(Oid));
+		*start_address += sizeof(Oid);
+
+		/* Read datum/isnull. */
+		svarval->value = datumRestore(start_address, &svarval->isnull);
+	}
+
+	return schema_variables;
+}
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 0568ae123f..1b37ef33a4 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -2867,6 +2867,9 @@ _SPI_error_callback(void *arg)
 			case RAW_PARSE_PLPGSQL_ASSIGN3:
 				errcontext("PL/pgSQL assignment \"%s\"", query);
 				break;
+			case RAW_PARSE_PLPGSQL_LET:
+				errcontext("LET statement \"%s\"", query);
+				break;
 			default:
 				errcontext("SQL statement \"%s\"", query);
 				break;
diff --git a/src/backend/executor/svariableReceiver.c b/src/backend/executor/svariableReceiver.c
new file mode 100644
index 0000000000..298330c1cf
--- /dev/null
+++ b/src/backend/executor/svariableReceiver.c
@@ -0,0 +1,145 @@
+/*-------------------------------------------------------------------------
+ *
+ * svariableReceiver.c
+ *	  An implementation of DestReceiver that stores the result value in
+ *	  a schema variable.
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/backend/executor/svariableReceiver.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/detoast.h"
+#include "executor/svariableReceiver.h"
+#include "commands/schema_variable.h"
+
+typedef struct
+{
+	DestReceiver pub;
+	Oid			varid;
+	Oid			typid;
+	int32		typmod;
+	int			typlen;
+	int			slot_offset;
+	int			rows;
+}			svariableState;
+
+
+/*
+ * Prepare to receive tuples from executor.
+ */
+static void
+svariableStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
+{
+	svariableState *myState = (svariableState *) self;
+	int			natts = typeinfo->natts;
+	int			outcols = 0;
+	int			i;
+
+	for (i = 0; i < natts; i++)
+	{
+		Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
+
+		if (attr->attisdropped)
+			continue;
+
+		if (++outcols > 1)
+			elog(ERROR, "svariable DestReceiver can take only one attribute");
+
+		myState->typid = attr->atttypid;
+		myState->typmod = attr->atttypmod;
+		myState->typlen = attr->attlen;
+		myState->slot_offset = i;
+	}
+
+	myState->rows = 0;
+}
+
+/*
+ * Receive a tuple from the executor and store it in schema variable.
+ */
+static bool
+svariableReceiveSlot(TupleTableSlot *slot, DestReceiver *self)
+{
+	svariableState *myState = (svariableState *) self;
+	Datum		value;
+	bool		isnull;
+	bool		freeval = false;
+
+	/* Make sure the tuple is fully deconstructed */
+	slot_getallattrs(slot);
+
+	value = slot->tts_values[myState->slot_offset];
+	isnull = slot->tts_isnull[myState->slot_offset];
+
+	if (myState->typlen == -1 && !isnull && VARATT_IS_EXTERNAL(DatumGetPointer(value)))
+	{
+		value = PointerGetDatum(detoast_external_attr((struct varlena *)
+													  DatumGetPointer(value)));
+		freeval = true;
+	}
+
+	SetSchemaVariable(myState->varid, value, isnull, myState->typid);
+
+	if (freeval)
+		pfree(DatumGetPointer(value));
+
+	return true;
+}
+
+/*
+ * Clean up at end of an executor run
+ */
+static void
+svariableShutdownReceiver(DestReceiver *self)
+{
+	/* Do nothing */
+}
+
+/*
+ * Destroy receiver when done with it
+ */
+static void
+svariableDestroyReceiver(DestReceiver *self)
+{
+	pfree(self);
+}
+
+/*
+ * Initially create a DestReceiver object.
+ */
+DestReceiver *
+CreateVariableDestReceiver(void)
+{
+	svariableState *self = (svariableState *) palloc0(sizeof(svariableState));
+
+	self->pub.receiveSlot = svariableReceiveSlot;
+	self->pub.rStartup = svariableStartupReceiver;
+	self->pub.rShutdown = svariableShutdownReceiver;
+	self->pub.rDestroy = svariableDestroyReceiver;
+	self->pub.mydest = DestVariable;
+
+	/* private fields will be set by SetVariableDestReceiverParams */
+
+	return (DestReceiver *) self;
+}
+
+/*
+ * Set parameters for a VariableDestReceiver
+ */
+void
+SetVariableDestReceiverParams(DestReceiver *self, Oid varid)
+{
+	svariableState *myState = (svariableState *) self;
+
+	Assert(myState->pub.mydest == DestVariable);
+	Assert(OidIsValid(varid));
+
+	myState->varid = varid;
+}
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 6d1181225e..4299809eb5 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -1073,6 +1073,12 @@ llvm_compile_expr(ExprState *state)
 				LLVMBuildBr(b, opblocks[opno + 1]);
 				break;
 
+			case EEOP_PARAM_VARIABLE:
+				build_EvalXFunc(b, mod, "ExecEvalParamVariable",
+								v_state, op, v_econtext);
+				LLVMBuildBr(b, opblocks[opno + 1]);
+				break;
+
 			case EEOP_PARAM_CALLBACK:
 				{
 					LLVMTypeRef v_functype;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 82464c9889..44e42c6f69 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -106,6 +106,7 @@ _copyPlannedStmt(const PlannedStmt *from)
 	COPY_NODE_FIELD(invalItems);
 	COPY_NODE_FIELD(paramExecTypes);
 	COPY_NODE_FIELD(utilityStmt);
+	COPY_NODE_FIELD(schemaVariables);
 	COPY_LOCATION_FIELD(stmt_location);
 	COPY_SCALAR_FIELD(stmt_len);
 
@@ -1506,6 +1507,7 @@ _copyParam(const Param *from)
 	COPY_SCALAR_FIELD(paramtype);
 	COPY_SCALAR_FIELD(paramtypmod);
 	COPY_SCALAR_FIELD(paramcollid);
+	COPY_SCALAR_FIELD(paramvarid);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
@@ -3162,6 +3164,7 @@ _copyQuery(const Query *from)
 	COPY_SCALAR_FIELD(canSetTag);
 	COPY_NODE_FIELD(utilityStmt);
 	COPY_SCALAR_FIELD(resultRelation);
+	COPY_SCALAR_FIELD(resultVariable);
 	COPY_SCALAR_FIELD(hasAggs);
 	COPY_SCALAR_FIELD(hasWindowFuncs);
 	COPY_SCALAR_FIELD(hasTargetSRFs);
@@ -3172,6 +3175,7 @@ _copyQuery(const Query *from)
 	COPY_SCALAR_FIELD(hasForUpdate);
 	COPY_SCALAR_FIELD(hasRowSecurity);
 	COPY_SCALAR_FIELD(isReturn);
+	COPY_SCALAR_FIELD(hasSchemaVariables);
 	COPY_NODE_FIELD(cteList);
 	COPY_NODE_FIELD(rtable);
 	COPY_NODE_FIELD(jointree);
@@ -3285,6 +3289,19 @@ _copySelectStmt(const SelectStmt *from)
 	return newnode;
 }
 
+static LetStmt *
+_copyLetStmt(const LetStmt * from)
+{
+	LetStmt    *newnode = makeNode(LetStmt);
+
+	COPY_NODE_FIELD(target);
+	COPY_NODE_FIELD(query);
+	COPY_SCALAR_FIELD(plpgsql_mode);
+	COPY_LOCATION_FIELD(location);
+
+	return newnode;
+}
+
 static SetOperationStmt *
 _copySetOperationStmt(const SetOperationStmt *from)
 {
@@ -4899,6 +4916,23 @@ _copyDropSubscriptionStmt(const DropSubscriptionStmt *from)
 	return newnode;
 }
 
+static CreateSchemaVarStmt *
+_copyCreateSchemaVarStmt(const CreateSchemaVarStmt *from)
+{
+	CreateSchemaVarStmt *newnode = makeNode(CreateSchemaVarStmt);
+
+	COPY_NODE_FIELD(variable);
+	COPY_NODE_FIELD(typeName);
+	COPY_NODE_FIELD(collClause);
+	COPY_NODE_FIELD(defexpr);
+	COPY_SCALAR_FIELD(eoxaction);
+	COPY_SCALAR_FIELD(if_not_exists);
+	COPY_SCALAR_FIELD(is_not_null);
+	COPY_SCALAR_FIELD(is_immutable);
+
+	return newnode;
+}
+
 /* ****************************************************************
  *					extensible.h copy functions
  * ****************************************************************
@@ -5402,6 +5436,9 @@ copyObjectImpl(const void *from)
 		case T_SelectStmt:
 			retval = _copySelectStmt(from);
 			break;
+		case T_LetStmt:
+			retval = _copyLetStmt(from);
+			break;
 		case T_SetOperationStmt:
 			retval = _copySetOperationStmt(from);
 			break;
@@ -5747,6 +5784,9 @@ copyObjectImpl(const void *from)
 		case T_DropSubscriptionStmt:
 			retval = _copyDropSubscriptionStmt(from);
 			break;
+		case  T_CreateSchemaVarStmt:
+			retval = _copyCreateSchemaVarStmt(from);
+			break;
 		case T_A_Expr:
 			retval = _copyA_Expr(from);
 			break;
@@ -5915,7 +5955,7 @@ copyObjectImpl(const void *from)
 			break;
 
 		default:
-			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
+			elog(ERROR, "urecognized node type: %d", (int) nodeTag(from));
 			retval = 0;			/* keep compiler quiet */
 			break;
 	}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index f537d3eb96..33bc273880 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -215,6 +215,7 @@ _equalParam(const Param *a, const Param *b)
 	COMPARE_SCALAR_FIELD(paramtype);
 	COMPARE_SCALAR_FIELD(paramtypmod);
 	COMPARE_SCALAR_FIELD(paramcollid);
+	COMPARE_SCALAR_FIELD(paramvarid);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
@@ -980,6 +981,7 @@ _equalQuery(const Query *a, const Query *b)
 	COMPARE_SCALAR_FIELD(canSetTag);
 	COMPARE_NODE_FIELD(utilityStmt);
 	COMPARE_SCALAR_FIELD(resultRelation);
+	COMPARE_SCALAR_FIELD(resultVariable);
 	COMPARE_SCALAR_FIELD(hasAggs);
 	COMPARE_SCALAR_FIELD(hasWindowFuncs);
 	COMPARE_SCALAR_FIELD(hasTargetSRFs);
@@ -990,6 +992,7 @@ _equalQuery(const Query *a, const Query *b)
 	COMPARE_SCALAR_FIELD(hasForUpdate);
 	COMPARE_SCALAR_FIELD(hasRowSecurity);
 	COMPARE_SCALAR_FIELD(isReturn);
+	COMPARE_SCALAR_FIELD(hasSchemaVariables);
 	COMPARE_NODE_FIELD(cteList);
 	COMPARE_NODE_FIELD(rtable);
 	COMPARE_NODE_FIELD(jointree);
@@ -1093,6 +1096,16 @@ _equalSelectStmt(const SelectStmt *a, const SelectStmt *b)
 	return true;
 }
 
+static bool
+_equalLetStmt(const LetStmt * a, const LetStmt * b)
+{
+	COMPARE_NODE_FIELD(target);
+	COMPARE_NODE_FIELD(query);
+	COMPARE_SCALAR_FIELD(plpgsql_mode);
+
+	return true;
+}
+
 static bool
 _equalSetOperationStmt(const SetOperationStmt *a, const SetOperationStmt *b)
 {
@@ -2377,6 +2390,22 @@ _equalDropSubscriptionStmt(const DropSubscriptionStmt *a,
 	return true;
 }
 
+static bool
+_equalCreateSchemaVarStmt(const CreateSchemaVarStmt *a,
+						  const CreateSchemaVarStmt *b)
+{
+	COMPARE_NODE_FIELD(variable);
+	COMPARE_NODE_FIELD(typeName);
+	COMPARE_NODE_FIELD(collClause);
+	COMPARE_NODE_FIELD(defexpr);
+	COMPARE_SCALAR_FIELD(eoxaction);
+	COMPARE_SCALAR_FIELD(if_not_exists);
+	COMPARE_SCALAR_FIELD(is_not_null);
+	COMPARE_SCALAR_FIELD(is_immutable);
+
+	return true;
+}
+
 static bool
 _equalCreatePolicyStmt(const CreatePolicyStmt *a, const CreatePolicyStmt *b)
 {
@@ -3408,6 +3437,9 @@ equal(const void *a, const void *b)
 		case T_SelectStmt:
 			retval = _equalSelectStmt(a, b);
 			break;
+		case T_LetStmt:
+			retval = _equalLetStmt(a, b);
+			break;
 		case T_SetOperationStmt:
 			retval = _equalSetOperationStmt(a, b);
 			break;
@@ -3753,6 +3785,9 @@ equal(const void *a, const void *b)
 		case T_DropSubscriptionStmt:
 			retval = _equalDropSubscriptionStmt(a, b);
 			break;
+		case T_CreateSchemaVarStmt:
+			retval = _equalCreateSchemaVarStmt(a, b);
+			break;
 		case T_A_Expr:
 			retval = _equalA_Expr(a, b);
 			break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 2e5ed77e18..20f06beeae 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -324,6 +324,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
 	WRITE_NODE_FIELD(invalItems);
 	WRITE_NODE_FIELD(paramExecTypes);
 	WRITE_NODE_FIELD(utilityStmt);
+	WRITE_NODE_FIELD(schemaVariables);
 	WRITE_LOCATION_FIELD(stmt_location);
 	WRITE_INT_FIELD(stmt_len);
 }
@@ -1164,6 +1165,7 @@ _outParam(StringInfo str, const Param *node)
 	WRITE_OID_FIELD(paramtype);
 	WRITE_INT_FIELD(paramtypmod);
 	WRITE_OID_FIELD(paramcollid);
+	WRITE_OID_FIELD(paramvarid);
 	WRITE_LOCATION_FIELD(location);
 }
 
@@ -2276,6 +2278,7 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node)
 	WRITE_NODE_FIELD(relationOids);
 	WRITE_NODE_FIELD(invalItems);
 	WRITE_NODE_FIELD(paramExecTypes);
+	WRITE_NODE_FIELD(schemaVariables);
 	WRITE_UINT_FIELD(lastPHId);
 	WRITE_UINT_FIELD(lastRowMarkId);
 	WRITE_INT_FIELD(lastPlanNodeId);
@@ -2336,6 +2339,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
 	WRITE_BOOL_FIELD(hasPseudoConstantQuals);
 	WRITE_BOOL_FIELD(hasAlternativeSubPlans);
 	WRITE_BOOL_FIELD(hasRecursion);
+	WRITE_BOOL_FIELD(hasSchemaVariables);
 	WRITE_INT_FIELD(wt_param_id);
 	WRITE_BITMAPSET_FIELD(curOuterRels);
 	WRITE_NODE_FIELD(curOuterParams);
@@ -2870,6 +2874,17 @@ _outPLAssignStmt(StringInfo str, const PLAssignStmt *node)
 	WRITE_LOCATION_FIELD(location);
 }
 
+static void
+_outLetStmt(StringInfo str, const LetStmt * node)
+{
+	WRITE_NODE_TYPE("LET");
+
+	WRITE_NODE_FIELD(target);
+	WRITE_NODE_FIELD(query);
+	WRITE_BOOL_FIELD(plpgsql_mode);
+	WRITE_LOCATION_FIELD(location);
+}
+
 static void
 _outFuncCall(StringInfo str, const FuncCall *node)
 {
@@ -3050,6 +3065,7 @@ _outQuery(StringInfo str, const Query *node)
 			case T_IndexStmt:
 			case T_NotifyStmt:
 			case T_DeclareCursorStmt:
+			case T_LetStmt:
 				WRITE_NODE_FIELD(utilityStmt);
 				break;
 			default:
@@ -3061,6 +3077,7 @@ _outQuery(StringInfo str, const Query *node)
 		appendStringInfoString(str, " :utilityStmt <>");
 
 	WRITE_INT_FIELD(resultRelation);
+	WRITE_OID_FIELD(resultVariable);
 	WRITE_BOOL_FIELD(hasAggs);
 	WRITE_BOOL_FIELD(hasWindowFuncs);
 	WRITE_BOOL_FIELD(hasTargetSRFs);
@@ -3071,6 +3088,7 @@ _outQuery(StringInfo str, const Query *node)
 	WRITE_BOOL_FIELD(hasForUpdate);
 	WRITE_BOOL_FIELD(hasRowSecurity);
 	WRITE_BOOL_FIELD(isReturn);
+	WRITE_BOOL_FIELD(hasSchemaVariables);
 	WRITE_NODE_FIELD(cteList);
 	WRITE_NODE_FIELD(rtable);
 	WRITE_NODE_FIELD(jointree);
@@ -4371,6 +4389,9 @@ outNode(StringInfo str, const void *obj)
 			case T_PLAssignStmt:
 				_outPLAssignStmt(str, obj);
 				break;
+			case T_LetStmt:
+				_outLetStmt(str, obj);
+				break;
 			case T_ColumnDef:
 				_outColumnDef(str, obj);
 				break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index abf08b7a2f..ce58599c20 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -254,6 +254,7 @@ _readQuery(void)
 	READ_BOOL_FIELD(canSetTag);
 	READ_NODE_FIELD(utilityStmt);
 	READ_INT_FIELD(resultRelation);
+	READ_OID_FIELD(resultVariable);
 	READ_BOOL_FIELD(hasAggs);
 	READ_BOOL_FIELD(hasWindowFuncs);
 	READ_BOOL_FIELD(hasTargetSRFs);
@@ -264,6 +265,7 @@ _readQuery(void)
 	READ_BOOL_FIELD(hasForUpdate);
 	READ_BOOL_FIELD(hasRowSecurity);
 	READ_BOOL_FIELD(isReturn);
+	READ_BOOL_FIELD(hasSchemaVariables);
 	READ_NODE_FIELD(cteList);
 	READ_NODE_FIELD(rtable);
 	READ_NODE_FIELD(jointree);
@@ -628,6 +630,7 @@ _readParam(void)
 	READ_OID_FIELD(paramtype);
 	READ_INT_FIELD(paramtypmod);
 	READ_OID_FIELD(paramcollid);
+	READ_OID_FIELD(paramvarid);
 	READ_LOCATION_FIELD(location);
 
 	READ_DONE();
@@ -1599,6 +1602,7 @@ _readPlannedStmt(void)
 	READ_NODE_FIELD(invalItems);
 	READ_NODE_FIELD(paramExecTypes);
 	READ_NODE_FIELD(utilityStmt);
+	READ_NODE_FIELD(schemaVariables);
 	READ_LOCATION_FIELD(stmt_location);
 	READ_INT_FIELD(stmt_len);
 
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index bd01ec0526..b93e7dd5a0 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -316,6 +316,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 	glob->lastPlanNodeId = 0;
 	glob->transientPlan = false;
 	glob->dependsOnRole = false;
+	glob->schemaVariables = NIL;
 
 	/*
 	 * Assess whether it's feasible to use parallel mode for this query. We
@@ -529,6 +530,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 	result->paramExecTypes = glob->paramExecTypes;
 	/* utilityStmt should be null, but we might as well copy it */
 	result->utilityStmt = parse->utilityStmt;
+	result->schemaVariables = glob->schemaVariables;
 	result->stmt_location = parse->stmt_location;
 	result->stmt_len = parse->stmt_len;
 
@@ -678,6 +680,12 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
 	 */
 	pull_up_subqueries(root);
 
+	/*
+	 * Check if some subquery uses schema variable. Flag hasSchemaVariables
+	 * should be true if query or some subquery uses any schema variable.
+	 */
+	pull_up_has_schema_variables(root);
+
 	/*
 	 * If this is a simple UNION ALL query, flatten it into an appendrel. We
 	 * do this now because it requires applying pull_up_subqueries to the leaf
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 6ccec759bd..91717cd4e1 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -172,7 +172,8 @@ static List *set_returning_clause_references(PlannerInfo *root,
 											 Plan *topplan,
 											 Index resultRelation,
 											 int rtoffset);
-
+static bool pull_up_has_schema_variables_walker(Node *node,
+											   PlannerInfo *root);
 
 /*****************************************************************************
  *
@@ -1127,6 +1128,50 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 	return plan;
 }
 
+/*
+ * Search usage of schema variables in subqueries
+ */
+void
+pull_up_has_schema_variables(PlannerInfo *root)
+{
+	Query	   *query = root->parse;
+
+	if (query->hasSchemaVariables)
+	{
+		root->hasSchemaVariables = true;
+	}
+	else
+	{
+		(void) query_tree_walker(query,
+								 pull_up_has_schema_variables_walker,
+								 (void *) root, 0);
+	}
+}
+
+static bool
+pull_up_has_schema_variables_walker(Node *node, PlannerInfo *root)
+{
+	if (node == NULL)
+		return false;
+	if (IsA(node, Query))
+	{
+		Query	   *query = (Query *) node;
+
+		if (query->hasSchemaVariables)
+		{
+			root->hasSchemaVariables = true;
+			return false;
+		}
+
+		/* Recurse into subselects */
+		return query_tree_walker((Query *) node,
+								 pull_up_has_schema_variables_walker,
+								 (void *) root, 0);
+	}
+	return expression_tree_walker(node, pull_up_has_schema_variables_walker,
+								  (void *) root);
+}
+
 /*
  * set_indexonlyscan_references
  *		Do set_plan_references processing on an IndexOnlyScan
@@ -1758,10 +1803,14 @@ fix_expr_common(PlannerInfo *root, Node *node)
 /*
  * fix_param_node
  *		Do set_plan_references processing on a Param
+ *		Collect schema variables list and replace variable oid by
+ *		index to collected list.
  *
  * If it's a PARAM_MULTIEXPR, replace it with the appropriate Param from
  * root->multiexpr_params; otherwise no change is needed.
  * Just for paranoia's sake, we make a copy of the node in either case.
+ *
+ * If it's a PARAM_VARIABLE, then we should to calculate paramid.
  */
 static Node *
 fix_param_node(PlannerInfo *root, Param *p)
@@ -1780,6 +1829,52 @@ fix_param_node(PlannerInfo *root, Param *p)
 			elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid);
 		return copyObject(list_nth(params, colno - 1));
 	}
+
+	if (p->paramkind == PARAM_VARIABLE)
+	{
+		ListCell   *lc;
+		int			n = 0;
+		bool		found = false;
+
+		/* We will modify object */
+		p = (Param *) copyObject(p);
+
+		/*
+		 * Now, we can actualize list of schema variables, and we can complete
+		 * paramid parameter.
+		 */
+		foreach(lc, root->glob->schemaVariables)
+		{
+			if (lfirst_oid(lc) == p->paramvarid)
+			{
+				p->paramid = n;
+				found = true;
+				break;
+			}
+			n += 1;
+		}
+
+		if (!found)
+		{
+			PlanInvalItem *inval_item = makeNode(PlanInvalItem);
+
+			/* paramid is still schema variable id */
+			inval_item->cacheId = VARIABLEOID;
+			inval_item->hashValue = GetSysCacheHashValue1(VARIABLEOID,
+														  ObjectIdGetDatum(p->paramvarid));
+
+			/* Append this variable to global, register dependency */
+			root->glob->invalItems = lappend(root->glob->invalItems,
+											 inval_item);
+			root->glob->schemaVariables = lappend_oid(root->glob->schemaVariables,
+													  p->paramvarid);
+
+			p->paramid = n;
+		}
+
+		return (Node *) p;
+	}
+
 	return (Node *) copyObject(p);
 }
 
@@ -1841,7 +1936,9 @@ fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan,
  * replacing Aggref nodes that should be replaced by initplan output Params,
  * choosing the best implementation for AlternativeSubPlans,
  * looking up operator opcode info for OpExpr and related nodes,
- * and adding OIDs from regclass Const nodes into root->glob->relationOids.
+ * and adding OIDs from regclass Const nodes into root->glob->relationOids,
+ * and replacing PARAM_VARIABLE paramid, that is oid of schema variable
+ * to offset to array of by query used schema variables.
  *
  * 'node': the expression to be modified
  * 'rtoffset': how much to increment varnos by
@@ -1863,7 +1960,8 @@ fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset, double num_exec)
 		root->multiexpr_params != NIL ||
 		root->glob->lastPHId != 0 ||
 		root->minmax_aggs != NIL ||
-		root->hasAlternativeSubPlans)
+		root->hasAlternativeSubPlans ||
+		root->hasSchemaVariables)
 	{
 		return fix_scan_expr_mutator(node, &context);
 	}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 109f93d109..b18528ffbc 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -26,6 +26,7 @@
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "commands/schema_variable.h"
 #include "executor/executor.h"
 #include "executor/functions.h"
 #include "funcapi.h"
@@ -818,7 +819,8 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
 	{
 		Param	   *param = (Param *) node;
 
-		if (param->paramkind == PARAM_EXTERN)
+		if (param->paramkind == PARAM_EXTERN ||
+			param->paramkind == PARAM_VARIABLE)
 			return false;
 
 		if (param->paramkind != PARAM_EXEC ||
@@ -2228,6 +2230,7 @@ convert_saop_to_hashed_saop_walker(Node *node, void *context)
  *	  value of the Param.
  * 2. Fold stable, as well as immutable, functions to constants.
  * 3. Reduce PlaceHolderVar nodes to their contained expressions.
+ * 4. Current value of schema variable can be used for estimation too.
  *--------------------
  */
 Node *
@@ -2350,6 +2353,30 @@ eval_const_expressions_mutator(Node *node,
 						}
 					}
 				}
+				else if (param->paramkind == PARAM_VARIABLE &&
+						 context->estimate)
+				{
+					int16		typLen;
+					bool		typByVal;
+					Datum		pval;
+					bool		isnull;
+
+					get_typlenbyval(param->paramtype,
+									&typLen, &typByVal);
+
+					pval = GetSchemaVariable(param->paramvarid,
+											 &isnull,
+											 param->paramtype,
+											 true);
+
+					return (Node *) makeConst(param->paramtype,
+											  param->paramtypmod,
+											  param->paramcollid,
+											  (int) typLen,
+											  pval,
+											  isnull,
+											  typByVal);
+				}
 
 				/*
 				 * Not replaceable, so just copy the Param (no need to
@@ -4734,7 +4761,7 @@ substitute_actual_parameters_mutator(Node *node,
 {
 	if (node == NULL)
 		return NULL;
-	if (IsA(node, Param))
+	if (IsA(node, Param) &&((Param *) node)->paramkind != PARAM_VARIABLE)
 	{
 		Param	   *param = (Param *) node;
 
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 146ee8dd1e..8971cf7e80 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -25,8 +25,11 @@
 #include "postgres.h"
 
 #include "access/sysattr.h"
+#include "catalog/namespace.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_variable.h"
+#include "commands/schema_variable.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
@@ -50,6 +53,7 @@
 #include "utils/builtins.h"
 #include "utils/guc.h"
 #include "utils/queryjumble.h"
+#include "utils/lsyscache.h"
 #include "utils/rel.h"
 #include "utils/syscache.h"
 
@@ -88,6 +92,8 @@ static Query *transformCreateTableAsStmt(ParseState *pstate,
 										 CreateTableAsStmt *stmt);
 static Query *transformCallStmt(ParseState *pstate,
 								CallStmt *stmt);
+static Query *transformLetStmt(ParseState *pstate,
+							   LetStmt * stmt);
 static void transformLockingClause(ParseState *pstate, Query *qry,
 								   LockingClause *lc, bool pushedDown);
 #ifdef RAW_EXPRESSION_COVERAGE_TEST
@@ -289,6 +295,7 @@ transformStmt(ParseState *pstate, Node *parseTree)
 		case T_InsertStmt:
 		case T_UpdateStmt:
 		case T_DeleteStmt:
+		case T_LetStmt:
 			(void) test_raw_expression_coverage(parseTree, NULL);
 			break;
 		default:
@@ -358,6 +365,11 @@ transformStmt(ParseState *pstate, Node *parseTree)
 									   (CallStmt *) parseTree);
 			break;
 
+		case T_LetStmt:
+			result = transformLetStmt(pstate,
+									  (LetStmt *) parseTree);
+			break;
+
 		default:
 
 			/*
@@ -399,6 +411,7 @@ analyze_requires_snapshot(RawStmt *parseTree)
 		case T_UpdateStmt:
 		case T_SelectStmt:
 		case T_PLAssignStmt:
+		case T_LetStmt:
 			result = true;
 			break;
 
@@ -482,6 +495,8 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
 	qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
 	qry->hasAggs = pstate->p_hasAggs;
 
+	qry->hasSchemaVariables = pstate->p_hasSchemaVariables;
+
 	assign_query_collations(pstate, qry);
 
 	/* this must be done after collations, for reliable comparison of exprs */
@@ -899,6 +914,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
 
 	qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
 	qry->hasSubLinks = pstate->p_hasSubLinks;
+	qry->hasSchemaVariables = pstate->p_hasSchemaVariables;
 
 	assign_query_collations(pstate, qry);
 
@@ -1241,6 +1257,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 	Query	   *qry = makeNode(Query);
 	Node	   *qual;
 	ListCell   *l;
+	ParseExprKind		target_exprkind;
 
 	qry->commandType = CMD_SELECT;
 
@@ -1269,9 +1286,19 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 	/* process the FROM clause */
 	transformFromClause(pstate, stmt->fromClause);
 
-	/* transform targetlist */
-	qry->targetList = transformTargetList(pstate, stmt->targetList,
-										  EXPR_KIND_SELECT_TARGET);
+	/*
+	 * Transform targetlist. Second usage of this transformation
+	 * is for Let statement. In this case we would to allow DEFAULT
+	 * keyword - we specify EXPR_KIND_LET_TARGET.
+	 */
+	target_exprkind =
+		(pstate->p_expr_kind != EXPR_KIND_LET_TARGET ||
+		 pstate->parentParseState != NULL) ?
+					EXPR_KIND_SELECT_TARGET : EXPR_KIND_LET_TARGET;
+
+	qry->targetList = transformTargetList(pstate,
+										  stmt->targetList,
+										  target_exprkind);
 
 	/* mark column origins */
 	markTargetListOrigins(pstate, qry->targetList);
@@ -1361,6 +1388,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 							   (LockingClause *) lfirst(l), false);
 	}
 
+	qry->hasSchemaVariables = pstate->p_hasSchemaVariables;
+
 	assign_query_collations(pstate, qry);
 
 	/* this must be done after collations, for reliable comparison of exprs */
@@ -1585,12 +1614,261 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
 	qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
 
 	qry->hasSubLinks = pstate->p_hasSubLinks;
+	qry->hasSchemaVariables = pstate->p_hasSchemaVariables;
 
 	assign_query_collations(pstate, qry);
 
 	return qry;
 }
 
+/*
+ * transformLetStmt -
+ *	  transform an Let Statement
+ */
+static Query *
+transformLetStmt(ParseState *pstate, LetStmt * stmt)
+{
+	Query	   *query;
+	Query	   *result;
+	List	   *exprList = NIL;
+	List	   *exprListCoer = NIL;
+	List	   *indirection = NIL;
+	ListCell   *lc;
+	Query	   *selectQuery;
+	int			i = 0;
+	Oid			varid;
+	ParseExprKind sv_expr_kind;
+	char	   *attrname = NULL;
+	bool		not_unique;
+	bool		is_rowtype;
+	bool		to_default = false;
+	Oid			typid;
+	int32		typmod;
+	Oid			collid;
+	AclResult	aclresult;
+	List	   *names = NULL;
+	int			indirection_start;
+
+	sv_expr_kind = pstate->p_expr_kind;
+	pstate->p_expr_kind = EXPR_KIND_LET_TARGET;
+
+	/* There can't be any outer WITH to worry about */
+	Assert(pstate->p_ctenamespace == NIL);
+
+	names = NamesFromList(stmt->target);
+
+	varid = IdentifyVariable(names, &attrname, &not_unique);
+	if (not_unique)
+		ereport(ERROR,
+				(errcode(ERRCODE_AMBIGUOUS_PARAMETER),
+				 errmsg("target \"%s\" of LET command is ambiguous",
+						NameListToString(names)),
+				 parser_errposition(pstate, stmt->location)));
+
+	if (!OidIsValid(varid))
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("schema variable \"%s\" doesn't exists",
+						NameListToString(names)),
+				 parser_errposition(pstate, stmt->location)));
+
+	indirection_start = list_length(names) - (attrname ? 1 : 0);
+	indirection = list_copy_tail(stmt->target, indirection_start);
+
+	get_schema_variable_type_typmod_collid(varid, &typid, &typmod, &collid);
+
+	is_rowtype = type_is_rowtype(typid);
+
+	if (attrname && !is_rowtype)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("target variable \"%s\" is not row type",
+						schema_variable_get_name(varid)),
+				 parser_errposition(pstate, stmt->location)));
+
+	aclresult = pg_variable_aclcheck(varid, GetUserId(), ACL_WRITE);
+	if (aclresult != ACLCHECK_OK)
+		aclcheck_error(aclresult, OBJECT_VARIABLE, NameListToString(names));
+
+	selectQuery = transformStmt(pstate, stmt->query);
+
+	/* The grammar should have produced a SELECT */
+	if (!IsA(selectQuery, Query) ||
+		selectQuery->commandType != CMD_SELECT)
+		elog(ERROR, "unexpected non-SELECT command in LET command");
+
+	/*----------
+	 * Generate an expression list for the LET that selects all the
+	 * non-resjunk columns from the subquery.
+	 *----------
+	 */
+	exprList = NIL;
+	foreach(lc, selectQuery->targetList)
+	{
+		TargetEntry *tle = (TargetEntry *) lfirst(lc);
+
+		if (tle->resjunk)
+			continue;
+
+		if (IsA(tle->expr, SetToDefault))
+			to_default = true;
+
+		exprList = lappend(exprList, tle->expr);
+	}
+
+	/*
+	 * Because doesn't support pattern matching, don't allow multicolumn
+	 * result
+	 */
+	if (list_length(exprList) != 1)
+		ereport(ERROR,
+				(errcode(ERRCODE_SYNTAX_ERROR),
+				 errmsg("expression is not scalar value"),
+				 parser_errposition(pstate,
+									exprLocation((Node *) exprList))));
+
+	if (to_default && attrname != NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("only complete variable can be set to default"),
+				 parser_errposition(pstate, stmt->location)));
+
+	exprListCoer = NIL;
+
+	foreach(lc, exprList)
+	{
+		Expr	   *expr = (Expr *) lfirst(lc);
+		Expr	   *coerced_expr;
+		Param	   *param;
+		Oid			exprtypid;
+
+		if (IsA(expr, SetToDefault))
+		{
+			SetToDefault *def = (SetToDefault *) expr;
+
+			def->typeId = typid;
+			def->typeMod = typmod;
+			def->collation = collid;
+		}
+		else if (IsA(expr, Const) && ((Const *) expr)->constisnull)
+		{
+			/* use known type for NULL value */
+			expr = (Expr *) makeNullConst(typid, typmod, collid);
+		}
+
+		/* now we can read type of expression */
+		exprtypid = exprType((Node *) expr);
+
+		param = makeNode(Param);
+		param->paramkind = PARAM_VARIABLE;
+		param->paramvarid = varid;
+		param->paramtype = typid;
+		param->paramtypmod = typmod;
+
+		if (indirection != NULL)
+		{
+			bool		targetIsArray;
+			char	   *targetName;
+
+			targetName = attrname != NULL ? attrname : get_schema_variable_name(varid);
+			targetIsArray = OidIsValid(get_element_type(typid));
+
+			pstate->p_hasSchemaVariables = true;
+
+			coerced_expr = (Expr *)
+				transformAssignmentIndirection(pstate,
+											   (Node *) param,
+											   targetName,
+											   targetIsArray,
+											   typid,
+											   typmod,
+											   InvalidOid,
+											   indirection,
+											   list_head(indirection),
+											   (Node *) expr,
+											   COERCION_PLPGSQL,
+											   stmt->location);
+		}
+		else
+			coerced_expr = (Expr *)
+				coerce_to_target_type(pstate,
+									  (Node *) expr,
+									  exprtypid,
+									  typid, typmod,
+									  COERCION_ASSIGNMENT,
+									  COERCE_IMPLICIT_CAST,
+									  stmt->location);
+
+		if (coerced_expr == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_DATATYPE_MISMATCH),
+					 errmsg("variable \"%s\" is of type %s,"
+							" but expression is of type %s",
+							schema_variable_get_name(varid),
+							format_type_be(typid),
+							format_type_be(exprtypid)),
+					 errhint("You will need to rewrite or cast the expression."),
+					 parser_errposition(pstate, exprLocation((Node *) expr))));
+
+		exprListCoer = lappend(exprListCoer, coerced_expr);
+	}
+
+	/*
+	 * Generate query's target list using the computed list of expressions.
+	 */
+	query = makeNode(Query);
+	query->commandType = CMD_SELECT;
+
+	foreach(lc, exprListCoer)
+	{
+		Expr	   *expr = (Expr *) lfirst(lc);
+		TargetEntry *tle;
+
+		tle = makeTargetEntry(expr,
+							  i + 1,
+							  FigureColname((Node *) expr),
+							  false);
+		query->targetList = lappend(query->targetList, tle);
+	}
+
+	/* done building the range table and jointree */
+	query->rtable = pstate->p_rtable;
+	query->jointree = makeFromExpr(pstate->p_joinlist, NULL);
+
+	query->hasTargetSRFs = pstate->p_hasTargetSRFs;
+	query->hasSubLinks = pstate->p_hasSubLinks;
+	query->hasSchemaVariables = pstate->p_hasSchemaVariables;
+
+	/* This is top query */
+	query->canSetTag = true;
+
+	/*
+	 * rewrite SetToDefaults needs varid in Query structure
+	 */
+	query->resultVariable = varid;
+
+	assign_query_collations(pstate, query);
+
+	pstate->p_expr_kind = sv_expr_kind;
+
+	stmt->query = (Node *) query;
+
+	/*
+	 * When statement is executed as an expression as PLpgSQL LET
+	 * statement, then we should to return query. We should not
+	 * to use an utility wrapper node.
+	 */
+	if (stmt->plpgsql_mode)
+		return query;
+
+	/* represent the command as a utility Query */
+	result = makeNode(Query);
+	result->commandType = CMD_UTILITY;
+	result->utilityStmt = (Node *) stmt;
+
+	return result;
+}
+
 /*
  * transformSetOperationStmt -
  *	  transforms a set-operations tree
@@ -1841,6 +2119,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 							   (LockingClause *) lfirst(l), false);
 	}
 
+	qry->hasSchemaVariables = pstate->p_hasSchemaVariables;
+
 	assign_query_collations(pstate, qry);
 
 	/* this must be done after collations, for reliable comparison of exprs */
@@ -2369,6 +2649,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
 
 	qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
 	qry->hasSubLinks = pstate->p_hasSubLinks;
+	qry->hasSchemaVariables = pstate->p_hasSchemaVariables;
 
 	assign_query_collations(pstate, qry);
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index d0eb80e69c..fb5391d173 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -231,6 +231,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	JoinType			jtype;
 	DropBehavior		dbehavior;
 	OnCommitAction		oncommit;
+	VariableEOXAction	oneoxaction;
 	List				*list;
 	Node				*node;
 	ObjectType			objtype;
@@ -281,8 +282,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 		ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
 		CreateDomainStmt CreateExtensionStmt CreateGroupStmt CreateOpClassStmt
 		CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
-		CreateSchemaStmt CreateSeqStmt CreateStmt CreateStatsStmt CreateTableSpaceStmt
-		CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt
+		CreateSchemaStmt CreateSchemaVarStmt CreateSeqStmt CreateStmt CreateStatsStmt
+		CreateTableSpaceStmt CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt
 		CreateAssertionStmt CreateTransformStmt CreateTrigStmt CreateEventTrigStmt
 		CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatePolicyStmt
 		CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
@@ -292,7 +293,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 		DropTransformStmt
 		DropUserMappingStmt ExplainStmt FetchStmt
 		GrantStmt GrantRoleStmt ImportForeignSchemaStmt IndexStmt InsertStmt
-		ListenStmt LoadStmt LockStmt NotifyStmt ExplainableStmt PreparableStmt
+		LetStmt ListenStmt LoadStmt LockStmt NotifyStmt ExplainableStmt PreparableStmt
 		CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
 		RemoveFuncStmt RemoveOperStmt RenameStmt ReturnStmt RevokeStmt RevokeRoleStmt
 		RuleActionStmt RuleActionStmtOrEmpty RuleStmt
@@ -432,6 +433,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 				TriggerTransitions TriggerReferencing
 				vacuum_relation_list opt_vacuum_relation_list
 				drop_option_list pub_obj_list
+				let_target
 
 %type <node>	opt_routine_body
 %type <groupclause> group_clause
@@ -454,6 +456,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <ival>	 OptTemp
 %type <ival>	 OptNoLog
 %type <oncommit> OnCommitOption
+%type <oneoxaction> OnEOXActionOption
 
 %type <ival>	for_locking_strength
 %type <node>	for_locking_item
@@ -615,6 +618,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <partboundspec> PartitionBoundSpec
 %type <list>		hash_partbound
 %type <defelt>		hash_partbound_elem
+%type <node>		OptSchemaVarDefExpr
+%type <boolean>		OptNotNull OptImmutable
 
 
 /*
@@ -684,7 +689,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	KEY
 
 	LABEL LANGUAGE LARGE_P LAST_P LATERAL_P
-	LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL
+	LEADING LEAKPROOF LEAST LEFT LET LEVEL LIKE LIMIT LISTEN LOAD LOCAL
 	LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED
 
 	MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE
@@ -723,8 +728,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	UESCAPE UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN
 	UNLISTEN UNLOGGED UNTIL UPDATE USER USING
 
-	VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
-	VERBOSE VERSION_P VIEW VIEWS VOLATILE
+	VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIABLE VARIABLES
+	VARIADIC VARYING VERBOSE VERSION_P VIEW VIEWS VOLATILE
 
 	WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE
 
@@ -759,6 +764,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %token		MODE_PLPGSQL_ASSIGN1
 %token		MODE_PLPGSQL_ASSIGN2
 %token		MODE_PLPGSQL_ASSIGN3
+%token		MODE_PLPGSQL_LET
 
 
 /* Precedence: lowest to highest */
@@ -864,6 +870,13 @@ parse_toplevel:
 				pg_yyget_extra(yyscanner)->parsetree =
 					list_make1(makeRawStmt((Node *) n, 0));
 			}
+			| MODE_PLPGSQL_LET LetStmt
+			{
+				LetStmt *n = (LetStmt *) $2;
+				n->plpgsql_mode = true;
+				pg_yyget_extra(yyscanner)->parsetree =
+					list_make1(makeRawStmt((Node *) n, 0));
+			}
 		;
 
 /*
@@ -967,6 +980,7 @@ stmt:
 			| CreatePolicyStmt
 			| CreatePLangStmt
 			| CreateSchemaStmt
+			| CreateSchemaVarStmt
 			| CreateSeqStmt
 			| CreateStmt
 			| CreateSubscriptionStmt
@@ -1004,6 +1018,7 @@ stmt:
 			| ImportForeignSchemaStmt
 			| IndexStmt
 			| InsertStmt
+			| LetStmt
 			| ListenStmt
 			| RefreshMatViewStmt
 			| LoadStmt
@@ -1896,7 +1911,12 @@ DiscardStmt:
 					n->target = DISCARD_SEQUENCES;
 					$$ = (Node *) n;
 				}
-
+			| DISCARD VARIABLES
+				{
+					DiscardStmt *n = makeNode(DiscardStmt);
+					n->target = DISCARD_VARIABLES;
+					$$ = (Node *) n;
+				}
 		;
 
 
@@ -4655,6 +4675,61 @@ create_extension_opt_item:
 				}
 		;
 
+/*****************************************************************************
+ *
+ *		QUERY :
+ *				CREATE VARIABLE varname [AS] type
+ *
+ *****************************************************************************/
+
+CreateSchemaVarStmt:
+			CREATE OptTemp OptImmutable VARIABLE qualified_name opt_as Typename opt_collate_clause OptNotNull OptSchemaVarDefExpr OnEOXActionOption
+				{
+					CreateSchemaVarStmt *n = makeNode(CreateSchemaVarStmt);
+					$5->relpersistence = $2;
+					n->is_immutable = $3;
+					n->variable = $5;
+					n->typeName = $7;
+					n->collClause = (CollateClause *) $8;
+					n->is_not_null = $9;
+					n->defexpr = $10;
+					n->eoxaction = $11;
+					n->if_not_exists = false;
+					$$ = (Node *) n;
+				}
+			| CREATE OptTemp OptImmutable VARIABLE IF_P NOT EXISTS qualified_name opt_as Typename opt_collate_clause OptNotNull OptSchemaVarDefExpr OnEOXActionOption
+				{
+					CreateSchemaVarStmt *n = makeNode(CreateSchemaVarStmt);
+					$8->relpersistence = $2;
+					n->is_immutable = $3;
+					n->variable = $8;
+					n->typeName = $10;
+					n->collClause = (CollateClause *) $11;
+					n->is_not_null = $12;
+					n->defexpr = $13;
+					n->eoxaction = $14;
+					n->if_not_exists = true;
+					$$ = (Node *) n;
+				}
+		;
+
+OptSchemaVarDefExpr: DEFAULT b_expr					{ $$ = $2; }
+			| /* EMPTY */							{ $$ = NULL; }
+		;
+
+OnEOXActionOption:  ON COMMIT DROP					{ $$ = VARIABLE_EOX_DROP; }
+			| ON TRANSACTION END_P RESET			{ $$ = VARIABLE_EOX_RESET; }
+			| /*EMPTY*/								{ $$ = VARIABLE_EOX_NOOP; }
+		;
+
+OptNotNull: NOT NULL_P								{ $$ = true; }
+			| /* EMPTY */							{ $$ = false; }
+		;
+
+OptImmutable: IMMUTABLE								{ $$ = true; }
+			| /* EMPTY */							{ $$ = false; }
+		;
+
 /*****************************************************************************
  *
  * ALTER EXTENSION name UPDATE [ TO version ]
@@ -6342,6 +6417,7 @@ object_type_any_name:
 			| TEXT_P SEARCH DICTIONARY				{ $$ = OBJECT_TSDICTIONARY; }
 			| TEXT_P SEARCH TEMPLATE				{ $$ = OBJECT_TSTEMPLATE; }
 			| TEXT_P SEARCH CONFIGURATION			{ $$ = OBJECT_TSCONFIGURATION; }
+			| VARIABLE								{ $$ = OBJECT_VARIABLE; }
 		;
 
 /*
@@ -7110,6 +7186,14 @@ privilege_target:
 					n->objs = $2;
 					$$ = n;
 				}
+			| VARIABLE qualified_name_list
+				{
+					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+					n->targtype = ACL_TARGET_OBJECT;
+					n->objtype = OBJECT_VARIABLE;
+					n->objs = $2;
+					$$ = n;
+				}
 			| ALL TABLES IN_P SCHEMA name_list
 				{
 					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
@@ -7150,6 +7234,14 @@ privilege_target:
 					n->objs = $5;
 					$$ = n;
 				}
+			| ALL VARIABLES IN_P SCHEMA name_list
+				{
+					PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+					n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
+					n->objtype = OBJECT_VARIABLE;
+					n->objs = $5;
+					$$ = n;
+				}
 		;
 
 
@@ -7310,6 +7402,7 @@ defacl_privilege_target:
 			| SEQUENCES		{ $$ = OBJECT_SEQUENCE; }
 			| TYPES_P		{ $$ = OBJECT_TYPE; }
 			| SCHEMAS		{ $$ = OBJECT_SCHEMA; }
+			| VARIABLES		{ $$ = OBJECT_VARIABLE; }
 		;
 
 
@@ -9012,6 +9105,25 @@ RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
+			| ALTER VARIABLE any_name RENAME TO name
+				{
+					RenameStmt *n = makeNode(RenameStmt);
+					n->renameType = OBJECT_VARIABLE;
+					n->object = (Node *) $3;
+					n->newname = $6;
+					n->missing_ok = false;
+					$$ = (Node *)n;
+				}
+			| ALTER VARIABLE IF_P EXISTS any_name RENAME TO name
+				{
+					RenameStmt *n = makeNode(RenameStmt);
+					n->renameType = OBJECT_VARIABLE;
+					n->object = (Node *) $5;
+					n->newname = $8;
+					n->missing_ok = true;
+					$$ = (Node *)n;
+				}
+
 		;
 
 opt_column: COLUMN
@@ -9340,6 +9452,25 @@ AlterObjectSchemaStmt:
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
+			| ALTER VARIABLE any_name SET SCHEMA name
+				{
+					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+					n->objectType = OBJECT_VARIABLE;
+					n->object = (Node *) $3;
+					n->newschema = $6;
+					n->missing_ok = false;
+					$$ = (Node *)n;
+				}
+			| ALTER VARIABLE IF_P EXISTS any_name SET SCHEMA name
+				{
+					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+					n->objectType = OBJECT_VARIABLE;
+					n->object = (Node *) $5;
+					n->newschema = $8;
+					n->missing_ok = true;
+					$$ = (Node *)n;
+				}
+
 		;
 
 /*****************************************************************************
@@ -9593,6 +9724,14 @@ AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec
 					n->newowner = $6;
 					$$ = (Node *)n;
 				}
+			| ALTER VARIABLE any_name OWNER TO RoleSpec
+				{
+					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+					n->objectType = OBJECT_VARIABLE;
+					n->object = (Node *) $3;
+					n->newowner = $6;
+					$$ = (Node *)n;
+				}
 		;
 
 
@@ -10928,6 +11067,7 @@ ExplainableStmt:
 			| CreateMatViewStmt
 			| RefreshMatViewStmt
 			| ExecuteStmt					/* by default all are $$=$1 */
+			| LetStmt
 		;
 
 /*****************************************************************************
@@ -10956,6 +11096,7 @@ PreparableStmt:
 			| InsertStmt
 			| UpdateStmt
 			| DeleteStmt					/* by default all are $$=$1 */
+			| LetStmt
 		;
 
 /*****************************************************************************
@@ -11373,6 +11514,47 @@ opt_hold: /* EMPTY */						{ $$ = 0; }
 			| WITHOUT HOLD					{ $$ = 0; }
 		;
 
+/*****************************************************************************
+ *
+ *		QUERY:
+ *				LET STATEMENTS
+ *
+ *****************************************************************************/
+LetStmt:	LET let_target '=' a_expr
+				{
+					LetStmt	   *n = makeNode(LetStmt);
+					SelectStmt *select;
+					ResTarget  *res;
+
+					n->target = $2;
+
+					select = makeNode(SelectStmt);
+					res = makeNode(ResTarget);
+
+					/* Create target list for implicit query */
+					res->name = NULL;
+					res->indirection = NIL;
+					res->val = (Node *) $4;
+					res->location = @4;
+
+					select->targetList = list_make1(res);
+					n->query = (Node *) select;
+
+					n->location = @2;
+					$$ = (Node *) n;
+				}
+		;
+
+let_target:
+			ColId opt_indirection
+				{
+					$$ = list_make1(makeString($1));
+					if ($2)
+						  $$ = list_concat($$,
+										   check_indirection($2, yyscanner));
+				}
+		;
+
 /*****************************************************************************
  *
  *		QUERY:
@@ -15681,6 +15863,7 @@ unreserved_keyword:
 			| LARGE_P
 			| LAST_P
 			| LEAKPROOF
+			| LET
 			| LEVEL
 			| LISTEN
 			| LOAD
@@ -15838,6 +16021,8 @@ unreserved_keyword:
 			| VALIDATE
 			| VALIDATOR
 			| VALUE_P
+			| VARIABLE
+			| VARIABLES
 			| VARYING
 			| VERSION_P
 			| VIEW
@@ -16245,6 +16430,7 @@ bare_label_keyword:
 			| LEAKPROOF
 			| LEAST
 			| LEFT
+			| LET
 			| LEVEL
 			| LIKE
 			| LISTEN
@@ -16444,6 +16630,8 @@ bare_label_keyword:
 			| VALUE_P
 			| VALUES
 			| VARCHAR
+			| VARIABLE
+			| VARIABLES
 			| VARIADIC
 			| VERBOSE
 			| VERSION_P
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 7d829a05a9..f3b384efbe 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -348,6 +348,7 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr)
 			Assert(false);		/* can't happen */
 			break;
 		case EXPR_KIND_OTHER:
+		case EXPR_KIND_LET_TARGET:
 
 			/*
 			 * Accept aggregate/grouping here; caller must throw error if
@@ -464,6 +465,7 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr)
 			break;
 		case EXPR_KIND_COLUMN_DEFAULT:
 		case EXPR_KIND_FUNCTION_DEFAULT:
+		case EXPR_KIND_VARIABLE_DEFAULT:
 
 			if (isAgg)
 				err = _("aggregate functions are not allowed in DEFAULT expressions");
@@ -905,6 +907,7 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
 			break;
 		case EXPR_KIND_COLUMN_DEFAULT:
 		case EXPR_KIND_FUNCTION_DEFAULT:
+		case EXPR_KIND_VARIABLE_DEFAULT:
 			err = _("window functions are not allowed in DEFAULT expressions");
 			break;
 		case EXPR_KIND_INDEX_EXPRESSION:
@@ -943,6 +946,9 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
 		case EXPR_KIND_CYCLE_MARK:
 			errkind = true;
 			break;
+		case EXPR_KIND_LET_TARGET:
+			err = _("window functions are not allowed in LET statement");
+			break;
 
 			/*
 			 * There is intentionally no default: case here, so that the
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 2d1a477154..6aaaa5bb29 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -16,6 +16,7 @@
 #include "postgres.h"
 
 #include "catalog/pg_type.h"
+#include "catalog/pg_variable.h"
 #include "commands/dbcommands.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
@@ -36,6 +37,7 @@
 #include "utils/date.h"
 #include "utils/lsyscache.h"
 #include "utils/timestamp.h"
+#include "utils/typcache.h"
 #include "utils/xml.h"
 
 /* GUC parameters */
@@ -82,7 +84,9 @@ static Expr *make_distinct_op(ParseState *pstate, List *opname,
 							  Node *ltree, Node *rtree, int location);
 static Node *make_nulltest_from_distinct(ParseState *pstate,
 										 A_Expr *distincta, Node *arg);
-
+static Node *makeParamSchemaVariable(ParseState *pstate,
+									 Oid varid, Oid typid, int32 typmod, Oid collid,
+									 char *attrname, int location);
 
 /*
  * transformExpr -
@@ -277,6 +281,7 @@ transformExprRecurse(ParseState *pstate, Node *expr)
 			 * processed it rather than passing it to transformExpr().
 			 */
 		case T_SetToDefault:
+			Assert(false);
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 					 errmsg("DEFAULT is not allowed in this context"),
@@ -443,6 +448,9 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
 	char	   *relname = NULL;
 	char	   *colname = NULL;
 	ParseNamespaceItem *nsitem;
+	Oid			varid = InvalidOid;
+	char	   *attrname = NULL;
+	bool		not_unique;
 	int			levels_up;
 	enum
 	{
@@ -504,6 +512,9 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
 		case EXPR_KIND_COPY_WHERE:
 		case EXPR_KIND_GENERATED_COLUMN:
 		case EXPR_KIND_CYCLE_MARK:
+		case EXPR_KIND_VARIABLE_DEFAULT:
+		case EXPR_KIND_LET_TARGET:
+
 			/* okay */
 			break;
 
@@ -761,6 +772,15 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
 			break;
 	}
 
+	varid = IdentifyVariable(cref->fields, &attrname, &not_unique);
+
+	if (not_unique)
+		ereport(ERROR,
+				(errcode(ERRCODE_AMBIGUOUS_PARAMETER),
+				 errmsg("schema variable reference \"%s\" is ambiguous",
+						NameListToString(cref->fields)),
+				 parser_errposition(pstate, cref->location)));
+
 	/*
 	 * Now give the PostParseColumnRefHook, if any, a chance.  We pass the
 	 * translation-so-far so that it can throw an error if it wishes in the
@@ -785,6 +805,78 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
 					 parser_errposition(pstate, cref->location)));
 	}
 
+	if (OidIsValid(varid))
+	{
+		Oid			typid;
+		int32		typmod;
+		Oid			collid;
+
+		get_schema_variable_type_typmod_collid(varid, &typid, &typmod, &collid);
+
+		if (node != NULL)
+		{
+			/*
+			 * Some cases with ambiguous references can be solved without
+			 * raising an error. When there is an collision between column
+			 * name (or label) and some schema variable name, and when we know
+			 * attribute name, then we can ignore the collision when:
+			 *
+			 *   a) variable is of scalar type (then indirection cannot be
+			 *      applied on this schema variable.
+			 *
+			 *   b) when related variable has no field of attrname, then
+			 *      indirection cannot be applied on this schema variable.
+			 */
+			if (attrname)
+			{
+				if (type_is_rowtype(typid))
+				{
+					TupleDesc	tupdesc;
+					bool		found = false;
+					int			i;
+
+					/* slow part, I hope it will not be to often */
+					tupdesc = lookup_rowtype_tupdesc(typid, typmod);
+					for (i = 0; i < tupdesc->natts; i++)
+					{
+						if (namestrcmp(&(TupleDescAttr(tupdesc, i)->attname), attrname) == 0 &&
+							!TupleDescAttr(tupdesc, i)->attisdropped)
+						{
+							found = true;
+							break;
+						}
+					}
+
+					FreeTupleDesc(tupdesc);
+
+					/* there are not composite variable with this field */
+					if (!found)
+						varid = InvalidOid;
+				}
+				else
+					/* there are not composite variable with this name */
+					varid = InvalidOid;
+			}
+
+			/*
+			 * Raise error if varid is still valid. It should be really
+			 * amigonuous
+			 */
+			if (OidIsValid(varid))
+				ereport(ERROR,
+						(errcode(ERRCODE_AMBIGUOUS_COLUMN),
+						 errmsg("column reference \"%s\" is ambiguous",
+								NameListToString(cref->fields)),
+						 errdetail("The qualified identifier can be column reference or schema variable reference"),
+						 parser_errposition(pstate, cref->location)));
+		}
+
+		if (OidIsValid(varid))
+			node = makeParamSchemaVariable(pstate,
+										   varid, typid, typmod, collid,
+										   attrname, cref->location);
+	}
+
 	/*
 	 * Throw error if no translation found.
 	 */
@@ -819,6 +911,74 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
 	return node;
 }
 
+/*
+ * Generate param variable for reference to schema variable
+ */
+static Node *
+makeParamSchemaVariable(ParseState *pstate,
+						Oid varid, Oid typid, int32 typmod, Oid collid,
+						char *attrname, int location)
+{
+	Param	   *param;
+
+	param = makeNode(Param);
+
+	param->paramkind = PARAM_VARIABLE;
+	param->paramvarid = varid;
+	param->paramtype = typid;
+	param->paramtypmod = typmod;
+	param->paramcollid = collid;
+
+	/*
+	 * There are two access to schema variables - direct, used by simple
+	 * plpgsql expressions, where there are not necessary to emulate
+	 * stability. Buffered access is used elsewhere. We should to ensure
+	 * stable values, and because schema variables are global, then we should
+	 * to work with copied values instead direct access to variables. For
+	 * direct access the varid is best for access. For buffered access we need
+	 * to assign index to buffer - later, when we will know what variables are
+	 * used. Now, we just remember, so we use schema variables.
+	 */
+	pstate->p_hasSchemaVariables = true;
+
+	if (attrname != NULL)
+	{
+		TupleDesc	tupdesc;
+		int			i;
+
+		tupdesc = lookup_rowtype_tupdesc(typid, typmod);
+
+		for (i = 0; i < tupdesc->natts; i++)
+		{
+			Form_pg_attribute att = TupleDescAttr(tupdesc, i);
+
+			if (strcmp(attrname, NameStr(att->attname)) == 0 &&
+				!att->attisdropped)
+			{
+				/* Success, so generate a FieldSelect expression */
+				FieldSelect *fselect = makeNode(FieldSelect);
+
+				fselect->arg = (Expr *) param;
+				fselect->fieldnum = i + 1;
+				fselect->resulttype = att->atttypid;
+				fselect->resulttypmod = att->atttypmod;
+				/* save attribute's collation for parse_collate.c */
+				fselect->resultcollid = att->attcollation;
+
+				ReleaseTupleDesc(tupdesc);
+				return (Node *) fselect;
+			}
+		}
+
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_COLUMN),
+				 errmsg("could not identify column \"%s\" in variable", attrname),
+				 parser_errposition(pstate, location)));
+	}
+
+	return (Node *) param;
+}
+
 static Node *
 transformParamRef(ParseState *pstate, ParamRef *pref)
 {
@@ -1721,6 +1881,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
 		case EXPR_KIND_VALUES:
 		case EXPR_KIND_VALUES_SINGLE:
 		case EXPR_KIND_CYCLE_MARK:
+		case EXPR_KIND_LET_TARGET:
 			/* okay */
 			break;
 		case EXPR_KIND_CHECK_CONSTRAINT:
@@ -1729,6 +1890,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
 			break;
 		case EXPR_KIND_COLUMN_DEFAULT:
 		case EXPR_KIND_FUNCTION_DEFAULT:
+		case EXPR_KIND_VARIABLE_DEFAULT:
 			err = _("cannot use subquery in DEFAULT expression");
 			break;
 		case EXPR_KIND_INDEX_EXPRESSION:
@@ -3059,6 +3221,7 @@ ParseExprKindName(ParseExprKind exprKind)
 			return "CHECK";
 		case EXPR_KIND_COLUMN_DEFAULT:
 		case EXPR_KIND_FUNCTION_DEFAULT:
+		case EXPR_KIND_VARIABLE_DEFAULT:
 			return "DEFAULT";
 		case EXPR_KIND_INDEX_EXPRESSION:
 			return "index expression";
@@ -3084,6 +3247,8 @@ ParseExprKindName(ParseExprKind exprKind)
 			return "GENERATED AS";
 		case EXPR_KIND_CYCLE_MARK:
 			return "CYCLE";
+		case EXPR_KIND_LET_TARGET:
+			return "LET";
 
 			/*
 			 * There is intentionally no default: case here, so that the
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 542f9167aa..a1198d64ce 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -2617,6 +2617,7 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location)
 			break;
 		case EXPR_KIND_COLUMN_DEFAULT:
 		case EXPR_KIND_FUNCTION_DEFAULT:
+		case EXPR_KIND_VARIABLE_DEFAULT:
 			err = _("set-returning functions are not allowed in DEFAULT expressions");
 			break;
 		case EXPR_KIND_INDEX_EXPRESSION:
@@ -2655,6 +2656,9 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location)
 		case EXPR_KIND_CYCLE_MARK:
 			errkind = true;
 			break;
+		case EXPR_KIND_LET_TARGET:
+			err = _("set-returning functions are not allowed in CALL arguments");
+			break;
 
 			/*
 			 * There is intentionally no default: case here, so that the
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 9ce3a0de96..a79e612129 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -89,7 +89,9 @@ transformTargetEntry(ParseState *pstate,
 		 * through unmodified.  (transformExpr will throw the appropriate
 		 * error if we're disallowing it.)
 		 */
-		if (exprKind == EXPR_KIND_UPDATE_SOURCE && IsA(node, SetToDefault))
+		if ((exprKind == EXPR_KIND_UPDATE_SOURCE ||
+			 exprKind == EXPR_KIND_LET_TARGET)
+			&& IsA(node, SetToDefault))
 			expr = node;
 		else
 			expr = transformExpr(pstate, node, exprKind);
diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c
index 875de7ba28..0f499712d8 100644
--- a/src/backend/parser/parser.c
+++ b/src/backend/parser/parser.c
@@ -61,7 +61,8 @@ raw_parser(const char *str, RawParseMode mode)
 			MODE_PLPGSQL_EXPR,	/* RAW_PARSE_PLPGSQL_EXPR */
 			MODE_PLPGSQL_ASSIGN1,	/* RAW_PARSE_PLPGSQL_ASSIGN1 */
 			MODE_PLPGSQL_ASSIGN2,	/* RAW_PARSE_PLPGSQL_ASSIGN2 */
-			MODE_PLPGSQL_ASSIGN3	/* RAW_PARSE_PLPGSQL_ASSIGN3 */
+			MODE_PLPGSQL_ASSIGN3,	/* RAW_PARSE_PLPGSQL_ASSIGN3 */
+			MODE_PLPGSQL_LET	/* RAW_PARSE_PLPGSQL_LET */
 		};
 
 		yyextra.have_lookahead = true;
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 9521e81100..e2c816bc4c 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -25,6 +25,7 @@
 #include "access/table.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_variable.h"
 #include "commands/trigger.h"
 #include "foreign/fdwapi.h"
 #include "miscadmin.h"
@@ -3664,6 +3665,39 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
 		}
 	}
 
+	/*
+	 * Rewrite SetToDefault by default expression of Let statement.
+	 */
+	if (event == CMD_SELECT && OidIsValid(parsetree->resultVariable))
+	{
+		Oid			resultVariable = parsetree->resultVariable;
+
+		if (list_length(parsetree->targetList) == 1 &&
+			IsA(((TargetEntry *) linitial(parsetree->targetList))->expr, SetToDefault))
+		{
+			Variable		var;
+			TargetEntry	   *tle;
+			TargetEntry	   *newtle;
+			Expr		   *defexpr;
+
+			/* Read schema variable metadata with defexpr */
+			initVariable(&var, resultVariable, false, false);
+
+			if (var.has_defexpr)
+				defexpr = (Expr *) var.defexpr;
+			else
+				defexpr = (Expr *) makeNullConst(var.typid, var.typmod, var.collation);
+
+			tle = (TargetEntry *) linitial(parsetree->targetList);
+			newtle = makeTargetEntry(defexpr,
+									  tle->resno,
+									  pstrdup(tle->resname),
+									  false);
+
+			parsetree->targetList = list_make1(newtle);
+		}
+	}
+
 	/*
 	 * If the statement is an insert, update, or delete, adjust its targetlist
 	 * as needed, and then fire INSERT/UPDATE/DELETE rules on it.
diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c
index e10f94904e..447c6f0abf 100644
--- a/src/backend/rewrite/rowsecurity.c
+++ b/src/backend/rewrite/rowsecurity.c
@@ -213,10 +213,10 @@ get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index,
 	}
 
 	/*
-	 * For SELECT, UPDATE and DELETE, add security quals to enforce the USING
-	 * policies.  These security quals control access to existing table rows.
-	 * Restrictive policies are combined together using AND, and permissive
-	 * policies are combined together using OR.
+	 * For SELECT, LET, UPDATE and DELETE, add security quals to enforce the
+	 * USING policies.  These security quals control access to existing table
+	 * rows. Restrictive policies are combined together using AND, and
+	 * permissive policies are combined together using OR.
 	 */
 
 	get_policies_for_relation(rel, commandType, user_id, &permissive_policies,
diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c
index 1dfadfa8e1..c676cb19fc 100644
--- a/src/backend/tcop/dest.c
+++ b/src/backend/tcop/dest.c
@@ -37,6 +37,7 @@
 #include "executor/functions.h"
 #include "executor/tqueue.h"
 #include "executor/tstoreReceiver.h"
+#include "executor/svariableReceiver.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
 #include "utils/portal.h"
@@ -152,6 +153,9 @@ CreateDestReceiver(CommandDest dest)
 
 		case DestTupleQueue:
 			return CreateTupleQueueDestReceiver(NULL);
+
+		case DestVariable:
+			return CreateVariableDestReceiver();
 	}
 
 	/* should never get here */
@@ -207,6 +211,7 @@ EndCommand(const QueryCompletion *qc, CommandDest dest, bool force_undecorated_o
 		case DestSQLFunction:
 		case DestTransientRel:
 		case DestTupleQueue:
+		case DestVariable:
 			break;
 	}
 }
@@ -252,6 +257,7 @@ NullCommand(CommandDest dest)
 		case DestSQLFunction:
 		case DestTransientRel:
 		case DestTupleQueue:
+		case DestVariable:
 			break;
 	}
 }
@@ -295,6 +301,7 @@ ReadyForQuery(CommandDest dest)
 		case DestSQLFunction:
 		case DestTransientRel:
 		case DestTupleQueue:
+		case DestVariable:
 			break;
 	}
 }
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 960f3fadce..6c2f393988 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -86,6 +86,9 @@ CreateQueryDesc(PlannedStmt *plannedstmt,
 	qd->queryEnv = queryEnv;
 	qd->instrument_options = instrument_options;	/* instrumentation wanted? */
 
+	qd->num_schema_variables = 0;
+	qd->schema_variables = NULL;
+
 	/* null these fields until set by ExecutorStart */
 	qd->tupDesc = NULL;
 	qd->estate = NULL;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index bf085aa93b..f5f7f9ead7 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -48,6 +48,7 @@
 #include "commands/proclang.h"
 #include "commands/publicationcmds.h"
 #include "commands/schemacmds.h"
+#include "commands/schema_variable.h"
 #include "commands/seclabel.h"
 #include "commands/sequence.h"
 #include "commands/subscriptioncmds.h"
@@ -186,6 +187,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree)
 		case T_CreateRangeStmt:
 		case T_CreateRoleStmt:
 		case T_CreateSchemaStmt:
+		case T_CreateSchemaVarStmt:
 		case T_CreateSeqStmt:
 		case T_CreateStatsStmt:
 		case T_CreateStmt:
@@ -237,6 +239,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree)
 
 		case T_CallStmt:
 		case T_DoStmt:
+		case T_LetStmt:
 			{
 				/*
 				 * Commands inside the DO block or the called procedure might
@@ -1061,6 +1064,11 @@ standard_ProcessUtility(PlannedStmt *pstmt,
 				break;
 			}
 
+		case T_LetStmt:
+			ExecuteLetStmt(pstate, (LetStmt *) parsetree, params,
+						   queryEnv, qc);
+			break;
+
 		default:
 			/* All other statement types have event trigger support */
 			ProcessUtilitySlow(pstate, pstmt, queryString,
@@ -1385,6 +1393,10 @@ ProcessUtilitySlow(ParseState *pstate,
 				}
 				break;
 
+			case T_CreateSchemaVarStmt:
+				address = DefineSchemaVariable(pstate, (CreateSchemaVarStmt *) parsetree);
+				break;
+
 				/*
 				 * ************* object creation / destruction **************
 				 */
@@ -2175,6 +2187,10 @@ UtilityContainsQuery(Node *parsetree)
 				return UtilityContainsQuery(qry->utilityStmt);
 			return qry;
 
+		case T_LetStmt:
+			qry = castNode(Query, ((LetStmt *) parsetree)->query);
+			return qry;
+
 		default:
 			return NULL;
 	}
@@ -2316,6 +2332,9 @@ AlterObjectTypeCommandTag(ObjectType objtype)
 		case OBJECT_STATISTIC_EXT:
 			tag = CMDTAG_ALTER_STATISTICS;
 			break;
+		case OBJECT_VARIABLE:
+			tag = CMDTAG_ALTER_VARIABLE;
+			break;
 		default:
 			tag = CMDTAG_UNKNOWN;
 			break;
@@ -2366,6 +2385,10 @@ CreateCommandTag(Node *parsetree)
 			tag = CMDTAG_SELECT;
 			break;
 
+		case T_LetStmt:
+			tag = CMDTAG_LET;
+			break;
+
 			/* utility statements --- same whether raw or cooked */
 		case T_TransactionStmt:
 			{
@@ -2620,6 +2643,9 @@ CreateCommandTag(Node *parsetree)
 				case OBJECT_STATISTIC_EXT:
 					tag = CMDTAG_DROP_STATISTICS;
 					break;
+				case OBJECT_VARIABLE:
+					tag = CMDTAG_DROP_VARIABLE;
+					break;
 				default:
 					tag = CMDTAG_UNKNOWN;
 			}
@@ -2908,6 +2934,9 @@ CreateCommandTag(Node *parsetree)
 				case DISCARD_SEQUENCES:
 					tag = CMDTAG_DISCARD_SEQUENCES;
 					break;
+				case DISCARD_VARIABLES:
+					tag = CMDTAG_DISCARD_VARIABLES;
+					break;
 				default:
 					tag = CMDTAG_UNKNOWN;
 			}
@@ -3192,6 +3221,10 @@ CreateCommandTag(Node *parsetree)
 			}
 			break;
 
+		case T_CreateSchemaVarStmt:
+			tag = CMDTAG_CREATE_VARIABLE;
+			break;
+
 		default:
 			elog(WARNING, "unrecognized node type: %d",
 				 (int) nodeTag(parsetree));
@@ -3239,6 +3272,7 @@ GetCommandLogLevel(Node *parsetree)
 			break;
 
 		case T_PLAssignStmt:
+		case T_LetStmt:
 			lev = LOGSTMT_ALL;
 			break;
 
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 67f8b29434..1b3c4bc41d 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -306,6 +306,12 @@ aclparse(const char *s, AclItem *aip)
 			case ACL_CONNECT_CHR:
 				read = ACL_CONNECT;
 				break;
+			case ACL_READ_CHR:
+				read = ACL_READ;
+				break;
+			case ACL_WRITE_CHR:
+				read = ACL_WRITE;
+				break;
 			case 'R':			/* ignore old RULE privileges */
 				read = 0;
 				break;
@@ -794,6 +800,10 @@ acldefault(ObjectType objtype, Oid ownerId)
 			world_default = ACL_USAGE;
 			owner_default = ACL_ALL_RIGHTS_TYPE;
 			break;
+		case OBJECT_VARIABLE:
+			world_default = ACL_NO_RIGHTS;
+			owner_default = ACL_ALL_RIGHTS_VARIABLE;
+			break;
 		default:
 			elog(ERROR, "unrecognized objtype: %d", (int) objtype);
 			world_default = ACL_NO_RIGHTS;	/* keep compiler quiet */
@@ -888,6 +898,9 @@ acldefault_sql(PG_FUNCTION_ARGS)
 		case 'T':
 			objtype = OBJECT_TYPE;
 			break;
+		case 'V':
+			objtype = OBJECT_VARIABLE;
+			break;
 		default:
 			elog(ERROR, "unrecognized objtype abbreviation: %c", objtypec);
 	}
@@ -1604,6 +1617,10 @@ convert_priv_string(text *priv_type_text)
 		return ACL_CONNECT;
 	if (pg_strcasecmp(priv_type, "RULE") == 0)
 		return 0;				/* ignore old RULE privileges */
+	if (pg_strcasecmp(priv_type, "READ") == 0)
+		return ACL_READ;
+	if (pg_strcasecmp(priv_type, "WRITE") == 0)
+		return ACL_WRITE;
 
 	ereport(ERROR,
 			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -1698,6 +1715,10 @@ convert_aclright_to_string(int aclright)
 			return "TEMPORARY";
 		case ACL_CONNECT:
 			return "CONNECT";
+		case ACL_READ:
+			return "READ";
+		case ACL_WRITE:
+			return "WRITE";
 		default:
 			elog(ERROR, "unrecognized aclright: %d", aclright);
 			return NULL;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 1bb25738a5..bfd860effa 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -38,6 +38,7 @@
 #include "catalog/pg_statistic_ext.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_variable.h"
 #include "commands/defrem.h"
 #include "commands/tablespace.h"
 #include "common/keywords.h"
@@ -7915,6 +7916,14 @@ get_parameter(Param *param, deparse_context *context)
 		return;
 	}
 
+	/* translate paramvarid to schema variable name */
+	if (param->paramkind == PARAM_VARIABLE)
+	{
+		appendStringInfo(context->buf, "%s",
+						 schema_variable_get_name(param->paramvarid));
+		return;
+	}
+
 	/*
 	 * If it's an external parameter, see if the outermost namespace provides
 	 * function argument names.
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 4ebaa552a2..7a1797b1db 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -35,6 +35,7 @@
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_transform.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_variable.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "utils/array.h"
@@ -1860,6 +1861,18 @@ get_relname_relid(const char *relname, Oid relnamespace)
 						   ObjectIdGetDatum(relnamespace));
 }
 
+/*
+ * get_varname_varid
+ *		Given name and namespace of variable, look up the OID.
+ */
+Oid
+get_varname_varid(const char *varname, Oid varnamespace)
+{
+	return GetSysCacheOid2(VARIABLENAMENSP, Anum_pg_variable_oid,
+						   PointerGetDatum(varname),
+						   ObjectIdGetDatum(varnamespace));
+}
+
 #ifdef NOT_USED
 /*
  * get_relnatts
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 6194751e99..a2867e7ac7 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -74,6 +74,7 @@
 #include "catalog/pg_ts_template.h"
 #include "catalog/pg_type.h"
 #include "catalog/pg_user_mapping.h"
+#include "catalog/pg_variable.h"
 #include "lib/qunique.h"
 #include "utils/catcache.h"
 #include "utils/rel.h"
@@ -1014,6 +1015,28 @@ static const struct cachedesc cacheinfo[] = {
 			0
 		},
 		2
+	},
+	{VariableRelationId,		/* VARIABLENAMENSP */
+		VariableNameNspIndexId,
+		2,
+		{
+			Anum_pg_variable_varname,
+			Anum_pg_variable_varnamespace,
+			0,
+			0
+		},
+		8
+	},
+	{VariableRelationId,		/* VARIABLEOID */
+		VariableObjectIndexId,
+		1,
+		{
+			Anum_pg_variable_oid,
+			0,
+			0,
+			0
+		},
+		8
 	}
 };
 
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 3dfe6e5825..3f60c7b365 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -1910,15 +1910,19 @@ get_call_expr_arg_stable(Node *expr, int argnum)
 	arg = (Node *) list_nth(args, argnum);
 
 	/*
-	 * Either a true Const or an external Param will have a value that doesn't
-	 * change during the execution of the query.  In future we might want to
-	 * consider other cases too, e.g. now().
+	 * Either a true Const or an external Param or variable will have a value
+	 * that doesn't change during the execution of the query.  In future we
+	 * might want to consider other cases too, e.g. now().
 	 */
 	if (IsA(arg, Const))
 		return true;
-	if (IsA(arg, Param) &&
-		((Param *) arg)->paramkind == PARAM_EXTERN)
-		return true;
+	if (IsA(arg, Param))
+	{
+		Param	   *p = (Param *) arg;
+
+		if (p->paramkind == PARAM_EXTERN || p->paramkind == PARAM_VARIABLE)
+			return true;
+	}
 
 	return false;
 }
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index ecab0a9e4e..8c206b0200 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -263,7 +263,8 @@ getSchemaData(Archive *fout, int *numTablesPtr)
 	pg_log_info("reading subscriptions");
 	getSubscriptions(fout);
 
-	free(inhinfo);				/* not needed any longer */
+	pg_log_info("reading variables");
+	getVariables(fout);
 
 	*numTablesPtr = numTables;
 	return tblinfo;
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index 6af10a85a2..29082a0926 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -113,12 +113,14 @@ typedef struct _restoreOptions
 	int			selFunction;
 	int			selTrigger;
 	int			selTable;
+	int			selVariable;
 	SimpleStringList indexNames;
 	SimpleStringList functionNames;
 	SimpleStringList schemaNames;
 	SimpleStringList schemaExcludeNames;
 	SimpleStringList triggerNames;
 	SimpleStringList tableNames;
+	SimpleStringList variableNames;
 
 	int			useDB;
 	ConnParams	cparams;		/* parameters to use if useDB */
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 2c4cfb9457..4141a21531 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -2922,6 +2922,14 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH)
 					!simple_string_list_member(&ropt->triggerNames, te->tag))
 					return 0;
 			}
+			else if (strcmp(te->desc, "VARIABLE") == 0)
+			{
+				if (!ropt->selVariable)
+					return 0;
+				if (ropt->variableNames.head != NULL &&
+					!simple_string_list_member(&ropt->variableNames, te->tag))
+					return 0;
+			}
 			else
 				return 0;
 		}
@@ -3405,6 +3413,7 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te)
 		strcmp(type, "TEXT SEARCH DICTIONARY") == 0 ||
 		strcmp(type, "TEXT SEARCH CONFIGURATION") == 0 ||
 		strcmp(type, "STATISTICS") == 0 ||
+		strcmp(type, "VARIABLE") == 0 ||
 	/* non-schema-specified objects */
 		strcmp(type, "DATABASE") == 0 ||
 		strcmp(type, "PROCEDURAL LANGUAGE") == 0 ||
@@ -3597,7 +3606,8 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
 			strcmp(te->desc, "SERVER") == 0 ||
 			strcmp(te->desc, "STATISTICS") == 0 ||
 			strcmp(te->desc, "PUBLICATION") == 0 ||
-			strcmp(te->desc, "SUBSCRIPTION") == 0)
+			strcmp(te->desc, "SUBSCRIPTION") == 0 ||
+			strcmp(te->desc, "VARIABLE") == 0)
 		{
 			PQExpBuffer temp = createPQExpBuffer();
 
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index b9635a95b6..a8b727898b 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -279,6 +279,7 @@ static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
 static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
 static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
 static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
+static void dumpVariable(Archive *fout, const VariableInfo * varinfo);
 static void dumpDatabase(Archive *AH);
 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
 							   const char *dbname, Oid dboid);
@@ -4701,6 +4702,232 @@ get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
 	return next_possible_free_oid;
 }
 
+/*
+ * getVariables
+ *	  get information about variables
+ */
+void
+getVariables(Archive *fout)
+{
+	DumpOptions *dopt = fout->dopt;
+	PQExpBuffer query;
+	PQExpBuffer acl_subquery = createPQExpBuffer();
+	PQExpBuffer racl_subquery = createPQExpBuffer();
+	PQExpBuffer init_acl_subquery = createPQExpBuffer();
+	PQExpBuffer init_racl_subquery = createPQExpBuffer();
+	PGresult   *res;
+	VariableInfo *varinfo;
+	int			i_tableoid;
+	int			i_oid;
+	int			i_varname;
+	int			i_varnamespace;
+	int			i_vartype;
+	int			i_vartypname;
+	int			i_vardefexpr;
+	int			i_rolname;
+	int			i_varacl;
+	int			i_rvaracl;
+	int			i_initvaracl;
+	int			i_initrvaracl;
+	int			i_vareoxaction;
+	int			i_varisnotnull;
+	int			i_varisimmutable;
+	int			i,
+				ntups;
+
+	if (fout->remoteVersion < 130000)
+		return;
+
+	acl_subquery = createPQExpBuffer();
+	racl_subquery = createPQExpBuffer();
+	init_acl_subquery = createPQExpBuffer();
+	init_racl_subquery = createPQExpBuffer();
+
+	buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
+					init_racl_subquery, "v.varacl", "v.varowner",
+					"pip.initprivs", "'V'", dopt->binary_upgrade);
+
+	query = createPQExpBuffer();
+
+	resetPQExpBuffer(query);
+
+	/* Get the variables in current database. */
+	appendPQExpBuffer(query,
+					  "SELECT v.tableoid, v.oid, v.varname, "
+					  "v.vareoxaction, "
+					  "v.varnamespace, "
+					  "(%s varowner) AS rolname, "
+					  "%s as varacl, "
+					  "%s as rvaracl, "
+					  "%s as initvaracl, "
+					  "%s as initrvaracl, "
+					  "v.vartype, "
+					  "pg_catalog.format_type(v.vartype, v.vartypmod) as vartypname, "
+					  "v.varisnotnull, "
+					  "v.varisimmutable, "
+					  "pg_catalog.pg_get_expr(v.vardefexpr,0) as vardefexpr "
+					  "FROM pg_variable v "
+					  "LEFT JOIN pg_init_privs pip "
+					  "ON (v.oid = pip.objoid "
+					  "AND pip.classoid = 'pg_variable'::regclass "
+					  "AND pip.objsubid = 0)",
+					  username_subquery,
+					  acl_subquery->data,
+					  racl_subquery->data,
+					  init_acl_subquery->data,
+					  init_racl_subquery->data);
+
+	destroyPQExpBuffer(acl_subquery);
+	destroyPQExpBuffer(racl_subquery);
+	destroyPQExpBuffer(init_acl_subquery);
+	destroyPQExpBuffer(init_racl_subquery);
+
+	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+	ntups = PQntuples(res);
+
+	i_tableoid = PQfnumber(res, "tableoid");
+	i_oid = PQfnumber(res, "oid");
+	i_varname = PQfnumber(res, "varname");
+	i_varnamespace = PQfnumber(res, "varnamespace");
+	i_rolname = PQfnumber(res, "rolname");
+	i_vartype = PQfnumber(res, "vartype");
+	i_vartypname = PQfnumber(res, "vartypname");
+	i_vareoxaction = PQfnumber(res, "vareoxaction");
+	i_vardefexpr = PQfnumber(res, "vardefexpr");
+	i_varacl = PQfnumber(res, "varacl");
+	i_rvaracl = PQfnumber(res, "rvaracl");
+	i_initvaracl = PQfnumber(res, "initvaracl");
+	i_initrvaracl = PQfnumber(res, "initrvaracl");
+	i_varisnotnull = PQfnumber(res, "varisnotnull");
+	i_varisimmutable = PQfnumber(res, "varisimmutable");
+
+	varinfo = pg_malloc(ntups * sizeof(VariableInfo));
+
+	for (i = 0; i < ntups; i++)
+	{
+		TypeInfo   *vtype;
+
+		varinfo[i].dobj.objType = DO_VARIABLE;
+		varinfo[i].dobj.catId.tableoid =
+			atooid(PQgetvalue(res, i, i_tableoid));
+		varinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+		AssignDumpId(&varinfo[i].dobj);
+		varinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_varname));
+		varinfo[i].dobj.namespace =
+			findNamespace(atooid(PQgetvalue(res, i, i_varnamespace)));
+
+		varinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
+		varinfo[i].vartype = atooid(PQgetvalue(res, i, i_vartype));
+		varinfo[i].vartypname = pg_strdup(PQgetvalue(res, i, i_vartypname));
+
+		varinfo[i].vareoxaction = pg_strdup(PQgetvalue(res, i, i_vareoxaction));
+
+		varinfo[i].varacl = pg_strdup(PQgetvalue(res, i, i_varacl));
+		varinfo[i].rvaracl = pg_strdup(PQgetvalue(res, i, i_rvaracl));
+		varinfo[i].initvaracl = pg_strdup(PQgetvalue(res, i, i_initvaracl));
+		varinfo[i].initrvaracl = pg_strdup(PQgetvalue(res, i, i_initrvaracl));
+
+		varinfo[i].varisnotnull = *(PQgetvalue(res, i, i_varisnotnull)) == 't';
+		varinfo[i].varisimmutable = *(PQgetvalue(res, i, i_varisimmutable)) == 't';
+
+		/* Decide whether we want to dump it */
+		selectDumpableObject(&(varinfo[i].dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_varacl) && PQgetisnull(res, i, i_rvaracl) &&
+			PQgetisnull(res, i, i_initvaracl) &&
+			PQgetisnull(res, i, i_initrvaracl))
+			varinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
+		if (PQgetisnull(res, i, i_vardefexpr))
+			varinfo[i].vardefexpr = NULL;
+		else
+			varinfo[i].vardefexpr = pg_strdup(PQgetvalue(res, i, i_vardefexpr));
+
+		if (strlen(varinfo[i].rolname) == 0)
+			pg_log_warning("owner of variable \"%s\" appears to be invalid",
+						   varinfo[i].dobj.name);
+
+		/* Decide whether we want to dump it */
+		selectDumpableObject(&(varinfo[i].dobj), fout);
+
+		vtype = findTypeByOid(varinfo[i].vartype);
+		addObjectDependency(&varinfo[i].dobj, vtype->dobj.dumpId);
+	}
+	PQclear(res);
+
+	destroyPQExpBuffer(query);
+}
+
+/*
+ * dumpVariable
+ *	  dump the definition of the given variables
+ */
+static void
+dumpVariable(Archive *fout, const VariableInfo * varinfo)
+{
+	DumpOptions *dopt = fout->dopt;
+
+	PQExpBuffer delq;
+	PQExpBuffer query;
+	const char *varname;
+	const char *vartypname;
+	const char *vardefexpr;
+	const char *vareoxaction;
+	const char *varisnotnull;
+	const char *varisimmutable;
+
+	/* Skip if not to be dumped */
+	if (!varinfo->dobj.dump || dopt->dataOnly)
+		return;
+
+	delq = createPQExpBuffer();
+	query = createPQExpBuffer();
+
+	varname = fmtQualifiedDumpable(varinfo);
+	vartypname = varinfo->vartypname;
+	vardefexpr = varinfo->vardefexpr;
+	vareoxaction = varinfo->vareoxaction;
+	varisnotnull = varinfo->varisnotnull ? " NOT NULL" : "";
+	varisimmutable = varinfo->varisimmutable ? "IMMUTABLE " : "";
+
+	appendPQExpBuffer(delq, "DROP VARIABLE %s;\n",
+					  varname);
+
+	appendPQExpBuffer(query, "CREATE %sVARIABLE %s AS %s%s",
+					  varisimmutable, varname, vartypname, varisnotnull);
+
+	if (vardefexpr)
+		appendPQExpBuffer(query, " DEFAULT %s",
+						  vardefexpr);
+
+	if (strcmp(vareoxaction, "d") == 0)
+		appendPQExpBuffer(query, " ON COMMIT DROP");
+	else if (strcmp(vareoxaction, "r") == 0)
+		appendPQExpBuffer(query, " ON TRANSACTION END RESET");
+
+	appendPQExpBuffer(query, ";\n");
+
+	if (varinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, varinfo->dobj.catId, varinfo->dobj.dumpId,
+					 ARCHIVE_OPTS(.tag = varinfo->dobj.name,
+								  .namespace = varinfo->dobj.namespace->dobj.name,
+								  .owner = varinfo->rolname,
+								  .description = "VARIABLE",
+								  .section = SECTION_PRE_DATA,
+								  .createStmt = query->data,
+								  .dropStmt = delq->data));
+
+	if (varinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, "VARIABLE", varname,
+					NULL, varinfo->rolname,
+					varinfo->dobj.catId, 0, varinfo->dobj.dumpId);
+
+	destroyPQExpBuffer(delq);
+	destroyPQExpBuffer(query);
+}
+
 static void
 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
 										 PQExpBuffer upgrade_buffer,
@@ -10338,6 +10565,9 @@ dumpDumpableObject(Archive *fout, const DumpableObject *dobj)
 		case DO_SUBSCRIPTION:
 			dumpSubscription(fout, (const SubscriptionInfo *) dobj);
 			break;
+		case DO_VARIABLE:
+			dumpVariable(fout, (VariableInfo *) dobj);
+			break;
 		case DO_PRE_DATA_BOUNDARY:
 		case DO_POST_DATA_BOUNDARY:
 			/* never dumped, nothing to do */
@@ -18527,6 +18757,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
 			case DO_CONVERSION:
 			case DO_TABLE:
 			case DO_TABLE_ATTACH:
+			case DO_VARIABLE:
 			case DO_ATTRDEF:
 			case DO_PROCLANG:
 			case DO_CAST:
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index f9af14b793..17a1f90da8 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -52,6 +52,7 @@ typedef enum
 	DO_TABLE,
 	DO_TABLE_ATTACH,
 	DO_ATTRDEF,
+	DO_VARIABLE,
 	DO_INDEX,
 	DO_INDEX_ATTACH,
 	DO_STATSEXT,
@@ -659,6 +660,26 @@ typedef struct _SubscriptionInfo
 	char	   *subpublications;
 } SubscriptionInfo;
 
+/*
+ * The VariableInfo struct is used to represent schema variables
+ */
+typedef struct _VariableInfo
+{
+	DumpableObject dobj;
+	Oid			vartype;
+	char	   *vartypname;
+	char	   *rolname;		/* name of owner, or empty string */
+	char	   *vareoxaction;
+	char	   *vardefexpr;
+	char	   *varacl;
+	char	   *rvaracl;
+	char	   *initvaracl;
+	char	   *initrvaracl;
+	bool		varisnotnull;
+	bool		varisimmutable;
+}			VariableInfo;
+
+
 /*
  *	common utility functions
  */
@@ -741,5 +762,6 @@ extern void getPublicationNamespaces(Archive *fout);
 extern void getPublicationTables(Archive *fout, TableInfo tblinfo[],
 								 int numTables);
 extern void getSubscriptions(Archive *fout);
+extern void getVariables(Archive *fout);
 
 #endif							/* PG_DUMP_H */
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 9901d9e0ba..b49d5c6c62 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -66,6 +66,7 @@ enum dbObjectTypePriorities
 	PRIO_TABLE_ATTACH,
 	PRIO_DUMMY_TYPE,
 	PRIO_ATTRDEF,
+	PRIO_VARIABLE,
 	PRIO_BLOB,
 	PRIO_PRE_DATA_BOUNDARY,		/* boundary! */
 	PRIO_TABLE_DATA,
@@ -107,6 +108,7 @@ static const int dbObjectTypePriority[] =
 	PRIO_TABLE,					/* DO_TABLE */
 	PRIO_TABLE_ATTACH,			/* DO_TABLE_ATTACH */
 	PRIO_ATTRDEF,				/* DO_ATTRDEF */
+	PRIO_VARIABLE,				/* DO_VARIABLE */
 	PRIO_INDEX,					/* DO_INDEX */
 	PRIO_INDEX_ATTACH,			/* DO_INDEX_ATTACH */
 	PRIO_STATSEXT,				/* DO_STATSEXT */
@@ -1499,6 +1501,10 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
 					 "POST-DATA BOUNDARY  (ID %d)",
 					 obj->dumpId);
 			return;
+		case DO_VARIABLE:
+			snprintf(buf, bufsize,
+					 "VARIABLE %s  (ID %d OID %u)",
+					 obj->name, obj->dumpId, obj->catId.oid);
 	}
 	/* shouldn't get here */
 	snprintf(buf, bufsize,
diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
index 64aaa80eee..3f0af55d7d 100644
--- a/src/bin/pg_dump/pg_restore.c
+++ b/src/bin/pg_dump/pg_restore.c
@@ -102,6 +102,7 @@ main(int argc, char **argv)
 		{"trigger", 1, NULL, 'T'},
 		{"use-list", 1, NULL, 'L'},
 		{"username", 1, NULL, 'U'},
+		{"variable", 1, NULL, 'A'},
 		{"verbose", 0, NULL, 'v'},
 		{"single-transaction", 0, NULL, '1'},
 
@@ -149,7 +150,7 @@ main(int argc, char **argv)
 		}
 	}
 
-	while ((c = getopt_long(argc, argv, "acCd:ef:F:h:I:j:lL:n:N:Op:P:RsS:t:T:U:vwWx1",
+	while ((c = getopt_long(argc, argv, "A:acCd:ef:F:h:I:j:lL:n:N:Op:P:RsS:t:T:U:vwWx1",
 							cmdopts, NULL)) != -1)
 	{
 		switch (c)
@@ -157,6 +158,11 @@ main(int argc, char **argv)
 			case 'a':			/* Dump data only */
 				opts->dataOnly = 1;
 				break;
+			case 'A':			/* vAriable */
+				opts->selTypes = 1;
+				opts->selVariable = 1;
+				simple_string_list_append(&opts->variableNames, optarg);
+				break;
 			case 'c':			/* clean (i.e., drop) schema prior to create */
 				opts->dropSchema = 1;
 				break;
@@ -461,6 +467,7 @@ usage(const char *progname)
 
 	printf(_("\nOptions controlling the restore:\n"));
 	printf(_("  -a, --data-only              restore only the data, no schema\n"));
+	printf(_("  -A, --variable=NAME          restore named schema variable\n"));
 	printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
 	printf(_("  -C, --create                 create the target database\n"));
 	printf(_("  -e, --exit-on-error          exit on error, default is to continue\n"));
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index d293f52b05..1595dfc513 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -2995,6 +2995,30 @@ my %tests = (
 		},
 	},
 
+	'CREATE VARIABLE test_variable' => {
+		all_runs     => 1,
+		catch_all    => 'CREATE ... commands',
+		create_order => 61,
+		create_sql   => 'CREATE VARIABLE dump_test.variable1 AS integer DEFAULT 0;',
+		regexp => qr/^
+			\QCREATE VARIABLE dump_test.variable1 AS integer DEFAULT 0;\E/xm,
+		like =>
+		  { %full_runs, %dump_test_schema_runs, section_pre_data => 1, },
+		unlike => { exclude_dump_test_schema => 1, },
+	},
+
+	'CREATE IMMUTABLE VARIABLE test_variable' => {
+		all_runs     => 1,
+		catch_all    => 'CREATE ... commands',
+		create_order => 61,
+		create_sql   => 'CREATE IMMUTABLE VARIABLE dump_test.variable2 AS integer DEFAULT 0;',
+		regexp => qr/^
+			\QCREATE IMMUTABLE VARIABLE dump_test.variable2 AS integer DEFAULT 0;\E/xm,
+		like =>
+		  { %full_runs, %dump_test_schema_runs, section_pre_data => 1, },
+		unlike => { exclude_dump_test_schema => 1, },
+	},
+
 	'CREATE VIEW test_view' => {
 		create_order => 61,
 		create_sql   => 'CREATE VIEW dump_test.test_view
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 49d4c0e3ce..3841b7e3e4 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -929,6 +929,9 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
 						break;
 				}
 				break;
+			case 'V':			/* Variables */
+				success = listVariables(pattern, show_verbose);
+				break;
 			case 'x':			/* Extensions */
 				if (show_verbose)
 					success = listExtensionContents(pattern);
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 006661412e..625b63ddcd 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -5154,6 +5154,88 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
 	return true;
 }
 
+/*
+ * \dV
+ *
+ * listVariables()
+ */
+bool
+listVariables(const char *pattern, bool verbose)
+{
+	PQExpBufferData buf;
+	PGresult   *res;
+	printQueryOpt myopt = pset.popt;
+	static const bool translate_columns[] = {false, false, false, false, false, false, false, false};
+
+	initPQExpBuffer(&buf);
+
+	printfPQExpBuffer(&buf,
+					  "SELECT n.nspname as \"%s\",\n"
+					  "  v.varname as \"%s\",\n"
+					  "  pg_catalog.format_type(v.vartype, v.vartypmod) as \"%s\",\n"
+					  "  NOT v.varisnotnull as \"%s\",\n"
+					  "  NOT v.varisimmutable as \"%s\",\n"
+					  "  pg_catalog.pg_get_expr(v.vardefexpr, 0) as \"%s\",\n"
+					  "  pg_catalog.pg_get_userbyid(v.varowner) as \"%s\",\n"
+					  "  CASE v.vareoxaction\n"
+					  "    WHEN 'd' THEN 'ON COMMIT DROP'\n"
+					  "    WHEN 'r' THEN 'ON TRANSACTION END RESET' END as \"%s\"\n",
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Type"),
+					  gettext_noop("Is nullable"),
+					  gettext_noop("Is mutable"),
+					  gettext_noop("Default"),
+					  gettext_noop("Owner"),
+					  gettext_noop("Transactional end action"));
+
+	appendPQExpBufferStr(&buf,
+						 "\nFROM pg_catalog.pg_variable v"
+						 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = v.varnamespace");
+
+	appendPQExpBufferStr(&buf, "\nWHERE true\n");
+	if (!pattern)
+		appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+							 "      AND n.nspname <> 'information_schema'\n");
+
+	processSQLNamePattern(pset.db, &buf, pattern, true, false,
+						  "n.nspname", "v.varname", NULL,
+						  "pg_catalog.pg_variable_is_visible(v.oid)");
+
+	appendPQExpBufferStr(&buf, "ORDER BY 1,2;");
+
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+
+	/*
+	 * Most functions in this file are content to print an empty table when
+	 * there are no matching objects.  We intentionally deviate from that
+	 * here, but only in !quiet mode, for historical reasons.
+	 */
+	if (PQntuples(res) == 0 && !pset.quiet)
+	{
+		if (pattern)
+			pg_log_error("Did not find any schema variable named \"%s\".",
+						 pattern);
+		else
+			pg_log_error("Did not find any schema variables.");
+	}
+	else
+	{
+		myopt.nullPrint = NULL;
+		myopt.title = _("List of variables");
+		myopt.translate_header = true;
+		myopt.translate_columns = translate_columns;
+		myopt.n_translate_columns = lengthof(translate_columns);
+
+		printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+	}
+
+	PQclear(res);
+	return true;
+}
 
 /*
  * \dFp
diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h
index 71b320f1fc..a86fccc0d7 100644
--- a/src/bin/psql/describe.h
+++ b/src/bin/psql/describe.h
@@ -139,5 +139,7 @@ extern bool listOpFamilyOperators(const char *accessMethod_pattern,
 extern bool listOpFamilyFunctions(const char *access_method_pattern,
 								  const char *family_pattern, bool verbose);
 
+/* \dV */
+extern bool listVariables(const char *pattern, bool varbose);
 
 #endif							/* DESCRIBE_H */
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index db12a8b2f3..a6a3b2eba2 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -265,6 +265,7 @@ slashUsage(unsigned short int pager)
 	fprintf(output, _("  \\dT[S+] [PATTERN]      list data types\n"));
 	fprintf(output, _("  \\du[S+] [PATTERN]      list roles\n"));
 	fprintf(output, _("  \\dv[S+] [PATTERN]      list views\n"));
+	fprintf(output, _("  \\dV     [PATTERN]      list variables\n"));
 	fprintf(output, _("  \\dx[+]  [PATTERN]      list extensions\n"));
 	fprintf(output, _("  \\dX     [PATTERN]      list extended statistics\n"));
 	fprintf(output, _("  \\dy[+]  [PATTERN]      list event triggers\n"));
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 8e01f54500..7045be20bf 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -628,6 +628,13 @@ static const SchemaQuery Query_for_list_of_collations = {
 	.result = "pg_catalog.quote_ident(c.collname)",
 };
 
+static const SchemaQuery Query_for_list_of_variables = {
+	.min_server_version = 120000,
+	.catname = "pg_catalog.pg_variable v",
+	.viscondition = "pg_catalog.pg_variable_is_visible(v.oid)",
+	.namespace = "v.varnamespace",
+	.result = "pg_catalog.quote_ident(v.varname)",
+};
 
 /*
  * Queries to get lists of names of various kinds of things, possibly
@@ -1097,6 +1104,7 @@ static const pgsql_thing_t words_after_create[] = {
 																	 * TABLE ... */
 	{"USER", Query_for_list_of_roles " UNION SELECT 'MAPPING FOR'"},
 	{"USER MAPPING FOR", NULL, NULL, NULL},
+	{"VARIABLE", NULL, NULL, &Query_for_list_of_variables},
 	{"VIEW", NULL, NULL, &Query_for_list_of_views},
 	{NULL}						/* end of list */
 };
@@ -1495,8 +1503,8 @@ psql_completion(const char *text, int start, int end)
 		"ABORT", "ALTER", "ANALYZE", "BEGIN", "CALL", "CHECKPOINT", "CLOSE", "CLUSTER",
 		"COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
 		"DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN",
-		"FETCH", "GRANT", "IMPORT FOREIGN SCHEMA", "INSERT INTO", "LISTEN", "LOAD", "LOCK",
-		"MOVE", "NOTIFY", "PREPARE",
+		"FETCH", "GRANT", "IMPORT FOREIGN SCHEMA", "INSERT INTO", "LET", "LISTEN", "LOAD",
+		"LOCK", "MOVE", "NOTIFY", "PREPARE",
 		"REASSIGN", "REFRESH MATERIALIZED VIEW", "REINDEX", "RELEASE",
 		"RESET", "REVOKE", "ROLLBACK",
 		"SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
@@ -1515,7 +1523,7 @@ psql_completion(const char *text, int start, int end)
 		"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
 		"\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt",
 		"\\drds", "\\dRs", "\\dRp", "\\ds",
-		"\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dX", "\\dy",
+		"\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dX", "\\dy", "\\dV",
 		"\\echo", "\\edit", "\\ef", "\\elif", "\\else", "\\encoding",
 		"\\endif", "\\errverbose", "\\ev",
 		"\\f",
@@ -1926,6 +1934,9 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars);
 	else if (Matches("ALTER", "SYSTEM", "SET", MatchAny))
 		COMPLETE_WITH("TO");
+	/* ALTER VARIABLE <name> */
+	else if (Matches("ALTER", "VARIABLE", MatchAny))
+		COMPLETE_WITH("OWNER TO", "RENAME TO", "SET SCHEMA");
 	/* ALTER VIEW <name> */
 	else if (Matches("ALTER", "VIEW", MatchAny))
 		COMPLETE_WITH("ALTER COLUMN", "OWNER TO", "RENAME",
@@ -2780,7 +2791,7 @@ psql_completion(const char *text, int start, int end)
 /* CREATE TABLE --- is allowed inside CREATE SCHEMA, so use TailMatches */
 	/* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
 	else if (TailMatches("CREATE", "TEMP|TEMPORARY"))
-		COMPLETE_WITH("SEQUENCE", "TABLE", "VIEW");
+		COMPLETE_WITH("SEQUENCE", "TABLE", "VIEW", "VARIABLE");
 	/* Complete "CREATE UNLOGGED" with TABLE or MATVIEW */
 	else if (TailMatches("CREATE", "UNLOGGED"))
 		COMPLETE_WITH("TABLE", "MATERIALIZED VIEW");
@@ -3070,6 +3081,14 @@ psql_completion(const char *text, int start, int end)
 		else if (TailMatches("=", MatchAnyExcept("*)")))
 			COMPLETE_WITH(",", ")");
 	}
+/* CREATE VARIABLE --- is allowed inside CREATE SCHEMA, so use TailMatches */
+	/* Complete CREATE VARIABLE <name> with AS */
+	else if (TailMatches("CREATE", "VARIABLE", MatchAny) ||
+			 TailMatches("TEMP|TEMPORARY", "VARIABLE", MatchAny))
+			COMPLETE_WITH("AS");
+	else if (TailMatches("VARIABLE", MatchAny, "AS"))
+			/* Complete CREATE VARIABLE <name> with AS types */
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
 
 /* CREATE VIEW --- is allowed inside CREATE SCHEMA, so use TailMatches */
 	/* Complete CREATE [ OR REPLACE ] VIEW <name> with AS */
@@ -3184,7 +3203,7 @@ psql_completion(const char *text, int start, int end)
 
 /* DISCARD */
 	else if (Matches("DISCARD"))
-		COMPLETE_WITH("ALL", "PLANS", "SEQUENCES", "TEMP");
+		COMPLETE_WITH("ALL", "PLANS", "SEQUENCES", "TEMP", "VARIABLES");
 
 /* DO */
 	else if (Matches("DO"))
@@ -3290,6 +3309,12 @@ psql_completion(const char *text, int start, int end)
 	else if (Matches("DROP", "RULE", MatchAny, "ON", MatchAny))
 		COMPLETE_WITH("CASCADE", "RESTRICT");
 
+	/* DROP VARIABLE */
+	else if (Matches("DROP", "VARIABLE"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_variables, NULL);
+	else if (Matches("DROP", "VARIABLE", MatchAny))
+		COMPLETE_WITH("CASCADE", "RESTRICT");
+
 /* EXECUTE */
 	else if (Matches("EXECUTE"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_prepared_statements);
@@ -3462,6 +3487,7 @@ psql_completion(const char *text, int start, int end)
 									   " UNION SELECT 'ALL ROUTINES IN SCHEMA'"
 									   " UNION SELECT 'ALL SEQUENCES IN SCHEMA'"
 									   " UNION SELECT 'ALL TABLES IN SCHEMA'"
+									   " UNION SELECT 'ALL VARIABLES IN SCHEMA'"
 									   " UNION SELECT 'DATABASE'"
 									   " UNION SELECT 'DOMAIN'"
 									   " UNION SELECT 'FOREIGN DATA WRAPPER'"
@@ -3475,14 +3501,16 @@ psql_completion(const char *text, int start, int end)
 									   " UNION SELECT 'SEQUENCE'"
 									   " UNION SELECT 'TABLE'"
 									   " UNION SELECT 'TABLESPACE'"
-									   " UNION SELECT 'TYPE'");
+									   " UNION SELECT 'TYPE'"
+									   " UNION SELECT 'VARIABLE'");
 	}
 	else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "ALL"))
 		COMPLETE_WITH("FUNCTIONS IN SCHEMA",
 					  "PROCEDURES IN SCHEMA",
 					  "ROUTINES IN SCHEMA",
 					  "SEQUENCES IN SCHEMA",
-					  "TABLES IN SCHEMA");
+					  "TABLES IN SCHEMA",
+					  "VARIABLES IN SCHEMA");
 	else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN"))
 		COMPLETE_WITH("DATA WRAPPER", "SERVER");
 
@@ -3516,6 +3544,8 @@ psql_completion(const char *text, int start, int end)
 			COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
 		else if (TailMatches("TYPE"))
 			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes, NULL);
+		else if (TailMatches("VARIABLE"))
+			COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_variables, NULL);
 		else if (TailMatches("GRANT", MatchAny, MatchAny, MatchAny))
 			COMPLETE_WITH("TO");
 		else
@@ -3688,7 +3718,7 @@ psql_completion(const char *text, int start, int end)
 
 /* PREPARE xx AS */
 	else if (Matches("PREPARE", MatchAny, "AS"))
-		COMPLETE_WITH("SELECT", "UPDATE", "INSERT INTO", "DELETE FROM");
+		COMPLETE_WITH("SELECT", "UPDATE", "INSERT INTO", "DELETE FROM", "LET");
 
 /*
  * PREPARE TRANSACTION is missing on purpose. It's intended for transaction
@@ -3962,6 +3992,14 @@ psql_completion(const char *text, int start, int end)
 	else if (TailMatches("UPDATE", MatchAny, "SET", MatchAnyExcept("*=")))
 		COMPLETE_WITH("=");
 
+/* LET --- can be inside EXPLAIN, PREPARE etc */
+	/* If prev. word is LET suggest a list of variables */
+	else if (TailMatches("LET"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_variables, NULL);
+	/* Complete LET <variable> with "=" */
+	else if (TailMatches("LET", MatchAny))
+		COMPLETE_WITH("=");
+
 /* USER MAPPING */
 	else if (Matches("ALTER|CREATE|DROP", "USER", "MAPPING"))
 		COMPLETE_WITH("FOR");
@@ -4126,6 +4164,8 @@ psql_completion(const char *text, int start, int end)
 		COMPLETE_WITH_QUERY(Query_for_list_of_roles);
 	else if (TailMatchesCS("\\dv*"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views, NULL);
+	else if (TailMatchesCS("\\dV*"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_variables, NULL);
 	else if (TailMatchesCS("\\dx*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_extensions);
 	else if (TailMatchesCS("\\dX*"))
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index 3eca295ff4..347008a606 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -125,10 +125,11 @@ typedef enum ObjectClass
 	OCLASS_PUBLICATION_NAMESPACE,	/* pg_publication_namespace */
 	OCLASS_PUBLICATION_REL,		/* pg_publication_rel */
 	OCLASS_SUBSCRIPTION,		/* pg_subscription */
-	OCLASS_TRANSFORM			/* pg_transform */
+	OCLASS_TRANSFORM,			/* pg_transform */
+	OCLASS_VARIABLE				/* pg_variable */
 } ObjectClass;
 
-#define LAST_OCLASS		OCLASS_TRANSFORM
+#define LAST_OCLASS		OCLASS_VARIABLE
 
 /* flag bits for performDeletion/performMultipleDeletions: */
 #define PERFORM_DELETION_INTERNAL			0x0001	/* internal action */
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index b98f284356..7058b1acb6 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -96,6 +96,8 @@ extern Oid	TypenameGetTypid(const char *typname);
 extern Oid	TypenameGetTypidExtended(const char *typname, bool temp_ok);
 extern bool TypeIsVisible(Oid typid);
 
+extern bool VariableIsVisible(Oid varid);
+
 extern FuncCandidateList FuncnameGetCandidates(List *names,
 											   int nargs, List *argnames,
 											   bool expand_variadic,
@@ -164,6 +166,10 @@ extern void SetTempNamespaceState(Oid tempNamespaceId,
 								  Oid tempToastNamespaceId);
 extern void ResetTempTableNamespace(void);
 
+extern List *NamesFromList(List *names);
+extern Oid	LookupVariable(const char *nspname, const char *varname, bool missing_ok);
+extern Oid	IdentifyVariable(List *names, char **attrname, bool *not_uniq);
+
 extern OverrideSearchPath *GetOverrideSearchPath(MemoryContext context);
 extern OverrideSearchPath *CopyOverrideSearchPath(OverrideSearchPath *path);
 extern bool OverrideSearchPathMatchesCurrent(OverrideSearchPath *path);
diff --git a/src/include/catalog/pg_default_acl.h b/src/include/catalog/pg_default_acl.h
index eb72dd6293..2ca72a0dcd 100644
--- a/src/include/catalog/pg_default_acl.h
+++ b/src/include/catalog/pg_default_acl.h
@@ -66,6 +66,7 @@ DECLARE_UNIQUE_INDEX_PKEY(pg_default_acl_oid_index, 828, DefaultAclOidIndexId, o
 #define DEFACLOBJ_FUNCTION		'f' /* function */
 #define DEFACLOBJ_TYPE			'T' /* type */
 #define DEFACLOBJ_NAMESPACE		'n' /* namespace */
+#define DEFACLOBJ_VARIABLE		'V' /* variable */
 
 #endif							/* EXPOSE_TO_CLIENT_CODE */
 
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index d068d6532e..28d1f9af17 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6242,6 +6242,9 @@
   proname => 'pg_collation_is_visible', procost => '10', provolatile => 's',
   prorettype => 'bool', proargtypes => 'oid',
   prosrc => 'pg_collation_is_visible' },
+{ oid => '9221', descr => 'is schema variable visible in search path?',
+  proname => 'pg_variable_is_visible', procost => '10', provolatile => 's',
+  prorettype => 'bool', proargtypes => 'oid', prosrc => 'pg_variable_is_visible' },
 
 { oid => '2854', descr => 'get OID of current session\'s temp schema, if any',
   proname => 'pg_my_temp_schema', provolatile => 's', proparallel => 'r',
diff --git a/src/include/catalog/pg_variable.h b/src/include/catalog/pg_variable.h
new file mode 100644
index 0000000000..7e53880a3c
--- /dev/null
+++ b/src/include/catalog/pg_variable.h
@@ -0,0 +1,117 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_variable.h
+ *	  definition of schema variables system catalog (pg_variables)
+ *
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/catalog/pg_variable.h
+ *
+ * NOTES
+ *	  The Catalog.pm module reads this file and derives schema
+ *	  information.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_VARIABLE_H
+#define PG_VARIABLE_H
+
+#include "catalog/genbki.h"
+#include "catalog/objectaddress.h"
+#include "catalog/pg_variable_d.h"
+#include "utils/acl.h"
+
+/* ----------------
+ *		pg_variable definition.  cpp turns this into
+ *		typedef struct FormData_pg_variable
+ * ----------------
+ */
+CATALOG(pg_variable,9222,VariableRelationId)
+{
+	Oid			oid;			/* oid */
+	NameData	varname;		/* variable name */
+	Oid			varnamespace;	/* OID of namespace containing variable class */
+	Oid			vartype;		/* OID of entry in pg_type for variable's type */
+	int32		vartypmod;		/* typmode for variable's type */
+	Oid			varowner;		/* class owner */
+	Oid			varcollation;	/* variable collation */
+	bool		varisnotnull;	/* Don't allow NULL */
+	bool		varisimmutable;	/* Don't allow changes */
+	char		vareoxaction;	/* action on transaction end */
+
+#ifdef CATALOG_VARLEN			/* variable-length fields start here */
+
+	/* list of expression trees for variable default (NULL if none) */
+	pg_node_tree vardefexpr BKI_DEFAULT(_null_);
+
+	aclitem		varacl[1] BKI_DEFAULT(_null_);	/* access permissions */
+
+#endif
+} FormData_pg_variable;
+
+typedef enum VariableEOXActionCodes
+{
+	VARIABLE_EOX_CODE_NOOP = 'n',	/* NOOP */
+	VARIABLE_EOX_CODE_DROP = 'd',	/* ON COMMIT DROP */
+	VARIABLE_EOX_CODE_RESET = 'r',	/* ON COMMIT RESET */
+}			VariableEOXActionCodes;
+
+/* ----------------
+ *		Form_pg_variable corresponds to a pointer to a tuple with
+ *		the format of pg_variable relation.
+ * ----------------
+ */
+typedef FormData_pg_variable * Form_pg_variable;
+
+DECLARE_UNIQUE_INDEX_PKEY(pg_variable_oid_index, 9223, VariableOidIndexId, on pg_variable using btree(oid oid_ops));
+#define VariableObjectIndexId 9223
+
+DECLARE_UNIQUE_INDEX(pg_variable_varname_nsp_index, 9224, VariableNameNspIndexId,  on pg_variable using btree(varname name_ops, varnamespace oid_ops));
+#define VariableNameNspIndexId  9224
+
+typedef struct Variable
+{
+	Oid			oid;
+	char	   *name;
+	Oid			namespace;
+	Oid			typid;
+	int32		typmod;
+	Oid			owner;
+	Oid			collation;
+	bool		is_not_null;
+	bool		is_immutable;
+	VariableEOXAction eoxaction;
+	bool		has_defexpr;
+	Node	   *defexpr;
+	Acl		   *acl;
+} Variable;
+
+/* returns fields from pg_variable table */
+extern char *get_schema_variable_name(Oid varid);
+extern void get_schema_variable_type_typmod_collid(Oid varid,
+												   Oid *typid,
+												   int32 *typmod,
+												   Oid *collid);
+
+/* returns name of variable based on current search path */
+extern char *schema_variable_get_name(Oid varid);
+
+extern void initVariable(Variable *var,
+						 Oid varid,
+						 bool missing_ok,
+						 bool fast_only);
+extern ObjectAddress VariableCreate(const char *varName,
+									Oid varNamespace,
+									Oid varType,
+									int32 varTypmod,
+									Oid varOwner,
+									Oid varCollation,
+									Node *varDefexpr,
+									VariableEOXAction eoxaction,
+									bool is_not_null,
+									bool if_not_exists,
+									bool is_immutable);
+
+#endif							/* PG_VARIABLE_H */
diff --git a/src/include/commands/schema_variable.h b/src/include/commands/schema_variable.h
new file mode 100644
index 0000000000..5350829669
--- /dev/null
+++ b/src/include/commands/schema_variable.h
@@ -0,0 +1,44 @@
+/*-------------------------------------------------------------------------
+ *
+ * schemavariable.h
+ *	  prototypes for schemavariable.c.
+ *
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/commands/schemavariable.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef SCHEMAVARIABLE_H
+#define SCHEMAVARIABLE_H
+
+#include "catalog/objectaddress.h"
+#include "catalog/pg_variable.h"
+#include "nodes/params.h"
+#include "nodes/parsenodes.h"
+#include "nodes/plannodes.h"
+#include "tcop/cmdtag.h"
+#include "utils/queryenvironment.h"
+
+extern void ResetSchemaVariableCache(void);
+
+extern void RemoveSchemaVariable(Oid varid);
+extern ObjectAddress DefineSchemaVariable(ParseState *pstate, CreateSchemaVarStmt * stmt);
+
+extern Datum GetSchemaVariable(Oid varid, bool *isNull, Oid expected_typid, bool copy);
+extern Datum CopySchemaVariable(Oid varid, bool *isNull, Oid *typid);
+extern void SetSchemaVariable(Oid varid, Datum value, bool isNull, Oid typid);
+extern void SetSchemaVariableWithSecurityCheck(Oid varid, Datum value, bool isNull, Oid typid);
+
+extern void ExecuteLetStmt(ParseState *pstate, LetStmt *stmt, ParamListInfo params,
+						   QueryEnvironment *queryEnv, QueryCompletion *qc);
+
+extern void register_variable_on_commit_action(Oid varid, VariableEOXAction action);
+
+extern void AtPreEOXact_SchemaVariable_on_commit_actions(bool isCommit);
+extern void AtEOXact_SchemaVariable_on_commit_actions(bool isCommit);
+
+#endif
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index 6a24341faa..123a18f298 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -158,6 +158,7 @@ typedef enum ExprEvalOp
 	EEOP_PARAM_EXEC,
 	EEOP_PARAM_EXTERN,
 	EEOP_PARAM_CALLBACK,
+	EEOP_PARAM_VARIABLE,
 
 	/* return CaseTestExpr value */
 	EEOP_CASE_TESTVAL,
@@ -380,6 +381,13 @@ typedef struct ExprEvalStep
 			Oid			paramtype;	/* OID of parameter's datatype */
 		}			param;
 
+		/* for EEOP_PARAM_VARIABLE */
+		struct
+		{
+			Oid			varid;	/* OID of assigned variable */
+			Oid			vartype;	/* OID of parameter's datatype */
+		}			vparam;
+
 		/* for EEOP_PARAM_CALLBACK */
 		struct
 		{
@@ -736,6 +744,8 @@ extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op,
 							  ExprContext *econtext);
 extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
 								ExprContext *econtext);
+extern void ExecEvalParamVariable(ExprState *state, ExprEvalStep *op,
+								  ExprContext *econtext);
 extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
 extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
 extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
diff --git a/src/include/executor/execdesc.h b/src/include/executor/execdesc.h
index 017ad87117..c85e7ee89d 100644
--- a/src/include/executor/execdesc.h
+++ b/src/include/executor/execdesc.h
@@ -48,6 +48,10 @@ typedef struct QueryDesc
 	EState	   *estate;			/* executor's query-wide state */
 	PlanState  *planstate;		/* tree of per-plan-node state */
 
+	/* reference to schema variables buffer */
+	int			num_schema_variables;
+	SchemaVariableValue *schema_variables;
+
 	/* This field is set by ExecutorRun */
 	bool		already_executed;	/* true if previously executed */
 
diff --git a/src/include/executor/svariableReceiver.h b/src/include/executor/svariableReceiver.h
new file mode 100644
index 0000000000..5305936547
--- /dev/null
+++ b/src/include/executor/svariableReceiver.h
@@ -0,0 +1,25 @@
+/*-------------------------------------------------------------------------
+ *
+ * svariableReceiver.h
+ *	  prototypes for svariableReceiver.c
+ *
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/executor/svariableReceiver.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef SVARIABLE_RECEIVER_H
+#define SVARIABLE_RECEIVER_H
+
+#include "tcop/dest.h"
+
+
+extern DestReceiver *CreateVariableDestReceiver(void);
+
+extern void SetVariableDestReceiverParams(DestReceiver *self, Oid varid);
+
+#endif							/* SVARIABLE_RECEIVER_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 2e8cbee69f..e0776ac489 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -544,6 +544,18 @@ typedef struct AsyncRequest
 								 * tuples) */
 } AsyncRequest;
 
+/* ----------------
+ * SchemaVariableValue
+ * ----------------
+ */
+typedef struct SchemaVariableValue
+{
+	Oid			varid;
+	Oid			typid;
+	bool		isnull;
+	Datum		value;
+}			SchemaVariableValue;
+
 /* ----------------
  *	  EState information
  *
@@ -595,6 +607,13 @@ typedef struct EState
 	ParamListInfo es_param_list_info;	/* values of external params */
 	ParamExecData *es_param_exec_vals;	/* values of internal params */
 
+	/* Variables info: */
+	/* number of used schema variables */
+	int			es_num_schema_variables;
+
+	/* array of copied values of schema variables */
+	SchemaVariableValue *es_schema_variables;
+
 	QueryEnvironment *es_queryEnv;	/* query environment */
 
 	/* Other working state: */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 7c657c1241..14bbe45624 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -355,6 +355,7 @@ typedef enum NodeTag
 	T_CreateTableAsStmt,
 	T_CreateSeqStmt,
 	T_AlterSeqStmt,
+	T_CreateSchemaVarStmt,
 	T_VariableSetStmt,
 	T_VariableShowStmt,
 	T_DiscardStmt,
@@ -428,6 +429,7 @@ typedef enum NodeTag
 	T_AlterCollationStmt,
 	T_CallStmt,
 	T_AlterStatsStmt,
+	T_LetStmt,
 
 	/*
 	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 49123e28a4..795bbc1170 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -92,7 +92,9 @@ typedef uint32 AclMode;			/* a bitmask of privilege bits */
 #define ACL_CREATE		(1<<9)	/* for namespaces and databases */
 #define ACL_CREATE_TEMP (1<<10) /* for databases */
 #define ACL_CONNECT		(1<<11) /* for databases */
-#define N_ACL_RIGHTS	12		/* 1 plus the last 1<<x */
+#define ACL_READ		(1<<12) /* for variables */
+#define ACL_WRITE		(1<<13) /* for variables */
+#define N_ACL_RIGHTS	14		/* 1 plus the last 1<<x */
 #define ACL_NO_RIGHTS	0
 /* Currently, SELECT ... FOR [KEY] UPDATE/SHARE requires UPDATE privileges */
 #define ACL_SELECT_FOR_UPDATE	ACL_UPDATE
@@ -129,7 +131,7 @@ typedef struct Query
 
 	int			resultRelation; /* rtable index of target relation for
 								 * INSERT/UPDATE/DELETE; 0 for SELECT */
-
+	Oid			resultVariable;	/* target variable of LET statement */
 	bool		hasAggs;		/* has aggregates in tlist or havingQual */
 	bool		hasWindowFuncs; /* has window functions in tlist */
 	bool		hasTargetSRFs;	/* has set-returning functions in tlist */
@@ -139,6 +141,7 @@ typedef struct Query
 	bool		hasModifyingCTE;	/* has INSERT/UPDATE/DELETE in WITH */
 	bool		hasForUpdate;	/* FOR [KEY] UPDATE/SHARE was specified */
 	bool		hasRowSecurity; /* rewriter has applied some RLS policy */
+	bool		hasSchemaVariables;	/* uses schema variables */
 
 	bool		isReturn;		/* is a RETURN statement */
 
@@ -1627,6 +1630,20 @@ typedef struct UpdateStmt
 	WithClause *withClause;		/* WITH clause */
 } UpdateStmt;
 
+/* ----------------------
+ *		Let Statement
+ * ----------------------
+ */
+typedef struct LetStmt
+{
+	NodeTag		type;
+	List	   *target;			/* target variable */
+	Node	   *query;			/* source expression */
+	bool		plpgsql_mode;	/* true, when command will be executed (parsed)
+								 * by plpgsql runtime */
+	int			location;
+}			LetStmt;
+
 /* ----------------------
  *		Select Statement
  *
@@ -1836,6 +1853,7 @@ typedef enum ObjectType
 	OBJECT_TSTEMPLATE,
 	OBJECT_TYPE,
 	OBJECT_USER_MAPPING,
+	OBJECT_VARIABLE,
 	OBJECT_VIEW
 } ObjectType;
 
@@ -2671,6 +2689,23 @@ typedef struct AlterSeqStmt
 	bool		missing_ok;		/* skip error if a role is missing? */
 } AlterSeqStmt;
 
+/* ----------------------
+ *		{Create|Alter} VARIABLE Statement
+ * ----------------------
+ */
+typedef struct CreateSchemaVarStmt
+{
+	NodeTag		type;
+	RangeVar   *variable;		/* the variable to create */
+	TypeName   *typeName;		/* the type of variable */
+	CollateClause *collClause;
+	Node	   *defexpr;		/* default expression */
+	VariableEOXAction eoxaction;	/* on commit action */
+	bool		if_not_exists;	/* do nothing if it already exists */
+	bool		is_not_null;	/* Disallow nulls */
+	bool		is_immutable;	/* Don't allow changes */
+}			CreateSchemaVarStmt;
+
 /* ----------------------
  *		Create {Aggregate|Operator|Type} Statement
  * ----------------------
@@ -3444,7 +3479,8 @@ typedef enum DiscardMode
 	DISCARD_ALL,
 	DISCARD_PLANS,
 	DISCARD_SEQUENCES,
-	DISCARD_TEMP
+	DISCARD_TEMP,
+	DISCARD_VARIABLES
 } DiscardMode;
 
 typedef struct DiscardStmt
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 884bda7232..a2d3fa5b4b 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -130,6 +130,8 @@ typedef struct PlannerGlobal
 	char		maxParallelHazard;	/* worst PROPARALLEL hazard level */
 
 	PartitionDirectory partition_directory; /* partition descriptors */
+
+	List	   *schemaVariables;	/* list of used schema variables */
 } PlannerGlobal;
 
 /* macro for fetching the Plan associated with a SubPlan node */
@@ -350,6 +352,7 @@ struct PlannerInfo
 										 * pseudoconstant = true */
 	bool		hasAlternativeSubPlans; /* true if we've made any of those */
 	bool		hasRecursion;	/* true if planning a recursive WITH item */
+	bool		hasSchemaVariables;	/* true if schema variables was used */
 
 	/*
 	 * Information about aggregates. Filled by preprocess_aggrefs().
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 01a246d50e..c9eafd6fcf 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -43,7 +43,7 @@ typedef struct PlannedStmt
 {
 	NodeTag		type;
 
-	CmdType		commandType;	/* select|insert|update|delete|utility */
+	CmdType		commandType;	/* select|let|insert|update|delete|utility */
 
 	uint64		queryId;		/* query identifier (copied from Query) */
 
@@ -85,6 +85,8 @@ typedef struct PlannedStmt
 
 	Node	   *utilityStmt;	/* non-null if this is utility stmt */
 
+	List	   *schemaVariables;	/* list of OIDs for PARAM_VARIABLE Params */
+
 	/* statement location in source string (copied from Query) */
 	int			stmt_location;	/* start location, or -1 if unknown */
 	int			stmt_len;		/* length in bytes; 0 means "rest of string" */
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 433437643e..dc7c2008b0 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -43,7 +43,10 @@ typedef struct Alias
 	List	   *colnames;		/* optional list of column aliases */
 } Alias;
 
-/* What to do at commit time for temporary relations */
+/*
+ * What to do at commit time for temporary relations or
+ * persistent/temporary variable.
+ */
 typedef enum OnCommitAction
 {
 	ONCOMMIT_NOOP,				/* No ON COMMIT clause (do nothing) */
@@ -52,6 +55,13 @@ typedef enum OnCommitAction
 	ONCOMMIT_DROP				/* ON COMMIT DROP */
 } OnCommitAction;
 
+typedef enum VariableEOXAction
+{
+	VARIABLE_EOX_NOOP,			/* Do nothing */
+	VARIABLE_EOX_DROP,			/* ON TRANSACTION END DROP */
+	VARIABLE_EOX_RESET			/* ON TRANSACTION END RESET */
+}			VariableEOXAction;
+
 /*
  * RangeVar - range variable, used in FROM clauses
  *
@@ -252,13 +262,17 @@ typedef struct Const
  *				of the `paramid' field contain the SubLink's subLinkId, and
  *				the low-order 16 bits contain the column number.  (This type
  *				of Param is also converted to PARAM_EXEC during planning.)
+ *
+ *		PARAM_VARIABLE:  The parameter is a access to schema variable
+ *				paramid holds varid.
  */
 typedef enum ParamKind
 {
 	PARAM_EXTERN,
 	PARAM_EXEC,
 	PARAM_SUBLINK,
-	PARAM_MULTIEXPR
+	PARAM_MULTIEXPR,
+	PARAM_VARIABLE
 } ParamKind;
 
 typedef struct Param
@@ -269,6 +283,7 @@ typedef struct Param
 	Oid			paramtype;		/* pg_type OID of parameter's datatype */
 	int32		paramtypmod;	/* typmod value, if known */
 	Oid			paramcollid;	/* OID of collation, or InvalidOid if none */
+	Oid			paramvarid;		/* OID of schema variable if it is used */
 	int			location;		/* token location, or -1 if unknown */
 } Param;
 
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index bf1adfc52a..4cbcbeba10 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -116,4 +116,6 @@ extern void record_plan_function_dependency(PlannerInfo *root, Oid funcid);
 extern void record_plan_type_dependency(PlannerInfo *root, Oid typid);
 extern bool extract_query_dependencies_walker(Node *node, PlannerInfo *root);
 
+extern void pull_up_has_schema_variables(PlannerInfo *root);
+
 #endif							/* PLANMAIN_H */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index f836acf876..82f3bd2eb0 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -237,6 +237,7 @@ PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, BARE_LABEL)
 PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("let", LET, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
 PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, AS_LABEL)
@@ -450,6 +451,8 @@ PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, BARE_LABEL)
 PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, BARE_LABEL)
+PG_KEYWORD("variable", VARIABLE, UNRESERVED_KEYWORD, BARE_LABEL)
+PG_KEYWORD("variables", VARIABLES, UNRESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, BARE_LABEL)
 PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, AS_LABEL)
 PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL)
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index ee179082ce..aad0953ddb 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -80,6 +80,8 @@ typedef enum ParseExprKind
 	EXPR_KIND_COPY_WHERE,		/* WHERE condition in COPY FROM */
 	EXPR_KIND_GENERATED_COLUMN, /* generation expression for a column */
 	EXPR_KIND_CYCLE_MARK,		/* cycle mark value */
+	EXPR_KIND_VARIABLE_DEFAULT, /* default value for schema variable */
+	EXPR_KIND_LET_TARGET		/* LET assignment (should be same like UPDATE) */
 } ParseExprKind;
 
 
@@ -210,6 +212,7 @@ struct ParseState
 	bool		p_hasTargetSRFs;
 	bool		p_hasSubLinks;
 	bool		p_hasModifyingCTE;
+	bool		p_hasSchemaVariables;
 
 	Node	   *p_last_srf;		/* most recent set-returning func/op found */
 
diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h
index 853b0f1606..587112e526 100644
--- a/src/include/parser/parser.h
+++ b/src/include/parser/parser.h
@@ -33,6 +33,9 @@
  * RAW_PARSE_PLPGSQL_ASSIGNn: parse a PL/pgSQL assignment statement,
  * and return a one-element List containing a RawStmt node.  "n"
  * gives the number of dotted names comprising the target ColumnRef.
+ *
+ * RAW_PARSE_PLPGSQL_LET: parse a LET statement, and return a
+ * one-element List containing a RawStmt node.
  */
 typedef enum
 {
@@ -41,7 +44,8 @@ typedef enum
 	RAW_PARSE_PLPGSQL_EXPR,
 	RAW_PARSE_PLPGSQL_ASSIGN1,
 	RAW_PARSE_PLPGSQL_ASSIGN2,
-	RAW_PARSE_PLPGSQL_ASSIGN3
+	RAW_PARSE_PLPGSQL_ASSIGN3,
+	RAW_PARSE_PLPGSQL_LET
 } RawParseMode;
 
 /* Values for the backslash_quote GUC */
diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h
index 9ba24d4ca9..8a81e62849 100644
--- a/src/include/tcop/cmdtaglist.h
+++ b/src/include/tcop/cmdtaglist.h
@@ -68,6 +68,7 @@ PG_CMDTAG(CMDTAG_ALTER_TRANSFORM, "ALTER TRANSFORM", true, false, false)
 PG_CMDTAG(CMDTAG_ALTER_TRIGGER, "ALTER TRIGGER", true, false, false)
 PG_CMDTAG(CMDTAG_ALTER_TYPE, "ALTER TYPE", true, true, false)
 PG_CMDTAG(CMDTAG_ALTER_USER_MAPPING, "ALTER USER MAPPING", true, false, false)
+PG_CMDTAG(CMDTAG_ALTER_VARIABLE, "ALTER VARIABLE", true, false, false)
 PG_CMDTAG(CMDTAG_ALTER_VIEW, "ALTER VIEW", true, false, false)
 PG_CMDTAG(CMDTAG_ANALYZE, "ANALYZE", false, false, false)
 PG_CMDTAG(CMDTAG_BEGIN, "BEGIN", false, false, false)
@@ -123,6 +124,7 @@ PG_CMDTAG(CMDTAG_CREATE_TRANSFORM, "CREATE TRANSFORM", true, false, false)
 PG_CMDTAG(CMDTAG_CREATE_TRIGGER, "CREATE TRIGGER", true, false, false)
 PG_CMDTAG(CMDTAG_CREATE_TYPE, "CREATE TYPE", true, false, false)
 PG_CMDTAG(CMDTAG_CREATE_USER_MAPPING, "CREATE USER MAPPING", true, false, false)
+PG_CMDTAG(CMDTAG_CREATE_VARIABLE, "CREATE VARIABLE", true, false, false)
 PG_CMDTAG(CMDTAG_CREATE_VIEW, "CREATE VIEW", true, false, false)
 PG_CMDTAG(CMDTAG_DEALLOCATE, "DEALLOCATE", false, false, false)
 PG_CMDTAG(CMDTAG_DEALLOCATE_ALL, "DEALLOCATE ALL", false, false, false)
@@ -133,6 +135,7 @@ PG_CMDTAG(CMDTAG_DISCARD_ALL, "DISCARD ALL", false, false, false)
 PG_CMDTAG(CMDTAG_DISCARD_PLANS, "DISCARD PLANS", false, false, false)
 PG_CMDTAG(CMDTAG_DISCARD_SEQUENCES, "DISCARD SEQUENCES", false, false, false)
 PG_CMDTAG(CMDTAG_DISCARD_TEMP, "DISCARD TEMP", false, false, false)
+PG_CMDTAG(CMDTAG_DISCARD_VARIABLES, "DISCARD VARIABLES", false, false, false)
 PG_CMDTAG(CMDTAG_DO, "DO", false, false, false)
 PG_CMDTAG(CMDTAG_DROP_ACCESS_METHOD, "DROP ACCESS METHOD", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_AGGREGATE, "DROP AGGREGATE", true, false, false)
@@ -175,6 +178,7 @@ PG_CMDTAG(CMDTAG_DROP_TRANSFORM, "DROP TRANSFORM", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_TRIGGER, "DROP TRIGGER", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_TYPE, "DROP TYPE", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_USER_MAPPING, "DROP USER MAPPING", true, false, false)
+PG_CMDTAG(CMDTAG_DROP_VARIABLE, "DROP VARIABLE", true, false, false)
 PG_CMDTAG(CMDTAG_DROP_VIEW, "DROP VIEW", true, false, false)
 PG_CMDTAG(CMDTAG_EXECUTE, "EXECUTE", false, false, false)
 PG_CMDTAG(CMDTAG_EXPLAIN, "EXPLAIN", false, false, false)
@@ -183,6 +187,7 @@ PG_CMDTAG(CMDTAG_GRANT, "GRANT", true, false, false)
 PG_CMDTAG(CMDTAG_GRANT_ROLE, "GRANT ROLE", false, false, false)
 PG_CMDTAG(CMDTAG_IMPORT_FOREIGN_SCHEMA, "IMPORT FOREIGN SCHEMA", true, false, false)
 PG_CMDTAG(CMDTAG_INSERT, "INSERT", false, false, true)
+PG_CMDTAG(CMDTAG_LET, "LET", false, false, false)
 PG_CMDTAG(CMDTAG_LISTEN, "LISTEN", false, false, false)
 PG_CMDTAG(CMDTAG_LOAD, "LOAD", false, false, false)
 PG_CMDTAG(CMDTAG_LOCK_TABLE, "LOCK TABLE", false, false, false)
diff --git a/src/include/tcop/dest.h b/src/include/tcop/dest.h
index 88a7e59de5..e2f348eb33 100644
--- a/src/include/tcop/dest.h
+++ b/src/include/tcop/dest.h
@@ -97,7 +97,8 @@ typedef enum
 	DestCopyOut,				/* results sent to COPY TO code */
 	DestSQLFunction,			/* results sent to SQL-language func mgr */
 	DestTransientRel,			/* results sent to transient relation */
-	DestTupleQueue				/* results sent to tuple queue */
+	DestTupleQueue,				/* results sent to tuple queue */
+	DestVariable				/* results sents to schema variable */
 } CommandDest;
 
 /* ----------------
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index af771c901d..84f670d7f4 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -146,9 +146,11 @@ typedef struct ArrayType Acl;
 #define ACL_CREATE_CHR			'C'
 #define ACL_CREATE_TEMP_CHR		'T'
 #define ACL_CONNECT_CHR			'c'
+#define ACL_READ_CHR			'S' /* 'R' is occupated by old RULE priv */
+#define ACL_WRITE_CHR			'W'
 
 /* string holding all privilege code chars, in order by bitmask position */
-#define ACL_ALL_RIGHTS_STR	"arwdDxtXUCTc"
+#define ACL_ALL_RIGHTS_STR	"arwdDxtXUCTcSW"
 
 /*
  * Bitmasks defining "all rights" for each supported object type
@@ -165,6 +167,7 @@ typedef struct ArrayType Acl;
 #define ACL_ALL_RIGHTS_SCHEMA		(ACL_USAGE|ACL_CREATE)
 #define ACL_ALL_RIGHTS_TABLESPACE	(ACL_CREATE)
 #define ACL_ALL_RIGHTS_TYPE			(ACL_USAGE)
+#define ACL_ALL_RIGHTS_VARIABLE		(ACL_READ|ACL_WRITE)
 
 /* operation codes for pg_*_aclmask */
 typedef enum
@@ -259,7 +262,8 @@ extern AclMode pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
 										 AclMode mask, AclMaskHow how);
 extern AclMode pg_type_aclmask(Oid type_oid, Oid roleid,
 							   AclMode mask, AclMaskHow how);
-
+extern AclMode pg_variable_aclmask(Oid var_oid, Oid roleid,
+								   AclMode mask, AclMaskHow how);
 extern AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
 									   Oid roleid, AclMode mode);
 extern AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
@@ -280,6 +284,7 @@ extern AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode);
 extern AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode);
 extern AclResult pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode);
 extern AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode);
+extern AclResult pg_variable_aclcheck(Oid type_oid, Oid roleid, AclMode mode);
 
 extern void aclcheck_error(AclResult aclerr, ObjectType objtype,
 						   const char *objectname);
@@ -316,6 +321,7 @@ extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid);
 extern bool pg_publication_ownercheck(Oid pub_oid, Oid roleid);
 extern bool pg_subscription_ownercheck(Oid sub_oid, Oid roleid);
 extern bool pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid);
+extern bool pg_variable_ownercheck(Oid stat_oid, Oid roleid);
 extern bool has_createrole_privilege(Oid roleid);
 extern bool has_bypassrls_privilege(Oid roleid);
 
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 77871aaefc..af645a6818 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -132,6 +132,7 @@ extern char get_func_prokind(Oid funcid);
 extern bool get_func_leakproof(Oid funcid);
 extern RegProcedure get_func_support(Oid funcid);
 extern Oid	get_relname_relid(const char *relname, Oid relnamespace);
+extern Oid	get_varname_varid(const char *varname, Oid varnamespace);
 extern char *get_rel_name(Oid relid);
 extern Oid	get_rel_namespace(Oid relid);
 extern Oid	get_rel_type_id(Oid relid);
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index c8cfbc30f6..d6f8611482 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -111,9 +111,11 @@ enum SysCacheIdentifier
 	TYPENAMENSP,
 	TYPEOID,
 	USERMAPPINGOID,
-	USERMAPPINGUSERSERVER
+	USERMAPPINGUSERSERVER,
+	VARIABLENAMENSP,
+	VARIABLEOID
 
-#define SysCacheSize (USERMAPPINGUSERSERVER + 1)
+#define SysCacheSize (VARIABLEOID + 1)
 };
 
 extern void InitCatalogCache(void);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 6dbfdb7be0..ab9a3c99a7 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -24,6 +24,7 @@
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
+#include "commands/schema_variable.h"
 #include "executor/execExpr.h"
 #include "executor/spi.h"
 #include "executor/tstoreReceiver.h"
@@ -318,6 +319,8 @@ static int	exec_stmt_commit(PLpgSQL_execstate *estate,
 							 PLpgSQL_stmt_commit *stmt);
 static int	exec_stmt_rollback(PLpgSQL_execstate *estate,
 							   PLpgSQL_stmt_rollback *stmt);
+static int	exec_stmt_let(PLpgSQL_execstate *estate,
+						  PLpgSQL_stmt_let *let);
 
 static void plpgsql_estate_setup(PLpgSQL_execstate *estate,
 								 PLpgSQL_function *func,
@@ -2103,6 +2106,10 @@ exec_stmts(PLpgSQL_execstate *estate, List *stmts)
 				rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
 				break;
 
+			case PLPGSQL_STMT_LET:
+				rc = exec_stmt_let(estate, (PLpgSQL_stmt_let *) stmt);
+				break;
+
 			default:
 				/* point err_stmt to parent, since this one seems corrupt */
 				estate->err_stmt = save_estmt;
@@ -4950,6 +4957,54 @@ exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
 	return PLPGSQL_RC_OK;
 }
 
+/* ----------
+ * exec_stmt_let			Evaluate an expression and
+ *					put the result into a schema variable.
+ * ----------
+ */
+static int
+exec_stmt_let(PLpgSQL_execstate *estate, PLpgSQL_stmt_let *stmt)
+{
+	bool		isNull;
+	Oid			valtype;
+	int32		valtypmod;
+	Datum		value;
+	Oid			varid;
+
+	List	   *plansources;
+	CachedPlanSource *plansource;
+
+	value = exec_eval_expr(estate,
+						   stmt->expr,
+						   &isNull,
+						   &valtype,
+						   &valtypmod);
+
+	/*
+	 * Oid of target schema variable is stored in Query structure.
+	 * It is safer to read this value directly from plan, then to
+	 * hold this value in plpgsql context, because I don't need to
+	 * solve invalidation of this cached value. Next operations
+	 * are read only without any allocations, so we can expect so
+	 * taking varid from Query should be fast.
+	 */
+	plansources = SPI_plan_get_plan_sources(stmt->expr->plan);
+	if (list_length(plansources) != 1)
+		elog(ERROR, "unexpected length of plansources of query for LET statement");
+
+	plansource = (CachedPlanSource *) linitial(plansources);
+	if (list_length(plansource->query_list) != 1)
+		elog(ERROR, "unexpected length of plansource of query for LET statement");
+
+	varid = linitial_node(Query, plansource->query_list)->resultVariable;
+	if (!OidIsValid(varid))
+		elog(ERROR, "oid of target schema variable is not valid");
+
+	SetSchemaVariableWithSecurityCheck(varid, value, isNull, valtype);
+
+	return PLPGSQL_RC_OK;
+}
+
 /* ----------
  * exec_assign_expr			Put an expression's result into a variable.
  * ----------
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index e0863acb3d..265f93fb7b 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -288,6 +288,8 @@ plpgsql_stmt_typename(PLpgSQL_stmt *stmt)
 			return "COMMIT";
 		case PLPGSQL_STMT_ROLLBACK:
 			return "ROLLBACK";
+		case PLPGSQL_STMT_LET:
+			return "LET";
 	}
 
 	return "unknown";
@@ -368,6 +370,7 @@ static void free_perform(PLpgSQL_stmt_perform *stmt);
 static void free_call(PLpgSQL_stmt_call *stmt);
 static void free_commit(PLpgSQL_stmt_commit *stmt);
 static void free_rollback(PLpgSQL_stmt_rollback *stmt);
+static void free_let(PLpgSQL_stmt_let *stmt);
 static void free_expr(PLpgSQL_expr *expr);
 
 
@@ -457,6 +460,9 @@ free_stmt(PLpgSQL_stmt *stmt)
 		case PLPGSQL_STMT_ROLLBACK:
 			free_rollback((PLpgSQL_stmt_rollback *) stmt);
 			break;
+		case PLPGSQL_STMT_LET:
+			free_let((PLpgSQL_stmt_let *) stmt);
+			break;
 		default:
 			elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
 			break;
@@ -711,6 +717,12 @@ free_getdiag(PLpgSQL_stmt_getdiag *stmt)
 {
 }
 
+static void
+free_let(PLpgSQL_stmt_let *stmt)
+{
+	free_expr(stmt->expr);
+}
+
 static void
 free_expr(PLpgSQL_expr *expr)
 {
@@ -813,6 +825,7 @@ static void dump_perform(PLpgSQL_stmt_perform *stmt);
 static void dump_call(PLpgSQL_stmt_call *stmt);
 static void dump_commit(PLpgSQL_stmt_commit *stmt);
 static void dump_rollback(PLpgSQL_stmt_rollback *stmt);
+static void dump_let(PLpgSQL_stmt_let *stmt);
 static void dump_expr(PLpgSQL_expr *expr);
 
 
@@ -912,6 +925,9 @@ dump_stmt(PLpgSQL_stmt *stmt)
 		case PLPGSQL_STMT_ROLLBACK:
 			dump_rollback((PLpgSQL_stmt_rollback *) stmt);
 			break;
+		case PLPGSQL_STMT_LET:
+			dump_let((PLpgSQL_stmt_let *) stmt);
+			break;
 		default:
 			elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
 			break;
@@ -1588,6 +1604,14 @@ dump_getdiag(PLpgSQL_stmt_getdiag *stmt)
 	printf("\n");
 }
 
+static void
+dump_let(PLpgSQL_stmt_let *stmt)
+{
+	dump_ind();
+	dump_expr(stmt->expr);
+	printf("\n");
+}
+
 static void
 dump_expr(PLpgSQL_expr *expr)
 {
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 0f6a5b30b1..14845e64a2 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -197,7 +197,7 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %type <stmt>	stmt_return stmt_raise stmt_assert stmt_execsql
 %type <stmt>	stmt_dynexecute stmt_for stmt_perform stmt_call stmt_getdiag
 %type <stmt>	stmt_open stmt_fetch stmt_move stmt_close stmt_null
-%type <stmt>	stmt_commit stmt_rollback
+%type <stmt>	stmt_commit stmt_rollback stmt_let
 %type <stmt>	stmt_case stmt_foreach_a
 
 %type <list>	proc_exceptions
@@ -304,6 +304,7 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>	K_INTO
 %token <keyword>	K_IS
 %token <keyword>	K_LAST
+%token <keyword>	K_LET
 %token <keyword>	K_LOG
 %token <keyword>	K_LOOP
 %token <keyword>	K_MESSAGE
@@ -897,6 +898,8 @@ proc_stmt		: pl_block ';'
 						{ $$ = $1; }
 				| stmt_rollback
 						{ $$ = $1; }
+				| stmt_let
+						{ $$ = $1; }
 				;
 
 stmt_perform	: K_PERFORM
@@ -1013,6 +1016,29 @@ stmt_assign		: T_DATUM
 					}
 				;
 
+stmt_let		: K_LET
+					{
+						PLpgSQL_stmt_let *new;
+						RawParseMode pmode;
+
+						pmode = RAW_PARSE_PLPGSQL_LET;
+
+						new = palloc0(sizeof(PLpgSQL_stmt_let));
+						new->cmd_type = PLPGSQL_STMT_LET;
+						new->lineno   = plpgsql_location_to_lineno(@1);
+						new->stmtid = ++plpgsql_curr_compile->nstatements;
+
+						/* Push back the head name to include it in the stmt */
+						plpgsql_push_back_token(K_LET);
+						new->expr = read_sql_construct(';', 0, 0, ";",
+													   pmode,
+													   false, true, true,
+													   NULL, NULL);
+
+						$$ = (PLpgSQL_stmt *)new;
+					}
+				;
+
 stmt_getdiag	: K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
 					{
 						PLpgSQL_stmt_getdiag	 *new;
diff --git a/src/pl/plpgsql/src/pl_reserved_kwlist.h b/src/pl/plpgsql/src/pl_reserved_kwlist.h
index daf835e683..5e64984ff4 100644
--- a/src/pl/plpgsql/src/pl_reserved_kwlist.h
+++ b/src/pl/plpgsql/src/pl_reserved_kwlist.h
@@ -40,6 +40,7 @@ PG_KEYWORD("from", K_FROM)
 PG_KEYWORD("if", K_IF)
 PG_KEYWORD("in", K_IN)
 PG_KEYWORD("into", K_INTO)
+PG_KEYWORD("let", K_LET)
 PG_KEYWORD("loop", K_LOOP)
 PG_KEYWORD("not", K_NOT)
 PG_KEYWORD("null", K_NULL)
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 3936866bb7..e4cb07d6b1 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -127,7 +127,8 @@ typedef enum PLpgSQL_stmt_type
 	PLPGSQL_STMT_PERFORM,
 	PLPGSQL_STMT_CALL,
 	PLPGSQL_STMT_COMMIT,
-	PLPGSQL_STMT_ROLLBACK
+	PLPGSQL_STMT_ROLLBACK,
+	PLPGSQL_STMT_LET
 } PLpgSQL_stmt_type;
 
 /*
@@ -519,6 +520,17 @@ typedef struct PLpgSQL_stmt_assign
 	PLpgSQL_expr *expr;
 } PLpgSQL_stmt_assign;
 
+/*
+ * Let statement
+ */
+typedef struct PLpgSQL_stmt_let
+{
+	PLpgSQL_stmt_type cmd_type;
+	int			lineno;
+	unsigned int stmtid;
+	PLpgSQL_expr *expr;
+} PLpgSQL_stmt_let;
+
 /*
  * PERFORM statement
  */
diff --git a/src/test/regress/expected/misc_sanity.out b/src/test/regress/expected/misc_sanity.out
index a57fd142a9..ce9bad7211 100644
--- a/src/test/regress/expected/misc_sanity.out
+++ b/src/test/regress/expected/misc_sanity.out
@@ -60,7 +60,9 @@ ORDER BY 1, 2;
  pg_index                | indpred       | pg_node_tree
  pg_largeobject          | data          | bytea
  pg_largeobject_metadata | lomacl        | aclitem[]
-(11 rows)
+ pg_variable             | varacl        | aclitem[]
+ pg_variable             | vardefexpr    | pg_node_tree
+(13 rows)
 
 -- system catalogs without primary keys
 --
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index d04dc66db9..54b2ac8383 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -165,6 +165,7 @@ pg_ts_parser|t
 pg_ts_template|t
 pg_type|t
 pg_user_mapping|t
+pg_variable|t
 point_tbl|t
 polygon_tbl|t
 quad_box_tbl|t
diff --git a/src/test/regress/expected/schema_variables.out b/src/test/regress/expected/schema_variables.out
new file mode 100644
index 0000000000..0246d86673
--- /dev/null
+++ b/src/test/regress/expected/schema_variables.out
@@ -0,0 +1,655 @@
+CREATE SCHEMA svartest;
+SET search_path = svartest;
+CREATE VARIABLE var1 AS integer;
+CREATE TEMP VARIABLE var2 AS text;
+DROP VARIABLE var1, var2;
+-- functional interface
+CREATE VARIABLE var1 AS numeric;
+CREATE ROLE var_test_role;
+GRANT USAGE ON SCHEMA svartest TO var_test_role;
+SET ROLE TO var_test_role;
+-- should fail
+SELECT var1;
+ERROR:  permission denied for schema variable var1
+SET ROLE TO DEFAULT;
+GRANT READ ON VARIABLE var1 TO var_test_role;
+SET ROLE TO var_test_role;
+-- should fail
+LET var1 = 10;
+ERROR:  permission denied for schema variable var1
+-- should work
+SELECT var1;
+ var1 
+------
+     
+(1 row)
+
+SET ROLE TO DEFAULT;
+GRANT WRITE ON VARIABLE var1 TO var_test_role;
+SET ROLE TO var_test_role;
+-- should work
+LET var1 = 333;
+SET ROLE TO DEFAULT;
+REVOKE ALL ON VARIABLE var1 FROM var_test_role;
+CREATE OR REPLACE FUNCTION secure_var()
+RETURNS int AS $$
+  SELECT svartest.var1::int;
+$$ LANGUAGE sql SECURITY DEFINER;
+SELECT secure_var();
+ secure_var 
+------------
+        333
+(1 row)
+
+SET ROLE TO var_test_role;
+-- should fail
+SELECT svartest.var1;
+ERROR:  permission denied for schema variable var1
+-- should work;
+SELECT secure_var();
+ secure_var 
+------------
+        333
+(1 row)
+
+SET ROLE TO DEFAULT;
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM generate_series(1,100) g(v) WHERE v = var1;
+                  QUERY PLAN                   
+-----------------------------------------------
+ Function Scan on pg_catalog.generate_series g
+   Output: v
+   Function Call: generate_series(1, 100)
+   Filter: ((g.v)::numeric = var1)
+(4 rows)
+
+CREATE VIEW schema_var_view AS SELECT var1;
+SELECT * FROM schema_var_view;
+ var1 
+------
+  333
+(1 row)
+
+\c -
+SET search_path = svartest;
+-- should work still, but var will be empty
+SELECT * FROM schema_var_view;
+ var1 
+------
+     
+(1 row)
+
+LET var1 = pi();
+SELECT var1;
+       var1       
+------------------
+ 3.14159265358979
+(1 row)
+
+-- we can see execution plan of LET statement
+EXPLAIN (VERBOSE, COSTS OFF) LET var1 = pi();
+         QUERY PLAN         
+----------------------------
+ SET SCHEMA VARIABLE
+ Result
+   Output: 3.14159265358979
+(3 rows)
+
+SELECT var1;
+       var1       
+------------------
+ 3.14159265358979
+(1 row)
+
+CREATE VARIABLE var3 AS int;
+CREATE OR REPLACE FUNCTION inc(int)
+RETURNS int AS $$
+BEGIN
+  LET svartest.var3 = COALESCE(svartest.var3 + $1, $1);
+  RETURN var3;
+END;
+$$ LANGUAGE plpgsql;
+SELECT inc(1);
+ inc 
+-----
+   1
+(1 row)
+
+SELECT inc(1);
+ inc 
+-----
+   2
+(1 row)
+
+SELECT inc(1);
+ inc 
+-----
+   3
+(1 row)
+
+SELECT inc(1) FROM generate_series(1,10);
+ inc 
+-----
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+(10 rows)
+
+SET ROLE TO var_test_role;
+-- should fail
+LET var3 = 0;
+ERROR:  permission denied for schema variable var3
+SET ROLE TO DEFAULT;
+DROP VIEW schema_var_view;
+DROP VARIABLE var1 CASCADE;
+DROP VARIABLE var3 CASCADE;
+-- composite variables
+CREATE TYPE sv_xyz AS (x int, y int, z numeric(10,2));
+CREATE VARIABLE v1 AS sv_xyz;
+CREATE VARIABLE v2 AS sv_xyz;
+\d v1
+\d v2
+LET v1 = (1,2,3.14);
+LET v2 = (10,20,3.14*10);
+-- should work too - there are prepared casts
+LET v1 = (1,2,3.14);
+SELECT v1;
+     v1     
+------------
+ (1,2,3.14)
+(1 row)
+
+SELECT v2;
+      v2       
+---------------
+ (10,20,31.40)
+(1 row)
+
+SELECT (v1).*;
+ x | y |  z   
+---+---+------
+ 1 | 2 | 3.14
+(1 row)
+
+SELECT (v2).*;
+ x  | y  |   z   
+----+----+-------
+ 10 | 20 | 31.40
+(1 row)
+
+SELECT v1.x + v1.z;
+ ?column? 
+----------
+     4.14
+(1 row)
+
+SELECT v2.x + v2.z;
+ ?column? 
+----------
+    41.40
+(1 row)
+
+-- access to composite fields should be safe too
+-- should fail
+SET ROLE TO var_test_role;
+SELECT v2.x;
+ERROR:  permission denied for schema variable v2
+SET ROLE TO DEFAULT;
+DROP VARIABLE v1;
+DROP VARIABLE v2;
+REVOKE USAGE ON SCHEMA svartest FROM var_test_role;
+DROP ROLE var_test_role;
+-- scalar variables should not be in conflict with qualified column
+CREATE VARIABLE varx AS text;
+SELECT varx.relname FROM pg_class varx WHERE varx.relname = 'pg_class';
+ relname  
+----------
+ pg_class
+(1 row)
+
+-- should fail
+SELECT varx.xxx;
+ERROR:  type text is not composite
+-- variables can be updated under RO transaction
+BEGIN;
+SET TRANSACTION READ ONLY;
+LET varx = 'hello';
+COMMIT;
+SELECT varx;
+ varx  
+-------
+ hello
+(1 row)
+
+DROP VARIABLE varx;
+CREATE TYPE t1 AS (a int, b numeric, c text);
+CREATE VARIABLE v1 AS t1;
+LET v1 = (1, pi(), 'hello');
+SELECT v1;
+             v1             
+----------------------------
+ (1,3.14159265358979,hello)
+(1 row)
+
+LET v1.b = 10.2222;
+SELECT v1;
+        v1         
+-------------------
+ (1,10.2222,hello)
+(1 row)
+
+-- should fail
+LET v1.x = 10;
+ERROR:  cannot assign to field "x" of column "x" because there is no such column in data type t1
+LINE 1: LET v1.x = 10;
+            ^
+DROP VARIABLE v1;
+DROP TYPE t1;
+-- arrays are supported
+CREATE VARIABLE va1 AS numeric[];
+LET va1 = ARRAY[1.1,2.1];
+LET va1[1] = 10.1;
+SELECT va1;
+    va1     
+------------
+ {10.1,2.1}
+(1 row)
+
+CREATE TYPE ta2 AS (a numeric, b numeric[]);
+CREATE VARIABLE va2 AS ta2;
+LET va2 = (10.1, ARRAY[0.0, 0.0]);
+LET va2.a = 10.2;
+SELECT va2;
+        va2         
+--------------------
+ (10.2,"{0.0,0.0}")
+(1 row)
+
+LET va2.b[1] = 10.3;
+SELECT va2;
+         va2         
+---------------------
+ (10.2,"{10.3,0.0}")
+(1 row)
+
+DROP VARIABLE va1;
+DROP VARIABLE va2;
+DROP TYPE ta2;
+-- default values
+CREATE VARIABLE v1 AS numeric DEFAULT pi();
+LET v1 = v1 * 2;
+SELECT v1;
+        v1        
+------------------
+ 6.28318530717958
+(1 row)
+
+CREATE TYPE t2 AS (a numeric, b text);
+CREATE VARIABLE v2 AS t2 DEFAULT (NULL, 'Hello');
+LET svartest.v2.a = pi();
+SELECT v2;
+            v2            
+--------------------------
+ (3.14159265358979,Hello)
+(1 row)
+
+-- shoudl fail due dependency
+DROP TYPE t2;
+ERROR:  cannot drop type t2 because other objects depend on it
+DETAIL:  schema variable v2 depends on type t2
+HINT:  Use DROP ... CASCADE to drop the dependent objects too.
+-- should be ok
+DROP VARIABLE v1;
+DROP VARIABLE v2;
+-- tests of alters
+CREATE SCHEMA var_schema1;
+CREATE SCHEMA var_schema2;
+CREATE VARIABLE var_schema1.var1 AS integer;
+LET var_schema1.var1 = 1000;
+SELECT var_schema1.var1;
+ var1 
+------
+ 1000
+(1 row)
+
+ALTER VARIABLE var_schema1.var1 SET SCHEMA var_schema2;
+SELECT var_schema2.var1;
+ var1 
+------
+ 1000
+(1 row)
+
+CREATE ROLE var_test_role;
+ALTER VARIABLE var_schema2.var1 OWNER TO var_test_role;
+SET ROLE TO var_test_role;
+-- should fail, no access to schema var_schema2.var
+SELECT var_schema2.var1;
+ERROR:  permission denied for schema var_schema2
+DROP VARIABLE var_schema2.var1;
+ERROR:  permission denied for schema var_schema2
+SET ROLE TO DEFAULT;
+ALTER VARIABLE var_schema2.var1 SET SCHEMA public;
+SET ROLE TO var_test_role;
+SELECT public.var1;
+ var1 
+------
+ 1000
+(1 row)
+
+ALTER VARIABLE public.var1 RENAME TO var1_renamed;
+SELECT public.var1_renamed;
+ var1_renamed 
+--------------
+         1000
+(1 row)
+
+DROP VARIABLE public.var1_renamed;
+SET ROLE TO DEFAULt;
+DROP ROLE var_test_role;
+CREATE VARIABLE xx AS text DEFAULT 'hello';
+SELECT xx, upper(xx);
+  xx   | upper 
+-------+-------
+ hello | HELLO
+(1 row)
+
+LET xx = 'Hi';
+SELECT xx;
+ xx 
+----
+ Hi
+(1 row)
+
+DROP VARIABLE xx;
+-- ON TRANSACTION END RESET tests
+CREATE VARIABLE t1 AS int DEFAULT -1 ON TRANSACTION END RESET;
+BEGIN;
+  SELECT t1;
+ t1 
+----
+ -1
+(1 row)
+
+  LET t1 = 100;
+  SELECT t1;
+ t1  
+-----
+ 100
+(1 row)
+
+COMMIT;
+SELECT t1;
+ t1 
+----
+ -1
+(1 row)
+
+BEGIN;
+  SELECT t1;
+ t1 
+----
+ -1
+(1 row)
+
+  LET t1 = 100;
+  SELECT t1;
+ t1  
+-----
+ 100
+(1 row)
+
+ROLLBACK;
+SELECT t1;
+ t1 
+----
+ -1
+(1 row)
+
+DROP VARIABLE t1;
+CREATE VARIABLE v1 AS int DEFAULT 0;
+CREATE VARIABLE v2 AS text DEFAULT 'none';
+LET v1 = 100;
+LET v2 = 'Hello';
+SELECT v1, v2;
+ v1  |  v2   
+-----+-------
+ 100 | Hello
+(1 row)
+
+LET v1 = DEFAULT;
+LET v2 = DEFAULT;
+SELECT v1, v2;
+ v1 |  v2  
+----+------
+  0 | none
+(1 row)
+
+DROP VARIABLE v1;
+DROP VARIABLE v2;
+-- ON COMMIT DROP tests
+-- should be 0 always
+SELECT count(*) FROM pg_variable;
+ count 
+-------
+     0
+(1 row)
+
+CREATE TEMP VARIABLE g AS int ON COMMIT DROP;
+SELECT count(*) FROM pg_variable;
+ count 
+-------
+     0
+(1 row)
+
+BEGIN;
+  CREATE TEMP VARIABLE g AS int ON COMMIT DROP;
+COMMIT;
+SELECT count(*) FROM pg_variable;
+ count 
+-------
+     0
+(1 row)
+
+BEGIN;
+  CREATE TEMP VARIABLE g AS int ON COMMIT DROP;
+ROLLBACK;
+SELECT count(*) FROM pg_variable;
+ count 
+-------
+     0
+(1 row)
+
+-- test on query with workers
+CREATE TABLE svar_test(a int);
+INSERT INTO svar_test SELECT * FROM generate_series(1,1000000);
+ANALYZE svar_test;
+CREATE VARIABLE zero int;
+LET zero = 0;
+-- parallel workers should be used
+EXPLAIN (costs off) SELECT count(*) FROM svar_test WHERE a%10 = zero;
+                    QUERY PLAN                    
+--------------------------------------------------
+ Finalize Aggregate
+   ->  Gather
+         Workers Planned: 2
+         ->  Partial Aggregate
+               ->  Parallel Seq Scan on svar_test
+                     Filter: ((a % 10) = zero)
+(6 rows)
+
+-- result should be 100000
+SELECT count(*) FROM svar_test WHERE a%10 = zero;
+ count  
+--------
+ 100000
+(1 row)
+
+LET zero = (SELECT count(*) FROM svar_test);
+-- result should be 1000000
+SELECT zero;
+  zero   
+---------
+ 1000000
+(1 row)
+
+-- parallel workers should be used
+EXPLAIN (costs off) LET zero = (SELECT count(*) FROM svar_test);
+                        QUERY PLAN                        
+----------------------------------------------------------
+ SET SCHEMA VARIABLE
+ Result
+   InitPlan 1 (returns $1)
+     ->  Finalize Aggregate
+           ->  Gather
+                 Workers Planned: 2
+                 ->  Partial Aggregate
+                       ->  Parallel Seq Scan on svar_test
+(8 rows)
+
+DROP TABLE svar_test;
+DROP VARIABLE zero;
+-- use variables in prepared statements
+CREATE VARIABLE v AS numeric;
+LET v = 3.14;
+-- use variables in views
+CREATE VIEW vv AS SELECT COALESCE(v, 0) + 1000 AS result;
+SELECT * FROM vv;
+ result  
+---------
+ 1003.14
+(1 row)
+
+-- start a new session
+\c
+SET search_path to svartest;
+SELECT * FROM vv;
+ result 
+--------
+   1000
+(1 row)
+
+LET v = 3.14;
+SELECT * FROM vv;
+ result  
+---------
+ 1003.14
+(1 row)
+
+-- should fail, dependency
+DROP VARIABLE v;
+ERROR:  cannot drop schema variable v because other objects depend on it
+DETAIL:  view vv depends on schema variable v
+HINT:  Use DROP ... CASCADE to drop the dependent objects too.
+-- should be ok
+DROP VARIABLE v CASCADE;
+NOTICE:  drop cascades to view vv
+-- other features
+CREATE VARIABLE dt AS integer DEFAULT 0;
+LET dt = 100;
+SELECT dt;
+ dt  
+-----
+ 100
+(1 row)
+
+DISCARD VARIABLES;
+SELECT dt;
+ dt 
+----
+  0
+(1 row)
+
+DROP VARIABLE dt;
+-- NOT NULL
+CREATE VARIABLE v1 AS int NOT NULL;
+CREATE VARIABLE v2 AS int NOT NULL DEFAULT NULL;
+-- should fail
+SELECT v1;
+ERROR:  null value is not allowed for NOT NULL schema variable "v1"
+DETAIL:  The schema variable was not initialized yet.
+SELECT v2;
+ERROR:  null value is not allowed for NOT NULL schema variable "v2"
+LET v1 = NULL;
+ERROR:  null value is not allowed for NOT NULL schema variable "v1"
+LET v2 = NULL;
+ERROR:  null value is not allowed for NOT NULL schema variable "v2"
+LET v1 = DEFAULT;
+ERROR:  null value is not allowed for NOT NULL schema variable "v1"
+LET v2 = DEFAULT;
+ERROR:  null value is not allowed for NOT NULL schema variable "v2"
+-- should be ok
+LET v1 = 100;
+LET v2 = 1000;
+SELECT v1, v2;
+ v1  |  v2  
+-----+------
+ 100 | 1000
+(1 row)
+
+DROP VARIABLE v1;
+DROP VARIABLE v2;
+CREATE VARIABLE tv AS int;
+CREATE VARIABLE IF NOT EXISTS tv AS int;
+NOTICE:  schema variable "tv" already exists, skipping
+DROP VARIABLE tv;
+CREATE IMMUTABLE VARIABLE iv AS int DEFAULT 100;
+SELECT iv;
+ iv  
+-----
+ 100
+(1 row)
+
+-- should fail;
+LET iv = 10000;
+ERROR:  schema variable "iv" is declared IMMUTABLE
+DROP VARIABLE iv;
+-- create variable inside plpgsql block
+DO $$
+BEGIN
+  CREATE VARIABLE do_test_svar AS date DEFAULT '2000-01-01';
+END;
+$$;
+SELECT do_test_svar;
+ do_test_svar 
+--------------
+ 01-01-2000
+(1 row)
+
+DROP VARIABLE do_test_svar;
+-- should fail
+CREATE IMMUTABLE VARIABLE xx AS int NOT NULL;
+ERROR:  IMMUTABLE NOT NULL variable requires default expression
+-- REASSIGN OWNED test
+CREATE ROLE var_test_role1;
+CREATE ROLE var_test_role2;
+CREATE VARIABLE xxx_var AS int;
+ALTER VARIABLE xxx_var OWNER TO var_test_role1;
+REASSIGN OWNED BY var_test_role1 to var_test_role2;
+SELECT varowner::regrole FROM pg_variable WHERE varname = 'xxx_var';
+    varowner    
+----------------
+ var_test_role2
+(1 row)
+
+DROP OWNED BY var_test_role1;
+DROP ROLE var_test_role1;
+SELECT count(*) FROM pg_variable WHERE varname = 'xxx_var';
+ count 
+-------
+     1
+(1 row)
+
+DROP OWNED BY var_test_role2;
+DROP ROLE var_test_role2;
+SELECT count(*) FROM pg_variable WHERE varname = 'xxx_var';
+ count 
+-------
+     0
+(1 row)
+
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 017e962fed..98f334d057 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -116,7 +116,7 @@ test: json jsonb json_encoding jsonpath jsonpath_encoding jsonb_jsonpath
 # NB: temp.sql does a reconnect which transiently uses 2 connections,
 # so keep this parallel group to at most 19 tests
 # ----------
-test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml
+test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml schema_variables
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/sql/schema_variables.sql b/src/test/regress/sql/schema_variables.sql
new file mode 100644
index 0000000000..0bd7798cf9
--- /dev/null
+++ b/src/test/regress/sql/schema_variables.sql
@@ -0,0 +1,438 @@
+CREATE SCHEMA svartest;
+
+SET search_path = svartest;
+
+CREATE VARIABLE var1 AS integer;
+CREATE TEMP VARIABLE var2 AS text;
+
+DROP VARIABLE var1, var2;
+
+-- functional interface
+CREATE VARIABLE var1 AS numeric;
+
+CREATE ROLE var_test_role;
+GRANT USAGE ON SCHEMA svartest TO var_test_role;
+
+SET ROLE TO var_test_role;
+
+-- should fail
+SELECT var1;
+
+SET ROLE TO DEFAULT;
+
+GRANT READ ON VARIABLE var1 TO var_test_role;
+
+SET ROLE TO var_test_role;
+-- should fail
+LET var1 = 10;
+-- should work
+SELECT var1;
+
+SET ROLE TO DEFAULT;
+
+GRANT WRITE ON VARIABLE var1 TO var_test_role;
+
+SET ROLE TO var_test_role;
+
+-- should work
+LET var1 = 333;
+
+SET ROLE TO DEFAULT;
+
+REVOKE ALL ON VARIABLE var1 FROM var_test_role;
+
+CREATE OR REPLACE FUNCTION secure_var()
+RETURNS int AS $$
+  SELECT svartest.var1::int;
+$$ LANGUAGE sql SECURITY DEFINER;
+
+SELECT secure_var();
+
+SET ROLE TO var_test_role;
+
+-- should fail
+SELECT svartest.var1;
+
+-- should work;
+SELECT secure_var();
+
+SET ROLE TO DEFAULT;
+
+EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM generate_series(1,100) g(v) WHERE v = var1;
+
+CREATE VIEW schema_var_view AS SELECT var1;
+
+SELECT * FROM schema_var_view;
+
+\c -
+
+SET search_path = svartest;
+
+-- should work still, but var will be empty
+SELECT * FROM schema_var_view;
+
+LET var1 = pi();
+
+SELECT var1;
+
+-- we can see execution plan of LET statement
+EXPLAIN (VERBOSE, COSTS OFF) LET var1 = pi();
+
+SELECT var1;
+
+CREATE VARIABLE var3 AS int;
+
+CREATE OR REPLACE FUNCTION inc(int)
+RETURNS int AS $$
+BEGIN
+  LET svartest.var3 = COALESCE(svartest.var3 + $1, $1);
+  RETURN var3;
+END;
+$$ LANGUAGE plpgsql;
+
+SELECT inc(1);
+SELECT inc(1);
+SELECT inc(1);
+
+SELECT inc(1) FROM generate_series(1,10);
+
+SET ROLE TO var_test_role;
+
+-- should fail
+LET var3 = 0;
+
+SET ROLE TO DEFAULT;
+
+DROP VIEW schema_var_view;
+
+DROP VARIABLE var1 CASCADE;
+DROP VARIABLE var3 CASCADE;
+
+-- composite variables
+
+CREATE TYPE sv_xyz AS (x int, y int, z numeric(10,2));
+
+CREATE VARIABLE v1 AS sv_xyz;
+CREATE VARIABLE v2 AS sv_xyz;
+
+\d v1
+\d v2
+
+LET v1 = (1,2,3.14);
+LET v2 = (10,20,3.14*10);
+
+-- should work too - there are prepared casts
+LET v1 = (1,2,3.14);
+
+SELECT v1;
+SELECT v2;
+SELECT (v1).*;
+SELECT (v2).*;
+
+SELECT v1.x + v1.z;
+SELECT v2.x + v2.z;
+
+-- access to composite fields should be safe too
+-- should fail
+SET ROLE TO var_test_role;
+
+SELECT v2.x;
+
+SET ROLE TO DEFAULT;
+
+DROP VARIABLE v1;
+DROP VARIABLE v2;
+
+REVOKE USAGE ON SCHEMA svartest FROM var_test_role;
+DROP ROLE var_test_role;
+
+-- scalar variables should not be in conflict with qualified column
+CREATE VARIABLE varx AS text;
+SELECT varx.relname FROM pg_class varx WHERE varx.relname = 'pg_class';
+
+-- should fail
+SELECT varx.xxx;
+
+-- variables can be updated under RO transaction
+
+BEGIN;
+SET TRANSACTION READ ONLY;
+LET varx = 'hello';
+COMMIT;
+
+SELECT varx;
+
+DROP VARIABLE varx;
+
+CREATE TYPE t1 AS (a int, b numeric, c text);
+
+CREATE VARIABLE v1 AS t1;
+LET v1 = (1, pi(), 'hello');
+SELECT v1;
+LET v1.b = 10.2222;
+SELECT v1;
+
+-- should fail
+LET v1.x = 10;
+
+DROP VARIABLE v1;
+DROP TYPE t1;
+
+-- arrays are supported
+CREATE VARIABLE va1 AS numeric[];
+LET va1 = ARRAY[1.1,2.1];
+LET va1[1] = 10.1;
+SELECT va1;
+
+CREATE TYPE ta2 AS (a numeric, b numeric[]);
+CREATE VARIABLE va2 AS ta2;
+LET va2 = (10.1, ARRAY[0.0, 0.0]);
+LET va2.a = 10.2;
+SELECT va2;
+LET va2.b[1] = 10.3;
+SELECT va2;
+
+DROP VARIABLE va1;
+DROP VARIABLE va2;
+DROP TYPE ta2;
+
+-- default values
+CREATE VARIABLE v1 AS numeric DEFAULT pi();
+LET v1 = v1 * 2;
+SELECT v1;
+
+CREATE TYPE t2 AS (a numeric, b text);
+CREATE VARIABLE v2 AS t2 DEFAULT (NULL, 'Hello');
+LET svartest.v2.a = pi();
+SELECT v2;
+
+-- shoudl fail due dependency
+DROP TYPE t2;
+
+-- should be ok
+DROP VARIABLE v1;
+DROP VARIABLE v2;
+
+-- tests of alters
+CREATE SCHEMA var_schema1;
+CREATE SCHEMA var_schema2;
+
+CREATE VARIABLE var_schema1.var1 AS integer;
+LET var_schema1.var1 = 1000;
+SELECT var_schema1.var1;
+ALTER VARIABLE var_schema1.var1 SET SCHEMA var_schema2;
+SELECT var_schema2.var1;
+
+CREATE ROLE var_test_role;
+
+ALTER VARIABLE var_schema2.var1 OWNER TO var_test_role;
+SET ROLE TO var_test_role;
+
+-- should fail, no access to schema var_schema2.var
+SELECT var_schema2.var1;
+DROP VARIABLE var_schema2.var1;
+
+SET ROLE TO DEFAULT;
+
+ALTER VARIABLE var_schema2.var1 SET SCHEMA public;
+
+SET ROLE TO var_test_role;
+SELECT public.var1;
+
+ALTER VARIABLE public.var1 RENAME TO var1_renamed;
+
+SELECT public.var1_renamed;
+
+DROP VARIABLE public.var1_renamed;
+
+SET ROLE TO DEFAULt;
+
+DROP ROLE var_test_role;
+
+CREATE VARIABLE xx AS text DEFAULT 'hello';
+
+SELECT xx, upper(xx);
+
+LET xx = 'Hi';
+
+SELECT xx;
+
+DROP VARIABLE xx;
+
+-- ON TRANSACTION END RESET tests
+CREATE VARIABLE t1 AS int DEFAULT -1 ON TRANSACTION END RESET;
+
+BEGIN;
+  SELECT t1;
+  LET t1 = 100;
+  SELECT t1;
+COMMIT;
+
+SELECT t1;
+
+BEGIN;
+  SELECT t1;
+  LET t1 = 100;
+  SELECT t1;
+ROLLBACK;
+
+SELECT t1;
+
+DROP VARIABLE t1;
+
+CREATE VARIABLE v1 AS int DEFAULT 0;
+CREATE VARIABLE v2 AS text DEFAULT 'none';
+
+LET v1 = 100;
+LET v2 = 'Hello';
+SELECT v1, v2;
+LET v1 = DEFAULT;
+LET v2 = DEFAULT;
+SELECT v1, v2;
+
+DROP VARIABLE v1;
+DROP VARIABLE v2;
+
+-- ON COMMIT DROP tests
+-- should be 0 always
+SELECT count(*) FROM pg_variable;
+
+CREATE TEMP VARIABLE g AS int ON COMMIT DROP;
+
+SELECT count(*) FROM pg_variable;
+
+BEGIN;
+  CREATE TEMP VARIABLE g AS int ON COMMIT DROP;
+COMMIT;
+
+SELECT count(*) FROM pg_variable;
+
+BEGIN;
+  CREATE TEMP VARIABLE g AS int ON COMMIT DROP;
+ROLLBACK;
+
+SELECT count(*) FROM pg_variable;
+
+-- test on query with workers
+CREATE TABLE svar_test(a int);
+INSERT INTO svar_test SELECT * FROM generate_series(1,1000000);
+ANALYZE svar_test;
+CREATE VARIABLE zero int;
+LET zero = 0;
+
+-- parallel workers should be used
+EXPLAIN (costs off) SELECT count(*) FROM svar_test WHERE a%10 = zero;
+
+-- result should be 100000
+SELECT count(*) FROM svar_test WHERE a%10 = zero;
+
+LET zero = (SELECT count(*) FROM svar_test);
+
+-- result should be 1000000
+SELECT zero;
+
+-- parallel workers should be used
+EXPLAIN (costs off) LET zero = (SELECT count(*) FROM svar_test);
+
+DROP TABLE svar_test;
+DROP VARIABLE zero;
+
+-- use variables in prepared statements
+CREATE VARIABLE v AS numeric;
+LET v = 3.14;
+
+-- use variables in views
+CREATE VIEW vv AS SELECT COALESCE(v, 0) + 1000 AS result;
+SELECT * FROM vv;
+
+-- start a new session
+\c
+
+SET search_path to svartest;
+
+SELECT * FROM vv;
+LET v = 3.14;
+SELECT * FROM vv;
+
+-- should fail, dependency
+DROP VARIABLE v;
+
+-- should be ok
+DROP VARIABLE v CASCADE;
+
+-- other features
+CREATE VARIABLE dt AS integer DEFAULT 0;
+
+LET dt = 100;
+SELECT dt;
+
+DISCARD VARIABLES;
+
+SELECT dt;
+
+DROP VARIABLE dt;
+
+-- NOT NULL
+CREATE VARIABLE v1 AS int NOT NULL;
+CREATE VARIABLE v2 AS int NOT NULL DEFAULT NULL;
+
+-- should fail
+SELECT v1;
+SELECT v2;
+LET v1 = NULL;
+LET v2 = NULL;
+LET v1 = DEFAULT;
+LET v2 = DEFAULT;
+
+-- should be ok
+LET v1 = 100;
+LET v2 = 1000;
+SELECT v1, v2;
+
+DROP VARIABLE v1;
+DROP VARIABLE v2;
+
+CREATE VARIABLE tv AS int;
+CREATE VARIABLE IF NOT EXISTS tv AS int;
+DROP VARIABLE tv;
+
+CREATE IMMUTABLE VARIABLE iv AS int DEFAULT 100;
+SELECT iv;
+
+-- should fail;
+LET iv = 10000;
+
+DROP VARIABLE iv;
+
+-- create variable inside plpgsql block
+DO $$
+BEGIN
+  CREATE VARIABLE do_test_svar AS date DEFAULT '2000-01-01';
+END;
+$$;
+
+SELECT do_test_svar;
+
+DROP VARIABLE do_test_svar;
+
+-- should fail
+CREATE IMMUTABLE VARIABLE xx AS int NOT NULL;
+
+-- REASSIGN OWNED test
+CREATE ROLE var_test_role1;
+CREATE ROLE var_test_role2;
+
+CREATE VARIABLE xxx_var AS int;
+
+ALTER VARIABLE xxx_var OWNER TO var_test_role1;
+REASSIGN OWNED BY var_test_role1 to var_test_role2;
+
+SELECT varowner::regrole FROM pg_variable WHERE varname = 'xxx_var';
+
+DROP OWNED BY var_test_role1;
+DROP ROLE var_test_role1;
+SELECT count(*) FROM pg_variable WHERE varname = 'xxx_var';
+
+DROP OWNED BY var_test_role2;
+DROP ROLE var_test_role2;
+SELECT count(*) FROM pg_variable WHERE varname = 'xxx_var';
-- 
2.17.0


--qxfKREH7IwbezJ+T
Content-Type: text/x-diff; charset=iso-8859-1
Content-Disposition: attachment;
 filename="0002-Schema-variables-new-implementation-for-Postgres-15.patch"
Content-Transfer-Encoding: 8bit



^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread

* [PATCH] Do not check the REPLICATION attribute when running REPACK.
@ 2026-04-20 07:20  Antonin Houska <ah@cybertec.at>
  0 siblings, 0 replies; 327+ messages in thread

From: Antonin Houska @ 2026-04-20 07:20 UTC (permalink / raw)

Although REPACK (CONCURRENTLY) uses replication slots, there is no concern
that the slot will leak data of other users because the MAINTAIN privilege on
the table is required anyway. The REPLICATION attribute is also not needed to
prevent REPACK from stealing slots from logical replication, since commit
e76d8c749c introduces a limit on the maximum number of slots used by REPACK.
---
 src/backend/commands/repack_worker.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index b17edd771e2..e4a4860805b 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -214,7 +214,6 @@ repack_setup_logical_decoding(Oid relid)
 	/*
 	 * Make sure we can use logical decoding.
 	 */
-	CheckSlotPermissions();
 	CheckLogicalDecodingRequirements(true);
 
 	/*
-- 
2.47.3


--=-=-=--





^ permalink  raw  reply  [nested|flat] 327+ messages in thread


end of thread, other threads:[~2026-04-20 07:20 UTC | newest]

Thread overview: 327+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2021-04-02 06:02 [PATCH] Asymmetric partitionwise join. Andrey Lepikhov <a.lepikhov@postgrespro.ru>
2021-04-02 06:02 [PATCH] Asymmetric partitionwise join. Andrey Lepikhov <a.lepikhov@postgrespro.ru>
2021-04-02 06:02 [PATCH] Asymmetric partitionwise join. Andrey Lepikhov <a.lepikhov@postgrespro.ru>
2021-10-30 06:35 [PATCH 1/3] Schema variables - new implementation for Postgres 15 Pavel Stehule <pavel.stehule@gmail.com>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>
2026-04-20 07:20 [PATCH] Do not check the REPLICATION attribute when running REPACK. Antonin Houska <ah@cybertec.at>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox