diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml index a90b4e2..b6fe908 100644 *** a/doc/src/sgml/xindex.sgml --- b/doc/src/sgml/xindex.sgml *************** *** 834,846 **** ALTER OPERATOR FAMILY integer_ops USING btree ADD In a B-tree operator family, all the operators in the family must sort compatibly, meaning that the transitive laws hold across all the data types ! supported by the family: if A = B and B = C, then A = ! C, and if A < B and B < C, then A < C. For each ! operator in the family there must be a support function having the same ! two input data types as the operator. It is recommended that a family be ! complete, i.e., for each combination of data types, all operators are ! included. Each operator class should include just the non-cross-type ! operators and support function for its data type. --- 834,848 ---- In a B-tree operator family, all the operators in the family must sort compatibly, meaning that the transitive laws hold across all the data types ! supported by the family: if A = B and B = C, then A = C, ! and if A < B and B < C, then A < C. Subjecting operands ! to any number of implicit casts or binary coercion casts involving only ! types represented in the family must not change the result other than to ! require a similar cast thereon. For each operator in the family there must ! be a support function having the same two input data types as the operator. ! It is recommended that a family be complete, i.e., for each combination of ! data types, all operators are included. Each operator class should include ! just the non-cross-type operators and support function for its data type. *************** *** 851,861 **** ALTER OPERATOR FAMILY integer_ops USING btree ADD by the family's equality operators, even when the values are of different types. This is usually difficult to accomplish when the types have different physical representations, but it can be done in some cases. ! Notice that there is only one support function per data type, not one ! per equality operator. It is recommended that a family be complete, i.e., ! provide an equality operator for each combination of data types. ! Each operator class should include just the non-cross-type equality ! operator and the support function for its data type. --- 853,865 ---- by the family's equality operators, even when the values are of different types. This is usually difficult to accomplish when the types have different physical representations, but it can be done in some cases. ! Implicit casts and binary coercion casts among types represented in the ! family must preserve this invariant. Notice that there is only one support ! function per data type, not one per equality operator. It is recommended ! that a family be complete, i.e., provide an equality operator for each ! combination of data types. Each operator class should include just the ! non-cross-type equality operator and the support function for its data ! type. diff --git a/src/backend/cataloindex 39ba486..6fc234b 100644 diff --git a/src/backend/catalog/sindex 57987be..682bd89 100644 *** a/src/backend/catalog/storage.c --- b/src/backend/catalog/storage.c *************** *** 221,229 **** RelationPreserveStorage(RelFileNode rnode) next = pending->next; if (RelFileNodeEquals(rnode, pending->relnode)) { - /* we should only find delete-on-abort entries, else trouble */ - if (pending->atCommit) - elog(ERROR, "cannot preserve a delete-on-commit relation"); /* unlink and delete list entry */ if (prev) prev->next = next; --- 221,226 ---- diff --git a/src/backend/commands/inindex b7c021d..073a3fa 100644 *** a/src/backend/commands/indexcmds.c --- b/src/backend/commands/indexcmds.c *************** *** 73,78 **** static char *ChooseIndexNameAddition(List *colnames); --- 73,264 ---- /* + * CheckIndexCompatible + * Determine whether an existing index definition is compatible with a + * prospective index definition, such that the existing index storage + * could become the storage of the new index, avoiding a rebuild. + * + * 'heapRelation': the relation the index would apply to. + * 'accessMethodName': name of the AM to use. + * 'attributeList': a list of IndexElem specifying columns and expressions + * to index on. + * 'exclusionOpNames': list of names of exclusion-constraint operators, + * or NIL if not an exclusion constraint. + * + * This is tailored to the needs of ALTER TABLE ALTER TYPE, which recreates + * any indexes that depended on a changing column from their pg_get_indexdef + * or pg_get_constraintdef definitions. We omit some of the sanity checks of + * DefineIndex. We assume that the old and new indexes have the same number + * of columns and that if one has an expression column or predicate, both do. + * Errors arising from the attribute list still apply. + * + * Most column type changes that can skip a table rewrite will not invalidate + * indexes. For btree and hash indexes, we assume continued validity when + * each column of an index would have the same operator family before and + * after the change. Since we do not document a contract for GIN or GiST + * operator families, we require an exact operator class match for them and + * for any other access methods. + * + * DefineIndex always verifies that each exclusion operator shares an operator + * family with its corresponding index operator class. For access methods + * having no operator family contract, confirm that the old and new indexes + * use the exact same exclusion operator. For btree and hash, there's nothing + * more to check. + * + * We do not yet implement a test to verify compatibility of expression + * columns or predicates, so assume any such index is incompatible. + */ + bool + CheckIndexCompatible(Oid oldId, + RangeVar *heapRelation, + char *accessMethodName, + List *attributeList, + List *exclusionOpNames) + { + bool isconstraint; + Oid *collationObjectId; + Oid *classObjectId; + Oid accessMethodId; + Oid relationId; + HeapTuple tuple; + Form_pg_am accessMethodForm; + bool amcanorder; + RegProcedure amoptions; + int16 *coloptions; + IndexInfo *indexInfo; + int numberOfAttributes; + int old_natts; + bool isnull; + bool family_am; + bool ret = true; + oidvector *old_indclass; + oidvector *old_indcollation; + int i; + Datum d; + + /* Caller should already have the relation locked in some way. */ + relationId = RangeVarGetRelid(heapRelation, false); + /* + * We can pretend isconstraint = false unconditionally. It only serves to + * decide the text of an error message that should never happen for us. + */ + isconstraint = false; + + numberOfAttributes = list_length(attributeList); + Assert(numberOfAttributes > 0); + Assert(numberOfAttributes <= INDEX_MAX_KEYS); + + /* look up the access method */ + tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("access method \"%s\" does not exist", + accessMethodName))); + accessMethodId = HeapTupleGetOid(tuple); + accessMethodForm = (Form_pg_am) GETSTRUCT(tuple); + amcanorder = accessMethodForm->amcanorder; + amoptions = accessMethodForm->amoptions; + ReleaseSysCache(tuple); + + indexInfo = makeNode(IndexInfo); + indexInfo->ii_Expressions = NIL; + indexInfo->ii_ExpressionsState = NIL; + indexInfo->ii_PredicateState = NIL; + indexInfo->ii_ExclusionOps = NULL; + indexInfo->ii_ExclusionProcs = NULL; + indexInfo->ii_ExclusionStrats = NULL; + collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); + classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); + coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16)); + + ComputeIndexAttrs(indexInfo, collationObjectId, classObjectId, + coloptions, attributeList, + exclusionOpNames, relationId, + accessMethodName, accessMethodId, + amcanorder, isconstraint); + + + /* Get the soon-obsolete pg_index tuple. */ + tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for index %u", oldId); + + /* We don't assess expressions or predicates; assume incompatibility. */ + if (!(heap_attisnull(tuple, Anum_pg_index_indpred) && + heap_attisnull(tuple, Anum_pg_index_indexprs))) + { + ReleaseSysCache(tuple); + return false; + } + + /* + * If the old and new operator class of any index column differ in + * operator family or collation, regard the old index as incompatible. + * For access methods other than btree and hash, a family match has no + * defined meaning; require an exact operator class match. + */ + old_natts = ((Form_pg_index) GETSTRUCT(tuple))->indnatts; + Assert(old_natts == numberOfAttributes); + + d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indcollation, &isnull); + Assert(!isnull); + old_indcollation = (oidvector *) DatumGetPointer(d); + + d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indclass, &isnull); + Assert(!isnull); + old_indclass = (oidvector *) DatumGetPointer(d); + + family_am = accessMethodId == BTREE_AM_OID || accessMethodId == HASH_AM_OID; + + for (i = 0; i < old_natts; i++) + { + Oid old_class = old_indclass->values[i]; + Oid new_class = classObjectId[i]; + + if (!(old_indcollation->values[i] == collationObjectId[i] + && (old_class == new_class + || (family_am && (get_opclass_family(old_class) + == get_opclass_family(new_class)))))) + { + ret = false; + break; + } + } + + ReleaseSysCache(tuple); + + /* + * For btree and hash, exclusion operators need only fall in the same + * operator family; ComputeIndexAttrs already verified that much. If we + * get this far, we know that the index operator family has not changed, + * and we're done. For other access methods, require exact matches for + * all exclusion operators. + */ + if (ret && !family_am && indexInfo->ii_ExclusionOps != NULL) + { + Relation irel; + Oid *old_operators, *old_procs; + uint16 *old_strats; + + /* Caller probably already holds a stronger lock. */ + irel = index_open(oldId, AccessShareLock); + RelationGetExclusionInfo(irel, &old_operators, &old_procs, &old_strats); + + for (i = 0; i < old_natts; i++) + if (old_operators[i] != indexInfo->ii_ExclusionOps[i]) + { + ret = false; + break; + } + + index_close(irel, NoLock); + } + + return ret; + } + + /* * DefineIndex * Creates a new index. * *************** *** 103,110 **** static char *ChooseIndexNameAddition(List *colnames); * it will be filled later. * 'quiet': suppress the NOTICE chatter ordinarily provided for constraints. * 'concurrent': avoid blocking writers to the table while building. */ ! void DefineIndex(RangeVar *heapRelation, char *indexRelationName, Oid indexRelationId, --- 289,298 ---- * it will be filled later. * 'quiet': suppress the NOTICE chatter ordinarily provided for constraints. * 'concurrent': avoid blocking writers to the table while building. + * + * Returns the OID of the new index relation. */ ! Oid DefineIndex(RangeVar *heapRelation, char *indexRelationName, Oid indexRelationId, *************** *** 421,427 **** DefineIndex(RangeVar *heapRelation, { /* Close the heap and we're done, in the non-concurrent case */ heap_close(rel, NoLock); ! return; } /* save lockrelid and locktag for below, then close rel */ --- 609,615 ---- { /* Close the heap and we're done, in the non-concurrent case */ heap_close(rel, NoLock); ! return indexRelationId; } /* save lockrelid and locktag for below, then close rel */ *************** *** 709,714 **** DefineIndex(RangeVar *heapRelation, --- 897,904 ---- * Last thing to do is release the session-level lock on the parent table. */ UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock); + + return indexRelationId; } diff --git a/src/backend/commands/tableindex 2c9f855..3860e61 100644 *** a/src/backend/commands/tablecmds.c --- b/src/backend/commands/tablecmds.c *************** *** 344,350 **** static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno); static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode); static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode); ! static void ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode); static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode); static void ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode); --- 344,352 ---- static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd, LOCKMODE lockmode); static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode); ! static void ATPostAlterTypeParse(Oid oldId, char *cmd, ! List **wqueue, LOCKMODE lockmode, bool rewrite); ! static void TryReuseIndex(Oid oldId, IndexStmt *stmt); static void change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lockmode); static void ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode); *************** *** 5179,5215 **** ATExecAddIndex(AlteredTableInfo *tab, Relation rel, bool check_rights; bool skip_build; bool quiet; Assert(IsA(stmt, IndexStmt)); /* suppress schema rights check when rebuilding existing index */ check_rights = !is_rebuild; ! /* skip index build if phase 3 will have to rewrite table anyway */ ! skip_build = tab->rewrite; /* suppress notices when rebuilding existing index */ quiet = is_rebuild; /* The IndexStmt has already been through transformIndexStmt */ ! DefineIndex(stmt->relation, /* relation */ ! stmt->idxname, /* index name */ ! InvalidOid, /* no predefined OID */ ! stmt->accessMethod, /* am name */ ! stmt->tableSpace, ! stmt->indexParams, /* parameters */ ! (Expr *) stmt->whereClause, ! stmt->options, ! stmt->excludeOpNames, ! stmt->unique, ! stmt->primary, ! stmt->isconstraint, ! stmt->deferrable, ! stmt->initdeferred, ! true, /* is_alter_table */ ! check_rights, ! skip_build, ! quiet, ! false); } /* --- 5181,5255 ---- bool check_rights; bool skip_build; bool quiet; + Oid new_index; Assert(IsA(stmt, IndexStmt)); /* suppress schema rights check when rebuilding existing index */ check_rights = !is_rebuild; ! /* skip index build if phase 3 will do it or we're reusing an old one */ ! skip_build = tab->rewrite || OidIsValid(stmt->oldNode); /* suppress notices when rebuilding existing index */ quiet = is_rebuild; /* The IndexStmt has already been through transformIndexStmt */ ! new_index = DefineIndex(stmt->relation, /* relation */ ! stmt->idxname, /* index name */ ! InvalidOid, /* no predefined OID */ ! stmt->accessMethod, /* am name */ ! stmt->tableSpace, ! stmt->indexParams, /* parameters */ ! (Expr *) stmt->whereClause, ! stmt->options, ! stmt->excludeOpNames, ! stmt->unique, ! stmt->primary, ! stmt->isconstraint, ! stmt->deferrable, ! stmt->initdeferred, ! true, /* is_alter_table */ ! check_rights, ! skip_build, ! quiet, ! false); ! ! /* ! * If TryReuseIndex() stashed a relfilenode for us, replace the fresh one ! * with that. This vaguely follows swap_relation_files(), but we need not ! * consider the case of a system table. Indexes inherit relfrozenxid and ! * never have TOAST tables. ! */ ! if (OidIsValid(stmt->oldNode)) ! { ! Relation pg_class; ! Relation irel; ! HeapTuple tup; ! ! /* Drop the empty storage just created under DefineIndex. */ ! irel = index_open(new_index, NoLock); ! RelationDropStorage(irel); ! ! /* Update pg_class.relfilenode. */ ! pg_class = heap_open(RelationRelationId, RowExclusiveLock); ! tup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(new_index)); ! if (!HeapTupleIsValid(tup)) /* shouldn't happen */ ! elog(ERROR, "cache lookup failed for relation %u", new_index); ! ! ((Form_pg_class) GETSTRUCT(tup))->relfilenode = stmt->oldNode; ! simple_heap_update(pg_class, &tup->t_self, tup); ! CatalogUpdateIndexes(pg_class, tup); ! heap_close(pg_class, RowExclusiveLock); ! ! CommandCounterIncrement(); ! ! /* ! * The reassigned storage is probably scheduled for deletion, having ! * been attached to a just-DROPped index. Revive it. ! */ ! RelationPreserveStorage(irel->rd_node); ! index_close(irel, NoLock); ! } } /* *************** *** 7171,7177 **** static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) { ObjectAddress obj; ! ListCell *l; /* * Re-parse the index and constraint definitions, and attach them to the --- 7211,7218 ---- ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) { ObjectAddress obj; ! ListCell *def; ! ListCell *oid; /* * Re-parse the index and constraint definitions, and attach them to the *************** *** 7181,7190 **** ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) * that before dropping. It's safe because the parser won't actually look * at the catalogs to detect the existing entry. */ ! foreach(l, tab->changedIndexDefs) ! ATPostAlterTypeParse((char *) lfirst(l), wqueue, lockmode); ! foreach(l, tab->changedConstraintDefs) ! ATPostAlterTypeParse((char *) lfirst(l), wqueue, lockmode); /* * Now we can drop the existing constraints and indexes --- constraints --- 7222,7233 ---- * that before dropping. It's safe because the parser won't actually look * at the catalogs to detect the existing entry. */ ! forboth(oid, tab->changedConstraintOids, def, tab->changedConstraintDefs) ! ATPostAlterTypeParse(lfirst_oid(oid), (char *) lfirst(def), ! wqueue, lockmode, tab->rewrite); ! forboth(oid, tab->changedIndexOids, def, tab->changedIndexDefs) ! ATPostAlterTypeParse(lfirst_oid(oid), (char *) lfirst(def), ! wqueue, lockmode, tab->rewrite); /* * Now we can drop the existing constraints and indexes --- constraints *************** *** 7194,7211 **** ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) * should be okay to use DROP_RESTRICT here, since nothing else should be * depending on these objects. */ ! foreach(l, tab->changedConstraintOids) { obj.classId = ConstraintRelationId; ! obj.objectId = lfirst_oid(l); obj.objectSubId = 0; performDeletion(&obj, DROP_RESTRICT); } ! foreach(l, tab->changedIndexOids) { obj.classId = RelationRelationId; ! obj.objectId = lfirst_oid(l); obj.objectSubId = 0; performDeletion(&obj, DROP_RESTRICT); } --- 7237,7254 ---- * should be okay to use DROP_RESTRICT here, since nothing else should be * depending on these objects. */ ! foreach(oid, tab->changedConstraintOids) { obj.classId = ConstraintRelationId; ! obj.objectId = lfirst_oid(oid); obj.objectSubId = 0; performDeletion(&obj, DROP_RESTRICT); } ! foreach(oid, tab->changedIndexOids) { obj.classId = RelationRelationId; ! obj.objectId = lfirst_oid(oid); obj.objectSubId = 0; performDeletion(&obj, DROP_RESTRICT); } *************** *** 7217,7223 **** ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) } static void ! ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode) { List *raw_parsetree_list; List *querytree_list; --- 7260,7267 ---- } static void ! ATPostAlterTypeParse(Oid oldId, char *cmd, ! List **wqueue, LOCKMODE lockmode, bool rewrite) { List *raw_parsetree_list; List *querytree_list; *************** *** 7264,7269 **** ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode) --- 7308,7316 ---- IndexStmt *stmt = (IndexStmt *) stm; AlterTableCmd *newcmd; + if (!rewrite) + TryReuseIndex(oldId, stmt); + rel = relation_openrv(stmt->relation, lockmode); tab = ATGetQueueEntry(wqueue, rel); newcmd = makeNode(AlterTableCmd); *************** *** 7288,7293 **** ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode) --- 7335,7344 ---- switch (cmd->subtype) { case AT_AddIndex: + Assert(IsA(cmd->def, IndexStmt)); + if (!rewrite) + TryReuseIndex(get_constraint_index(oldId), + (IndexStmt *) cmd->def); cmd->subtype = AT_ReAddIndex; tab->subcmds[AT_PASS_OLD_INDEX] = lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd); *************** *** 7311,7316 **** ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode) --- 7362,7387 ---- } } + /* + * Subroutine for ATPostAlterTypeParse(). Calls out to CheckIndexCompatible() + * for the real analysis, then mutates the IndexStmt based on that verdict. + */ + static void + TryReuseIndex(Oid oldId, IndexStmt *stmt) + { + + if (CheckIndexCompatible(oldId, + stmt->relation, + stmt->accessMethod, + stmt->indexParams, + stmt->excludeOpNames)) + { + Relation irel = index_open(oldId, NoLock); + stmt->oldNode = irel->rd_node.relNode; + index_close(irel, NoLock); + } + } + /* * ALTER TABLE OWNER diff --git a/src/backend/nodes/copyfuncindex c9133dd..c18d670 100644 *** a/src/backend/nodes/copyfuncs.c --- b/src/backend/nodes/copyfuncs.c *************** *** 2813,2818 **** _copyIndexStmt(IndexStmt *from) --- 2813,2819 ---- COPY_SCALAR_FIELD(deferrable); COPY_SCALAR_FIELD(initdeferred); COPY_SCALAR_FIELD(concurrent); + COPY_SCALAR_FIELD(oldNode); return newnode; } diff --git a/src/backend/nodes/equalindex 3a0267c..61fed33 100644 *** a/src/backend/nodes/equalfuncs.c --- b/src/backend/nodes/equalfuncs.c *************** *** 1251,1256 **** _equalIndexStmt(IndexStmt *a, IndexStmt *b) --- 1251,1257 ---- COMPARE_SCALAR_FIELD(deferrable); COMPARE_SCALAR_FIELD(initdeferred); COMPARE_SCALAR_FIELD(concurrent); + COMPARE_SCALAR_FIELD(oldNode); return true; } diff --git a/src/backend/nodes/outfunindex 681f5f8..0dfa5f4 100644 *** a/src/backend/nodes/outfuncs.c --- b/src/backend/nodes/outfuncs.c *************** *** 1982,1987 **** _outIndexStmt(StringInfo str, IndexStmt *node) --- 1982,1988 ---- WRITE_BOOL_FIELD(deferrable); WRITE_BOOL_FIELD(initdeferred); WRITE_BOOL_FIELD(concurrent); + WRITE_OID_FIELD(oldNode); } static void diff --git a/src/include/commands/dindex bbc024f..cbb5f1f 100644 *** a/src/include/commands/defrem.h --- b/src/include/commands/defrem.h *************** *** 18,24 **** /* commands/indexcmds.c */ ! extern void DefineIndex(RangeVar *heapRelation, char *indexRelationName, Oid indexRelationId, char *accessMethodName, --- 18,24 ---- /* commands/indexcmds.c */ ! extern Oid DefineIndex(RangeVar *heapRelation, char *indexRelationName, Oid indexRelationId, char *accessMethodName, *************** *** 49,54 **** extern char *ChooseIndexName(const char *tabname, Oid namespaceId, --- 49,59 ---- List *colnames, List *exclusionOpNames, bool primary, bool isconstraint); extern List *ChooseIndexColumnNames(List *indexElems); + extern bool CheckIndexCompatible(Oid oldId, + RangeVar *heapRelation, + char *accessMethodName, + List *attributeList, + List *exclusionOpNames); extern Oid GetDefaultOpClass(Oid type_id, Oid am_id); /* commands/functioncmds.c */ diff --git a/src/include/nodes/parseindex 14937d4..2d226a9 100644 *** a/src/include/nodes/parsenodes.h --- b/src/include/nodes/parsenodes.h *************** *** 2065,2070 **** typedef struct IndexStmt --- 2065,2071 ---- bool deferrable; /* is the constraint DEFERRABLE? */ bool initdeferred; /* is the constraint INITIALLY DEFERRED? */ bool concurrent; /* should this be a concurrent index build? */ + Oid oldNode; /* relfilenode of my former self */ } IndexStmt; /* ---------------------- diff --git a/src/test/regress/GNUmakeindex 90aea6c..949f82b 100644 diff --git a/src/test/regress/expecnew file mode 100644 index 0000000..10dbcc7 diff --git a/src/test/regress/parallel_schedule b/srindex 376f28d..e3b515e 100644 diff --git a/src/test/regress/serial_scheindex bb654f9..a7e6dc6 100644 diff --git a/src/test/regress/sql/big_anew file mode 100644 index 0000000..6ae9007