Skip to content

Commit 1c4c0fc

Browse files
committed
transfer_tables.patch
1 parent f7389cd commit 1c4c0fc

File tree

31 files changed

+1358
-61
lines changed

31 files changed

+1358
-61
lines changed

contrib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ SUBDIRS = \
3535
pg_query_state \
3636
pg_standby \
3737
pg_stat_statements \
38+
pg_transfer \
3839
pg_trgm \
3940
pgcrypto \
4041
pgrowlocks \

src/backend/catalog/catalog.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
393393
backend = BackendIdForTempRelations();
394394
break;
395395
case RELPERSISTENCE_UNLOGGED:
396+
case RELPERSISTENCE_CONSTANT:
396397
case RELPERSISTENCE_PERMANENT:
397398
backend = InvalidBackendId;
398399
break;

src/backend/catalog/index.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3509,6 +3509,9 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
35093509
* REINDEX_REL_FORCE_INDEXES_PERMANENT: if true, set the persistence of the
35103510
* rebuilt indexes to permanent.
35113511
*
3512+
* REINDEX_REL_FORCE_INDEXES_CONSTANT: if true, set the persistence of the
3513+
* rebuilt indexes to constant.
3514+
*
35123515
* Returns true if any indexes were rebuilt (including toast table's index
35133516
* when relevant). Note that a CommandCounterIncrement will occur after each
35143517
* index rebuild.
@@ -3592,6 +3595,8 @@ reindex_relation(Oid relid, int flags, int options)
35923595
persistence = RELPERSISTENCE_UNLOGGED;
35933596
else if (flags & REINDEX_REL_FORCE_INDEXES_PERMANENT)
35943597
persistence = RELPERSISTENCE_PERMANENT;
3598+
else if (flags & REINDEX_REL_FORCE_INDEXES_CONSTANT)
3599+
persistence = RELPERSISTENCE_CONSTANT;
35953600
else
35963601
persistence = rel->rd_rel->relpersistence;
35973602

src/backend/catalog/storage.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ RelationCreateStorage(RelFileNode rnode, char relpersistence)
9393
needs_wal = false;
9494
break;
9595
case RELPERSISTENCE_PERMANENT:
96+
case RELPERSISTENCE_CONSTANT:
9697
backend = InvalidBackendId;
9798
needs_wal = true;
9899
break;

src/backend/commands/cluster.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,15 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
15431543
reindex_flags |= REINDEX_REL_FORCE_INDEXES_UNLOGGED;
15441544
else if (newrelpersistence == RELPERSISTENCE_PERMANENT)
15451545
reindex_flags |= REINDEX_REL_FORCE_INDEXES_PERMANENT;
1546+
else if (newrelpersistence == RELPERSISTENCE_CONSTANT)
1547+
{
1548+
/*
1549+
* Actually, there is no need in rebuilding CONSTANT indexes,
1550+
* but if someone forced CLUSTER or VACUUM FULL on CONSTANT
1551+
* relation, we must do it.
1552+
*/
1553+
reindex_flags |= REINDEX_REL_FORCE_INDEXES_CONSTANT;
1554+
}
15461555

15471556
reindex_relation(OIDOldHeap, reindex_flags, 0);
15481557

src/backend/commands/sequence.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
125125
ereport(ERROR,
126126
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
127127
errmsg("unlogged sequences are not supported")));
128+
/* CONSTANT sequences are not implemented -- not clear if useful. */
129+
if (seq->sequence->relpersistence == RELPERSISTENCE_CONSTANT)
130+
ereport(ERROR,
131+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
132+
errmsg("CONSTANT sequences are not supported")));
128133

129134
/*
130135
* If if_not_exists was given and a relation with the same name already

src/backend/commands/tablecmds.c

Lines changed: 126 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ typedef struct AlteredTableInfo
160160
bool new_notnull; /* T if we added new NOT NULL constraints */
161161
int rewrite; /* Reason for forced rewrite, if any */
162162
Oid newTableSpace; /* new tablespace; 0 means no change */
163-
bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */
163+
bool chgPersistence; /* T if SET LOGGED/UNLOGGED/CONSTANT is used */
164164
char newrelpersistence; /* if above is true */
165165
/* Objects to rebuild after completing ALTER TYPE operations */
166166
List *changedConstraintOids; /* OIDs of constraints to rebuild */
@@ -402,7 +402,8 @@ static void change_owner_recurse_to_sequences(Oid relationOid,
402402
static ObjectAddress ATExecClusterOn(Relation rel, const char *indexName,
403403
LOCKMODE lockmode);
404404
static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
405-
static bool ATPrepChangePersistence(Relation rel, bool toLogged);
405+
static void ATExecSetConstant(Relation rel, LOCKMODE lockmode);
406+
static bool ATPrepChangePersistence(Relation rel, char newrelpersistence);
406407
static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
407408
char *tablespacename, LOCKMODE lockmode);
408409
static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
@@ -3036,6 +3037,7 @@ AlterTableGetLockLevel(List *cmds)
30363037

