aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/indexcmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/indexcmds.c')
-rw-r--r--src/backend/commands/indexcmds.c65
1 files changed, 53 insertions, 12 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 90378474d7d..9869a4dd0e7 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -438,6 +438,7 @@ DefineIndex(Oid relationId,
bool skip_build,
bool quiet)
{
+ bool concurrent;
char *indexRelationName;
char *accessMethodName;
Oid *typeObjectId;
@@ -486,6 +487,18 @@ DefineIndex(Oid relationId,
}
/*
+ * Force non-concurrent build on temporary relations, even if CONCURRENTLY
+ * was requested. Other backends can't access a temporary relation, so
+ * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
+ * is more efficient. Do this before any use of the concurrent option is
+ * done.
+ */
+ if (stmt->concurrent && get_rel_persistence(relationId) != RELPERSISTENCE_TEMP)
+ concurrent = true;
+ else
+ concurrent = false;
+
+ /*
* Start progress report. If we're building a partition, this was already
* done.
*/
@@ -494,7 +507,7 @@ DefineIndex(Oid relationId,
pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX,
relationId);
pgstat_progress_update_param(PROGRESS_CREATEIDX_COMMAND,
- stmt->concurrent ?
+ concurrent ?
PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY :
PROGRESS_CREATEIDX_COMMAND_CREATE);
}
@@ -547,7 +560,7 @@ DefineIndex(Oid relationId,
* parallel workers under the control of certain particular ambuild
* functions will need to be updated, too.
*/
- lockmode = stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock;
+ lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
rel = table_open(relationId, lockmode);
namespaceId = RelationGetNamespace(rel);
@@ -590,6 +603,12 @@ DefineIndex(Oid relationId,
partitioned = rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
if (partitioned)
{
+ /*
+ * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
+ * the error is thrown also for temporary tables. Seems better to be
+ * consistent, even though we could do it on temporary table because
+ * we're not actually doing it concurrently.
+ */
if (stmt->concurrent)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -781,8 +800,8 @@ DefineIndex(Oid relationId,
NIL, /* expressions, NIL for now */
make_ands_implicit((Expr *) stmt->whereClause),
stmt->unique,
- !stmt->concurrent,
- stmt->concurrent);
+ !concurrent,
+ concurrent);
typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
@@ -944,7 +963,7 @@ DefineIndex(Oid relationId,
* A valid stmt->oldNode implies that we already have a built form of the
* index. The caller should also decline any index build.
*/
- Assert(!OidIsValid(stmt->oldNode) || (skip_build && !stmt->concurrent));
+ Assert(!OidIsValid(stmt->oldNode) || (skip_build && !concurrent));
/*
* Make the catalog entries for the index, including constraints. This
@@ -955,11 +974,11 @@ DefineIndex(Oid relationId,
flags = constr_flags = 0;
if (stmt->isconstraint)
flags |= INDEX_CREATE_ADD_CONSTRAINT;
- if (skip_build || stmt->concurrent || partitioned)
+ if (skip_build || concurrent || partitioned)
flags |= INDEX_CREATE_SKIP_BUILD;
if (stmt->if_not_exists)
flags |= INDEX_CREATE_IF_NOT_EXISTS;
- if (stmt->concurrent)
+ if (concurrent)
flags |= INDEX_CREATE_CONCURRENT;
if (partitioned)
flags |= INDEX_CREATE_PARTITIONED;
@@ -1256,7 +1275,7 @@ DefineIndex(Oid relationId,
return address;
}
- if (!stmt->concurrent)
+ if (!concurrent)
{
/* Close the heap and we're done, in the non-concurrent case */
table_close(rel, NoLock);
@@ -2326,6 +2345,11 @@ ReindexIndex(RangeVar *indexRelation, int options, bool concurrent)
* Find and lock index, and check permissions on table; use callback to
* obtain lock on table first, to avoid deadlock hazard. The lock level
* used here must match the index lock obtained in reindex_index().
+ *
+ * If it's a temporary index, we will perform a non-concurrent reindex,
+ * even if CONCURRENTLY was requested. In that case, reindex_index() will
+ * upgrade the lock, but that's OK, because other sessions can't hold
+ * locks on our temporary table.
*/
state.concurrent = concurrent;
state.locked_table_oid = InvalidOid;
@@ -2350,7 +2374,7 @@ ReindexIndex(RangeVar *indexRelation, int options, bool concurrent)
persistence = irel->rd_rel->relpersistence;
index_close(irel, NoLock);
- if (concurrent)
+ if (concurrent && persistence != RELPERSISTENCE_TEMP)
ReindexRelationConcurrently(indOid, options);
else
reindex_index(indOid, false, persistence,
@@ -2437,13 +2461,20 @@ ReindexTable(RangeVar *relation, int options, bool concurrent)
Oid heapOid;
bool result;
- /* The lock level used here should match reindex_relation(). */
+ /*
+ * The lock level used here should match reindex_relation().
+ *
+ * If it's a temporary table, we will perform a non-concurrent reindex,
+ * even if CONCURRENTLY was requested. In that case, reindex_relation()
+ * will upgrade the lock, but that's OK, because other sessions can't hold
+ * locks on our temporary table.
+ */
heapOid = RangeVarGetRelidExtended(relation,
concurrent ? ShareUpdateExclusiveLock : ShareLock,
0,
RangeVarCallbackOwnsTable, NULL);
- if (concurrent)
+ if (concurrent && get_rel_persistence(heapOid) != RELPERSISTENCE_TEMP)
{
result = ReindexRelationConcurrently(heapOid, options);
@@ -2649,7 +2680,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
/* functions in indexes may want a snapshot set */
PushActiveSnapshot(GetTransactionSnapshot());
- if (concurrent)
+ if (concurrent && get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
{
(void) ReindexRelationConcurrently(relid, options);
/* ReindexRelationConcurrently() does the verbose output */
@@ -2697,6 +2728,12 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
*
* Returns true if any indexes have been rebuilt (including toast table's
* indexes, when relevant), otherwise returns false.
+ *
+ * NOTE: This cannot be used on temporary relations. A concurrent build would
+ * cause issues with ON COMMIT actions triggered by the transactions of the
+ * concurrent build. Temporary relations are not subject to concurrent
+ * concerns, so there's no need for the more complicated concurrent build,
+ * anyway, and a non-concurrent reindex is more efficient.
*/
static bool
ReindexRelationConcurrently(Oid relationOid, int options)
@@ -2940,6 +2977,10 @@ ReindexRelationConcurrently(Oid relationOid, int options)
heapRel = table_open(indexRel->rd_index->indrelid,
ShareUpdateExclusiveLock);
+ /* This function shouldn't be called for temporary relations. */
+ if (indexRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
+ elog(ERROR, "cannot reindex a temporary table concurrently");
+
pgstat_progress_start_command(PROGRESS_COMMAND_CREATE_INDEX,
RelationGetRelid(heapRel));
pgstat_progress_update_param(PROGRESS_CREATEIDX_COMMAND,