1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-30 06:01:21 +03:00

Implement table partitioning.

Table partitioning is like table inheritance and reuses much of the
existing infrastructure, but there are some important differences.
The parent is called a partitioned table and is always empty; it may
not have indexes or non-inherited constraints, since those make no
sense for a relation with no data of its own.  The children are called
partitions and contain all of the actual data.  Each partition has an
implicit partitioning constraint.  Multiple inheritance is not
allowed, and partitioning and inheritance can't be mixed.  Partitions
can't have extra columns and may not allow nulls unless the parent
does.  Tuples inserted into the parent are automatically routed to the
correct partition, so tuple-routing ON INSERT triggers are not needed.
Tuple routing isn't yet supported for partitions which are foreign
tables, and it doesn't handle updates that cross partition boundaries.

Currently, tables can be range-partitioned or list-partitioned.  List
partitioning is limited to a single column, but range partitioning can
involve multiple columns.  A partitioning "column" can be an
expression.

Because table partitioning is less general than table inheritance, it
is hoped that it will be easier to reason about properties of
partitions, and therefore that this will serve as a better foundation
for a variety of possible optimizations, including query planner
optimizations.  The tuple routing based which this patch does based on
the implicit partitioning constraints is an example of this, but it
seems likely that many other useful optimizations are also possible.

Amit Langote, reviewed and tested by Robert Haas, Ashutosh Bapat,
Amit Kapila, Rajkumar Raghuwanshi, Corey Huinker, Jaime Casanova,
Rushabh Lathia, Erik Rijkers, among others.  Minor revisions by me.
This commit is contained in:
Robert Haas
2016-12-07 13:17:43 -05:00
parent b7e1ae2328
commit f0e44751d7
85 changed files with 8896 additions and 281 deletions

View File

