agora inbox for [email protected]
help / color / mirror / Atom feed[PATCH v47 6/9] rename cluster.c/h to repack.c/h
81+ messages / 1 participants
[nested] [flat]
* [PATCH v47 6/9] rename cluster.c/h to repack.c/h
@ 2026-03-27 15:40 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-03-27 15:40 UTC (permalink / raw)
---
src/backend/commands/Makefile | 2 +-
src/backend/commands/matview.c | 2 +-
src/backend/commands/meson.build | 2 +-
src/backend/commands/{cluster.c => repack.c} | 6 +++---
src/backend/commands/repack_worker.c | 2 +-
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/vacuum.c | 2 +-
src/backend/libpq/pqmq.c | 2 +-
src/backend/postmaster/bgworker.c | 2 +-
src/backend/replication/logical/decode.c | 2 +-
src/backend/storage/ipc/procsignal.c | 2 +-
src/backend/tcop/postgres.c | 2 +-
src/backend/tcop/utility.c | 2 +-
src/include/commands/{cluster.h => repack.h} | 12 ++++++------
14 files changed, 21 insertions(+), 21 deletions(-)
rename src/backend/commands/{cluster.c => repack.c} (99%)
rename src/include/commands/{cluster.h => repack.h} (92%)
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index 6926bc44818..5b9d084977e 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -18,7 +18,6 @@ OBJS = \
amcmds.o \
analyze.o \
async.o \
- cluster.o \
collationcmds.o \
comment.o \
constraint.o \
@@ -51,6 +50,7 @@ OBJS = \
proclang.o \
propgraphcmds.o \
publicationcmds.o \
+ repack.o \
repack_worker.o \
schemacmds.o \
seclabel.o \
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 539969d6eef..146a65dae8d 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -24,8 +24,8 @@
#include "catalog/namespace.h"
#include "catalog/pg_am.h"
#include "catalog/pg_opclass.h"
-#include "commands/cluster.h"
#include "commands/matview.h"
+#include "commands/repack.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "executor/executor.h"
diff --git a/src/backend/commands/meson.build b/src/backend/commands/meson.build
index 4a0e6f0002b..9f258d566eb 100644
--- a/src/backend/commands/meson.build
+++ b/src/backend/commands/meson.build
@@ -6,7 +6,6 @@ backend_sources += files(
'amcmds.c',
'analyze.c',
'async.c',
- 'cluster.c',
'collationcmds.c',
'comment.c',
'constraint.c',
@@ -39,6 +38,7 @@ backend_sources += files(
'proclang.c',
'propgraphcmds.c',
'publicationcmds.c',
+ 'repack.c',
'repack_worker.c',
'schemacmds.c',
'seclabel.c',
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/repack.c
similarity index 99%
rename from src/backend/commands/cluster.c
rename to src/backend/commands/repack.c
index c0220cb3380..9c807f75d71 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/repack.c
@@ -1,6 +1,6 @@
/*-------------------------------------------------------------------------
*
- * cluster.c
+ * repack.c
* REPACK a table; formerly known as CLUSTER. VACUUM FULL also uses
* parts of this code.
*
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * src/backend/commands/cluster.c
+ * src/backend/commands/repack.c
*
*-------------------------------------------------------------------------
*/
@@ -52,9 +52,9 @@
#include "catalog/pg_control.h"
#include "catalog/pg_inherits.h"
#include "catalog/toasting.h"
-#include "commands/cluster.h"
#include "commands/defrem.h"
#include "commands/progress.h"
+#include "commands/repack.h"
#include "commands/repack_internal.h"
#include "commands/tablecmds.h"
#include "commands/vacuum.h"
diff --git a/src/backend/commands/repack_worker.c b/src/backend/commands/repack_worker.c
index 35ab1a25c42..106b2b60441 100644
--- a/src/backend/commands/repack_worker.c
+++ b/src/backend/commands/repack_worker.c
@@ -20,7 +20,7 @@
#include "access/xlog_internal.h"
#include "access/xlogutils.h"
#include "access/xlogwait.h"
-#include "commands/cluster.h"
+#include "commands/repack.h"
#include "commands/repack_internal.h"
#include "libpq/pqmq.h"
#include "replication/snapbuild.h"
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1f61bc8520d..860d6def3eb 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -57,10 +57,10 @@
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "catalog/toasting.h"
-#include "commands/cluster.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
+#include "commands/repack.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 4f00c697bfb..b2a3d372631 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -38,9 +38,9 @@
#include "catalog/pg_database.h"
#include "catalog/pg_inherits.h"
#include "commands/async.h"
-#include "commands/cluster.h"
#include "commands/defrem.h"
#include "commands/progress.h"
+#include "commands/repack.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index 1000b7bb06e..cbf6c5a004f 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -14,7 +14,7 @@
#include "postgres.h"
#include "access/parallel.h"
-#include "commands/cluster.h"
+#include "commands/repack.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "libpq/pqmq.h"
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index 423ce9d8709..bc477361e7a 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -13,7 +13,7 @@
#include "postgres.h"
#include "access/parallel.h"
-#include "commands/cluster.h"
+#include "commands/repack.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index f172c0b2b40..8a969ddca41 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -33,7 +33,7 @@
#include "access/xlogreader.h"
#include "access/xlogrecord.h"
#include "catalog/pg_control.h"
-#include "commands/cluster.h"
+#include "commands/repack.h"
#include "replication/decode.h"
#include "replication/logical.h"
#include "replication/message.h"
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index dd980145ced..f02b9eb8312 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -19,7 +19,7 @@
#include "access/parallel.h"
#include "commands/async.h"
-#include "commands/cluster.h"
+#include "commands/repack.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/pg_bitutils.h"
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index b2936d503b6..47a2960a197 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -36,10 +36,10 @@
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/async.h"
-#include "commands/cluster.h"
#include "commands/event_trigger.h"
#include "commands/explain_state.h"
#include "commands/prepare.h"
+#include "commands/repack.h"
#include "common/pg_prng.h"
#include "jit/jit.h"
#include "libpq/libpq.h"
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 2b609bfc824..5f8c766c4be 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -26,7 +26,6 @@
#include "catalog/toasting.h"
#include "commands/alter.h"
#include "commands/async.h"
-#include "commands/cluster.h"
#include "commands/collationcmds.h"
#include "commands/comment.h"
#include "commands/conversioncmds.h"
@@ -46,6 +45,7 @@
#include "commands/proclang.h"
#include "commands/propgraphcmds.h"
#include "commands/publicationcmds.h"
+#include "commands/repack.h"
#include "commands/schemacmds.h"
#include "commands/seclabel.h"
#include "commands/sequence.h"
diff --git a/src/include/commands/cluster.h b/src/include/commands/repack.h
similarity index 92%
rename from src/include/commands/cluster.h
rename to src/include/commands/repack.h
index 81673ffad1a..195b65dfd42 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/repack.h
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
- * cluster.h
- * header file for postgres cluster command stuff
+ * repack.h
+ * header file for the REPACK command
*
* Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California
*
- * src/include/commands/cluster.h
+ * src/include/commands/repack.h
*
*-------------------------------------------------------------------------
*/
-#ifndef CLUSTER_H
-#define CLUSTER_H
+#ifndef REPACK_H
+#define REPACK_H
#include <signal.h>
@@ -66,4 +66,4 @@ extern void RepackWorkerMain(Datum main_arg);
extern bool IsRepackWorker(void);
-#endif /* CLUSTER_H */
+#endif /* REPACK_H */
--
2.47.3
--2fxmamo6mu2qbxgv
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="v47-0007-Fix-a-few-problems-in-index-build-progress-repor.patch"
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <[email protected]>
0 siblings, 0 replies; 81+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <[email protected]>
Reviewed-by: Ewan Young <[email protected]>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 81+ messages in thread
end of thread, other threads:[~2026-07-03 10:47 UTC | newest]
Thread overview: 81+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-03-27 15:40 [PATCH v47 6/9] rename cluster.c/h to repack.c/h Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox