reindex-conc-predicates-v1.patch
text/x-diff
Filename: reindex-conc-predicates-v1.patch
Type: text/x-diff
Part: 0
Patch
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| contrib/amcheck/verify_nbtree.c | 1 | 1 |
| src/backend/access/brin/brin.c | 1 | 1 |
| src/backend/access/nbtree/nbtsort.c | 1 | 1 |
| src/backend/catalog/heap.c | 1 | 1 |
| src/backend/catalog/index.c | 11 | 7 |
| src/backend/commands/analyze.c | 1 | 1 |
| src/backend/commands/constraint.c | 1 | 1 |
| src/backend/commands/indexcmds.c | 1 | 1 |
| src/backend/commands/matview.c | 1 | 1 |
| src/backend/commands/tablecmds.c | 7 | 7 |
| src/backend/executor/execIndexing.c | 1 | 1 |
| src/backend/optimizer/plan/planner.c | 2 | 2 |
| src/backend/optimizer/util/plancat.c | 4 | 4 |
| src/backend/parser/parse_utilcmd.c | 2 | 2 |
| src/backend/utils/cache/relcache.c | 38 | 23 |
| src/backend/utils/sort/tuplesort.c | 1 | 1 |
| src/include/catalog/index.h | 1 | 1 |
| src/include/utils/relcache.h | 2 | 2 |
| src/test/regress/expected/create_index.out | 34 | 0 |
| src/test/regress/sql/create_index.sql | 30 | 0 |
diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index 9126c18d0e..6bfce99ca2 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -514,7 +514,7 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
*/
if (state->heapallindexed)
{
- IndexInfo *indexinfo = BuildIndexInfo(state->rel);
+ IndexInfo *indexinfo = BuildIndexInfo(state->rel, true);
TableScanDesc scan;
/* Report on extra downlink checks performed in readonly case */
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index ae7b729edd..ab68840ebc 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -1370,7 +1370,7 @@ brinsummarize(Relation index, Relation heapRel, BlockNumber pageRange,
Assert(!indexInfo);
state = initialize_brin_buildstate(index, revmap,
pagesPerRange);
- indexInfo = BuildIndexInfo(index);
+ indexInfo = BuildIndexInfo(index, true);
}
summarize_range(indexInfo, state, heapRel, startBlk, heapNumBlocks);
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index d0b9013caf..b73c40ee8b 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -1766,7 +1766,7 @@ _bt_parallel_scan_and_sort(BTSpool *btspool, BTSpool *btspool2,
buildstate.btleader = NULL;
/* Join parallel scan */
- indexInfo = BuildIndexInfo(btspool->index);
+ indexInfo = BuildIndexInfo(btspool->index, true);
indexInfo->ii_Concurrent = btshared->isconcurrent;
scan = table_beginscan_parallel(btspool->heap,
ParallelTableScanFromBTShared(btshared));
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 032fab9ac4..4db8f0615e 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -3149,7 +3149,7 @@ RelationTruncateIndexes(Relation heapRelation)
currentIndex = index_open(indexId, AccessExclusiveLock);
/* Fetch info needed for index_build */
- indexInfo = BuildIndexInfo(currentIndex);
+ indexInfo = BuildIndexInfo(currentIndex, true);
/*
* Now truncate the actual file (and discard buffers).
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9234e93261..80eaddb59a 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1212,7 +1212,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
indexRelation = index_open(oldIndexId, RowExclusiveLock);
/* New index uses the same index information as old index */
- indexInfo = BuildIndexInfo(indexRelation);
+ indexInfo = BuildIndexInfo(indexRelation, false);
/* Get the array of class and column options IDs from index info */
indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldIndexId));
@@ -1312,7 +1312,7 @@ index_concurrently_build(Oid heapRelationId,
* commit of the transaction where this concurrent index was created at
* the catalog level.
*/
- indexInfo = BuildIndexInfo(indexRelation);
+ indexInfo = BuildIndexInfo(indexRelation, true);
Assert(!indexInfo->ii_ReadyForInserts);
indexInfo->ii_Concurrent = true;
indexInfo->ii_BrokenHotChain = false;
@@ -2162,10 +2162,14 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
* FormIndexDatum, which is used for both index_build() and later insertion
* of individual index tuples. Normally we build an IndexInfo for an index
* just once per command, and then use it for (potentially) many tuples.
+ *
+ * If "optimize" is true, index expressions and predicates are not made
+ * planner-ready. This is used by REINDEX CONCURRENTLY when creating a
+ * duplicate index entry rebuilt concurrently.
* ----------------
*/
IndexInfo *
-BuildIndexInfo(Relation index)
+BuildIndexInfo(Relation index, bool optimize)
{
IndexInfo *ii = makeNode(IndexInfo);
Form_pg_index indexStruct = index->rd_index;
@@ -2186,11 +2190,11 @@ BuildIndexInfo(Relation index)
ii->ii_IndexAttrNumbers[i] = indexStruct->indkey.values[i];
/* fetch any expressions needed for expressional indexes */
- ii->ii_Expressions = RelationGetIndexExpressions(index);
+ ii->ii_Expressions = RelationGetIndexExpressions(index, optimize);
ii->ii_ExpressionsState = NIL;
/* fetch index predicate if any */
- ii->ii_Predicate = RelationGetIndexPredicate(index);
+ ii->ii_Predicate = RelationGetIndexPredicate(index, optimize);
ii->ii_PredicateState = NULL;
/* fetch exclusion constraint info if any */
@@ -3034,7 +3038,7 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
* passed in from DefineIndex, but its copy is long gone due to having
* been built in a previous transaction.)
*/
- indexInfo = BuildIndexInfo(indexRelation);
+ indexInfo = BuildIndexInfo(indexRelation, true);
/* mark build is concurrent just for consistency */
indexInfo->ii_Concurrent = true;
@@ -3322,7 +3326,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
TransferPredicateLocksToHeapRelation(iRel);
/* Fetch info needed for index_build */
- indexInfo = BuildIndexInfo(iRel);
+ indexInfo = BuildIndexInfo(iRel, true);
/* If requested, skip checking uniqueness/exclusion constraints */
if (skip_constraint_checks)
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 8d633f2585..3f5b05b325 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -434,7 +434,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
AnlIndexData *thisdata = &indexdata[ind];
IndexInfo *indexInfo;
- thisdata->indexInfo = indexInfo = BuildIndexInfo(Irel[ind]);
+ thisdata->indexInfo = indexInfo = BuildIndexInfo(Irel[ind], true);
thisdata->tupleFract = 1.0; /* fix later if partial */
if (indexInfo->ii_Expressions != NIL && va_cols == NIL)
{
diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c
index 806962a686..05fef01e79 100644
--- a/src/backend/commands/constraint.c
+++ b/src/backend/commands/constraint.c
@@ -132,7 +132,7 @@ unique_key_recheck(PG_FUNCTION_ARGS)
*/
indexRel = index_open(trigdata->tg_trigger->tgconstrindid,
RowExclusiveLock);
- indexInfo = BuildIndexInfo(indexRel);
+ indexInfo = BuildIndexInfo(indexRel, true);
/*
* Typically the index won't have expressions, but if it does we need an
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index fd299273c5..42675360ef 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1121,7 +1121,7 @@ DefineIndex(Oid relationId,
continue;
cldidx = index_open(cldidxid, lockmode);
- cldIdxInfo = BuildIndexInfo(cldidx);
+ cldIdxInfo = BuildIndexInfo(cldidx, true);
if (CompareIndexInfo(cldIdxInfo, indexInfo,
cldidx->rd_indcollation,
collationObjectId,
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 537d0e8cef..5dfd06447e 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -871,7 +871,7 @@ is_usable_unique_index(Relation indexRel)
indexStruct->indimmediate &&
indexRel->rd_rel->relam == BTREE_AM_OID &&
indexStruct->indisvalid &&
- RelationGetIndexPredicate(indexRel) == NIL &&
+ RelationGetIndexPredicate(indexRel, true) == NIL &&
indexStruct->indnatts > 0)
{
/*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index fc1c4dfa4c..7ba1bfdfeb 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7242,7 +7242,7 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
indexName = pstrdup(RelationGetRelationName(indexRel));
- indexInfo = BuildIndexInfo(indexRel);
+ indexInfo = BuildIndexInfo(indexRel, true);
/* this should have been checked at parse time */
if (!indexInfo->ii_Unique)
@@ -13817,13 +13817,13 @@ ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode
errmsg("cannot use non-immediate index \"%s\" as replica identity",
RelationGetRelationName(indexRel))));
/* Expression indexes aren't supported. */
- if (RelationGetIndexExpressions(indexRel) != NIL)
+ if (RelationGetIndexExpressions(indexRel, true) != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use expression index \"%s\" as replica identity",
RelationGetRelationName(indexRel))));
/* Predicate indexes aren't supported. */
- if (RelationGetIndexPredicate(indexRel) != NIL)
+ if (RelationGetIndexPredicate(indexRel, true) != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use partial index \"%s\" as replica identity",
@@ -15725,7 +15725,7 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
Oid cldIdxId = lfirst_oid(cell);
attachrelIdxRels[i] = index_open(cldIdxId, AccessShareLock);
- attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i]);
+ attachInfos[i] = BuildIndexInfo(attachrelIdxRels[i], true);
i++;
}
@@ -15781,7 +15781,7 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
}
/* construct an indexinfo to compare existing indexes against */
- info = BuildIndexInfo(idxRel);
+ info = BuildIndexInfo(idxRel, true);
attmap = convert_tuples_by_name_map(RelationGetDescr(attachrel),
RelationGetDescr(rel),
gettext_noop("could not convert row type"));
@@ -16357,8 +16357,8 @@ ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
RelationGetRelationName(parentTbl))));
/* Ensure the indexes are compatible */
- childInfo = BuildIndexInfo(partIdx);
- parentInfo = BuildIndexInfo(parentIdx);
+ childInfo = BuildIndexInfo(partIdx, true);
+ parentInfo = BuildIndexInfo(parentIdx, true);
attmap = convert_tuples_by_name_map(RelationGetDescr(partTbl),
RelationGetDescr(parentTbl),
gettext_noop("could not convert row type"));
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index 40bd8049f0..4158b02f04 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -199,7 +199,7 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative)
indexDesc = index_open(indexOid, RowExclusiveLock);
/* extract index key information from the index's pg_index info */
- ii = BuildIndexInfo(indexDesc);
+ ii = BuildIndexInfo(indexDesc, true);
/*
* If the indexes are to be used for speculative insertion, add extra
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ca3b7f29e1..076530172e 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -6307,8 +6307,8 @@ plan_create_index_workers(Oid tableOid, Oid indexOid)
* safe.
*/
if (heap->rd_rel->relpersistence == RELPERSISTENCE_TEMP ||
- !is_parallel_safe(root, (Node *) RelationGetIndexExpressions(index)) ||
- !is_parallel_safe(root, (Node *) RelationGetIndexPredicate(index)))
+ !is_parallel_safe(root, (Node *) RelationGetIndexExpressions(index, true)) ||
+ !is_parallel_safe(root, (Node *) RelationGetIndexPredicate(index, true)))
{
parallel_workers = 0;
goto done;
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 98e99481c6..93a300880c 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -368,8 +368,8 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
* correct varno for the parent relation, so that they match up
* correctly against qual clauses.
*/
- info->indexprs = RelationGetIndexExpressions(indexRelation);
- info->indpred = RelationGetIndexPredicate(indexRelation);
+ info->indexprs = RelationGetIndexExpressions(indexRelation, true);
+ info->indpred = RelationGetIndexPredicate(indexRelation, true);
if (info->indexprs && varno != 1)
ChangeVarNodes((Node *) info->indexprs, 1, varno, 0);
if (info->indpred && varno != 1)
@@ -759,7 +759,7 @@ infer_arbiter_indexes(PlannerInfo *root)
goto next;
/* Expression attributes (if any) must match */
- idxExprs = RelationGetIndexExpressions(idxRel);
+ idxExprs = RelationGetIndexExpressions(idxRel, true);
foreach(el, onconflict->arbiterElems)
{
InferenceElem *elem = (InferenceElem *) lfirst(el);
@@ -810,7 +810,7 @@ infer_arbiter_indexes(PlannerInfo *root)
* If it's a partial index, its predicate must be implied by the ON
* CONFLICT's WHERE clause.
*/
- predExprs = RelationGetIndexPredicate(idxRel);
+ predExprs = RelationGetIndexPredicate(idxRel, true);
if (!predicate_implied_by(predExprs, (List *) onconflict->arbiterWhere, false))
goto next;
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index f0f6ee7db6..4c03f38581 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2078,14 +2078,14 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
errdetail("Cannot create a primary key or unique constraint using such an index."),
parser_errposition(cxt->pstate, constraint->location)));
- if (RelationGetIndexExpressions(index_rel) != NIL)
+ if (RelationGetIndexExpressions(index_rel, true) != NIL)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("index \"%s\" contains expressions", index_name),
errdetail("Cannot create a primary key or unique constraint using such an index."),
parser_errposition(cxt->pstate, constraint->location)));
- if (RelationGetIndexPredicate(index_rel) != NIL)
+ if (RelationGetIndexPredicate(index_rel, true) != NIL)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is a partial index", index_name),
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 7aa5d7c7fa..5e478b785c 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -4570,9 +4570,13 @@ RelationGetReplicaIndex(Relation relation)
* Otherwise, the returned tree is copied into the caller's memory context.
* (We don't want to return a pointer to the relcache copy, since it could
* disappear due to relcache invalidation.)
+ *
+ * If "optimize" is true, apply all optimizations to make this result
+ * usable by the planner. Non-optimized expressions are currently used
+ * when creating a concurrent index for REINDEX CONCURRENTLY.
*/
List *
-RelationGetIndexExpressions(Relation relation)
+RelationGetIndexExpressions(Relation relation, bool optimize)
{
List *result;
Datum exprsDatum;
@@ -4603,14 +4607,17 @@ RelationGetIndexExpressions(Relation relation)
result = (List *) stringToNode(exprsString);
pfree(exprsString);
- /*
- * Run the expressions through eval_const_expressions. This is not just an
- * optimization, but is necessary, because the planner will be comparing
- * them to similarly-processed qual clauses, and may fail to detect valid
- * matches without this. We must not use canonicalize_qual, however,
- * since these aren't qual expressions.
- */
- result = (List *) eval_const_expressions(NULL, (Node *) result);
+ if (optimize)
+ {
+ /*
+ * Run the expressions through eval_const_expressions. This is not just an
+ * optimization, but is necessary, because the planner will be comparing
+ * them to similarly-processed qual clauses, and may fail to detect valid
+ * matches without this. We must not use canonicalize_qual, however,
+ * since these aren't qual expressions.
+ */
+ result = (List *) eval_const_expressions(NULL, (Node *) result);
+ }
/* May as well fix opfuncids too */
fix_opfuncids((Node *) result);
@@ -4627,14 +4634,18 @@ RelationGetIndexExpressions(Relation relation)
* RelationGetIndexPredicate -- get the index predicate for an index
*
* We cache the result of transforming pg_index.indpred into an implicit-AND
- * node tree (suitable for use in planning).
+ * node tree suitable for use in planning if "optimize" is true.
* If the rel is not an index or has no predicate, we return NIL.
* Otherwise, the returned tree is copied into the caller's memory context.
* (We don't want to return a pointer to the relcache copy, since it could
* disappear due to relcache invalidation.)
+ *
+ * If "optimize" is true, apply all optimizations to make this result
+ * usable by the planner. Non-optimized expressions are currently used
+ * when creating a concurrent index for REINDEX CONCURRENTLY.
*/
List *
-RelationGetIndexPredicate(Relation relation)
+RelationGetIndexPredicate(Relation relation, bool optimize)
{
List *result;
Datum predDatum;
@@ -4665,24 +4676,28 @@ RelationGetIndexPredicate(Relation relation)
result = (List *) stringToNode(predString);
pfree(predString);
- /*
- * Run the expression through const-simplification and canonicalization.
- * This is not just an optimization, but is necessary, because the planner
- * will be comparing it to similarly-processed qual clauses, and may fail
- * to detect valid matches without this. This must match the processing
- * done to qual clauses in preprocess_expression()! (We can skip the
- * stuff involving subqueries, however, since we don't allow any in index
- * predicates.)
- */
- result = (List *) eval_const_expressions(NULL, (Node *) result);
+ if (optimize)
+ {
+ /*
+ * Run the expression through const-simplification and canonicalization.
+ * This is not just an optimization, but is necessary, because the planner
+ * will be comparing it to similarly-processed qual clauses, and may fail
+ * to detect valid matches without this. This must match the processing
+ * done to qual clauses in preprocess_expression()! (We can skip the
+ * stuff involving subqueries, however, since we don't allow any in index
+ * predicates.)
+ */
+ result = (List *) eval_const_expressions(NULL, (Node *) result);
- result = (List *) canonicalize_qual((Expr *) result, false);
+ result = (List *) canonicalize_qual((Expr *) result, false);
+ }
/* Also convert to implicit-AND format */
result = make_ands_implicit((Expr *) result);
/* May as well fix opfuncids too */
- fix_opfuncids((Node *) result);
+ if (optimize)
+ fix_opfuncids((Node *) result);
/* Now save a copy of the completed tree in the relcache entry. */
oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 7b8e67899e..cd963fda3f 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -915,7 +915,7 @@ tuplesort_begin_cluster(TupleDesc tupDesc,
state->readtup = readtup_cluster;
state->abbrevNext = 10;
- state->indexInfo = BuildIndexInfo(indexRel);
+ state->indexInfo = BuildIndexInfo(indexRel, true);
state->tupDesc = tupDesc; /* assume we need not copy tupDesc */
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 1113d25b2d..5b9d429e9f 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -104,7 +104,7 @@ extern ObjectAddress index_constraint_create(Relation heapRelation,
extern void index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode);
-extern IndexInfo *BuildIndexInfo(Relation index);
+extern IndexInfo *BuildIndexInfo(Relation index, bool optimize);
extern bool CompareIndexInfo(IndexInfo *info1, IndexInfo *info2,
Oid *collations1, Oid *collations2,
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index d9c10ffcba..ee96bf0d36 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -47,8 +47,8 @@ extern List *RelationGetIndexList(Relation relation);
extern List *RelationGetStatExtList(Relation relation);
extern Oid RelationGetPrimaryKeyIndex(Relation relation);
extern Oid RelationGetReplicaIndex(Relation relation);
-extern List *RelationGetIndexExpressions(Relation relation);
-extern List *RelationGetIndexPredicate(Relation relation);
+extern List *RelationGetIndexExpressions(Relation relation, bool optimize);
+extern List *RelationGetIndexPredicate(Relation relation, bool optimize);
typedef enum IndexAttrBitmapKind
{
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 9305649c11..ab419972c8 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2170,6 +2170,40 @@ Indexes:
"concur_reindex_ind5" UNIQUE, btree (c1)
DROP TABLE concur_reindex_tab4;
+-- Check handling of indexes with expressions and predicates.
+-- Run a couple of commands, then the state of the expression and
+-- predicate tree stored in the catalogs before and after the rebuilds.
+-- Note that the index name is used for the tree comparison as the OID
+-- of an index rebuilt changes.
+CREATE TEMP TABLE concur_reindex_trees (
+ relname text,
+ indexprs_before pg_node_tree,
+ indexprs_after pg_node_tree,
+ indpred_before pg_node_tree,
+ indpred_after pg_node_tree);
+CREATE TABLE concur_exprs_tab (c1 int , c2 boolean);
+INSERT INTO concur_exprs_tab (c1, c2) VALUES (1369652450, FALSE),
+ (414515746, TRUE),
+ (897778963, FALSE);
+CREATE UNIQUE INDEX concur_exprs_index ON concur_exprs_tab ((1 / c1))
+ WHERE ('-H') >= (c2::TEXT) COLLATE "C";
+INSERT INTO concur_reindex_trees (relname, indexprs_before, indpred_before)
+ SELECT indexrelid::regclass, indexprs, indpred FROM pg_index
+ WHERE indexrelid = 'concur_exprs_index'::regclass;
+REINDEX TABLE CONCURRENTLY concur_exprs_tab;
+UPDATE concur_reindex_trees SET (indexprs_after, indpred_after) =
+ (SELECT indexprs, indpred FROM pg_index WHERE indexrelid = 'concur_exprs_index'::regclass)
+ WHERE relname = 'concur_exprs_index';
+SELECT relname,
+ indexprs_before = indexprs_after AS same_exprs,
+ indpred_before = indpred_after AS same_pred
+ FROM concur_reindex_trees;
+ relname | same_exprs | same_pred
+--------------------+------------+-----------
+ concur_exprs_index | f | f
+(1 row)
+
+DROP TABLE concur_exprs_tab;
--
-- REINDEX SCHEMA
--
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index cd46f071bd..c92e107b35 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -872,6 +872,36 @@ REINDEX INDEX CONCURRENTLY concur_reindex_ind5;
\d concur_reindex_tab4
DROP TABLE concur_reindex_tab4;
+-- Check handling of indexes with expressions and predicates.
+-- Run a couple of commands, then the state of the expression and
+-- predicate tree stored in the catalogs before and after the rebuilds.
+-- Note that the index name is used for the tree comparison as the OID
+-- of an index rebuilt changes.
+CREATE TEMP TABLE concur_reindex_trees (
+ relname text,
+ indexprs_before pg_node_tree,
+ indexprs_after pg_node_tree,
+ indpred_before pg_node_tree,
+ indpred_after pg_node_tree);
+CREATE TABLE concur_exprs_tab (c1 int , c2 boolean);
+INSERT INTO concur_exprs_tab (c1, c2) VALUES (1369652450, FALSE),
+ (414515746, TRUE),
+ (897778963, FALSE);
+CREATE UNIQUE INDEX concur_exprs_index ON concur_exprs_tab ((1 / c1))
+ WHERE ('-H') >= (c2::TEXT) COLLATE "C";
+INSERT INTO concur_reindex_trees (relname, indexprs_before, indpred_before)
+ SELECT indexrelid::regclass, indexprs, indpred FROM pg_index
+ WHERE indexrelid = 'concur_exprs_index'::regclass;
+REINDEX TABLE CONCURRENTLY concur_exprs_tab;
+UPDATE concur_reindex_trees SET (indexprs_after, indpred_after) =
+ (SELECT indexprs, indpred FROM pg_index WHERE indexrelid = 'concur_exprs_index'::regclass)
+ WHERE relname = 'concur_exprs_index';
+SELECT relname,
+ indexprs_before = indexprs_after AS same_exprs,
+ indpred_before = indpred_after AS same_pred
+ FROM concur_reindex_trees;
+DROP TABLE concur_exprs_tab;
+
--
-- REINDEX SCHEMA
--