@@ -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 ;
@@ -1256,7 +1275,7 @@ DefineIndex(Oid relationId,
1256
1275
return address ;
1257
1276
}
1258
1277
1259
- if (!stmt -> concurrent )
1278
+ if (!concurrent )
1260
1279
{
1261
1280
/* Close the heap and we're done, in the non-concurrent case */
1262
1281
table_close (rel , NoLock );
@@ -2326,6 +2345,11 @@ ReindexIndex(RangeVar *indexRelation, int options, bool concurrent)
2326
2345
* Find and lock index, and check permissions on table; use callback to
2327
2346
* obtain lock on table first, to avoid deadlock hazard. The lock level
2328
2347
* used here must match the index lock obtained in reindex_index().
2348
+ *
2349
+ * If it's a temporary index, we will perform a non-concurrent reindex,
2350
+ * even if CONCURRENTLY was requested. In that case, reindex_index() will
2351
+ * upgrade the lock, but that's OK, because other sessions can't hold
2352
+ * locks on our temporary table.
2329
2353
*/
2330
2354
state .concurrent = concurrent ;
2331
2355
state .locked_table_oid = InvalidOid ;
@@ -2350,7 +2374,7 @@ ReindexIndex(RangeVar *indexRelation, int options, bool concurrent)
2350
2374
persistence = irel -> rd_rel -> relpersistence ;
2351
2375
index_close (irel , NoLock );
2352
2376
2353
- if (concurrent )
2377
+ if (concurrent && persistence != RELPERSISTENCE_TEMP )
2354
2378
ReindexRelationConcurrently (indOid , options );
2355
2379
else
2356
2380
reindex_index (indOid , false, persistence ,
@@ -2437,13 +2461,20 @@ ReindexTable(RangeVar *relation, int options, bool concurrent)
2437
2461
Oid heapOid ;
2438
2462
bool result ;
2439
2463
2440
- /* The lock level used here should match reindex_relation(). */
2464
+ /*
2465
+ * The lock level used here should match reindex_relation().
2466
+ *
2467
+ * If it's a temporary table, we will perform a non-concurrent reindex,
2468
+ * even if CONCURRENTLY was requested. In that case, reindex_relation()
2469
+ * will upgrade the lock, but that's OK, because other sessions can't hold
2470
+ * locks on our temporary table.
2471
+ */
2441
2472
heapOid = RangeVarGetRelidExtended (relation ,
2442
2473
concurrent ? ShareUpdateExclusiveLock : ShareLock ,
2443
2474
0 ,
2444
2475
RangeVarCallbackOwnsTable , NULL );
2445
2476
2446
- if (concurrent )
2477
+ if (concurrent && get_rel_persistence ( heapOid ) != RELPERSISTENCE_TEMP )
2447
2478
{
2448
2479
result = ReindexRelationConcurrently (heapOid , options );
2449
2480
@@ -2649,7 +2680,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
2649
2680
/* functions in indexes may want a snapshot set */
2650
2681
PushActiveSnapshot (GetTransactionSnapshot ());
2651
2682
2652
- if (concurrent )
2683
+ if (concurrent && get_rel_persistence ( relid ) != RELPERSISTENCE_TEMP )
2653
2684
{
2654
2685
(void ) ReindexRelationConcurrently (relid , options );
2655
2686
/* ReindexRelationConcurrently() does the verbose output */
@@ -2697,6 +2728,12 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
2697
2728
*
2698
2729
* Returns true if any indexes have been rebuilt (including toast table's
2699
2730
* indexes, when relevant), otherwise returns false.
2731
+ *
2732
+ * NOTE: This cannot be used on temporary relations. A concurrent build would
2733
+ * cause issues with ON COMMIT actions triggered by the transactions of the
2734
+ * concurrent build. Temporary relations are not subject to concurrent
2735
+ * concerns, so there's no need for the more complicated concurrent build,
2736
+ * anyway, and a non-concurrent reindex is more efficient.
2700
2737
*/
2701
2738
static bool
2702
2739
ReindexRelationConcurrently (Oid relationOid , int options )
@@ -2940,6 +2977,10 @@ ReindexRelationConcurrently(Oid relationOid, int options)
2940
2977
heapRel = table_open (indexRel -> rd_index -> indrelid ,
2941
2978
ShareUpdateExclusiveLock );
2942
2979
2980
+ /* This function shouldn't be called for temporary relations. */
2981
+ if (indexRel -> rd_rel -> relpersistence == RELPERSISTENCE_TEMP )
2982
+ elog (ERROR , "cannot reindex a temporary table concurrently" );
2983
+
2943
2984
pgstat_progress_start_command (PROGRESS_COMMAND_CREATE_INDEX ,
2944
2985
RelationGetRelid (heapRel ));
2945
2986
pgstat_progress_update_param (PROGRESS_CREATEIDX_COMMAND ,
0 commit comments