30373038
case AT_SetLogged:
30383039
case AT_SetUnLogged:
3040+
case AT_SetConstant:
30393041
cmd_lockmode = AccessExclusiveLock;
30403042
break;
30413043

@@ -3258,7 +3260,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
32583260
break;
32593261
case AT_SetLogged: /* SET LOGGED */
32603262
ATSimplePermissions(rel, ATT_TABLE);
3261-
tab->chgPersistence = ATPrepChangePersistence(rel, true);
3263+
tab->chgPersistence = ATPrepChangePersistence(rel, RELPERSISTENCE_PERMANENT);
32623264
/* force rewrite if necessary; see comment in ATRewriteTables */
32633265
if (tab->chgPersistence)
32643266
{
@@ -3269,7 +3271,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
32693271
break;
32703272
case AT_SetUnLogged: /* SET UNLOGGED */
32713273
ATSimplePermissions(rel, ATT_TABLE);
3272-
tab->chgPersistence = ATPrepChangePersistence(rel, false);
3274+
tab->chgPersistence = ATPrepChangePersistence(rel, RELPERSISTENCE_UNLOGGED);
32733275
/* force rewrite if necessary; see comment in ATRewriteTables */
32743276
if (tab->chgPersistence)
32753277
{
@@ -3278,6 +3280,14 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
32783280
}
32793281
pass = AT_PASS_MISC;
32803282
break;
3283+
case AT_SetConstant: /* SET CONSTANT */
3284+
ATSimplePermissions(rel, ATT_TABLE);
3285+
tab->chgPersistence = ATPrepChangePersistence(rel, RELPERSISTENCE_CONSTANT);
3286+
/* We do not rewrite relation, just freeze it in ATExecSetConstant. */
3287+
if (tab->chgPersistence)
3288+
tab->newrelpersistence = RELPERSISTENCE_CONSTANT;
3289+
pass = AT_PASS_MISC;
3290+
break;
32813291
case AT_AddOids: /* SET WITH OIDS */
32823292
ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
32833293
if (!rel->rd_rel->relhasoids || recursing)
@@ -3579,6 +3589,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
35793589
case AT_SetLogged: /* SET LOGGED */
35803590
case AT_SetUnLogged: /* SET UNLOGGED */
35813591
break;
3592+
case AT_SetConstant: /* SET CONSTANT */
3593+
ATExecSetConstant(rel, lockmode);
3594+
break;
35823595
case AT_AddOids: /* SET WITH OIDS */
35833596
/* Use the ADD COLUMN code, unless prep decided to do nothing */
35843597
if (cmd->def != NULL)
@@ -6312,6 +6325,12 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
63126325
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
63136326
errmsg("constraints on temporary tables must involve temporary tables of this session")));
63146327
break;
6328+
case RELPERSISTENCE_CONSTANT:
6329+
ereport(ERROR,
6330+
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6331+
errmsg("constraints on CONSTANT tables are not supported")));
6332+
break;
6333+
63156334
}
63166335

