@@ -438,6 +438,7 @@ DefineIndex(Oid relationId,
438
438
bool skip_build ,
439
439
bool quiet )
440
440
{
441
+ bool concurrent ;
441
442
char * indexRelationName ;
442
443
char * accessMethodName ;
443
444
Oid * typeObjectId ;
@@ -485,6 +486,18 @@ DefineIndex(Oid relationId,
485
486
GUC_ACTION_SAVE , true, 0 , false);
486
487
}
487
488
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
+
488
501
/*
489
502
* Start progress report. If we're building a partition, this was already
490
503
* done.
@@ -494,7 +507,7 @@ DefineIndex(Oid relationId,
494
507
pgstat_progress_start_command (PROGRESS_COMMAND_CREATE_INDEX ,
495
508
relationId );
496
509
pgstat_progress_update_param (PROGRESS_CREATEIDX_COMMAND ,
497
- stmt -> concurrent ?
510
+ concurrent ?
498
511
PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY :
499
512
PROGRESS_CREATEIDX_COMMAND_CREATE );
500
513
}
@@ -547,7 +560,7 @@ DefineIndex(Oid relationId,
547
560
* parallel workers under the control of certain particular ambuild
548
561
* functions will need to be updated, too.
549
562
*/
550
- lockmode = stmt -> concurrent ? ShareUpdateExclusiveLock : ShareLock ;
563
+ lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock ;
551
564
rel = table_open (relationId , lockmode );
552
565
553
566
namespaceId = RelationGetNamespace (rel );
@@ -590,6 +603,12 @@ DefineIndex(Oid relationId,
590
603
partitioned = rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE ;
591
604
if (partitioned )
592
605
{
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
+ */
593
612
if (stmt -> concurrent )
594
613
ereport (ERROR ,
595
614
(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
@@ -781,8 +800,8 @@ DefineIndex(Oid relationId,
781
800
NIL , /* expressions, NIL for now */
782
801
make_ands_implicit ((Expr * ) stmt -> whereClause ),
783
802
stmt -> unique ,
784
- !stmt -> concurrent ,
785
- stmt -> concurrent );
803
+ !concurrent ,
804
+ concurrent );
786
805
787
806
typeObjectId = (Oid * ) palloc (numberOfAttributes * sizeof (Oid ));
788
807
collationObjectId = (Oid * ) palloc (numberOfAttributes * sizeof (Oid ));
@@ -944,7 +963,7 @@ DefineIndex(Oid relationId,
944
963
* A valid stmt->oldNode implies that we already have a built form of the
945
964
* index. The caller should also decline any index build.
946
965
*/
947
- Assert (!OidIsValid (stmt -> oldNode ) || (skip_build && !stmt -> concurrent ));
966
+ Assert (!OidIsValid (stmt -> oldNode ) || (skip_build && !concurrent ));
948
967
949
968
/*
950
969
* Make the catalog entries for the index, including constraints. This
@@ -955,11 +974,11 @@ DefineIndex(Oid relationId,
955
974
flags = constr_flags = 0 ;
956
975
if (stmt -> isconstraint )
957
976
flags |= INDEX_CREATE_ADD_CONSTRAINT ;
958
- if (skip_build || stmt -> concurrent || partitioned )
977
+ if (skip_build || concurrent || partitioned )
959
978
flags |= INDEX_CREATE_SKIP_BUILD ;
960
979
if (stmt -> if_not_exists )
961
980
flags |= INDEX_CREATE_IF_NOT_EXISTS ;
962
- if (stmt -> concurrent )
981
+ if (concurrent )
963
982
flags |= INDEX_CREATE_CONCURRENT ;
964
983
if (partitioned )
965
984
flags |= INDEX_CREATE_PARTITIONED ;
@@ -1253,7 +1272,7 @@ DefineIndex(Oid relationId,
1253
1272
return address ;
1254
1273
}
1255
1274
1256
- if (!stmt -> concurrent )
1275
+ if (!concurrent )
1257
1276
{
1258
1277
/* Close the heap and we're done, in the non-concurrent case */
1259
1278
table_close (rel , NoLock );
@@ -2323,6 +2342,11 @@ ReindexIndex(RangeVar *indexRelation, int options, bool concurrent)
2323
2342
* Find and lock index, and check permissions on table; use callback to
2324
2343
* obtain lock on table first, to avoid deadlock hazard. The lock level
2325
2344
* 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.
2326
2350
*/
2327
2351
state .concurrent = concurrent ;
2328
2352
state .locked_table_oid = InvalidOid ;
@@ -2347,7 +2371,7 @@ ReindexIndex(RangeVar *indexRelation, int options, bool concurrent)
2347
2371
persistence = irel -> rd_rel -> relpersistence ;
2348
2372
index_close (irel , NoLock );
2349
2373
2350
- if (concurrent )
2374
+ if (concurrent && persistence != RELPERSISTENCE_TEMP )
2351
2375
ReindexRelationConcurrently (indOid , options );
2352
2376
else
2353
2377
reindex_index (indOid , false, persistence ,
@@ -2434,13 +2458,20 @@ ReindexTable(RangeVar *relation, int options, bool concurrent)
2434
2458
Oid heapOid ;
2435
2459
bool result ;
2436
2460
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
+ */
2438
2469
heapOid = RangeVarGetRelidExtended (relation ,
2439
2470
concurrent ? ShareUpdateExclusiveLock : ShareLock ,
2440
2471
0 ,
2441
2472
RangeVarCallbackOwnsTable , NULL );
2442
2473
2443
- if (concurrent )
2474
+ if (concurrent && get_rel_persistence ( heapOid ) != RELPERSISTENCE_TEMP )
2444
2475
{
2445
2476
result = ReindexRelationConcurrently (heapOid , options );
2446
2477
@@ -2646,7 +2677,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
2646
2677
/* functions in indexes may want a snapshot set */
2647
2678
PushActiveSnapshot (GetTransactionSnapshot ());
2648
2679
2649
- if (concurrent )
2680
+ if (concurrent && get_rel_persistence ( relid ) != RELPERSISTENCE_TEMP )
2650
2681
{
2651
2682
(void ) ReindexRelationConcurrently (relid , options );
2652
2683
/* ReindexRelationConcurrently() does the verbose output */
@@ -2694,6 +2725,12 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
2694
2725
*
2695
2726
* Returns true if any indexes have been rebuilt (including toast table's
2696
2727
* 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.
2697
2734
*/
2698
2735
static bool
2699
2736
ReindexRelationConcurrently (Oid relationOid , int options )
@@ -2937,6 +2974,10 @@ ReindexRelationConcurrently(Oid relationOid, int options)
2937
2974
heapRel = table_open (indexRel -> rd_index -> indrelid ,
2938
2975
ShareUpdateExclusiveLock );
2939
2976
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
+
2940
2981
pgstat_progress_start_command (PROGRESS_COMMAND_CREATE_INDEX ,
2941
2982
RelationGetRelid (heapRel ));
2942
2983
pgstat_progress_update_param (PROGRESS_CREATEIDX_COMMAND ,
0 commit comments