Commit a61f5ab9 authored by Alvaro Herrera's avatar Alvaro Herrera

Simplify index_[constraint_]create API

Instead of passing large swaths of boolean arguments, define some flags
that can be used in a bitmask.  This makes it easier not only to figure
out what each call site is doing, but also to add some new flags.

The flags are split in two -- one set for index_create directly and
another for constraints.  index_create() itself receives both, and then
passes down the latter to index_constraint_create(), which can also be
called standalone.

Discussion: https://postgr.es/m/20171023151251.j75uoe27gajdjmlm@alvherre.pgsql
Reviewed-by: Simon Riggs
parent 591c504f
...@@ -680,19 +680,25 @@ UpdateIndexRelation(Oid indexoid, ...@@ -680,19 +680,25 @@ UpdateIndexRelation(Oid indexoid,
* classObjectId: array of index opclass OIDs, one per index column * classObjectId: array of index opclass OIDs, one per index column
* coloptions: array of per-index-column indoption settings * coloptions: array of per-index-column indoption settings
* reloptions: AM-specific options * reloptions: AM-specific options
* isprimary: index is a PRIMARY KEY * flags: bitmask that can include any combination of these bits:
* isconstraint: index is owned by PRIMARY KEY, UNIQUE, or EXCLUSION constraint * INDEX_CREATE_IS_PRIMARY
* deferrable: constraint is DEFERRABLE * the index is a primary key
* initdeferred: constraint is INITIALLY DEFERRED * INDEX_CREATE_ADD_CONSTRAINT:
* allow_system_table_mods: allow table to be a system catalog * invoke index_constraint_create also
* skip_build: true to skip the index_build() step for the moment; caller * INDEX_CREATE_SKIP_BUILD:
* must do it later (typically via reindex_index()) * skip the index_build() step for the moment; caller must do it
* concurrent: if true, do not lock the table against writers. The index * later (typically via reindex_index())
* will be marked "invalid" and the caller must take additional steps * INDEX_CREATE_CONCURRENT:
* do not lock the table against writers. The index will be
* marked "invalid" and the caller must take additional steps
* to fix it up. * to fix it up.
* INDEX_CREATE_IF_NOT_EXISTS:
* do not throw an error if a relation with the same name
* already exists.
* constr_flags: flags passed to index_constraint_create
* (only if INDEX_CREATE_ADD_CONSTRAINT is set)
* allow_system_table_mods: allow table to be a system catalog
* is_internal: if true, post creation hook for new index * is_internal: if true, post creation hook for new index
* if_not_exists: if true, do not throw an error if a relation with
* the same name already exists.
* *
* Returns the OID of the created index. * Returns the OID of the created index.
*/ */
...@@ -709,15 +715,10 @@ index_create(Relation heapRelation, ...@@ -709,15 +715,10 @@ index_create(Relation heapRelation,
Oid *classObjectId, Oid *classObjectId,
int16 *coloptions, int16 *coloptions,
Datum reloptions, Datum reloptions,
bool isprimary, bits16 flags,
bool isconstraint, bits16 constr_flags,
bool deferrable,
bool initdeferred,
bool allow_system_table_mods, bool allow_system_table_mods,
bool skip_build, bool is_internal)
bool concurrent,
bool is_internal,
bool if_not_exists)
{ {
Oid heapRelationId = RelationGetRelid(heapRelation); Oid heapRelationId = RelationGetRelid(heapRelation);
Relation pg_class; Relation pg_class;
...@@ -729,6 +730,12 @@ index_create(Relation heapRelation, ...@@ -729,6 +730,12 @@ index_create(Relation heapRelation,
Oid namespaceId; Oid namespaceId;
int i; int i;
char relpersistence; char relpersistence;
bool isprimary = (flags & INDEX_CREATE_IS_PRIMARY) != 0;
bool concurrent = (flags & INDEX_CREATE_CONCURRENT) != 0;
/* constraint flags can only be set when a constraint is requested */
Assert((constr_flags == 0) ||
((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0));
is_exclusion = (indexInfo->ii_ExclusionOps != NULL); is_exclusion = (indexInfo->ii_ExclusionOps != NULL);
...@@ -794,7 +801,7 @@ index_create(Relation heapRelation, ...@@ -794,7 +801,7 @@ index_create(Relation heapRelation,
if (get_relname_relid(indexRelationName, namespaceId)) if (get_relname_relid(indexRelationName, namespaceId))
{ {
if (if_not_exists) if ((flags & INDEX_CREATE_IF_NOT_EXISTS) != 0)
{ {
ereport(NOTICE, ereport(NOTICE,
(errcode(ERRCODE_DUPLICATE_TABLE), (errcode(ERRCODE_DUPLICATE_TABLE),
...@@ -917,7 +924,7 @@ index_create(Relation heapRelation, ...@@ -917,7 +924,7 @@ index_create(Relation heapRelation,
UpdateIndexRelation(indexRelationId, heapRelationId, indexInfo, UpdateIndexRelation(indexRelationId, heapRelationId, indexInfo,
collationObjectId, classObjectId, coloptions, collationObjectId, classObjectId, coloptions,
isprimary, is_exclusion, isprimary, is_exclusion,
!deferrable, (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) == 0,
!concurrent); !concurrent);
/* /*
...@@ -943,7 +950,7 @@ index_create(Relation heapRelation, ...@@ -943,7 +950,7 @@ index_create(Relation heapRelation,
myself.objectId = indexRelationId; myself.objectId = indexRelationId;
myself.objectSubId = 0; myself.objectSubId = 0;
if (isconstraint) if ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0)
{ {
char constraintType; char constraintType;
...@@ -964,11 +971,7 @@ index_create(Relation heapRelation, ...@@ -964,11 +971,7 @@ index_create(Relation heapRelation,
indexInfo, indexInfo,
indexRelationName, indexRelationName,
constraintType, constraintType,
deferrable, constr_flags,
initdeferred,
false, /* already marked primary */
false, /* pg_index entry is OK */
false, /* no old dependencies */
allow_system_table_mods, allow_system_table_mods,
is_internal); is_internal);
} }
...@@ -1005,10 +1008,6 @@ index_create(Relation heapRelation, ...@@ -1005,10 +1008,6 @@ index_create(Relation heapRelation,
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
} }
/* Non-constraint indexes can't be deferrable */
Assert(!deferrable);
Assert(!initdeferred);
} }
/* Store dependency on collations */ /* Store dependency on collations */
...@@ -1059,9 +1058,7 @@ index_create(Relation heapRelation, ...@@ -1059,9 +1058,7 @@ index_create(Relation heapRelation,
else else
{ {
/* Bootstrap mode - assert we weren't asked for constraint support */ /* Bootstrap mode - assert we weren't asked for constraint support */
Assert(!isconstraint); Assert((flags & INDEX_CREATE_ADD_CONSTRAINT) == 0);
Assert(!deferrable);
Assert(!initdeferred);
} }
/* Post creation hook for new index */ /* Post creation hook for new index */
...@@ -1089,15 +1086,16 @@ index_create(Relation heapRelation, ...@@ -1089,15 +1086,16 @@ index_create(Relation heapRelation,
* If this is bootstrap (initdb) time, then we don't actually fill in the * If this is bootstrap (initdb) time, then we don't actually fill in the
* index yet. We'll be creating more indexes and classes later, so we * index yet. We'll be creating more indexes and classes later, so we
* delay filling them in until just before we're done with bootstrapping. * delay filling them in until just before we're done with bootstrapping.
* Similarly, if the caller specified skip_build then filling the index is * Similarly, if the caller specified to skip the build then filling the
* delayed till later (ALTER TABLE can save work in some cases with this). * index is delayed till later (ALTER TABLE can save work in some cases
* Otherwise, we call the AM routine that constructs the index. * with this). Otherwise, we call the AM routine that constructs the
* index.
*/ */
if (IsBootstrapProcessingMode()) if (IsBootstrapProcessingMode())
{ {
index_register(heapRelationId, indexRelationId, indexInfo); index_register(heapRelationId, indexRelationId, indexInfo);
} }
else if (skip_build) else if ((flags & INDEX_CREATE_SKIP_BUILD) != 0)
{ {
/* /*
* Caller is responsible for filling the index later on. However, * Caller is responsible for filling the index later on. However,
...@@ -1137,12 +1135,13 @@ index_create(Relation heapRelation, ...@@ -1137,12 +1135,13 @@ index_create(Relation heapRelation,
* constraintName: what it say (generally, should match name of index) * constraintName: what it say (generally, should match name of index)
* constraintType: one of CONSTRAINT_PRIMARY, CONSTRAINT_UNIQUE, or * constraintType: one of CONSTRAINT_PRIMARY, CONSTRAINT_UNIQUE, or
* CONSTRAINT_EXCLUSION * CONSTRAINT_EXCLUSION
* deferrable: constraint is DEFERRABLE * flags: bitmask that can include any combination of these bits:
* initdeferred: constraint is INITIALLY DEFERRED * INDEX_CONSTR_CREATE_MARK_AS_PRIMARY: index is a PRIMARY KEY
* mark_as_primary: if true, set flags to mark index as primary key * INDEX_CONSTR_CREATE_DEFERRABLE: constraint is DEFERRABLE
* update_pgindex: if true, update pg_index row (else caller's done that) * INDEX_CONSTR_CREATE_INIT_DEFERRED: constraint is INITIALLY DEFERRED
* remove_old_dependencies: if true, remove existing dependencies of index * INDEX_CONSTR_CREATE_UPDATE_INDEX: update the pg_index row
* on table's columns * INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS: remove existing dependencies
* of index on table's columns
* allow_system_table_mods: allow table to be a system catalog * allow_system_table_mods: allow table to be a system catalog
* is_internal: index is constructed due to internal process * is_internal: index is constructed due to internal process
*/ */
...@@ -1152,11 +1151,7 @@ index_constraint_create(Relation heapRelation, ...@@ -1152,11 +1151,7 @@ index_constraint_create(Relation heapRelation,
IndexInfo *indexInfo, IndexInfo *indexInfo,
const char *constraintName, const char *constraintName,
char constraintType, char constraintType,
bool deferrable, bits16 constr_flags,
bool initdeferred,
bool mark_as_primary,
bool update_pgindex,
bool remove_old_dependencies,
bool allow_system_table_mods, bool allow_system_table_mods,
bool is_internal) bool is_internal)
{ {
...@@ -1164,6 +1159,13 @@ index_constraint_create(Relation heapRelation, ...@@ -1164,6 +1159,13 @@ index_constraint_create(Relation heapRelation,
ObjectAddress myself, ObjectAddress myself,
referenced; referenced;
Oid conOid; Oid conOid;
bool deferrable;
bool initdeferred;
bool mark_as_primary;
deferrable = (constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) != 0;
initdeferred = (constr_flags & INDEX_CONSTR_CREATE_INIT_DEFERRED) != 0;
mark_as_primary = (constr_flags & INDEX_CONSTR_CREATE_MARK_AS_PRIMARY) != 0;
/* constraint creation support doesn't work while bootstrapping */ /* constraint creation support doesn't work while bootstrapping */
Assert(!IsBootstrapProcessingMode()); Assert(!IsBootstrapProcessingMode());
...@@ -1190,7 +1192,7 @@ index_constraint_create(Relation heapRelation, ...@@ -1190,7 +1192,7 @@ index_constraint_create(Relation heapRelation,
* has any expressions or predicate, but we'd never be turning such an * has any expressions or predicate, but we'd never be turning such an
* index into a UNIQUE or PRIMARY KEY constraint. * index into a UNIQUE or PRIMARY KEY constraint.
*/ */
if (remove_old_dependencies) if (constr_flags & INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS)
deleteDependencyRecordsForClass(RelationRelationId, indexRelationId, deleteDependencyRecordsForClass(RelationRelationId, indexRelationId,
RelationRelationId, DEPENDENCY_AUTO); RelationRelationId, DEPENDENCY_AUTO);
...@@ -1295,7 +1297,8 @@ index_constraint_create(Relation heapRelation, ...@@ -1295,7 +1297,8 @@ index_constraint_create(Relation heapRelation,
* is a risk that concurrent readers of the table will miss seeing this * is a risk that concurrent readers of the table will miss seeing this
* index at all. * index at all.
*/ */
if (update_pgindex && (mark_as_primary || deferrable)) if ((constr_flags & INDEX_CONSTR_CREATE_UPDATE_INDEX) &&
(mark_as_primary || deferrable))
{ {
Relation pg_index; Relation pg_index;
HeapTuple indexTuple; HeapTuple indexTuple;
......
...@@ -333,8 +333,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, ...@@ -333,8 +333,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
BTREE_AM_OID, BTREE_AM_OID,
rel->rd_rel->reltablespace, rel->rd_rel->reltablespace,
collationObjectId, classObjectId, coloptions, (Datum) 0, collationObjectId, classObjectId, coloptions, (Datum) 0,
true, false, false, false, INDEX_CREATE_IS_PRIMARY, 0, true, true);
true, false, false, true, false);
heap_close(toast_rel, NoLock); heap_close(toast_rel, NoLock);
......
...@@ -333,6 +333,8 @@ DefineIndex(Oid relationId, ...@@ -333,6 +333,8 @@ DefineIndex(Oid relationId,
Datum reloptions; Datum reloptions;
int16 *coloptions; int16 *coloptions;
IndexInfo *indexInfo; IndexInfo *indexInfo;
bits16 flags;
bits16 constr_flags;
int numberOfAttributes; int numberOfAttributes;
TransactionId limitXmin; TransactionId limitXmin;
VirtualTransactionId *old_snapshots; VirtualTransactionId *old_snapshots;
...@@ -661,20 +663,35 @@ DefineIndex(Oid relationId, ...@@ -661,20 +663,35 @@ DefineIndex(Oid relationId,
Assert(!OidIsValid(stmt->oldNode) || (skip_build && !stmt->concurrent)); Assert(!OidIsValid(stmt->oldNode) || (skip_build && !stmt->concurrent));
/* /*
* Make the catalog entries for the index, including constraints. Then, if * Make the catalog entries for the index, including constraints. This
* not skip_build || concurrent, actually build the index. * step also actually builds the index, except if caller requested not to
* or in concurrent mode, in which case it'll be done later.
*/ */
flags = constr_flags = 0;
if (stmt->isconstraint)
flags |= INDEX_CREATE_ADD_CONSTRAINT;
if (skip_build || stmt->concurrent)
flags |= INDEX_CREATE_SKIP_BUILD;
if (stmt->if_not_exists)
flags |= INDEX_CREATE_IF_NOT_EXISTS;
if (stmt->concurrent)
flags |= INDEX_CREATE_CONCURRENT;
if (stmt->primary)
flags |= INDEX_CREATE_IS_PRIMARY;
if (stmt->deferrable)
constr_flags |= INDEX_CONSTR_CREATE_DEFERRABLE;
if (stmt->initdeferred)
constr_flags |= INDEX_CONSTR_CREATE_INIT_DEFERRED;
indexRelationId = indexRelationId =
index_create(rel, indexRelationName, indexRelationId, stmt->oldNode, index_create(rel, indexRelationName, indexRelationId, stmt->oldNode,
indexInfo, indexColNames, indexInfo, indexColNames,
accessMethodId, tablespaceId, accessMethodId, tablespaceId,
collationObjectId, classObjectId, collationObjectId, classObjectId,
coloptions, reloptions, stmt->primary, coloptions, reloptions,
stmt->isconstraint, stmt->deferrable, stmt->initdeferred, flags, constr_flags,
allowSystemTableMods, allowSystemTableMods, !check_rights);
skip_build || stmt->concurrent,
stmt->concurrent, !check_rights,
stmt->if_not_exists);
ObjectAddressSet(address, RelationRelationId, indexRelationId); ObjectAddressSet(address, RelationRelationId, indexRelationId);
......
...@@ -6836,6 +6836,7 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, ...@@ -6836,6 +6836,7 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
char *constraintName; char *constraintName;
char constraintType; char constraintType;
ObjectAddress address; ObjectAddress address;
bits16 flags;
Assert(IsA(stmt, IndexStmt)); Assert(IsA(stmt, IndexStmt));
Assert(OidIsValid(index_oid)); Assert(OidIsValid(index_oid));
...@@ -6880,16 +6881,18 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, ...@@ -6880,16 +6881,18 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
constraintType = CONSTRAINT_UNIQUE; constraintType = CONSTRAINT_UNIQUE;
/* Create the catalog entries for the constraint */ /* Create the catalog entries for the constraint */
flags = INDEX_CONSTR_CREATE_UPDATE_INDEX |
INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS |
(stmt->initdeferred ? INDEX_CONSTR_CREATE_INIT_DEFERRED : 0) |
(stmt->deferrable ? INDEX_CONSTR_CREATE_DEFERRABLE : 0) |
(stmt->primary ? INDEX_CONSTR_CREATE_MARK_AS_PRIMARY : 0);
address = index_constraint_create(rel, address = index_constraint_create(rel,
index_oid, index_oid,
indexInfo, indexInfo,
constraintName, constraintName,
constraintType, constraintType,
stmt->deferrable, flags,
stmt->initdeferred,
stmt->primary,
true, /* update pg_index */
true, /* remove old dependencies */
allowSystemTableMods, allowSystemTableMods,
false); /* is_internal */ false); /* is_internal */
......
...@@ -42,6 +42,12 @@ extern void index_check_primary_key(Relation heapRel, ...@@ -42,6 +42,12 @@ extern void index_check_primary_key(Relation heapRel,
IndexInfo *indexInfo, IndexInfo *indexInfo,
bool is_alter_table); bool is_alter_table);
#define INDEX_CREATE_IS_PRIMARY (1 << 0)
#define INDEX_CREATE_ADD_CONSTRAINT (1 << 1)
#define INDEX_CREATE_SKIP_BUILD (1 << 2)
#define INDEX_CREATE_CONCURRENT (1 << 3)
#define INDEX_CREATE_IF_NOT_EXISTS (1 << 4)
extern Oid index_create(Relation heapRelation, extern Oid index_create(Relation heapRelation,
const char *indexRelationName, const char *indexRelationName,
Oid indexRelationId, Oid indexRelationId,
...@@ -54,26 +60,23 @@ extern Oid index_create(Relation heapRelation, ...@@ -54,26 +60,23 @@ extern Oid index_create(Relation heapRelation,
Oid *classObjectId, Oid *classObjectId,
int16 *coloptions, int16 *coloptions,
Datum reloptions, Datum reloptions,
bool isprimary, bits16 flags,
bool isconstraint, bits16 constr_flags,
bool deferrable,
bool initdeferred,
bool allow_system_table_mods, bool allow_system_table_mods,
bool skip_build, bool is_internal);
bool concurrent,
bool is_internal, #define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY (1 << 0)
bool if_not_exists); #define INDEX_CONSTR_CREATE_DEFERRABLE (1 << 1)
#define INDEX_CONSTR_CREATE_INIT_DEFERRED (1 << 2)
#define INDEX_CONSTR_CREATE_UPDATE_INDEX (1 << 3)
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS (1 << 4)
extern ObjectAddress index_constraint_create(Relation heapRelation, extern ObjectAddress index_constraint_create(Relation heapRelation,
Oid indexRelationId, Oid indexRelationId,
IndexInfo *indexInfo, IndexInfo *indexInfo,
const char *constraintName, const char *constraintName,
char constraintType, char constraintType,
bool deferrable, bits16 constr_flags,
bool initdeferred,
bool mark_as_primary,
bool update_pgindex,
bool remove_old_dependencies,
bool allow_system_table_mods, bool allow_system_table_mods,
bool is_internal); bool is_internal);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment