agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH v1 3/3] LO frontend PQexecParams 261+ messages / 2 participants [nested] [flat]
* [PATCH v1 3/3] LO frontend PQexecParams @ 2026-05-26 16:12 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 261+ messages in thread From: Nathan Bossart @ 2026-05-26 16:12 UTC (permalink / raw) --- src/interfaces/libpq/fe-connect.c | 1 - src/interfaces/libpq/fe-lobj.c | 236 ++++-------------------------- src/interfaces/libpq/libpq-int.h | 1 - 3 files changed, 26 insertions(+), 212 deletions(-) diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 01c9735f276..9f6aa01dc0e 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -692,7 +692,6 @@ pqDropServerData(PGconn *conn) conn->in_hot_standby = PG_BOOL_UNKNOWN; conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS; conn->sversion = 0; - conn->lobjprepared = false; /* Reset assorted other per-connection state */ conn->last_sqlstate[0] = '\0'; diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c index 41573c22c80..17c1d699a48 100644 --- a/src/interfaces/libpq/fe-lobj.c +++ b/src/interfaces/libpq/fe-lobj.c @@ -41,89 +41,6 @@ #define LO_BUFSIZE 8192 -typedef struct PGlobjfuncs -{ - char *name; - char *args; - int nargs; - int version; -} PGlobjfuncs; - -static const PGlobjfuncs lobjfuncs[] = -{ - { - "lo_open", - "$1::pg_catalog.oid, $2::pg_catalog.int4", - 2 - }, - { - "lo_close", - "$1::pg_catalog.int4", - 1 - }, - { - "lo_creat", - "$1::pg_catalog.int4", - 1 - }, - { - "lo_create", - "$1::pg_catalog.oid", - 1, - 80100 - }, - { - "lo_unlink", - "$1::pg_catalog.oid", - 1 - }, - { - "lo_lseek", - "$1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4", - 3 - }, - { - "lo_lseek64", - "$1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4", - 3, - 90300 - }, - { - "lo_tell", - "$1::pg_catalog.int4", - 1 - }, - { - "lo_tell64", - "$1::pg_catalog.int4", - 1, - 90300 - }, - { - "lo_truncate", - "$1::pg_catalog.int4, $2::pg_catalog.int4", - 2, - 80300 - }, - { - "lo_truncate64", - "$1::pg_catalog.int4, $2::pg_catalog.int8", - 2, - 90300 - }, - { - "loread", - "$1::pg_catalog.int4, $2::pg_catalog.int4", - 2 - }, - { - "lowrite", - "$1::pg_catalog.int4, $2::pg_catalog.bytea", - 2 - } -}; - -static int lo_initialize(PGconn *conn); static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid); static bool @@ -153,17 +70,14 @@ lo_open(PGconn *conn, Oid lobjId, int mode) int argFormats[] = {1, 1}; PGresult *res; - if (lo_initialize(conn) < 0) - return -1; - lobjId = pg_hton32(lobjId); argv[0] = (char *) &lobjId; mode = pg_hton32(mode); argv[1] = (char *) &mode; - res = PQexecPrepared(conn, "libpq_internal_lo_open", 2, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lo_open($1::pg_catalog.oid, $2::pg_catalog.int4)", 2, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(fd))) { @@ -194,14 +108,11 @@ lo_close(PGconn *conn, int fd) PGresult *res; int retval; - if (lo_initialize(conn) < 0) - return -1; - fd = pg_hton32(fd); argv[0] = (char *) &fd; - res = PQexecPrepared(conn, "libpq_internal_lo_close", 1, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lo_close($1::pg_catalog.int4)", 1, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { @@ -232,9 +143,6 @@ lo_truncate(PGconn *conn, int fd, size_t len) PGresult *res; int retval; - if (lo_initialize(conn) < 0) - return -1; - if (PQserverVersion(conn) < 80300) { libpq_append_conn_error(conn, "server does not support function \"%s\"", @@ -263,8 +171,8 @@ lo_truncate(PGconn *conn, int fd, size_t len) len = pg_hton32(len); argv[1] = (char *) &len; - res = PQexecPrepared(conn, "libpq_internal_lo_truncate", 2, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { @@ -295,9 +203,6 @@ lo_truncate64(PGconn *conn, int fd, int64_t len) PGresult *res; int retval; - if (lo_initialize(conn) < 0) - return -1; - if (PQserverVersion(conn) < 90300) { libpq_append_conn_error(conn, "server does not support function \"%s\"", @@ -311,8 +216,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len) len = pg_hton64(len); argv[1] = (char *) &len; - res = PQexecPrepared(conn, "ligpq_internal_lo_truncate64", 2, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lo_truncate64($1::pg_catalog.int4, $2::pg_catalog.int8)", 2, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { @@ -343,9 +248,6 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len) int argFormats[] = {1, 1}; PGresult *res; - if (lo_initialize(conn) < 0) - return -1; - /* * Long ago, somebody thought it'd be a good idea to declare this function * as taking size_t ... but the underlying backend function only accepts a @@ -364,8 +266,8 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len) len = pg_hton32(len); argv[1] = (char *) &len; - res = PQexecPrepared(conn, "libpq_internal_loread", 2, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.loread($1::pg_catalog.int4, $2::pg_catalog.int4)", 2, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, -1)) { @@ -401,9 +303,6 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len) PGresult *res; int retval; - if (lo_initialize(conn) < 0) - return -1; - /* * Long ago, somebody thought it'd be a good idea to declare this function * as taking size_t ... but the underlying backend function only accepts a @@ -421,8 +320,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len) argv[1] = unconstify(char *, buf); - res = PQexecPrepared(conn, "libpq_internal_lowrite", 2, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lowrite($1::pg_catalog.int4, $2::pg_catalog.bytea)", 2, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { @@ -450,9 +349,6 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence) PGresult *res; int retval; - if (lo_initialize(conn) < 0) - return -1; - fd = pg_hton32(fd); argv[0] = (char *) &fd; @@ -462,8 +358,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence) whence = pg_hton32(whence); argv[2] = (char *) &whence; - res = PQexecPrepared(conn, "libpq_internal_lseek", 3, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lseek($1::pg_catalog.int4, $2::pg_catalog.int4, $3::pg_catalog.int4)", 3, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { @@ -491,9 +387,6 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence) PGresult *res; int64 retval; - if (lo_initialize(conn) < 0) - return -1; - if (PQserverVersion(conn) < 90300) { libpq_append_conn_error(conn, "server does not support function \"%s\"", @@ -510,8 +403,8 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence) whence = pg_hton32(whence); argv[2] = (char *) &whence; - res = PQexecPrepared(conn, "ligpq_internal_lo_lseek64", 3, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lo_lseek64($1::pg_catalog.int4, $2::pg_catalog.int8, $3::pg_catalog.int4)", 3, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { memcpy(&retval, PQgetvalue(res, 0, 0), sizeof(retval)); @@ -542,14 +435,11 @@ lo_creat(PGconn *conn, int mode) PGresult *res; int retval; - if (lo_initialize(conn) < 0) - return InvalidOid; - mode = pg_hton32(mode); argv[0] = (char *) &mode; - res = PQexecPrepared(conn, "libpq_internal_lo_creat", 1, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lo_creat($1::pg_catalog.int4)", 1, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { @@ -581,9 +471,6 @@ lo_create(PGconn *conn, Oid lobjId) PGresult *res; int retval; - if (lo_initialize(conn) < 0) - return InvalidOid; - if (PQserverVersion(conn) < 80100) { libpq_append_conn_error(conn, "server does not support function \"%s\"", @@ -594,8 +481,8 @@ lo_create(PGconn *conn, Oid lobjId) lobjId = pg_hton32(lobjId); argv[0] = (char *) &lobjId; - res = PQexecPrepared(conn, "libpq_internal_lo_create", 1, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lo_create($1::pg_catalog.oid)", 1, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { @@ -624,14 +511,11 @@ lo_tell(PGconn *conn, int fd) int argFormats[] = {1}; PGresult *res; - if (lo_initialize(conn) < 0) - return -1; - fd = pg_hton32(fd); argv[0] = (char *) &fd; - res = PQexecPrepared(conn, "libpq_internal_lo_tell", 1, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lo_tell($1::pg_catalog.int4)", 1, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { @@ -659,9 +543,6 @@ lo_tell64(PGconn *conn, int fd) int argFormats[] = {1}; PGresult *res; - if (lo_initialize(conn) < 0) - return -1; - if (PQserverVersion(conn) < 90300) { libpq_append_conn_error(conn, "server does not support functions \"%s\"", @@ -672,8 +553,8 @@ lo_tell64(PGconn *conn, int fd) fd = pg_hton32(fd); argv[0] = (char *) &fd; - res = PQexecPrepared(conn, "libpq_internal_lo_tell64", 1, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lo_tell64($1::pg_catalog.int4)", 1, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { @@ -702,14 +583,11 @@ lo_unlink(PGconn *conn, Oid lobjId) PGresult *res; int retval; - if (lo_initialize(conn) < 0) - return -1; - lobjId = pg_hton32(lobjId); argv[0] = (char *) &lobjId; - res = PQexecPrepared(conn, "libpq_internal_lo_unlink", 1, - (const char *const *) argv, argLens, argFormats, 1); + res = PQexecParams(conn, "SELECT pg_catalog.lo_unlink($1::pg_catalog.oid)", 1, NULL, + (const char *const *) argv, argLens, argFormats, 1); if (lo_result_is_valid(res, sizeof(retval))) { @@ -938,65 +816,3 @@ lo_export(PGconn *conn, Oid lobjId, const char *filename) return result; } - - -/* - * lo_initialize - * - * Initialize for a new large-object operation on an existing connection. - * Return 0 if OK, -1 on failure. - * - * If we haven't previously done so, we prepared statements for all the - * functions that are required for large object operations. - */ -static int -lo_initialize(PGconn *conn) -{ - /* Nothing we can do with no connection */ - if (conn == NULL) - return -1; - - /* Since this is the beginning of a query cycle, reset the error state */ - pqClearConnErrorState(conn); - - /* Nothing else to do if we already prepared the statements */ - if (conn->lobjprepared) - return 0; - - for (int i = 0; i < lengthof(lobjfuncs); i++) - { - PGresult *res; - ExecStatusType status; - PQExpBufferData pname; - PQExpBufferData pquery; - - if (PQserverVersion(conn) < lobjfuncs[i].version) - continue; - - initPQExpBuffer(&pname); - initPQExpBuffer(&pquery); - - appendPQExpBuffer(&pname, "libpq_internal_%s", - lobjfuncs[i].name); - appendPQExpBuffer(&pquery, "SELECT pg_catalog.%s(%s)", - lobjfuncs[i].name, lobjfuncs[i].args); - - res = PQprepare(conn, pname.data, pquery.data, - lobjfuncs[i].nargs, NULL); - status = PQresultStatus(res); - if (res) - PQclear(res); - - termPQExpBuffer(&pname); - termPQExpBuffer(&pquery); - - if (status == PGRES_COMMAND_OK) - continue; - - libpq_append_conn_error(conn, "query to prepare large object statements failed"); - return -1; - } - - conn->lobjprepared = true; - return 0; -} diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 9dd0f42b6b7..cf968f1519b 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -544,7 +544,6 @@ struct pg_conn PGTernaryBool in_hot_standby; /* in_hot_standby */ PGVerbosity verbosity; /* error/notice message verbosity */ PGContextVisibility show_context; /* whether to show CONTEXT field */ - bool lobjprepared; /* whether LO statements have been prepared */ pg_prng_state prng_state; /* prng state for load balancing connections */ -- 2.50.1 (Apple Git-155) --NDf4SqMA2rj1ZNJ4-- ^ permalink raw reply [nested|flat] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ 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; 261+ 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] 261+ messages in thread
end of thread, other threads:[~2026-07-03 10:47 UTC | newest] Thread overview: 261+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2026-05-26 16:12 [PATCH v1 3/3] LO frontend PQexecParams Nathan Bossart <[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]> 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]> 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]> 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