63176336
/*
@@ -9350,6 +9369,74 @@ ATExecDropCluster(Relation rel, LOCKMODE lockmode)
93509369
mark_index_clustered(rel, InvalidOid, false);
93519370
}
93529371

9372+
9373+
static void
9374+
setRelpersistenceConstant(Relation rel)
9375+
{
9376+
Relation pg_class;
9377+
Oid relid;
9378+
HeapTuple tuple;
9379+
9380+
relid = RelationGetRelid(rel);
9381+
9382+
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
9383+
9384+
tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
9385+
9386+
if (!HeapTupleIsValid(tuple))
9387+
elog(ERROR, "cache lookup failed for relation %u", relid);
9388+
9389+
((Form_pg_class) GETSTRUCT(tuple))->relpersistence = RELPERSISTENCE_CONSTANT;
9390+
simple_heap_update(pg_class, &tuple->t_self, tuple);
9391+
9392+
/* keep catalog indexes current */
9393+
CatalogUpdateIndexes(pg_class, tuple);
9394+
/* Invalidate cached info about relation. */
9395+
CacheInvalidateRelcache(rel);
9396+
9397+
heap_close(pg_class, RowExclusiveLock);
9398+
heap_freetuple(tuple);
9399+
}
9400+
9401+
/*
9402+
* Change relation relpersistence to RELPERSISTENCE_CONSTANT.
9403+
*/
9404+
static void
9405+
ATExecSetConstant(Relation rel, LOCKMODE lockmode)
9406+
{
9407+
List *index_oid_list;
9408+
ListCell *i;
9409+
9410+
if (rel->rd_rel->relkind != RELKIND_RELATION
9411+
&& rel->rd_rel->relkind != RELKIND_TOASTVALUE)
9412+
elog(ERROR, "cannot apply SET CONSTANT to relation %s, because it's not a table.",
9413+
NameStr(rel->rd_rel->relname));
9414+
setRelpersistenceConstant(rel);
9415+
9416+
/* Find all the indexes belonging to this relation */
9417+
index_oid_list = RelationGetIndexList(rel);
9418+
9419+
/* For each index, change its relpersistence */
9420+
foreach(i, index_oid_list)
9421+
{
9422+
Relation indexRelation = index_open(lfirst_oid(i), lockmode);
9423+
setRelpersistenceConstant(indexRelation);
9424+
index_close(indexRelation, NoLock);
9425+
}
9426+
9427+
list_free(index_oid_list);
9428+
9429+
/* If it has a toast table, change its relpersistence.
9430+
* And also recursevily for toast_index
9431+
*/
9432+
if (rel->rd_rel->reltoastrelid != InvalidOid)
9433+
{
9434+
Relation toastRelation = heap_open(rel->rd_rel->reltoastrelid, lockmode);
9435+
ATExecSetConstant(toastRelation, lockmode);
9436+
heap_close(toastRelation, NoLock);
9437+
}
9438+
}
9439+
93539440
/*
93549441
* ALTER TABLE SET TABLESPACE
93559442
*/
@@ -11290,46 +11377,55 @@ ATExecGenericOptions(Relation rel, List *options)
1129011377
}
1129111378

1129211379
/*
11293-
* Preparation phase for SET LOGGED/UNLOGGED
11380+
* Preparation phase for SET LOGGED/UNLOGGED/CONSTANT
1129411381
*
1129511382
* This verifies that we're not trying to change a temp table. Also,
1129611383
* existing foreign key constraints are checked to avoid ending up with
1129711384
* permanent tables referencing unlogged tables.
11385+
* Foreign key constraints on CONSTANT tables are not allowed.
1129811386
*
1129911387
* Return value is false if the operation is a no-op (in which case the
1130011388
* checks are skipped), otherwise true.
1130111389
*/
1130211390
static bool
11303-
ATPrepChangePersistence(Relation rel, bool toLogged)
11391+
ATPrepChangePersistence(Relation rel, char newrelpersistence)
1130411392
{
1130511393
Relation pg_constraint;
1130611394
HeapTuple tuple;
1130711395
SysScanDesc scan;
1130811396
ScanKeyData skey[1];
11397+
bool toLogged = false;
11398+
11399+
/*
11400+
* When we track constraints, constant tables behaves just like
11401+
* permanent ones.
11402+
*/
11403+
if (newrelpersistence == RELPERSISTENCE_PERMANENT
11404+
|| newrelpersistence == RELPERSISTENCE_CONSTANT)
11405+
toLogged = true;
11406+
11407+
/* Nothing to do */
11408+
if (rel->rd_rel->relpersistence == newrelpersistence)
11409+
return false;
1130911410

1131011411
/*
11311-
* Disallow changing status for a temp table. Also verify whether we can
11312-
* get away with doing nothing; in such cases we don't need to run the
11313-
* checks below, either.
11412+
* Disallow changing status for a temp and constant tables.
1131411413
*/
1131511414
switch (rel->rd_rel->relpersistence)
1131611415
{
1131711416
case RELPERSISTENCE_TEMP:
1131811417
ereport(ERROR,
1131911418
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11320-
errmsg("cannot change logged status of table \"%s\" because it is temporary",
11419+
errmsg("cannot change persistence of table \"%s\" because it is temporary",
1132111420
RelationGetRelationName(rel)),
1132211421
errtable(rel)));
1132311422
break;
11324-
case RELPERSISTENCE_PERMANENT:
11325-
if (toLogged)
11326-
/* nothing to do */
11327-
return false;
11328-
break;
11329-
case RELPERSISTENCE_UNLOGGED:
11330-
if (!toLogged)
11331-
/* nothing to do */
11332-
return false;
11423+
case RELPERSISTENCE_CONSTANT:
11424+
ereport(ERROR,
11425+
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11426+
errmsg("cannot change persistence of table \"%s\" because it is constant",
11427+
RelationGetRelationName(rel)),
11428+
errtable(rel)));
1133311429
break;
1133411430
}
1133511431

