@@ -2474,6 +2474,7 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
2474
2474
ListCell * lc ;
2475
2475
bool concurrently = false;
2476
2476
bool verbose = false;
2477
+ char * tablespacename = NULL ;
2477
2478
2478
2479
/* Parse option list */
2479
2480
foreach (lc , stmt -> params )
@@ -2484,6 +2485,8 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
2484
2485
verbose = defGetBoolean (opt );
2485
2486
else if (strcmp (opt -> defname , "concurrently" ) == 0 )
2486
2487
concurrently = defGetBoolean (opt );
2488
+ else if (strcmp (opt -> defname , "tablespace" ) == 0 )
2489
+ tablespacename = defGetString (opt );
2487
2490
else
2488
2491
ereport (ERROR ,
2489
2492
(errcode (ERRCODE_SYNTAX_ERROR ),
@@ -2500,6 +2503,30 @@ ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel)
2500
2503
(verbose ? REINDEXOPT_VERBOSE : 0 ) |
2501
2504
(concurrently ? REINDEXOPT_CONCURRENTLY : 0 );
2502
2505
2506
+ /*
2507
+ * Assign the tablespace OID to move indexes to, with InvalidOid to do
2508
+ * nothing.
2509
+ */
2510
+ if (tablespacename != NULL )
2511
+ {
2512
+ params .tablespaceOid = get_tablespace_oid (tablespacename , false);
2513
+
2514
+ /* Check permissions except when moving to database's default */
2515
+ if (OidIsValid (params .tablespaceOid ) &&
2516
+ params .tablespaceOid != MyDatabaseTableSpace )
2517
+ {
2518
+ AclResult aclresult ;
2519
+
2520
+ aclresult = pg_tablespace_aclcheck (params .tablespaceOid ,
2521
+ GetUserId (), ACL_CREATE );
2522
+ if (aclresult != ACLCHECK_OK )
2523
+ aclcheck_error (aclresult , OBJECT_TABLESPACE ,
2524
+ get_tablespace_name (params .tablespaceOid ));
2525
+ }
2526
+ }
2527
+ else
2528
+ params .tablespaceOid = InvalidOid ;
2529
+
2503
2530
switch (stmt -> kind )
2504
2531
{
2505
2532
case REINDEX_OBJECT_INDEX :
@@ -2730,6 +2757,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
2730
2757
List * relids = NIL ;
2731
2758
int num_keys ;
2732
2759
bool concurrent_warning = false;
2760
+ bool tablespace_warning = false;
2733
2761
2734
2762
AssertArg (objectName );
2735
2763
Assert (objectKind == REINDEX_OBJECT_SCHEMA ||
@@ -2856,6 +2884,40 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
2856
2884
continue ;
2857
2885
}
2858
2886
2887
+ /*
2888
+ * If a new tablespace is set, check if this relation has to be
2889
+ * skipped.
2890
+ */
2891
+ if (OidIsValid (params -> tablespaceOid ))
2892
+ {
2893
+ bool skip_rel = false;
2894
+
2895
+ /*
2896
+ * Mapped relations cannot be moved to different tablespaces (in
2897
+ * particular this eliminates all shared catalogs.).
2898
+ */
2899
+ if (RELKIND_HAS_STORAGE (classtuple -> relkind ) &&
2900
+ !OidIsValid (classtuple -> relfilenode ))
2901
+ skip_rel = true;
2902
+
2903
+ /*
2904
+ * A system relation is always skipped, even with
2905
+ * allow_system_table_mods enabled.
2906
+ */
2907
+ if (IsSystemClass (relid , classtuple ))
2908
+ skip_rel = true;
2909
+
2910
+ if (skip_rel )
2911
+ {
2912
+ if (!tablespace_warning )
2913
+ ereport (WARNING ,
2914
+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
2915
+ errmsg ("cannot move system relations, skipping all" )));
2916
+ tablespace_warning = true;
2917
+ continue ;
2918
+ }
2919
+ }
2920
+
2859
2921
/* Save the list of relation OIDs in private context */
2860
2922
old = MemoryContextSwitchTo (private_context );
2861
2923
@@ -3032,6 +3094,24 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
3032
3094
continue ;
3033
3095
}
3034
3096
3097
+ /*
3098
+ * Check permissions except when moving to database's default if a new
3099
+ * tablespace is chosen. Note that this check also happens in
3100
+ * ExecReindex(), but we do an extra check here as this runs across
3101
+ * multiple transactions.
3102
+ */
3103
+ if (OidIsValid (params -> tablespaceOid ) &&
3104
+ params -> tablespaceOid != MyDatabaseTableSpace )
3105
+ {
3106
+ AclResult aclresult ;
3107
+
3108
+ aclresult = pg_tablespace_aclcheck (params -> tablespaceOid ,
3109
+ GetUserId (), ACL_CREATE );
3110
+ if (aclresult != ACLCHECK_OK )
3111
+ aclcheck_error (aclresult , OBJECT_TABLESPACE ,
3112
+ get_tablespace_name (params -> tablespaceOid ));
3113
+ }
3114
+
3035
3115
relkind = get_rel_relkind (relid );
3036
3116
relpersistence = get_rel_persistence (relid );
3037
3117
@@ -3210,6 +3290,13 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
3210
3290
heapRelation = table_open (relationOid ,
3211
3291
ShareUpdateExclusiveLock );
3212
3292
3293
+ if (OidIsValid (params -> tablespaceOid ) &&
3294
+ IsSystemRelation (heapRelation ))
3295
+ ereport (ERROR ,
3296
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
3297
+ errmsg ("cannot move system relation \"%s\"" ,
3298
+ RelationGetRelationName (heapRelation ))));
3299
+
3213
3300
/* Add all the valid indexes of relation to list */
3214
3301
foreach (lc , RelationGetIndexList (heapRelation ))
3215
3302
{
@@ -3346,6 +3433,14 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
3346
3433
else
3347
3434
heapRelation = table_open (heapId ,
3348
3435
ShareUpdateExclusiveLock );
3436
+
3437
+ if (OidIsValid (params -> tablespaceOid ) &&
3438
+ IsSystemRelation (heapRelation ))
3439
+ ereport (ERROR ,
3440
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
3441
+ errmsg ("cannot move system relation \"%s\"" ,
3442
+ get_rel_name (relationOid ))));
3443
+
3349
3444
table_close (heapRelation , NoLock );
3350
3445
3351
3446
/* Save the list of relation OIDs in private context */
@@ -3390,6 +3485,13 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
3390
3485
return false;
3391
3486
}
3392
3487
3488
+ /* It's not a shared catalog, so refuse to move it to shared tablespace */
3489
+ if (params -> tablespaceOid == GLOBALTABLESPACE_OID )
3490
+ ereport (ERROR ,
3491
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
3492
+ errmsg ("cannot move non-shared relation to tablespace \"%s\"" ,
3493
+ get_tablespace_name (params -> tablespaceOid ))));
3494
+
3393
3495
Assert (heapRelationIds != NIL );
3394
3496
3395
3497
/*-----
@@ -3427,6 +3529,7 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
3427
3529
Relation heapRel ;
3428
3530
Relation newIndexRel ;
3429
3531
LockRelId * lockrelid ;
3532
+ Oid tablespaceid ;
3430
3533
3431
3534
indexRel = index_open (idx -> indexId , ShareUpdateExclusiveLock );
3432
3535
heapRel = table_open (indexRel -> rd_index -> indrelid ,
@@ -3458,9 +3561,17 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
3458
3561
get_rel_namespace (indexRel -> rd_index -> indrelid ),
3459
3562
false);
3460
3563
3564
+ /* Choose the new tablespace, indexes of toast tables are not moved */
3565
+ if (OidIsValid (params -> tablespaceOid ) &&
3566
+ heapRel -> rd_rel -> relkind != RELKIND_TOASTVALUE )
3567
+ tablespaceid = params -> tablespaceOid ;
3568
+ else
3569
+ tablespaceid = indexRel -> rd_rel -> reltablespace ;
3570
+
3461
3571
/* Create new index definition based on given index */
3462
3572
newIndexId = index_concurrently_create_copy (heapRel ,
3463
3573
idx -> indexId ,
3574
+ tablespaceid ,
3464
3575
concurrentName );
3465
3576
3466
3577
/*
0 commit comments