@@ -438,6 +438,7 @@ DefineIndex(Oid relationId,
438438 bool skip_build ,
439439 bool quiet )
440440{
441+ bool concurrent ;
441442 char * indexRelationName ;
442443 char * accessMethodName ;
443444 Oid * typeObjectId ;
@@ -485,6 +486,18 @@ DefineIndex(Oid relationId,
485486 GUC_ACTION_SAVE , true, 0 , false);
486487 }
487488
489+ /*
490+ * Force non-concurrent build on temporary relations, even if CONCURRENTLY
491+ * was requested. Other backends can't access a temporary relation, so
492+ * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
493+ * is more efficient. Do this before any use of the concurrent option is
494+ * done.
495+ */
496+ if (stmt -> concurrent && get_rel_persistence (relationId ) != RELPERSISTENCE_TEMP )
497+ concurrent = true;
498+ else
499+ concurrent = false;
500+
488501 /*
489502 * Start progress report. If we're building a partition, this was already
490503 * done.
@@ -494,7 +507,7 @@ DefineIndex(Oid relationId,
494507 pgstat_progress_start_command (PROGRESS_COMMAND_CREATE_INDEX ,
495508 relationId );
496509 pgstat_progress_update_param (PROGRESS_CREATEIDX_COMMAND ,
497- stmt -> concurrent ?
510+ concurrent ?
498511 PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY :
499512 PROGRESS_CREATEIDX_COMMAND_CREATE );
500513 }
@@ -547,7 +560,7 @@ DefineIndex(Oid relationId,
547560 * parallel workers under the control of certain particular ambuild
548561 * functions will need to be updated, too.
549562 */
550- lockmode = stmt -> concurrent ? ShareUpdateExclusiveLock : ShareLock ;
563+ lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock ;
551564 rel = table_open (relationId , lockmode );
552565
553566 namespaceId = RelationGetNamespace (rel );
@@ -590,6 +603,12 @@ DefineIndex(Oid relationId,
590603 partitioned = rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE ;
591604 if (partitioned )
592605 {
606+ /*
607+ * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
608+ * the error is thrown also for temporary tables. Seems better to be
609+ * consistent, even though we could do it on temporary table because
610+ * we're not actually doing it concurrently.
611+ */
593612 if (stmt -> concurrent )
594613 ereport (ERROR ,
595614 (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
@@ -781,8 +800,8 @@ DefineIndex(Oid relationId,
781800 NIL , /* expressions, NIL for now */
782801 make_ands_implicit ((Expr * ) stmt -> whereClause ),
783802 stmt -> unique ,
784- !stmt -> concurrent ,
785- stmt -> concurrent );
803+ !concurrent ,
804+ concurrent );
786805
787806 typeObjectId = (Oid * ) palloc (numberOfAttributes * sizeof (Oid ));
788807 collationObjectId = (Oid * ) palloc (numberOfAttributes * sizeof (Oid ));
@@ -944,7 +963,7 @@ DefineIndex(Oid relationId,
944963 * A valid stmt->oldNode implies that we already have a built form of the
945964 * index. The caller should also decline any index build.
946965 */
947- Assert (!OidIsValid (stmt -> oldNode ) || (skip_build && !stmt -> concurrent ));
966+ Assert (!OidIsValid (stmt -> oldNode ) || (skip_build && !concurrent ));
948967
949968 /*
950969 * Make the catalog entries for the index, including constraints. This
@@ -955,11 +974,11 @@ DefineIndex(Oid relationId,
955974 flags = constr_flags = 0 ;
956975 if (stmt -> isconstraint )
957976 flags |= INDEX_CREATE_ADD_CONSTRAINT ;
958- if (skip_build || stmt -> concurrent || partitioned )
977+ if (skip_build || concurrent || partitioned )
959978 flags |= INDEX_CREATE_SKIP_BUILD ;
960979 if (stmt -> if_not_exists )
961980 flags |= INDEX_CREATE_IF_NOT_EXISTS ;
962- if (stmt -> concurrent )
981+ if (concurrent )
963982 flags |= INDEX_CREATE_CONCURRENT ;
964983 if (partitioned )
965984 flags |= INDEX_CREATE_PARTITIONED ;
@@ -1253,7 +1272,7 @@ DefineIndex(Oid relationId,
12531272 return address ;
12541273 }
12551274
1256- if (!stmt -> concurrent )
1275+ if (!concurrent )
12571276 {
12581277 /* Close the heap and we're done, in the non-concurrent case */
12591278 table_close (rel , NoLock );
@@ -2323,6 +2342,11 @@ ReindexIndex(RangeVar *indexRelation, int options, bool concurrent)
23232342 * Find and lock index, and check permissions on table; use callback to
23242343 * obtain lock on table first, to avoid deadlock hazard. The lock level
23252344 * used here must match the index lock obtained in reindex_index().
2345+ *
2346+ * If it's a temporary index, we will perform a non-concurrent reindex,
2347+ * even if CONCURRENTLY was requested. In that case, reindex_index() will
2348+ * upgrade the lock, but that's OK, because other sessions can't hold
2349+ * locks on our temporary table.
23262350 */
23272351 state .concurrent = concurrent ;
23282352 state .locked_table_oid = InvalidOid ;
@@ -2347,7 +2371,7 @@ ReindexIndex(RangeVar *indexRelation, int options, bool concurrent)
23472371 persistence = irel -> rd_rel -> relpersistence ;
23482372 index_close (irel , NoLock );
23492373
2350- if (concurrent )
2374+ if (concurrent && persistence != RELPERSISTENCE_TEMP )
23512375 ReindexRelationConcurrently (indOid , options );
23522376 else
23532377 reindex_index (indOid , false, persistence ,
@@ -2434,13 +2458,20 @@ ReindexTable(RangeVar *relation, int options, bool concurrent)
24342458 Oid heapOid ;
24352459 bool result ;
24362460
2437- /* The lock level used here should match reindex_relation(). */
2461+ /*
2462+ * The lock level used here should match reindex_relation().
2463+ *
2464+ * If it's a temporary table, we will perform a non-concurrent reindex,
2465+ * even if CONCURRENTLY was requested. In that case, reindex_relation()
2466+ * will upgrade the lock, but that's OK, because other sessions can't hold
2467+ * locks on our temporary table.
2468+ */
24382469 heapOid = RangeVarGetRelidExtended (relation ,
24392470 concurrent ? ShareUpdateExclusiveLock : ShareLock ,
24402471 0 ,
24412472 RangeVarCallbackOwnsTable , NULL );
24422473
2443- if (concurrent )
2474+ if (concurrent && get_rel_persistence ( heapOid ) != RELPERSISTENCE_TEMP )
24442475 {
24452476 result = ReindexRelationConcurrently (heapOid , options );
24462477
@@ -2646,7 +2677,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
26462677 /* functions in indexes may want a snapshot set */
26472678 PushActiveSnapshot (GetTransactionSnapshot ());
26482679
2649- if (concurrent )
2680+ if (concurrent && get_rel_persistence ( relid ) != RELPERSISTENCE_TEMP )
26502681 {
26512682 (void ) ReindexRelationConcurrently (relid , options );
26522683 /* ReindexRelationConcurrently() does the verbose output */
@@ -2694,6 +2725,12 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
26942725 *
26952726 * Returns true if any indexes have been rebuilt (including toast table's
26962727 * indexes, when relevant), otherwise returns false.
2728+ *
2729+ * NOTE: This cannot be used on temporary relations. A concurrent build would
2730+ * cause issues with ON COMMIT actions triggered by the transactions of the
2731+ * concurrent build. Temporary relations are not subject to concurrent
2732+ * concerns, so there's no need for the more complicated concurrent build,
2733+ * anyway, and a non-concurrent reindex is more efficient.
26972734 */
26982735static bool
26992736ReindexRelationConcurrently (Oid relationOid , int options )
@@ -2937,6 +2974,10 @@ ReindexRelationConcurrently(Oid relationOid, int options)
29372974 heapRel = table_open (indexRel -> rd_index -> indrelid ,
29382975 ShareUpdateExclusiveLock );
29392976
2977+ /* This function shouldn't be called for temporary relations. */
2978+ if (indexRel -> rd_rel -> relpersistence == RELPERSISTENCE_TEMP )
2979+ elog (ERROR , "cannot reindex a temporary table concurrently" );
2980+
29402981 pgstat_progress_start_command (PROGRESS_COMMAND_CREATE_INDEX ,
29412982 RelationGetRelid (heapRel ));
29422983 pgstat_progress_update_param (PROGRESS_CREATEIDX_COMMAND ,
0 commit comments