@@ -11363,15 +11459,23 @@ ATPrepChangePersistence(Relation rel, bool toLogged)
1136311459
Relation foreignrel;
1136411460

1136511461
/* the opposite end of what we used as scankey */
11366-
foreignrelid = toLogged ? con->confrelid : con->conrelid;
11462+
foreignrelid = toLogged? con->confrelid : con->conrelid;
1136711463

1136811464
/* ignore if self-referencing */
1136911465
if (RelationGetRelid(rel) == foreignrelid)
1137011466
continue;
1137111467

1137211468
foreignrel = relation_open(foreignrelid, AccessShareLock);
1137311469

11374-
if (toLogged)
11470+
if (newrelpersistence == RELPERSISTENCE_CONSTANT)
11471+
ereport(ERROR,
11472+
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11473+
errmsg("could not change table \"%s\" to constant because it references table \"%s\"",
11474+
RelationGetRelationName(rel),
11475+
RelationGetRelationName(foreignrel)),
11476+
errtableconstraint(rel, NameStr(con->conname))));
11477+
11478+
if (newrelpersistence == RELPERSISTENCE_PERMANENT)
1137511479
{
1137611480
if (foreignrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
1137711481
ereport(ERROR,
@@ -11381,7 +11485,7 @@ ATPrepChangePersistence(Relation rel, bool toLogged)
1138111485
RelationGetRelationName(foreignrel)),
1138211486
errtableconstraint(rel, NameStr(con->conname))));
1138311487
}
11384-
else
11488+
if (newrelpersistence == RELPERSISTENCE_UNLOGGED)
1138511489
{
1138611490
if (foreignrel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT)
1138711491
ereport(ERROR,

src/backend/commands/view.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,11 @@ DefineView(ViewStmt *stmt, const char *queryString)
505505
ereport(ERROR,
506506
(errcode(ERRCODE_SYNTAX_ERROR),
507507
errmsg("views cannot be unlogged because they do not have storage")));
508+
/* CONSTANT views are not sensible. */
509+
if (stmt->view->relpersistence == RELPERSISTENCE_CONSTANT)
510+
ereport(ERROR,
511+
(errcode(ERRCODE_SYNTAX_ERROR),
512+
errmsg("views cannot be CONSTANT because they do not have storage")));
508513

509514
/*
510515
* If the user didn't explicitly ask for a temporary view, check whether

src/backend/optimizer/util/pathnode.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2977,6 +2977,16 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
29772977
Assert(returningLists == NIL ||
29782978
list_length(resultRelations) == list_length(returningLists));
29792979

2980+
foreach(lc, resultRelations)
2981+
{
2982+
Index rti = lfirst_int(lc);
2983+
RangeTblEntry *rte = planner_rt_fetch(rti, root);
2984+
2985+
/* RELPERSISTENCE_CONSTANT */
2986+
if (rte->relpersistence == 'c')
2987+
elog(ERROR, "This operation is not allowed on CONSTANT relations");
2988+
}
2989+
29802990
pathnode->path.pathtype = T_ModifyTable;
29812991
pathnode->path.parent = rel;
29822992
/* pathtarget is not interesting, just make it minimally valid */

src/backend/optimizer/util/plancat.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
107107
relation = heap_open(relationObjectId, NoLock);
108108

109109
/* Temporary and unlogged relations are inaccessible during recovery. */
110-
if (!RelationNeedsWAL(relation) && RecoveryInProgress())
110+
if (!RelationNeedsWAL(relation) && RecoveryInProgress())
111111
ereport(ERROR,
112112
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
113113
errmsg("cannot access temporary or unlogged relations during recovery")));

src/backend/parser/analyze.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2470,7 +2470,11 @@ transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
24702470
ereport(ERROR,
24712471
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
24722472
errmsg("materialized views cannot be UNLOGGED")));
2473-
2473+
/* Constant materialized views are not implemented. */
2474+
if (stmt->into->rel->relpersistence == RELPERSISTENCE_CONSTANT)
2475+
ereport(ERROR,
2476+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2477+
errmsg("materialized views cannot be CONSTANT")));
24742478
/*
24752479
* At runtime, we'll need a copy of the parsed-but-not-rewritten Query
24762480
* for purposes of creating the view's ON SELECT rule. We stash that

0 commit comments

Comments
 (0)