aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_utilcmd.c
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2018-01-19 11:49:22 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2018-01-19 11:49:22 -0300
commit8b08f7d4820fd7a8ef6152a9dd8c6e3cb01e5f99 (patch)
tree0ecb879a9568e7e14275afe72a77e316e72376c6 /src/backend/parser/parse_utilcmd.c
parent1ef61ddce9086c30a18a6ecc48bc3ce0ef62cb39 (diff)
downloadpostgresql-8b08f7d4820fd7a8ef6152a9dd8c6e3cb01e5f99.tar.gz
postgresql-8b08f7d4820fd7a8ef6152a9dd8c6e3cb01e5f99.zip
Local partitioned indexes
When CREATE INDEX is run on a partitioned table, create catalog entries for an index on the partitioned table (which is just a placeholder since the table proper has no data of its own), and recurse to create actual indexes on the existing partitions; create them in future partitions also. As a convenience gadget, if the new index definition matches some existing index in partitions, these are picked up and used instead of creating new ones. Whichever way these indexes come about, they become attached to the index on the parent table and are dropped alongside it, and cannot be dropped on isolation unless they are detached first. To support pg_dump'ing these indexes, add commands CREATE INDEX ON ONLY <table> (which creates the index on the parent partitioned table, without recursing) and ALTER INDEX ATTACH PARTITION (which is used after the indexes have been created individually on each partition, to attach them to the parent index). These reconstruct prior database state exactly. Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit Langote, Jesper Pedersen, Simon Riggs, David Rowley Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql
Diffstat (limited to 'src/backend/parser/parse_utilcmd.c')
-rw-r--r--src/backend/parser/parse_utilcmd.c65
1 files changed, 45 insertions, 20 deletions
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 128f1679c6b..90bb356df85 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -118,9 +118,6 @@ static void transformTableLikeClause(CreateStmtContext *cxt,
TableLikeClause *table_like_clause);
static void transformOfType(CreateStmtContext *cxt,
TypeName *ofTypename);
-static IndexStmt *generateClonedIndexStmt(CreateStmtContext *cxt,
- Relation source_idx,
- const AttrNumber *attmap, int attmap_length);
static List *get_collation(Oid collation, Oid actual_datatype);
static List *get_opclass(Oid opclass, Oid actual_datatype);
static void transformIndexConstraints(CreateStmtContext *cxt);
@@ -1185,7 +1182,8 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
parent_index = index_open(parent_index_oid, AccessShareLock);
/* Build CREATE INDEX statement to recreate the parent_index */
- index_stmt = generateClonedIndexStmt(cxt, parent_index,
+ index_stmt = generateClonedIndexStmt(cxt->relation, InvalidOid,
+ parent_index,
attmap, tupleDesc->natts);
/* Copy comment on index, if requested */
@@ -1263,10 +1261,12 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
/*
* Generate an IndexStmt node using information from an already existing index
- * "source_idx". Attribute numbers should be adjusted according to attmap.
+ * "source_idx", for the rel identified either by heapRel or heapRelid.
+ *
+ * Attribute numbers should be adjusted according to attmap.
*/
-static IndexStmt *
-generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
+IndexStmt *
+generateClonedIndexStmt(RangeVar *heapRel, Oid heapRelid, Relation source_idx,
const AttrNumber *attmap, int attmap_length)
{
Oid source_relid = RelationGetRelid(source_idx);
@@ -1287,6 +1287,9 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
Datum datum;
bool isnull;
+ Assert((heapRel == NULL && OidIsValid(heapRelid)) ||
+ (heapRel != NULL && !OidIsValid(heapRelid)));
+
/*
* Fetch pg_class tuple of source index. We can't use the copy in the
* relcache entry because it doesn't include optional fields.
@@ -1322,7 +1325,8 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
/* Begin building the IndexStmt */
index = makeNode(IndexStmt);
- index->relation = cxt->relation;
+ index->relation = heapRel;
+ index->relationId = heapRelid;
index->accessMethod = pstrdup(NameStr(amrec->amname));
if (OidIsValid(idxrelrec->reltablespace))
index->tableSpace = get_tablespace_name(idxrelrec->reltablespace);
@@ -3289,18 +3293,39 @@ transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd)
{
Relation parentRel = cxt->rel;
- /* the table must be partitioned */
- if (parentRel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("\"%s\" is not partitioned",
- RelationGetRelationName(parentRel))));
-
- /* transform the partition bound, if any */
- Assert(RelationGetPartitionKey(parentRel) != NULL);
- if (cmd->bound != NULL)
- cxt->partbound = transformPartitionBound(cxt->pstate, parentRel,
- cmd->bound);
+ switch (parentRel->rd_rel->relkind)
+ {
+ case RELKIND_PARTITIONED_TABLE:
+ /* transform the partition bound, if any */
+ Assert(RelationGetPartitionKey(parentRel) != NULL);
+ if (cmd->bound != NULL)
+ cxt->partbound = transformPartitionBound(cxt->pstate, parentRel,
+ cmd->bound);
+ break;
+ case RELKIND_PARTITIONED_INDEX:
+ /* nothing to check */
+ Assert(cmd->bound == NULL);
+ break;
+ case RELKIND_RELATION:
+ /* the table must be partitioned */
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("table \"%s\" is not partitioned",
+ RelationGetRelationName(parentRel))));
+ break;
+ case RELKIND_INDEX:
+ /* the index must be partitioned */
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("index \"%s\" is not partitioned",
+ RelationGetRelationName(parentRel))));
+ break;
+ default:
+ /* parser shouldn't let this case through */
+ elog(ERROR, "\"%s\" is not a partitioned table or index",
+ RelationGetRelationName(parentRel));
+ break;
+ }
}
/*