@@ -3030,6 +3030,8 @@ CopyCreateStmtFields(const CreateStmt *from, CreateStmt *newnode)
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(tableElts);
COPY_NODE_FIELD(inhRelations);
COPY_NODE_FIELD(partspec);
COPY_NODE_FIELD(partbound);
COPY_NODE_FIELD(ofTypename);
COPY_NODE_FIELD(constraints);
COPY_NODE_FIELD(options);
@@ -4188,6 +4190,70 @@ _copyAlterPolicyStmt(const AlterPolicyStmt *from)
return newnode;
}
static PartitionSpec *
_copyPartitionSpec(const PartitionSpec *from)
{
PartitionSpec *newnode = makeNode(PartitionSpec);
COPY_STRING_FIELD(strategy);
COPY_NODE_FIELD(partParams);
COPY_LOCATION_FIELD(location);
return newnode;
}
static PartitionElem *
_copyPartitionElem(const PartitionElem *from)
{
PartitionElem *newnode = makeNode(PartitionElem);
COPY_STRING_FIELD(name);
COPY_NODE_FIELD(expr);
COPY_NODE_FIELD(collation);
COPY_NODE_FIELD(opclass);
COPY_LOCATION_FIELD(location);
return newnode;
}
static PartitionBoundSpec *
_copyPartitionBoundSpec(const PartitionBoundSpec *from)
{
PartitionBoundSpec *newnode = makeNode(PartitionBoundSpec);
COPY_SCALAR_FIELD(strategy);
COPY_NODE_FIELD(listdatums);
COPY_NODE_FIELD(lowerdatums);
COPY_NODE_FIELD(upperdatums);
COPY_LOCATION_FIELD(location);
return newnode;
}
static PartitionRangeDatum *
_copyPartitionRangeDatum(const PartitionRangeDatum *from)
{
PartitionRangeDatum *newnode = makeNode(PartitionRangeDatum);
COPY_SCALAR_FIELD(infinite);
COPY_NODE_FIELD(value);
COPY_LOCATION_FIELD(location);
return newnode;
}
static PartitionCmd *
_copyPartitionCmd(const PartitionCmd *from)
{
PartitionCmd *newnode = makeNode(PartitionCmd);
COPY_NODE_FIELD(name);
COPY_NODE_FIELD(bound);
return newnode;
}
/* ****************************************************************
* pg_list.h copy functions
* ****************************************************************
@@ -5105,6 +5171,21 @@ copyObject(const void *from)
case T_TriggerTransition:
retval = _copyTriggerTransition(from);
break;
case T_PartitionSpec:
retval = _copyPartitionSpec(from);
break;
case T_PartitionElem:
retval = _copyPartitionElem(from);
break;
case T_PartitionBoundSpec:
retval = _copyPartitionBoundSpec(from);
break;
case T_PartitionRangeDatum:
retval = _copyPartitionRangeDatum(from);
break;
case T_PartitionCmd:
retval = _copyPartitionCmd(from);
break;
/*
* MISCELLANEOUS NODES

View File

@@ -1168,6 +1168,8 @@ _equalCreateStmt(const CreateStmt *a, const CreateStmt *b)
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(tableElts);
COMPARE_NODE_FIELD(inhRelations);
COMPARE_NODE_FIELD(partspec);
COMPARE_NODE_FIELD(partbound);
COMPARE_NODE_FIELD(ofTypename);
COMPARE_NODE_FIELD(constraints);
COMPARE_NODE_FIELD(options);
@@ -2646,6 +2648,59 @@ _equalTriggerTransition(const TriggerTransition *a, const TriggerTransition *b)
return true;
}
static bool
_equalPartitionSpec(const PartitionSpec *a, const PartitionSpec *b)
{
COMPARE_STRING_FIELD(strategy);
COMPARE_NODE_FIELD(partParams);
COMPARE_LOCATION_FIELD(location);
return true;
}
static bool
_equalPartitionElem(const PartitionElem *a, const PartitionElem *b)
{
COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(expr);
COMPARE_NODE_FIELD(collation);
COMPARE_NODE_FIELD(opclass);
COMPARE_LOCATION_FIELD(location);
return true;
}
static bool
_equalPartitionBoundSpec(const PartitionBoundSpec *a, const PartitionBoundSpec *b)
{
COMPARE_SCALAR_FIELD(strategy);
COMPARE_NODE_FIELD(listdatums);
COMPARE_NODE_FIELD(lowerdatums);
COMPARE_NODE_FIELD(upperdatums);
COMPARE_LOCATION_FIELD(location);
return true;
}
static bool
_equalPartitionRangeDatum(const PartitionRangeDatum *a, const PartitionRangeDatum *b)
{
COMPARE_SCALAR_FIELD(infinite);
COMPARE_NODE_FIELD(value);
COMPARE_LOCATION_FIELD(location);
return true;
}
static bool
_equalPartitionCmd(const PartitionCmd *a, const PartitionCmd *b)
{
COMPARE_NODE_FIELD(name);
COMPARE_NODE_FIELD(bound);
return true;
}
/*
* Stuff from pg_list.h
*/
@@ -3402,6 +3457,21 @@ equal(const void *a, const void *b)
case T_TriggerTransition:
retval = _equalTriggerTransition(a, b);
break;
case T_PartitionSpec:
retval = _equalPartitionSpec(a, b);
break;
case T_PartitionElem:
retval = _equalPartitionElem(a, b);
break;
case T_PartitionBoundSpec:
retval = _equalPartitionBoundSpec(a, b);
break;
case T_PartitionRangeDatum:
retval = _equalPartitionRangeDatum(a, b);
break;
case T_PartitionCmd:
retval = _equalPartitionCmd(a, b);
break;
default:
elog(ERROR, "unrecognized node type: %d",

View File

@@ -1552,6 +1552,12 @@ exprLocation(const Node *expr)
/* just use nested expr's location */
loc = exprLocation((Node *) ((const InferenceElem *) expr)->expr);
break;
case T_PartitionBoundSpec:
loc = ((const PartitionBoundSpec *) expr)->location;
break;
case T_PartitionRangeDatum:
loc = ((const PartitionRangeDatum *) expr)->location;
break;
default:
/* for any other node type it's just unknown... */
loc = -1;

View File

@@ -2392,6 +2392,8 @@ _outCreateStmtInfo(StringInfo str, const CreateStmt *node)
WRITE_NODE_FIELD(relation);
WRITE_NODE_FIELD(tableElts);
WRITE_NODE_FIELD(inhRelations);
WRITE_NODE_FIELD(partspec);
WRITE_NODE_FIELD(partbound);
WRITE_NODE_FIELD(ofTypename);
WRITE_NODE_FIELD(constraints);
WRITE_NODE_FIELD(options);
@@ -3277,6 +3279,47 @@ _outForeignKeyCacheInfo(StringInfo str, const ForeignKeyCacheInfo *node)
appendStringInfo(str, " %u", node->conpfeqop[i]);
}
static void
_outPartitionSpec(StringInfo str, const PartitionSpec *node)
{
WRITE_NODE_TYPE("PARTITIONBY");
WRITE_STRING_FIELD(strategy);
WRITE_NODE_FIELD(partParams);
WRITE_LOCATION_FIELD(location);
}
static void
_outPartitionElem(StringInfo str, const PartitionElem *node)
{
WRITE_NODE_TYPE("PARTITIONELEM");
WRITE_STRING_FIELD(name);
WRITE_NODE_FIELD(expr);
WRITE_NODE_FIELD(collation);
WRITE_NODE_FIELD(opclass);
WRITE_LOCATION_FIELD(location);
}
static void
_outPartitionBoundSpec(StringInfo str, const PartitionBoundSpec *node)
{
WRITE_NODE_TYPE("PARTITIONBOUND");
WRITE_CHAR_FIELD(strategy);
WRITE_NODE_FIELD(listdatums);
WRITE_NODE_FIELD(lowerdatums);
WRITE_NODE_FIELD(upperdatums);
}
static void
_outPartitionRangeDatum(StringInfo str, const PartitionRangeDatum *node)
{
WRITE_NODE_TYPE("PARTRANGEDATUM");
WRITE_BOOL_FIELD(infinite);
WRITE_NODE_FIELD(value);
}
/*
* outNode -
@@ -3865,6 +3908,18 @@ outNode(StringInfo str, const void *obj)
case T_TriggerTransition:
_outTriggerTransition(str, obj);
break;
case T_PartitionSpec:
_outPartitionSpec(str, obj);
break;
case T_PartitionElem:
_outPartitionElem(str, obj);
break;
case T_PartitionBoundSpec:
_outPartitionBoundSpec(str, obj);
break;
case T_PartitionRangeDatum:
_outPartitionRangeDatum(str, obj);
break;
default:

View File

@@ -2265,6 +2265,36 @@ _readExtensibleNode(void)
READ_DONE();
}
/*
* _readPartitionBoundSpec
*/
static PartitionBoundSpec *
_readPartitionBoundSpec(void)
{
READ_LOCALS(PartitionBoundSpec);
READ_CHAR_FIELD(strategy);
READ_NODE_FIELD(listdatums);
READ_NODE_FIELD(lowerdatums);
READ_NODE_FIELD(upperdatums);
READ_DONE();
}
/*
* _readPartitionRangeDatum
*/
static PartitionRangeDatum *
_readPartitionRangeDatum(void)
{
READ_LOCALS(PartitionRangeDatum);
READ_BOOL_FIELD(infinite);
READ_NODE_FIELD(value);
READ_DONE();
}
/*
* parseNodeString
*
@@ -2497,6 +2527,10 @@ parseNodeString(void)
return_value = _readAlternativeSubPlan();
else if (MATCH("EXTENSIBLENODE", 14))
return_value = _readExtensibleNode();
else if (MATCH("PARTITIONBOUND", 14))
return_value = _readPartitionBoundSpec();
else if (MATCH("PARTRANGEDATUM", 14))
return_value = _readPartitionRangeDatum();
else
{
elog(ERROR, "badly formatted node string \"%.32s\"...", token);