mirror of
https://github.com/postgres/postgres.git
synced 2025-06-17 17:02:08 +03:00
Avoid index rebuild for no-rewrite ALTER TABLE .. ALTER TYPE.
Noah Misch. Review and minor cosmetic changes by me.
This commit is contained in:
@ -834,8 +834,10 @@ ALTER OPERATOR FAMILY integer_ops USING btree ADD
|
|||||||
<para>
|
<para>
|
||||||
In a B-tree operator family, all the operators in the family must sort
|
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
|
compatibly, meaning that the transitive laws hold across all the data types
|
||||||
supported by the family: <quote>if A = B and B = C, then A =
|
supported by the family: <quote>if A = B and B = C, then A = C</>,
|
||||||
C</>, and <quote>if A < B and B < C, then A < C</>. For each
|
and <quote>if A < B and B < C, then A < C</>. Moreover, implicit
|
||||||
|
or binary coercion casts between types represented in the operator family
|
||||||
|
must not change the associated sort ordering. For each
|
||||||
operator in the family there must be a support function having the same
|
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
|
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
|
complete, i.e., for each combination of data types, all operators are
|
||||||
@ -851,6 +853,9 @@ ALTER OPERATOR FAMILY integer_ops USING btree ADD
|
|||||||
by the family's equality operators, even when the values are of different
|
by the family's equality operators, even when the values are of different
|
||||||
types. This is usually difficult to accomplish when the types have
|
types. This is usually difficult to accomplish when the types have
|
||||||
different physical representations, but it can be done in some cases.
|
different physical representations, but it can be done in some cases.
|
||||||
|
Furthermore, casting a value from one data type represented in the operator
|
||||||
|
family to another data type also represented in the operator family via
|
||||||
|
an implicit or binary coercion cast must not change the computed hash value.
|
||||||
Notice that there is only one support function per data type, not one
|
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.,
|
per equality operator. It is recommended that a family be complete, i.e.,
|
||||||
provide an equality operator for each combination of data types.
|
provide an equality operator for each combination of data types.
|
||||||
|
@ -217,6 +217,7 @@ Boot_CreateStmt:
|
|||||||
PG_CATALOG_NAMESPACE,
|
PG_CATALOG_NAMESPACE,
|
||||||
shared_relation ? GLOBALTABLESPACE_OID : 0,
|
shared_relation ? GLOBALTABLESPACE_OID : 0,
|
||||||
$3,
|
$3,
|
||||||
|
InvalidOid,
|
||||||
tupdesc,
|
tupdesc,
|
||||||
RELKIND_RELATION,
|
RELKIND_RELATION,
|
||||||
RELPERSISTENCE_PERMANENT,
|
RELPERSISTENCE_PERMANENT,
|
||||||
@ -284,6 +285,7 @@ Boot_DeclareIndexStmt:
|
|||||||
DefineIndex(makeRangeVar(NULL, $6, -1),
|
DefineIndex(makeRangeVar(NULL, $6, -1),
|
||||||
$3,
|
$3,
|
||||||
$4,
|
$4,
|
||||||
|
InvalidOid,
|
||||||
$8,
|
$8,
|
||||||
NULL,
|
NULL,
|
||||||
$10,
|
$10,
|
||||||
@ -302,6 +304,7 @@ Boot_DeclareUniqueIndexStmt:
|
|||||||
DefineIndex(makeRangeVar(NULL, $7, -1),
|
DefineIndex(makeRangeVar(NULL, $7, -1),
|
||||||
$4,
|
$4,
|
||||||
$5,
|
$5,
|
||||||
|
InvalidOid,
|
||||||
$9,
|
$9,
|
||||||
NULL,
|
NULL,
|
||||||
$11,
|
$11,
|
||||||
|
@ -229,7 +229,8 @@ SystemAttributeByName(const char *attname, bool relhasoids)
|
|||||||
* heap_create - Create an uncataloged heap relation
|
* heap_create - Create an uncataloged heap relation
|
||||||
*
|
*
|
||||||
* Note API change: the caller must now always provide the OID
|
* Note API change: the caller must now always provide the OID
|
||||||
* to use for the relation.
|
* to use for the relation. The relfilenode may (and, normally,
|
||||||
|
* should) be left unspecified.
|
||||||
*
|
*
|
||||||
* rel->rd_rel is initialized by RelationBuildLocalRelation,
|
* rel->rd_rel is initialized by RelationBuildLocalRelation,
|
||||||
* and is mostly zeroes at return.
|
* and is mostly zeroes at return.
|
||||||
@ -240,6 +241,7 @@ heap_create(const char *relname,
|
|||||||
Oid relnamespace,
|
Oid relnamespace,
|
||||||
Oid reltablespace,
|
Oid reltablespace,
|
||||||
Oid relid,
|
Oid relid,
|
||||||
|
Oid relfilenode,
|
||||||
TupleDesc tupDesc,
|
TupleDesc tupDesc,
|
||||||
char relkind,
|
char relkind,
|
||||||
char relpersistence,
|
char relpersistence,
|
||||||
@ -296,6 +298,16 @@ heap_create(const char *relname,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unless otherwise requested, the physical ID (relfilenode) is initially
|
||||||
|
* the same as the logical ID (OID). When the caller did specify a
|
||||||
|
* relfilenode, it already exists; do not attempt to create it.
|
||||||
|
*/
|
||||||
|
if (OidIsValid(relfilenode))
|
||||||
|
create_storage = false;
|
||||||
|
else
|
||||||
|
relfilenode = relid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Never allow a pg_class entry to explicitly specify the database's
|
* Never allow a pg_class entry to explicitly specify the database's
|
||||||
* default tablespace in reltablespace; force it to zero instead. This
|
* default tablespace in reltablespace; force it to zero instead. This
|
||||||
@ -315,6 +327,7 @@ heap_create(const char *relname,
|
|||||||
relnamespace,
|
relnamespace,
|
||||||
tupDesc,
|
tupDesc,
|
||||||
relid,
|
relid,
|
||||||
|
relfilenode,
|
||||||
reltablespace,
|
reltablespace,
|
||||||
shared_relation,
|
shared_relation,
|
||||||
mapped_relation,
|
mapped_relation,
|
||||||
@ -1103,6 +1116,7 @@ heap_create_with_catalog(const char *relname,
|
|||||||
relnamespace,
|
relnamespace,
|
||||||
reltablespace,
|
reltablespace,
|
||||||
relid,
|
relid,
|
||||||
|
InvalidOid,
|
||||||
tupdesc,
|
tupdesc,
|
||||||
relkind,
|
relkind,
|
||||||
relpersistence,
|
relpersistence,
|
||||||
|
@ -649,6 +649,8 @@ UpdateIndexRelation(Oid indexoid,
|
|||||||
* indexRelationId: normally, pass InvalidOid to let this routine
|
* indexRelationId: normally, pass InvalidOid to let this routine
|
||||||
* generate an OID for the index. During bootstrap this may be
|
* generate an OID for the index. During bootstrap this may be
|
||||||
* nonzero to specify a preselected OID.
|
* nonzero to specify a preselected OID.
|
||||||
|
* relFileNode: normally, pass InvalidOid to get new storage. May be
|
||||||
|
* nonzero to attach an existing valid build.
|
||||||
* indexInfo: same info executor uses to insert into the index
|
* indexInfo: same info executor uses to insert into the index
|
||||||
* indexColNames: column names to use for index (List of char *)
|
* indexColNames: column names to use for index (List of char *)
|
||||||
* accessMethodObjectId: OID of index AM to use
|
* accessMethodObjectId: OID of index AM to use
|
||||||
@ -674,6 +676,7 @@ Oid
|
|||||||
index_create(Relation heapRelation,
|
index_create(Relation heapRelation,
|
||||||
const char *indexRelationName,
|
const char *indexRelationName,
|
||||||
Oid indexRelationId,
|
Oid indexRelationId,
|
||||||
|
Oid relFileNode,
|
||||||
IndexInfo *indexInfo,
|
IndexInfo *indexInfo,
|
||||||
List *indexColNames,
|
List *indexColNames,
|
||||||
Oid accessMethodObjectId,
|
Oid accessMethodObjectId,
|
||||||
@ -813,6 +816,7 @@ index_create(Relation heapRelation,
|
|||||||
namespaceId,
|
namespaceId,
|
||||||
tableSpaceId,
|
tableSpaceId,
|
||||||
indexRelationId,
|
indexRelationId,
|
||||||
|
relFileNode,
|
||||||
indexTupDesc,
|
indexTupDesc,
|
||||||
RELKIND_INDEX,
|
RELKIND_INDEX,
|
||||||
relpersistence,
|
relpersistence,
|
||||||
|
@ -206,10 +206,13 @@ RelationDropStorage(Relation rel)
|
|||||||
* The relation mapper fixes this by telling us to not delete such relations
|
* The relation mapper fixes this by telling us to not delete such relations
|
||||||
* after all as part of its commit.
|
* after all as part of its commit.
|
||||||
*
|
*
|
||||||
|
* We also use this to reuse an old build of an index during ALTER TABLE, this
|
||||||
|
* time removing the delete-at-commit entry.
|
||||||
|
*
|
||||||
* No-op if the relation is not among those scheduled for deletion.
|
* No-op if the relation is not among those scheduled for deletion.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RelationPreserveStorage(RelFileNode rnode)
|
RelationPreserveStorage(RelFileNode rnode, bool atCommit)
|
||||||
{
|
{
|
||||||
PendingRelDelete *pending;
|
PendingRelDelete *pending;
|
||||||
PendingRelDelete *prev;
|
PendingRelDelete *prev;
|
||||||
@ -219,11 +222,9 @@ RelationPreserveStorage(RelFileNode rnode)
|
|||||||
for (pending = pendingDeletes; pending != NULL; pending = next)
|
for (pending = pendingDeletes; pending != NULL; pending = next)
|
||||||
{
|
{
|
||||||
next = pending->next;
|
next = pending->next;
|
||||||
if (RelFileNodeEquals(rnode, pending->relnode))
|
if (RelFileNodeEquals(rnode, pending->relnode)
|
||||||
|
&& pending->atCommit == atCommit)
|
||||||
{
|
{
|
||||||
/* 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 */
|
/* unlink and delete list entry */
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
|
@ -274,7 +274,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
|
|||||||
coloptions[0] = 0;
|
coloptions[0] = 0;
|
||||||
coloptions[1] = 0;
|
coloptions[1] = 0;
|
||||||
|
|
||||||
index_create(toast_rel, toast_idxname, toastIndexOid,
|
index_create(toast_rel, toast_idxname, toastIndexOid, InvalidOid,
|
||||||
indexInfo,
|
indexInfo,
|
||||||
list_make2("chunk_id", "chunk_seq"),
|
list_make2("chunk_id", "chunk_seq"),
|
||||||
BTREE_AM_OID,
|
BTREE_AM_OID,
|
||||||
|
@ -72,6 +72,198 @@ static Oid GetIndexOpClass(List *opclass, Oid attrType,
|
|||||||
static char *ChooseIndexNameAddition(List *colnames);
|
static char *ChooseIndexNameAddition(List *colnames);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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, NoLock, false, 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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the operator classes, collations, and exclusion operators
|
||||||
|
* for the new index, so we can test whether it's compatible with the
|
||||||
|
* existing one. Note that ComputeIndexAttrs might fail here, but that's
|
||||||
|
* OK: DefineIndex would have called this function with the same arguments
|
||||||
|
* later on, and it would have failed then anyway.
|
||||||
|
*/
|
||||||
|
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
|
* DefineIndex
|
||||||
* Creates a new index.
|
* Creates a new index.
|
||||||
@ -81,6 +273,8 @@ static char *ChooseIndexNameAddition(List *colnames);
|
|||||||
* that a nonconflicting default name should be picked.
|
* that a nonconflicting default name should be picked.
|
||||||
* 'indexRelationId': normally InvalidOid, but during bootstrap can be
|
* 'indexRelationId': normally InvalidOid, but during bootstrap can be
|
||||||
* nonzero to specify a preselected OID for the index.
|
* nonzero to specify a preselected OID for the index.
|
||||||
|
* 'relFileNode': normally InvalidOid, but can be nonzero to specify existing
|
||||||
|
* storage constituting a valid build of this index.
|
||||||
* 'accessMethodName': name of the AM to use.
|
* 'accessMethodName': name of the AM to use.
|
||||||
* 'tableSpaceName': name of the tablespace to create the index in.
|
* 'tableSpaceName': name of the tablespace to create the index in.
|
||||||
* NULL specifies using the appropriate default.
|
* NULL specifies using the appropriate default.
|
||||||
@ -103,11 +297,14 @@ static char *ChooseIndexNameAddition(List *colnames);
|
|||||||
* it will be filled later.
|
* it will be filled later.
|
||||||
* 'quiet': suppress the NOTICE chatter ordinarily provided for constraints.
|
* 'quiet': suppress the NOTICE chatter ordinarily provided for constraints.
|
||||||
* 'concurrent': avoid blocking writers to the table while building.
|
* 'concurrent': avoid blocking writers to the table while building.
|
||||||
|
*
|
||||||
|
* Returns the OID of the created index.
|
||||||
*/
|
*/
|
||||||
void
|
Oid
|
||||||
DefineIndex(RangeVar *heapRelation,
|
DefineIndex(RangeVar *heapRelation,
|
||||||
char *indexRelationName,
|
char *indexRelationName,
|
||||||
Oid indexRelationId,
|
Oid indexRelationId,
|
||||||
|
Oid relFileNode,
|
||||||
char *accessMethodName,
|
char *accessMethodName,
|
||||||
char *tableSpaceName,
|
char *tableSpaceName,
|
||||||
List *attributeList,
|
List *attributeList,
|
||||||
@ -402,12 +599,18 @@ DefineIndex(RangeVar *heapRelation,
|
|||||||
indexRelationName, RelationGetRelationName(rel))));
|
indexRelationName, RelationGetRelationName(rel))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A valid relFileNode implies that we already have a built form of the
|
||||||
|
* index. The caller should also decline any index build.
|
||||||
|
*/
|
||||||
|
Assert(!OidIsValid(relFileNode) || (skip_build && !concurrent));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make the catalog entries for the index, including constraints. Then, if
|
* Make the catalog entries for the index, including constraints. Then, if
|
||||||
* not skip_build || concurrent, actually build the index.
|
* not skip_build || concurrent, actually build the index.
|
||||||
*/
|
*/
|
||||||
indexRelationId =
|
indexRelationId =
|
||||||
index_create(rel, indexRelationName, indexRelationId,
|
index_create(rel, indexRelationName, indexRelationId, relFileNode,
|
||||||
indexInfo, indexColNames,
|
indexInfo, indexColNames,
|
||||||
accessMethodId, tablespaceId,
|
accessMethodId, tablespaceId,
|
||||||
collationObjectId, classObjectId,
|
collationObjectId, classObjectId,
|
||||||
@ -421,7 +624,7 @@ DefineIndex(RangeVar *heapRelation,
|
|||||||
{
|
{
|
||||||
/* Close the heap and we're done, in the non-concurrent case */
|
/* Close the heap and we're done, in the non-concurrent case */
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
return;
|
return indexRelationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save lockrelid and locktag for below, then close rel */
|
/* save lockrelid and locktag for below, then close rel */
|
||||||
@ -709,6 +912,8 @@ DefineIndex(RangeVar *heapRelation,
|
|||||||
* Last thing to do is release the session-level lock on the parent table.
|
* Last thing to do is release the session-level lock on the parent table.
|
||||||
*/
|
*/
|
||||||
UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
|
UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
|
||||||
|
|
||||||
|
return indexRelationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -347,7 +347,9 @@ static bool ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno);
|
|||||||
static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
||||||
AlterTableCmd *cmd, LOCKMODE lockmode);
|
AlterTableCmd *cmd, LOCKMODE lockmode);
|
||||||
static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode);
|
static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode);
|
||||||
static void ATPostAlterTypeParse(char *cmd, List **wqueue, 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,
|
static void change_owner_recurse_to_sequences(Oid relationOid,
|
||||||
Oid newOwnerId, LOCKMODE lockmode);
|
Oid newOwnerId, LOCKMODE lockmode);
|
||||||
static void ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode);
|
static void ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode);
|
||||||
@ -5232,21 +5234,23 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
|
|||||||
bool check_rights;
|
bool check_rights;
|
||||||
bool skip_build;
|
bool skip_build;
|
||||||
bool quiet;
|
bool quiet;
|
||||||
|
Oid new_index;
|
||||||
|
|
||||||
Assert(IsA(stmt, IndexStmt));
|
Assert(IsA(stmt, IndexStmt));
|
||||||
|
|
||||||
/* suppress schema rights check when rebuilding existing index */
|
/* suppress schema rights check when rebuilding existing index */
|
||||||
check_rights = !is_rebuild;
|
check_rights = !is_rebuild;
|
||||||
/* skip index build if phase 3 will have to rewrite table anyway */
|
/* skip index build if phase 3 will do it or we're reusing an old one */
|
||||||
skip_build = tab->rewrite;
|
skip_build = tab->rewrite || OidIsValid(stmt->oldNode);
|
||||||
/* suppress notices when rebuilding existing index */
|
/* suppress notices when rebuilding existing index */
|
||||||
quiet = is_rebuild;
|
quiet = is_rebuild;
|
||||||
|
|
||||||
/* The IndexStmt has already been through transformIndexStmt */
|
/* The IndexStmt has already been through transformIndexStmt */
|
||||||
|
|
||||||
DefineIndex(stmt->relation, /* relation */
|
new_index = DefineIndex(stmt->relation, /* relation */
|
||||||
stmt->idxname, /* index name */
|
stmt->idxname, /* index name */
|
||||||
InvalidOid, /* no predefined OID */
|
InvalidOid, /* no predefined OID */
|
||||||
|
stmt->oldNode,
|
||||||
stmt->accessMethod, /* am name */
|
stmt->accessMethod, /* am name */
|
||||||
stmt->tableSpace,
|
stmt->tableSpace,
|
||||||
stmt->indexParams, /* parameters */
|
stmt->indexParams, /* parameters */
|
||||||
@ -5263,6 +5267,19 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
|
|||||||
skip_build,
|
skip_build,
|
||||||
quiet,
|
quiet,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If TryReuseIndex() stashed a relfilenode for us, we used it for the new
|
||||||
|
* index instead of building from scratch. The DROP of the old edition of
|
||||||
|
* this index will have scheduled the storage for deletion at commit, so
|
||||||
|
* cancel that pending deletion.
|
||||||
|
*/
|
||||||
|
if (OidIsValid(stmt->oldNode))
|
||||||
|
{
|
||||||
|
Relation irel = index_open(new_index, NoLock);
|
||||||
|
RelationPreserveStorage(irel->rd_node, true);
|
||||||
|
index_close(irel, NoLock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -7389,7 +7406,8 @@ static void
|
|||||||
ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
|
ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
ObjectAddress obj;
|
ObjectAddress obj;
|
||||||
ListCell *l;
|
ListCell *def_item;
|
||||||
|
ListCell *oid_item;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Re-parse the index and constraint definitions, and attach them to the
|
* Re-parse the index and constraint definitions, and attach them to the
|
||||||
@ -7399,10 +7417,14 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
|
|||||||
* that before dropping. It's safe because the parser won't actually look
|
* that before dropping. It's safe because the parser won't actually look
|
||||||
* at the catalogs to detect the existing entry.
|
* at the catalogs to detect the existing entry.
|
||||||
*/
|
*/
|
||||||
foreach(l, tab->changedIndexDefs)
|
forboth(oid_item, tab->changedConstraintOids,
|
||||||
ATPostAlterTypeParse((char *) lfirst(l), wqueue, lockmode);
|
def_item, tab->changedConstraintDefs)
|
||||||
foreach(l, tab->changedConstraintDefs)
|
ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item),
|
||||||
ATPostAlterTypeParse((char *) lfirst(l), wqueue, lockmode);
|
wqueue, lockmode, tab->rewrite);
|
||||||
|
forboth(oid_item, tab->changedIndexOids,
|
||||||
|
def_item, tab->changedIndexDefs)
|
||||||
|
ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item),
|
||||||
|
wqueue, lockmode, tab->rewrite);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we can drop the existing constraints and indexes --- constraints
|
* Now we can drop the existing constraints and indexes --- constraints
|
||||||
@ -7412,18 +7434,18 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
|
|||||||
* should be okay to use DROP_RESTRICT here, since nothing else should be
|
* should be okay to use DROP_RESTRICT here, since nothing else should be
|
||||||
* depending on these objects.
|
* depending on these objects.
|
||||||
*/
|
*/
|
||||||
foreach(l, tab->changedConstraintOids)
|
foreach(oid_item, tab->changedConstraintOids)
|
||||||
{
|
{
|
||||||
obj.classId = ConstraintRelationId;
|
obj.classId = ConstraintRelationId;
|
||||||
obj.objectId = lfirst_oid(l);
|
obj.objectId = lfirst_oid(oid_item);
|
||||||
obj.objectSubId = 0;
|
obj.objectSubId = 0;
|
||||||
performDeletion(&obj, DROP_RESTRICT);
|
performDeletion(&obj, DROP_RESTRICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(l, tab->changedIndexOids)
|
foreach(oid_item, tab->changedIndexOids)
|
||||||
{
|
{
|
||||||
obj.classId = RelationRelationId;
|
obj.classId = RelationRelationId;
|
||||||
obj.objectId = lfirst_oid(l);
|
obj.objectId = lfirst_oid(oid_item);
|
||||||
obj.objectSubId = 0;
|
obj.objectSubId = 0;
|
||||||
performDeletion(&obj, DROP_RESTRICT);
|
performDeletion(&obj, DROP_RESTRICT);
|
||||||
}
|
}
|
||||||
@ -7435,7 +7457,8 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode)
|
ATPostAlterTypeParse(Oid oldId, char *cmd,
|
||||||
|
List **wqueue, LOCKMODE lockmode, bool rewrite)
|
||||||
{
|
{
|
||||||
List *raw_parsetree_list;
|
List *raw_parsetree_list;
|
||||||
List *querytree_list;
|
List *querytree_list;
|
||||||
@ -7482,6 +7505,9 @@ ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode)
|
|||||||
IndexStmt *stmt = (IndexStmt *) stm;
|
IndexStmt *stmt = (IndexStmt *) stm;
|
||||||
AlterTableCmd *newcmd;
|
AlterTableCmd *newcmd;
|
||||||
|
|
||||||
|
if (!rewrite)
|
||||||
|
TryReuseIndex(oldId, stmt);
|
||||||
|
|
||||||
rel = relation_openrv(stmt->relation, lockmode);
|
rel = relation_openrv(stmt->relation, lockmode);
|
||||||
tab = ATGetQueueEntry(wqueue, rel);
|
tab = ATGetQueueEntry(wqueue, rel);
|
||||||
newcmd = makeNode(AlterTableCmd);
|
newcmd = makeNode(AlterTableCmd);
|
||||||
@ -7506,6 +7532,10 @@ ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode)
|
|||||||
switch (cmd->subtype)
|
switch (cmd->subtype)
|
||||||
{
|
{
|
||||||
case AT_AddIndex:
|
case AT_AddIndex:
|
||||||
|
Assert(IsA(cmd->def, IndexStmt));
|
||||||
|
if (!rewrite)
|
||||||
|
TryReuseIndex(get_constraint_index(oldId),
|
||||||
|
(IndexStmt *) cmd->def);
|
||||||
cmd->subtype = AT_ReAddIndex;
|
cmd->subtype = AT_ReAddIndex;
|
||||||
tab->subcmds[AT_PASS_OLD_INDEX] =
|
tab->subcmds[AT_PASS_OLD_INDEX] =
|
||||||
lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
|
lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
|
||||||
@ -7529,6 +7559,26 @@ ATPostAlterTypeParse(char *cmd, List **wqueue, LOCKMODE lockmode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* ALTER TABLE OWNER
|
||||||
|
@ -2807,6 +2807,7 @@ _copyIndexStmt(IndexStmt *from)
|
|||||||
COPY_NODE_FIELD(whereClause);
|
COPY_NODE_FIELD(whereClause);
|
||||||
COPY_NODE_FIELD(excludeOpNames);
|
COPY_NODE_FIELD(excludeOpNames);
|
||||||
COPY_SCALAR_FIELD(indexOid);
|
COPY_SCALAR_FIELD(indexOid);
|
||||||
|
COPY_SCALAR_FIELD(oldNode);
|
||||||
COPY_SCALAR_FIELD(unique);
|
COPY_SCALAR_FIELD(unique);
|
||||||
COPY_SCALAR_FIELD(primary);
|
COPY_SCALAR_FIELD(primary);
|
||||||
COPY_SCALAR_FIELD(isconstraint);
|
COPY_SCALAR_FIELD(isconstraint);
|
||||||
|
@ -1245,6 +1245,7 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b)
|
|||||||
COMPARE_NODE_FIELD(whereClause);
|
COMPARE_NODE_FIELD(whereClause);
|
||||||
COMPARE_NODE_FIELD(excludeOpNames);
|
COMPARE_NODE_FIELD(excludeOpNames);
|
||||||
COMPARE_SCALAR_FIELD(indexOid);
|
COMPARE_SCALAR_FIELD(indexOid);
|
||||||
|
COMPARE_SCALAR_FIELD(oldNode);
|
||||||
COMPARE_SCALAR_FIELD(unique);
|
COMPARE_SCALAR_FIELD(unique);
|
||||||
COMPARE_SCALAR_FIELD(primary);
|
COMPARE_SCALAR_FIELD(primary);
|
||||||
COMPARE_SCALAR_FIELD(isconstraint);
|
COMPARE_SCALAR_FIELD(isconstraint);
|
||||||
|
@ -1976,6 +1976,7 @@ _outIndexStmt(StringInfo str, IndexStmt *node)
|
|||||||
WRITE_NODE_FIELD(whereClause);
|
WRITE_NODE_FIELD(whereClause);
|
||||||
WRITE_NODE_FIELD(excludeOpNames);
|
WRITE_NODE_FIELD(excludeOpNames);
|
||||||
WRITE_OID_FIELD(indexOid);
|
WRITE_OID_FIELD(indexOid);
|
||||||
|
WRITE_OID_FIELD(oldNode);
|
||||||
WRITE_BOOL_FIELD(unique);
|
WRITE_BOOL_FIELD(unique);
|
||||||
WRITE_BOOL_FIELD(primary);
|
WRITE_BOOL_FIELD(primary);
|
||||||
WRITE_BOOL_FIELD(isconstraint);
|
WRITE_BOOL_FIELD(isconstraint);
|
||||||
|
@ -953,6 +953,7 @@ standard_ProcessUtility(Node *parsetree,
|
|||||||
DefineIndex(stmt->relation, /* relation */
|
DefineIndex(stmt->relation, /* relation */
|
||||||
stmt->idxname, /* index name */
|
stmt->idxname, /* index name */
|
||||||
InvalidOid, /* no predefined OID */
|
InvalidOid, /* no predefined OID */
|
||||||
|
InvalidOid, /* no previous storage */
|
||||||
stmt->accessMethod, /* am name */
|
stmt->accessMethod, /* am name */
|
||||||
stmt->tableSpace,
|
stmt->tableSpace,
|
||||||
stmt->indexParams, /* parameters */
|
stmt->indexParams, /* parameters */
|
||||||
|
11
src/backend/utils/cache/relcache.c
vendored
11
src/backend/utils/cache/relcache.c
vendored
@ -2395,6 +2395,7 @@ RelationBuildLocalRelation(const char *relname,
|
|||||||
Oid relnamespace,
|
Oid relnamespace,
|
||||||
TupleDesc tupDesc,
|
TupleDesc tupDesc,
|
||||||
Oid relid,
|
Oid relid,
|
||||||
|
Oid relfilenode,
|
||||||
Oid reltablespace,
|
Oid reltablespace,
|
||||||
bool shared_relation,
|
bool shared_relation,
|
||||||
bool mapped_relation,
|
bool mapped_relation,
|
||||||
@ -2529,10 +2530,8 @@ RelationBuildLocalRelation(const char *relname,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Insert relation physical and logical identifiers (OIDs) into the right
|
* Insert relation physical and logical identifiers (OIDs) into the right
|
||||||
* places. Note that the physical ID (relfilenode) is initially the same
|
* places. For a mapped relation, we set relfilenode to zero and rely on
|
||||||
* as the logical ID (OID); except that for a mapped relation, we set
|
* RelationInitPhysicalAddr to consult the map.
|
||||||
* relfilenode to zero and rely on RelationInitPhysicalAddr to consult the
|
|
||||||
* map.
|
|
||||||
*/
|
*/
|
||||||
rel->rd_rel->relisshared = shared_relation;
|
rel->rd_rel->relisshared = shared_relation;
|
||||||
|
|
||||||
@ -2547,10 +2546,10 @@ RelationBuildLocalRelation(const char *relname,
|
|||||||
{
|
{
|
||||||
rel->rd_rel->relfilenode = InvalidOid;
|
rel->rd_rel->relfilenode = InvalidOid;
|
||||||
/* Add it to the active mapping information */
|
/* Add it to the active mapping information */
|
||||||
RelationMapUpdateMap(relid, relid, shared_relation, true);
|
RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rel->rd_rel->relfilenode = relid;
|
rel->rd_rel->relfilenode = relfilenode;
|
||||||
|
|
||||||
RelationInitLockInfo(rel); /* see lmgr.c */
|
RelationInitLockInfo(rel); /* see lmgr.c */
|
||||||
|
|
||||||
|
2
src/backend/utils/cache/relmapper.c
vendored
2
src/backend/utils/cache/relmapper.c
vendored
@ -792,7 +792,7 @@ write_relmap_file(bool shared, RelMapFile *newmap,
|
|||||||
rnode.spcNode = tsid;
|
rnode.spcNode = tsid;
|
||||||
rnode.dbNode = dbid;
|
rnode.dbNode = dbid;
|
||||||
rnode.relNode = newmap->mappings[i].mapfilenode;
|
rnode.relNode = newmap->mappings[i].mapfilenode;
|
||||||
RelationPreserveStorage(rnode);
|
RelationPreserveStorage(rnode, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ extern Relation heap_create(const char *relname,
|
|||||||
Oid relnamespace,
|
Oid relnamespace,
|
||||||
Oid reltablespace,
|
Oid reltablespace,
|
||||||
Oid relid,
|
Oid relid,
|
||||||
|
Oid relfilenode,
|
||||||
TupleDesc tupDesc,
|
TupleDesc tupDesc,
|
||||||
char relkind,
|
char relkind,
|
||||||
char relpersistence,
|
char relpersistence,
|
||||||
|
@ -35,6 +35,7 @@ extern void index_check_primary_key(Relation heapRel,
|
|||||||
extern Oid index_create(Relation heapRelation,
|
extern Oid index_create(Relation heapRelation,
|
||||||
const char *indexRelationName,
|
const char *indexRelationName,
|
||||||
Oid indexRelationId,
|
Oid indexRelationId,
|
||||||
|
Oid relFileNode,
|
||||||
IndexInfo *indexInfo,
|
IndexInfo *indexInfo,
|
||||||
List *indexColNames,
|
List *indexColNames,
|
||||||
Oid accessMethodObjectId,
|
Oid accessMethodObjectId,
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
extern void RelationCreateStorage(RelFileNode rnode, char relpersistence);
|
extern void RelationCreateStorage(RelFileNode rnode, char relpersistence);
|
||||||
extern void RelationDropStorage(Relation rel);
|
extern void RelationDropStorage(Relation rel);
|
||||||
extern void RelationPreserveStorage(RelFileNode rnode);
|
extern void RelationPreserveStorage(RelFileNode rnode, bool atCommit);
|
||||||
extern void RelationTruncate(Relation rel, BlockNumber nblocks);
|
extern void RelationTruncate(Relation rel, BlockNumber nblocks);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -18,9 +18,10 @@
|
|||||||
|
|
||||||
|
|
||||||
/* commands/indexcmds.c */
|
/* commands/indexcmds.c */
|
||||||
extern void DefineIndex(RangeVar *heapRelation,
|
extern Oid DefineIndex(RangeVar *heapRelation,
|
||||||
char *indexRelationName,
|
char *indexRelationName,
|
||||||
Oid indexRelationId,
|
Oid indexRelationId,
|
||||||
|
Oid relFileNode,
|
||||||
char *accessMethodName,
|
char *accessMethodName,
|
||||||
char *tableSpaceName,
|
char *tableSpaceName,
|
||||||
List *attributeList,
|
List *attributeList,
|
||||||
@ -49,6 +50,11 @@ extern char *ChooseIndexName(const char *tabname, Oid namespaceId,
|
|||||||
List *colnames, List *exclusionOpNames,
|
List *colnames, List *exclusionOpNames,
|
||||||
bool primary, bool isconstraint);
|
bool primary, bool isconstraint);
|
||||||
extern List *ChooseIndexColumnNames(List *indexElems);
|
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);
|
extern Oid GetDefaultOpClass(Oid type_id, Oid am_id);
|
||||||
|
|
||||||
/* commands/functioncmds.c */
|
/* commands/functioncmds.c */
|
||||||
|
@ -2062,6 +2062,7 @@ typedef struct IndexStmt
|
|||||||
Node *whereClause; /* qualification (partial-index predicate) */
|
Node *whereClause; /* qualification (partial-index predicate) */
|
||||||
List *excludeOpNames; /* exclusion operator names, or NIL if none */
|
List *excludeOpNames; /* exclusion operator names, or NIL if none */
|
||||||
Oid indexOid; /* OID of an existing index, if any */
|
Oid indexOid; /* OID of an existing index, if any */
|
||||||
|
Oid oldNode; /* relfilenode of my former self */
|
||||||
bool unique; /* is index unique? */
|
bool unique; /* is index unique? */
|
||||||
bool primary; /* is index on primary key? */
|
bool primary; /* is index on primary key? */
|
||||||
bool isconstraint; /* is it from a CONSTRAINT clause? */
|
bool isconstraint; /* is it from a CONSTRAINT clause? */
|
||||||
|
@ -67,6 +67,7 @@ extern Relation RelationBuildLocalRelation(const char *relname,
|
|||||||
Oid relnamespace,
|
Oid relnamespace,
|
||||||
TupleDesc tupDesc,
|
TupleDesc tupDesc,
|
||||||
Oid relid,
|
Oid relid,
|
||||||
|
Oid relfilenode,
|
||||||
Oid reltablespace,
|
Oid reltablespace,
|
||||||
bool shared_relation,
|
bool shared_relation,
|
||||||
bool mapped_relation,
|
bool mapped_relation,
|
||||||
|
Reference in New Issue
Block a user