Commit 76a3df6e authored by Tom Lane's avatar Tom Lane

Code review focused on new node types added by partitioning support.

Fix failure to check that we got a plain Const from const-simplification of
a coercion request.  This is the cause of bug #14666 from Tian Bing: there
is an int4 to money cast, but it's only stable not immutable (because of
dependence on lc_monetary), resulting in a FuncExpr that the code was
miserably unequipped to deal with, or indeed even to notice that it was
failing to deal with.  Add test cases around this coercion behavior.

In view of the above, sprinkle the code liberally with castNode() macros,
in hope of catching the next such bug a bit sooner.  Also, change some
functions that were randomly declared to take Node* to take more specific
pointer types.  And change some struct fields that were declared Node*
but could be given more specific types, allowing removal of assorted
explicit casts.

Place PARTITION_MAX_KEYS check a bit closer to the code it's protecting.
Likewise check only-one-key-for-list-partitioning restriction in a less
random place.

Avoid not-per-project-style usages like !strcmp(...).

Fix assorted failures to avoid scribbling on the input of parse
transformation.  I'm not sure how necessary this is, but it's entirely
silly for these functions to be expending cycles to avoid that and not
getting it right.

Add guards against partitioning on system columns.

Put backend/nodes/ support code into an order that matches handling
of these node types elsewhere.

Annotate the fact that somebody added location fields to PartitionBoundSpec
and PartitionRangeDatum but forgot to handle them in
outfuncs.c/readfuncs.c.  This is fairly harmless for production purposes
(since readfuncs.c would just substitute -1 anyway) but it's still bogus.
It's not worth forcing a post-beta1 initdb just to fix this, but if we
have another reason to force initdb before 10.0, we should go back and
clean this up.

Contrariwise, somebody added location fields to PartitionElem and
PartitionSpec but forgot to teach exprLocation() about them.

Consolidate duplicative code in transformPartitionBound().

Improve a couple of error messages.

Improve assorted commentary.

Re-pgindent the files touched by this patch; this affects a few comment
blocks that must have been added quite recently.

Report: https://postgr.es/m/20170524024550.29935.14396@wrigleys.postgresql.org
parent 54bb322e
...@@ -3219,7 +3219,7 @@ RemovePartitionKeyByRelId(Oid relid) ...@@ -3219,7 +3219,7 @@ RemovePartitionKeyByRelId(Oid relid)
* the new partition's info into its partition descriptor. * the new partition's info into its partition descriptor.
*/ */
void void
StorePartitionBound(Relation rel, Relation parent, Node *bound) StorePartitionBound(Relation rel, Relation parent, PartitionBoundSpec *bound)
{ {
Relation classRel; Relation classRel;
HeapTuple tuple, HeapTuple tuple,
......
...@@ -247,15 +247,16 @@ RelationBuildPartitionDesc(Relation rel) ...@@ -247,15 +247,16 @@ RelationBuildPartitionDesc(Relation rel)
null_index = -1; null_index = -1;
foreach(cell, boundspecs) foreach(cell, boundspecs)
{ {
PartitionBoundSpec *spec = castNode(PartitionBoundSpec,
lfirst(cell));
ListCell *c; ListCell *c;
PartitionBoundSpec *spec = lfirst(cell);
if (spec->strategy != PARTITION_STRATEGY_LIST) if (spec->strategy != PARTITION_STRATEGY_LIST)
elog(ERROR, "invalid strategy in partition bound spec"); elog(ERROR, "invalid strategy in partition bound spec");
foreach(c, spec->listdatums) foreach(c, spec->listdatums)
{ {
Const *val = lfirst(c); Const *val = castNode(Const, lfirst(c));
PartitionListValue *list_value = NULL; PartitionListValue *list_value = NULL;
if (!val->constisnull) if (!val->constisnull)
...@@ -327,7 +328,8 @@ RelationBuildPartitionDesc(Relation rel) ...@@ -327,7 +328,8 @@ RelationBuildPartitionDesc(Relation rel)
i = j = 0; i = j = 0;
foreach(cell, boundspecs) foreach(cell, boundspecs)
{ {
PartitionBoundSpec *spec = lfirst(cell); PartitionBoundSpec *spec = castNode(PartitionBoundSpec,
lfirst(cell));
PartitionRangeBound *lower, PartitionRangeBound *lower,
*upper; *upper;
...@@ -665,9 +667,9 @@ partition_bounds_equal(PartitionKey key, ...@@ -665,9 +667,9 @@ partition_bounds_equal(PartitionKey key,
* of parent. Also performs additional checks as necessary per strategy. * of parent. Also performs additional checks as necessary per strategy.
*/ */
void void
check_new_partition_bound(char *relname, Relation parent, Node *bound) check_new_partition_bound(char *relname, Relation parent,
PartitionBoundSpec *spec)
{ {
PartitionBoundSpec *spec = (PartitionBoundSpec *) bound;
PartitionKey key = RelationGetPartitionKey(parent); PartitionKey key = RelationGetPartitionKey(parent);
PartitionDesc partdesc = RelationGetPartitionDesc(parent); PartitionDesc partdesc = RelationGetPartitionDesc(parent);
ParseState *pstate = make_parsestate(NULL); ParseState *pstate = make_parsestate(NULL);
...@@ -692,7 +694,7 @@ check_new_partition_bound(char *relname, Relation parent, Node *bound) ...@@ -692,7 +694,7 @@ check_new_partition_bound(char *relname, Relation parent, Node *bound)
foreach(cell, spec->listdatums) foreach(cell, spec->listdatums)
{ {
Const *val = lfirst(cell); Const *val = castNode(Const, lfirst(cell));
if (!val->constisnull) if (!val->constisnull)
{ {
...@@ -889,9 +891,9 @@ get_partition_parent(Oid relid) ...@@ -889,9 +891,9 @@ get_partition_parent(Oid relid)
* expressions as partition constraint * expressions as partition constraint
*/ */
List * List *
get_qual_from_partbound(Relation rel, Relation parent, Node *bound) get_qual_from_partbound(Relation rel, Relation parent,
PartitionBoundSpec *spec)
{ {
PartitionBoundSpec *spec = (PartitionBoundSpec *) bound;
PartitionKey key = RelationGetPartitionKey(parent); PartitionKey key = RelationGetPartitionKey(parent);
List *my_qual = NIL; List *my_qual = NIL;
...@@ -1328,7 +1330,7 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec) ...@@ -1328,7 +1330,7 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
prev = NULL; prev = NULL;
for (cell = list_head(spec->listdatums); cell; cell = next) for (cell = list_head(spec->listdatums); cell; cell = next)
{ {
Const *val = (Const *) lfirst(cell); Const *val = castNode(Const, lfirst(cell));
next = lnext(cell); next = lnext(cell);
...@@ -1427,12 +1429,12 @@ get_range_key_properties(PartitionKey key, int keynum, ...@@ -1427,12 +1429,12 @@ get_range_key_properties(PartitionKey key, int keynum,
} }
if (!ldatum->infinite) if (!ldatum->infinite)
*lower_val = (Const *) ldatum->value; *lower_val = castNode(Const, ldatum->value);
else else
*lower_val = NULL; *lower_val = NULL;
if (!udatum->infinite) if (!udatum->infinite)
*upper_val = (Const *) udatum->value; *upper_val = castNode(Const, udatum->value);
else else
*upper_val = NULL; *upper_val = NULL;
} }
...@@ -1448,7 +1450,7 @@ get_range_key_properties(PartitionKey key, int keynum, ...@@ -1448,7 +1450,7 @@ get_range_key_properties(PartitionKey key, int keynum,
* as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we * as the lower bound tuple and (au, bu, cu) as the upper bound tuple, we
* generate an expression tree of the following form: * generate an expression tree of the following form:
* *
* (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL) * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
* AND * AND
* (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl)) * (a > al OR (a = al AND b > bl) OR (a = al AND b = bl AND c >= cl))
* AND * AND
...@@ -1458,7 +1460,7 @@ get_range_key_properties(PartitionKey key, int keynum, ...@@ -1458,7 +1460,7 @@ get_range_key_properties(PartitionKey key, int keynum,
* the same values, for example, (al = au), in which case, we will emit an * the same values, for example, (al = au), in which case, we will emit an
* expression tree of the following form: * expression tree of the following form:
* *
* (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL) * (a IS NOT NULL) and (b IS NOT NULL) and (c IS NOT NULL)
* AND * AND
* (a = al) * (a = al)
* AND * AND
...@@ -1512,8 +1514,8 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec) ...@@ -1512,8 +1514,8 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
num_or_arms = key->partnatts; num_or_arms = key->partnatts;
/* /*
* A range-partitioned table does not currently allow partition keys to * A range-partitioned table does not currently allow partition keys to be
* be null, so emit an IS NOT NULL expression for each key column. * null, so emit an IS NOT NULL expression for each key column.
*/ */
partexprs_item = list_head(key->partexprs); partexprs_item = list_head(key->partexprs);
for (i = 0; i < key->partnatts; i++) for (i = 0; i < key->partnatts; i++)
...@@ -1565,8 +1567,8 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec) ...@@ -1565,8 +1567,8 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
Datum test_result; Datum test_result;
bool isNull; bool isNull;
ldatum = lfirst(cell1); ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
udatum = lfirst(cell2); udatum = castNode(PartitionRangeDatum, lfirst(cell2));
/* /*
* Since get_range_key_properties() modifies partexprs_item, and we * Since get_range_key_properties() modifies partexprs_item, and we
...@@ -1644,12 +1646,14 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec) ...@@ -1644,12 +1646,14 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
PartitionRangeDatum *ldatum_next = NULL, PartitionRangeDatum *ldatum_next = NULL,
*udatum_next = NULL; *udatum_next = NULL;
ldatum = lfirst(cell1); ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
if (lnext(cell1)) if (lnext(cell1))
ldatum_next = lfirst(lnext(cell1)); ldatum_next = castNode(PartitionRangeDatum,
udatum = lfirst(cell2); lfirst(lnext(cell1)));
udatum = castNode(PartitionRangeDatum, lfirst(cell2));
if (lnext(cell2)) if (lnext(cell2))
udatum_next = lfirst(lnext(cell2)); udatum_next = castNode(PartitionRangeDatum,
lfirst(lnext(cell2)));
get_range_key_properties(key, j, ldatum, udatum, get_range_key_properties(key, j, ldatum, udatum,
&partexprs_item, &partexprs_item,
&keyCol, &keyCol,
...@@ -1779,7 +1783,7 @@ generate_partition_qual(Relation rel) ...@@ -1779,7 +1783,7 @@ generate_partition_qual(Relation rel)
MemoryContext oldcxt; MemoryContext oldcxt;
Datum boundDatum; Datum boundDatum;
bool isnull; bool isnull;
Node *bound; PartitionBoundSpec *bound;
List *my_qual = NIL, List *my_qual = NIL,
*result = NIL; *result = NIL;
Relation parent; Relation parent;
...@@ -1807,7 +1811,8 @@ generate_partition_qual(Relation rel) ...@@ -1807,7 +1811,8 @@ generate_partition_qual(Relation rel)
if (isnull) /* should not happen */ if (isnull) /* should not happen */
elog(ERROR, "relation \"%s\" has relpartbound = null", elog(ERROR, "relation \"%s\" has relpartbound = null",
RelationGetRelationName(rel)); RelationGetRelationName(rel));
bound = stringToNode(TextDatumGetCString(boundDatum)); bound = castNode(PartitionBoundSpec,
stringToNode(TextDatumGetCString(boundDatum)));
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
my_qual = get_qual_from_partbound(rel, parent, bound); my_qual = get_qual_from_partbound(rel, parent, bound);
...@@ -1971,9 +1976,8 @@ get_partition_for_tuple(PartitionDispatch *pd, ...@@ -1971,9 +1976,8 @@ get_partition_for_tuple(PartitionDispatch *pd,
if (key->strategy == PARTITION_STRATEGY_RANGE) if (key->strategy == PARTITION_STRATEGY_RANGE)
{ {
/* /*
* Since we cannot route tuples with NULL partition keys through * Since we cannot route tuples with NULL partition keys through a
* a range-partitioned table, simply return that no partition * range-partitioned table, simply return that no partition exists
* exists
*/ */
for (i = 0; i < key->partnatts; i++) for (i = 0; i < key->partnatts; i++)
{ {
...@@ -2080,7 +2084,7 @@ static PartitionRangeBound * ...@@ -2080,7 +2084,7 @@ static PartitionRangeBound *
make_one_range_bound(PartitionKey key, int index, List *datums, bool lower) make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
{ {
PartitionRangeBound *bound; PartitionRangeBound *bound;
ListCell *cell; ListCell *lc;
int i; int i;
bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound)); bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
...@@ -2091,9 +2095,9 @@ make_one_range_bound(PartitionKey key, int index, List *datums, bool lower) ...@@ -2091,9 +2095,9 @@ make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
bound->lower = lower; bound->lower = lower;
i = 0; i = 0;
foreach(cell, datums) foreach(lc, datums)
{ {
PartitionRangeDatum *datum = lfirst(cell); PartitionRangeDatum *datum = castNode(PartitionRangeDatum, lfirst(lc));
/* What's contained in this range datum? */ /* What's contained in this range datum? */
bound->content[i] = !datum->infinite bound->content[i] = !datum->infinite
...@@ -2103,7 +2107,7 @@ make_one_range_bound(PartitionKey key, int index, List *datums, bool lower) ...@@ -2103,7 +2107,7 @@ make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
if (bound->content[i] == RANGE_DATUM_FINITE) if (bound->content[i] == RANGE_DATUM_FINITE)
{ {
Const *val = (Const *) datum->value; Const *val = castNode(Const, datum->value);
if (val->constisnull) if (val->constisnull)
elog(ERROR, "invalid range bound datum"); elog(ERROR, "invalid range bound datum");
......
...@@ -756,7 +756,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ...@@ -756,7 +756,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
/* Process and store partition bound, if any. */ /* Process and store partition bound, if any. */
if (stmt->partbound) if (stmt->partbound)
{ {
Node *bound; PartitionBoundSpec *bound;
ParseState *pstate; ParseState *pstate;
Oid parentId = linitial_oid(inheritOids); Oid parentId = linitial_oid(inheritOids);
Relation parent; Relation parent;
...@@ -777,6 +777,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ...@@ -777,6 +777,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
/* Tranform the bound values */ /* Tranform the bound values */
pstate = make_parsestate(NULL); pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString; pstate->p_sourcetext = queryString;
bound = transformPartitionBound(pstate, parent, stmt->partbound); bound = transformPartitionBound(pstate, parent, stmt->partbound);
/* /*
...@@ -812,6 +813,15 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ...@@ -812,6 +813,15 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
Oid partcollation[PARTITION_MAX_KEYS]; Oid partcollation[PARTITION_MAX_KEYS];
List *partexprs = NIL; List *partexprs = NIL;
partnatts = list_length(stmt->partspec->partParams);
/* Protect fixed-size arrays here and in executor */
if (partnatts > PARTITION_MAX_KEYS)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_COLUMNS),
errmsg("cannot partition using more than %d columns",
PARTITION_MAX_KEYS)));
/* /*
* We need to transform the raw parsetrees corresponding to partition * We need to transform the raw parsetrees corresponding to partition
* expressions into executable expression trees. Like column defaults * expressions into executable expression trees. Like column defaults
...@@ -820,11 +830,11 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ...@@ -820,11 +830,11 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
*/ */
stmt->partspec = transformPartitionSpec(rel, stmt->partspec, stmt->partspec = transformPartitionSpec(rel, stmt->partspec,
&strategy); &strategy);
ComputePartitionAttrs(rel, stmt->partspec->partParams, ComputePartitionAttrs(rel, stmt->partspec->partParams,
partattrs, &partexprs, partopclass, partattrs, &partexprs, partopclass,
partcollation); partcollation);
partnatts = list_length(stmt->partspec->partParams);
StorePartitionKey(rel, strategy, partnatts, partattrs, partexprs, StorePartitionKey(rel, strategy, partnatts, partattrs, partexprs,
partopclass, partcollation); partopclass, partcollation);
} }
...@@ -13109,6 +13119,8 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid, ...@@ -13109,6 +13119,8 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
/* /*
* Transform any expressions present in the partition key * Transform any expressions present in the partition key
*
* Returns a transformed PartitionSpec, as well as the strategy code
*/ */
static PartitionSpec * static PartitionSpec *
transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy) transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
...@@ -13121,13 +13133,13 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy) ...@@ -13121,13 +13133,13 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
newspec = makeNode(PartitionSpec); newspec = makeNode(PartitionSpec);
newspec->strategy = partspec->strategy; newspec->strategy = partspec->strategy;
newspec->location = partspec->location;
newspec->partParams = NIL; newspec->partParams = NIL;
newspec->location = partspec->location;
/* Parse partitioning strategy name */ /* Parse partitioning strategy name */
if (!pg_strcasecmp(partspec->strategy, "list")) if (pg_strcasecmp(partspec->strategy, "list") == 0)
*strategy = PARTITION_STRATEGY_LIST; *strategy = PARTITION_STRATEGY_LIST;
else if (!pg_strcasecmp(partspec->strategy, "range")) else if (pg_strcasecmp(partspec->strategy, "range") == 0)
*strategy = PARTITION_STRATEGY_RANGE; *strategy = PARTITION_STRATEGY_RANGE;
else else
ereport(ERROR, ereport(ERROR,
...@@ -13135,6 +13147,13 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy) ...@@ -13135,6 +13147,13 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
errmsg("unrecognized partitioning strategy \"%s\"", errmsg("unrecognized partitioning strategy \"%s\"",
partspec->strategy))); partspec->strategy)));
/* Check valid number of columns for strategy */
if (*strategy == PARTITION_STRATEGY_LIST &&
list_length(partspec->partParams) != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cannot use \"list\" partition strategy with more than one column")));
/* /*
* Create a dummy ParseState and insert the target relation as its sole * Create a dummy ParseState and insert the target relation as its sole
* rangetable entry. We need a ParseState for transformExpr. * rangetable entry. We need a ParseState for transformExpr.
...@@ -13146,16 +13165,16 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy) ...@@ -13146,16 +13165,16 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
/* take care of any partition expressions */ /* take care of any partition expressions */
foreach(l, partspec->partParams) foreach(l, partspec->partParams)
{ {
PartitionElem *pelem = castNode(PartitionElem, lfirst(l));
ListCell *lc; ListCell *lc;
PartitionElem *pelem = (PartitionElem *) lfirst(l);
/* Check for PARTITION BY ... (foo, foo) */ /* Check for PARTITION BY ... (foo, foo) */
foreach(lc, newspec->partParams) foreach(lc, newspec->partParams)
{ {
PartitionElem *pparam = (PartitionElem *) lfirst(lc); PartitionElem *pparam = castNode(PartitionElem, lfirst(lc));
if (pelem->name && pparam->name && if (pelem->name && pparam->name &&
!strcmp(pelem->name, pparam->name)) strcmp(pelem->name, pparam->name) == 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_COLUMN), (errcode(ERRCODE_DUPLICATE_COLUMN),
errmsg("column \"%s\" appears more than once in partition key", errmsg("column \"%s\" appears more than once in partition key",
...@@ -13165,6 +13184,9 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy) ...@@ -13165,6 +13184,9 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
if (pelem->expr) if (pelem->expr)
{ {
/* Copy, to avoid scribbling on the input */
pelem = copyObject(pelem);
/* Now do parse transformation of the expression */ /* Now do parse transformation of the expression */
pelem->expr = transformExpr(pstate, pelem->expr, pelem->expr = transformExpr(pstate, pelem->expr,
EXPR_KIND_PARTITION_EXPRESSION); EXPR_KIND_PARTITION_EXPRESSION);
...@@ -13180,7 +13202,8 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy) ...@@ -13180,7 +13202,8 @@ transformPartitionSpec(Relation rel, PartitionSpec *partspec, char *strategy)
} }
/* /*
* Compute per-partition-column information from a list of PartitionElem's * Compute per-partition-column information from a list of PartitionElems.
* Expressions in the PartitionElems must be parse-analyzed already.
*/ */
static void static void
ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
...@@ -13192,7 +13215,7 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, ...@@ -13192,7 +13215,7 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
attn = 0; attn = 0;
foreach(lc, partParams) foreach(lc, partParams)
{ {
PartitionElem *pelem = (PartitionElem *) lfirst(lc); PartitionElem *pelem = castNode(PartitionElem, lfirst(lc));
Oid atttype; Oid atttype;
Oid attcollation; Oid attcollation;
...@@ -13202,7 +13225,8 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, ...@@ -13202,7 +13225,8 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
HeapTuple atttuple; HeapTuple atttuple;
Form_pg_attribute attform; Form_pg_attribute attform;
atttuple = SearchSysCacheAttName(RelationGetRelid(rel), pelem->name); atttuple = SearchSysCacheAttName(RelationGetRelid(rel),
pelem->name);
if (!HeapTupleIsValid(atttuple)) if (!HeapTupleIsValid(atttuple))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_UNDEFINED_COLUMN),
...@@ -13212,7 +13236,7 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, ...@@ -13212,7 +13236,7 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
if (attform->attnum <= 0) if (attform->attnum <= 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cannot use system column \"%s\" in partition key", errmsg("cannot use system column \"%s\" in partition key",
pelem->name))); pelem->name)));
...@@ -13220,8 +13244,6 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, ...@@ -13220,8 +13244,6 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
atttype = attform->atttypid; atttype = attform->atttypid;
attcollation = attform->attcollation; attcollation = attform->attcollation;
ReleaseSysCache(atttuple); ReleaseSysCache(atttuple);
/* Note that whole-row references can't happen here; see below */
} }
else else
{ {
...@@ -13240,7 +13262,7 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, ...@@ -13240,7 +13262,7 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
expr = (Node *) ((CollateExpr *) expr)->arg; expr = (Node *) ((CollateExpr *) expr)->arg;
if (IsA(expr, Var) && if (IsA(expr, Var) &&
((Var *) expr)->varattno != InvalidAttrNumber) ((Var *) expr)->varattno > 0)
{ {
/* /*
* User wrote "(column)" or "(column COLLATE something)". * User wrote "(column)" or "(column COLLATE something)".
...@@ -13251,11 +13273,18 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, ...@@ -13251,11 +13273,18 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
else else
{ {
Bitmapset *expr_attrs = NULL; Bitmapset *expr_attrs = NULL;
int i;
partattrs[attn] = 0; /* marks the column as expression */ partattrs[attn] = 0; /* marks the column as expression */
*partexprs = lappend(*partexprs, expr); *partexprs = lappend(*partexprs, expr);
/* /*
* Try to simplify the expression before checking for
* mutability. The main practical value of doing it in this
* order is that an inline-able SQL-language function will be
* accepted if its expansion is immutable, whether or not the
* function itself is marked immutable.
*
* Note that expression_planner does not change the passed in * Note that expression_planner does not change the passed in
* expression destructively and we have already saved the * expression destructively and we have already saved the
* expression to be stored into the catalog above. * expression to be stored into the catalog above.
...@@ -13273,28 +13302,39 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs, ...@@ -13273,28 +13302,39 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("functions in partition key expression must be marked IMMUTABLE"))); errmsg("functions in partition key expression must be marked IMMUTABLE")));
/*
* While it is not exactly *wrong* for an expression to be a
* constant value, it seems better to prevent such input.
*/
if (IsA(expr, Const))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cannot use constant expression as partition key")));
/* /*
* transformPartitionSpec() should have already rejected * transformPartitionSpec() should have already rejected
* subqueries, aggregates, window functions, and SRFs, based * subqueries, aggregates, window functions, and SRFs, based
* on the EXPR_KIND_ for partition expressions. * on the EXPR_KIND_ for partition expressions.
*/ */
/* Cannot have expressions containing whole-row references */ /*
* Cannot have expressions containing whole-row references or
* system column references.
*/
pull_varattnos(expr, 1, &expr_attrs); pull_varattnos(expr, 1, &expr_attrs);
if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber, if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber,
expr_attrs)) expr_attrs))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("partition key expressions cannot contain whole-row references"))); errmsg("partition key expressions cannot contain whole-row references")));
for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
{
if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
expr_attrs))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("partition key expressions cannot contain system column references")));
}
/*
* While it is not exactly *wrong* for a partition expression
* to be a constant, it seems better to reject such keys.
*/
if (IsA(expr, Const))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cannot use constant expression as partition key")));
} }
} }
......
...@@ -4412,18 +4412,6 @@ _copyAlterPolicyStmt(const AlterPolicyStmt *from) ...@@ -4412,18 +4412,6 @@ _copyAlterPolicyStmt(const AlterPolicyStmt *from)
return newnode; 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 * static PartitionElem *
_copyPartitionElem(const PartitionElem *from) _copyPartitionElem(const PartitionElem *from)
{ {
...@@ -4438,6 +4426,18 @@ _copyPartitionElem(const PartitionElem *from) ...@@ -4438,6 +4426,18 @@ _copyPartitionElem(const PartitionElem *from)
return newnode; 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 PartitionBoundSpec * static PartitionBoundSpec *
_copyPartitionBoundSpec(const PartitionBoundSpec *from) _copyPartitionBoundSpec(const PartitionBoundSpec *from)
{ {
...@@ -5509,12 +5509,12 @@ copyObjectImpl(const void *from) ...@@ -5509,12 +5509,12 @@ copyObjectImpl(const void *from)
case T_TriggerTransition: case T_TriggerTransition:
retval = _copyTriggerTransition(from); retval = _copyTriggerTransition(from);
break; break;
case T_PartitionSpec:
retval = _copyPartitionSpec(from);
break;
case T_PartitionElem: case T_PartitionElem:
retval = _copyPartitionElem(from); retval = _copyPartitionElem(from);
break; break;
case T_PartitionSpec:
retval = _copyPartitionSpec(from);
break;
case T_PartitionBoundSpec: case T_PartitionBoundSpec:
retval = _copyPartitionBoundSpec(from); retval = _copyPartitionBoundSpec(from);
break; break;
......
...@@ -2813,22 +2813,22 @@ _equalTriggerTransition(const TriggerTransition *a, const TriggerTransition *b) ...@@ -2813,22 +2813,22 @@ _equalTriggerTransition(const TriggerTransition *a, const TriggerTransition *b)
} }
static bool static bool
_equalPartitionSpec(const PartitionSpec *a, const PartitionSpec *b) _equalPartitionElem(const PartitionElem *a, const PartitionElem *b)
{ {
COMPARE_STRING_FIELD(strategy); COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(partParams); COMPARE_NODE_FIELD(expr);
COMPARE_NODE_FIELD(collation);
COMPARE_NODE_FIELD(opclass);
COMPARE_LOCATION_FIELD(location); COMPARE_LOCATION_FIELD(location);
return true; return true;
} }
static bool static bool
_equalPartitionElem(const PartitionElem *a, const PartitionElem *b) _equalPartitionSpec(const PartitionSpec *a, const PartitionSpec *b)
{ {
COMPARE_STRING_FIELD(name); COMPARE_STRING_FIELD(strategy);
COMPARE_NODE_FIELD(expr); COMPARE_NODE_FIELD(partParams);
COMPARE_NODE_FIELD(collation);
COMPARE_NODE_FIELD(opclass);
COMPARE_LOCATION_FIELD(location); COMPARE_LOCATION_FIELD(location);
return true; return true;
...@@ -3660,12 +3660,12 @@ equal(const void *a, const void *b) ...@@ -3660,12 +3660,12 @@ equal(const void *a, const void *b)
case T_TriggerTransition: case T_TriggerTransition:
retval = _equalTriggerTransition(a, b); retval = _equalTriggerTransition(a, b);
break; break;
case T_PartitionSpec:
retval = _equalPartitionSpec(a, b);
break;
case T_PartitionElem: case T_PartitionElem:
retval = _equalPartitionElem(a, b); retval = _equalPartitionElem(a, b);
break; break;
case T_PartitionSpec:
retval = _equalPartitionSpec(a, b);
break;
case T_PartitionBoundSpec: case T_PartitionBoundSpec:
retval = _equalPartitionBoundSpec(a, b); retval = _equalPartitionBoundSpec(a, b);
break; break;
......
...@@ -1560,6 +1560,12 @@ exprLocation(const Node *expr) ...@@ -1560,6 +1560,12 @@ exprLocation(const Node *expr)
/* just use nested expr's location */ /* just use nested expr's location */
loc = exprLocation((Node *) ((const InferenceElem *) expr)->expr); loc = exprLocation((Node *) ((const InferenceElem *) expr)->expr);
break; break;
case T_PartitionElem:
loc = ((const PartitionElem *) expr)->location;
break;
case T_PartitionSpec:
loc = ((const PartitionSpec *) expr)->location;
break;
case T_PartitionBoundSpec: case T_PartitionBoundSpec:
loc = ((const PartitionBoundSpec *) expr)->location; loc = ((const PartitionBoundSpec *) expr)->location;
break; break;
......
...@@ -3515,16 +3515,6 @@ _outForeignKeyCacheInfo(StringInfo str, const ForeignKeyCacheInfo *node) ...@@ -3515,16 +3515,6 @@ _outForeignKeyCacheInfo(StringInfo str, const ForeignKeyCacheInfo *node)
appendStringInfo(str, " %u", node->conpfeqop[i]); 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 static void
_outPartitionElem(StringInfo str, const PartitionElem *node) _outPartitionElem(StringInfo str, const PartitionElem *node)
{ {
...@@ -3537,6 +3527,16 @@ _outPartitionElem(StringInfo str, const PartitionElem *node) ...@@ -3537,6 +3527,16 @@ _outPartitionElem(StringInfo str, const PartitionElem *node)
WRITE_LOCATION_FIELD(location); WRITE_LOCATION_FIELD(location);
} }
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 static void
_outPartitionBoundSpec(StringInfo str, const PartitionBoundSpec *node) _outPartitionBoundSpec(StringInfo str, const PartitionBoundSpec *node)
{ {
...@@ -3546,6 +3546,7 @@ _outPartitionBoundSpec(StringInfo str, const PartitionBoundSpec *node) ...@@ -3546,6 +3546,7 @@ _outPartitionBoundSpec(StringInfo str, const PartitionBoundSpec *node)
WRITE_NODE_FIELD(listdatums); WRITE_NODE_FIELD(listdatums);
WRITE_NODE_FIELD(lowerdatums); WRITE_NODE_FIELD(lowerdatums);
WRITE_NODE_FIELD(upperdatums); WRITE_NODE_FIELD(upperdatums);
/* XXX somebody forgot location field; too late to change for v10 */
} }
static void static void
...@@ -3555,6 +3556,7 @@ _outPartitionRangeDatum(StringInfo str, const PartitionRangeDatum *node) ...@@ -3555,6 +3556,7 @@ _outPartitionRangeDatum(StringInfo str, const PartitionRangeDatum *node)
WRITE_BOOL_FIELD(infinite); WRITE_BOOL_FIELD(infinite);
WRITE_NODE_FIELD(value); WRITE_NODE_FIELD(value);
/* XXX somebody forgot location field; too late to change for v10 */
} }
/* /*
...@@ -4184,12 +4186,12 @@ outNode(StringInfo str, const void *obj) ...@@ -4184,12 +4186,12 @@ outNode(StringInfo str, const void *obj)
case T_TriggerTransition: case T_TriggerTransition:
_outTriggerTransition(str, obj); _outTriggerTransition(str, obj);
break; break;
case T_PartitionSpec:
_outPartitionSpec(str, obj);
break;
case T_PartitionElem: case T_PartitionElem:
_outPartitionElem(str, obj); _outPartitionElem(str, obj);
break; break;
case T_PartitionSpec:
_outPartitionSpec(str, obj);
break;
case T_PartitionBoundSpec: case T_PartitionBoundSpec:
_outPartitionBoundSpec(str, obj); _outPartitionBoundSpec(str, obj);
break; break;
......
...@@ -2376,6 +2376,8 @@ _readPartitionBoundSpec(void) ...@@ -2376,6 +2376,8 @@ _readPartitionBoundSpec(void)
READ_NODE_FIELD(listdatums); READ_NODE_FIELD(listdatums);
READ_NODE_FIELD(lowerdatums); READ_NODE_FIELD(lowerdatums);
READ_NODE_FIELD(upperdatums); READ_NODE_FIELD(upperdatums);
/* XXX somebody forgot location field; too late to change for v10 */
local_node->location = -1;
READ_DONE(); READ_DONE();
} }
...@@ -2390,6 +2392,8 @@ _readPartitionRangeDatum(void) ...@@ -2390,6 +2392,8 @@ _readPartitionRangeDatum(void)
READ_BOOL_FIELD(infinite); READ_BOOL_FIELD(infinite);
READ_NODE_FIELD(value); READ_NODE_FIELD(value);
/* XXX somebody forgot location field; too late to change for v10 */
local_node->location = -1;
READ_DONE(); READ_DONE();
} }
......
...@@ -239,7 +239,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); ...@@ -239,7 +239,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
VariableSetStmt *vsetstmt; VariableSetStmt *vsetstmt;
PartitionElem *partelem; PartitionElem *partelem;
PartitionSpec *partspec; PartitionSpec *partspec;
PartitionRangeDatum *partrange_datum; PartitionBoundSpec *partboundspec;
RoleSpec *rolespec; RoleSpec *rolespec;
} }
...@@ -575,11 +575,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); ...@@ -575,11 +575,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> part_strategy %type <str> part_strategy
%type <partelem> part_elem %type <partelem> part_elem
%type <list> part_params %type <list> part_params
%type <node> ForValues %type <partboundspec> ForValues
%type <node> partbound_datum %type <node> partbound_datum PartitionRangeDatum
%type <list> partbound_datum_list %type <list> partbound_datum_list range_datum_list
%type <partrange_datum> PartitionRangeDatum
%type <list> range_datum_list
/* /*
* Non-keyword token types. These are hard-wired into the "flex" lexer. * Non-keyword token types. These are hard-wired into the "flex" lexer.
...@@ -2020,7 +2018,7 @@ partition_cmd: ...@@ -2020,7 +2018,7 @@ partition_cmd:
n->subtype = AT_AttachPartition; n->subtype = AT_AttachPartition;
cmd->name = $3; cmd->name = $3;
cmd->bound = (Node *) $4; cmd->bound = $4;
n->def = (Node *) cmd; n->def = (Node *) cmd;
$$ = (Node *) n; $$ = (Node *) n;
...@@ -2033,6 +2031,7 @@ partition_cmd: ...@@ -2033,6 +2031,7 @@ partition_cmd:
n->subtype = AT_DetachPartition; n->subtype = AT_DetachPartition;
cmd->name = $3; cmd->name = $3;
cmd->bound = NULL;
n->def = (Node *) cmd; n->def = (Node *) cmd;
$$ = (Node *) n; $$ = (Node *) n;
...@@ -2661,7 +2660,7 @@ ForValues: ...@@ -2661,7 +2660,7 @@ ForValues:
n->listdatums = $5; n->listdatums = $5;
n->location = @3; n->location = @3;
$$ = (Node *) n; $$ = n;
} }
/* a RANGE partition */ /* a RANGE partition */
...@@ -2674,7 +2673,7 @@ ForValues: ...@@ -2674,7 +2673,7 @@ ForValues:
n->upperdatums = $9; n->upperdatums = $9;
n->location = @3; n->location = @3;
$$ = (Node *) n; $$ = n;
} }
; ;
...@@ -2705,7 +2704,7 @@ PartitionRangeDatum: ...@@ -2705,7 +2704,7 @@ PartitionRangeDatum:
n->value = NULL; n->value = NULL;
n->location = @1; n->location = @1;
$$ = n; $$ = (Node *) n;
} }
| partbound_datum | partbound_datum
{ {
...@@ -2715,7 +2714,7 @@ PartitionRangeDatum: ...@@ -2715,7 +2714,7 @@ PartitionRangeDatum:
n->value = $1; n->value = $1;
n->location = @1; n->location = @1;
$$ = n; $$ = (Node *) n;
} }
; ;
...@@ -3144,7 +3143,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' ...@@ -3144,7 +3143,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
n->relation = $4; n->relation = $4;
n->tableElts = $8; n->tableElts = $8;
n->inhRelations = list_make1($7); n->inhRelations = list_make1($7);
n->partbound = (Node *) $9; n->partbound = $9;
n->partspec = $10; n->partspec = $10;
n->ofTypename = NULL; n->ofTypename = NULL;
n->constraints = NIL; n->constraints = NIL;
...@@ -3163,7 +3162,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' ...@@ -3163,7 +3162,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
n->relation = $7; n->relation = $7;
n->tableElts = $11; n->tableElts = $11;
n->inhRelations = list_make1($10); n->inhRelations = list_make1($10);
n->partbound = (Node *) $12; n->partbound = $12;
n->partspec = $13; n->partspec = $13;
n->ofTypename = NULL; n->ofTypename = NULL;
n->constraints = NIL; n->constraints = NIL;
...@@ -4866,7 +4865,7 @@ CreateForeignTableStmt: ...@@ -4866,7 +4865,7 @@ CreateForeignTableStmt:
n->base.relation = $4; n->base.relation = $4;
n->base.inhRelations = list_make1($7); n->base.inhRelations = list_make1($7);
n->base.tableElts = $8; n->base.tableElts = $8;
n->base.partbound = (Node *) $9; n->base.partbound = $9;
n->base.ofTypename = NULL; n->base.ofTypename = NULL;
n->base.constraints = NIL; n->base.constraints = NIL;
n->base.options = NIL; n->base.options = NIL;
...@@ -4887,7 +4886,7 @@ CreateForeignTableStmt: ...@@ -4887,7 +4886,7 @@ CreateForeignTableStmt:
n->base.relation = $7; n->base.relation = $7;
n->base.inhRelations = list_make1($10); n->base.inhRelations = list_make1($10);
n->base.tableElts = $11; n->base.tableElts = $11;
n->base.partbound = (Node *) $12; n->base.partbound = $12;
n->base.ofTypename = NULL; n->base.ofTypename = NULL;
n->base.constraints = NIL; n->base.constraints = NIL;
n->base.options = NIL; n->base.options = NIL;
......
This diff is collapsed.
...@@ -8652,12 +8652,11 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -8652,12 +8652,11 @@ get_rule_expr(Node *node, deparse_context *context,
case PARTITION_STRATEGY_LIST: case PARTITION_STRATEGY_LIST:
Assert(spec->listdatums != NIL); Assert(spec->listdatums != NIL);
appendStringInfoString(buf, "FOR VALUES"); appendStringInfoString(buf, "FOR VALUES IN (");
appendStringInfoString(buf, " IN (");
sep = ""; sep = "";
foreach(cell, spec->listdatums) foreach(cell, spec->listdatums)
{ {
Const *val = lfirst(cell); Const *val = castNode(Const, lfirst(cell));
appendStringInfoString(buf, sep); appendStringInfoString(buf, sep);
get_const_expr(val, context, -1); get_const_expr(val, context, -1);
...@@ -8673,41 +8672,38 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -8673,41 +8672,38 @@ get_rule_expr(Node *node, deparse_context *context,
list_length(spec->lowerdatums) == list_length(spec->lowerdatums) ==
list_length(spec->upperdatums)); list_length(spec->upperdatums));
appendStringInfoString(buf, "FOR VALUES"); appendStringInfoString(buf, "FOR VALUES FROM (");
appendStringInfoString(buf, " FROM");
appendStringInfoString(buf, " (");
sep = ""; sep = "";
foreach(cell, spec->lowerdatums) foreach(cell, spec->lowerdatums)
{ {
PartitionRangeDatum *datum = lfirst(cell); PartitionRangeDatum *datum =
Const *val; castNode(PartitionRangeDatum, lfirst(cell));
appendStringInfoString(buf, sep); appendStringInfoString(buf, sep);
if (datum->infinite) if (datum->infinite)
appendStringInfoString(buf, "UNBOUNDED"); appendStringInfoString(buf, "UNBOUNDED");
else else
{ {
val = (Const *) datum->value; Const *val = castNode(Const, datum->value);
get_const_expr(val, context, -1); get_const_expr(val, context, -1);
} }
sep = ", "; sep = ", ";
} }
appendStringInfoString(buf, ")"); appendStringInfoString(buf, ") TO (");
appendStringInfoString(buf, " TO");
appendStringInfoString(buf, " (");
sep = ""; sep = "";
foreach(cell, spec->upperdatums) foreach(cell, spec->upperdatums)
{ {
PartitionRangeDatum *datum = lfirst(cell); PartitionRangeDatum *datum =
Const *val; castNode(PartitionRangeDatum, lfirst(cell));
appendStringInfoString(buf, sep); appendStringInfoString(buf, sep);
if (datum->infinite) if (datum->infinite)
appendStringInfoString(buf, "UNBOUNDED"); appendStringInfoString(buf, "UNBOUNDED");
else else
{ {
val = (Const *) datum->value; Const *val = castNode(Const, datum->value);
get_const_expr(val, context, -1); get_const_expr(val, context, -1);
} }
sep = ", "; sep = ", ";
......
...@@ -143,6 +143,7 @@ extern void StorePartitionKey(Relation rel, ...@@ -143,6 +143,7 @@ extern void StorePartitionKey(Relation rel,
Oid *partopclass, Oid *partopclass,
Oid *partcollation); Oid *partcollation);
extern void RemovePartitionKeyByRelId(Oid relid); extern void RemovePartitionKeyByRelId(Oid relid);
extern void StorePartitionBound(Relation rel, Relation parent, Node *bound); extern void StorePartitionBound(Relation rel, Relation parent,
PartitionBoundSpec *bound);
#endif /* HEAP_H */ #endif /* HEAP_H */
...@@ -74,9 +74,11 @@ extern void RelationBuildPartitionDesc(Relation relation); ...@@ -74,9 +74,11 @@ extern void RelationBuildPartitionDesc(Relation relation);
extern bool partition_bounds_equal(PartitionKey key, extern bool partition_bounds_equal(PartitionKey key,
PartitionBoundInfo p1, PartitionBoundInfo p2); PartitionBoundInfo p1, PartitionBoundInfo p2);
extern void check_new_partition_bound(char *relname, Relation parent, Node *bound); extern void check_new_partition_bound(char *relname, Relation parent,
PartitionBoundSpec *spec);
extern Oid get_partition_parent(Oid relid); extern Oid get_partition_parent(Oid relid);
extern List *get_qual_from_partbound(Relation rel, Relation parent, Node *bound); extern List *get_qual_from_partbound(Relation rel, Relation parent,
PartitionBoundSpec *spec);
extern List *map_partition_varattnos(List *expr, int target_varno, extern List *map_partition_varattnos(List *expr, int target_varno,
Relation partrel, Relation parent); Relation partrel, Relation parent);
extern List *RelationGetPartitionQual(Relation rel); extern List *RelationGetPartitionQual(Relation rel);
......
...@@ -406,7 +406,6 @@ typedef enum NodeTag ...@@ -406,7 +406,6 @@ typedef enum NodeTag
T_AlterPolicyStmt, T_AlterPolicyStmt,
T_CreateTransformStmt, T_CreateTransformStmt,
T_CreateAmStmt, T_CreateAmStmt,
T_PartitionCmd,
T_CreatePublicationStmt, T_CreatePublicationStmt,
T_AlterPublicationStmt, T_AlterPublicationStmt,
T_CreateSubscriptionStmt, T_CreateSubscriptionStmt,
...@@ -468,6 +467,7 @@ typedef enum NodeTag ...@@ -468,6 +467,7 @@ typedef enum NodeTag
T_PartitionSpec, T_PartitionSpec,
T_PartitionBoundSpec, T_PartitionBoundSpec,
T_PartitionRangeDatum, T_PartitionRangeDatum,
T_PartitionCmd,
/* /*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h) * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
......
...@@ -755,7 +755,10 @@ typedef struct XmlSerialize ...@@ -755,7 +755,10 @@ typedef struct XmlSerialize
/* Partitioning related definitions */ /* Partitioning related definitions */
/* /*
* PartitionElem - a column in the partition key * PartitionElem - parse-time representation of a single partition key
*
* expr can be either a raw expression tree or a parse-analyzed expression.
* We don't store these on-disk, though.
*/ */
typedef struct PartitionElem typedef struct PartitionElem
{ {
...@@ -768,7 +771,9 @@ typedef struct PartitionElem ...@@ -768,7 +771,9 @@ typedef struct PartitionElem
} PartitionElem; } PartitionElem;
/* /*
* PartitionSpec - partition key specification * PartitionSpec - parse-time representation of a partition key specification
*
* This represents the key space we will be partitioning on.
*/ */
typedef struct PartitionSpec typedef struct PartitionSpec
{ {
...@@ -778,52 +783,55 @@ typedef struct PartitionSpec ...@@ -778,52 +783,55 @@ typedef struct PartitionSpec
int location; /* token location, or -1 if unknown */ int location; /* token location, or -1 if unknown */
} PartitionSpec; } PartitionSpec;
/* Internal codes for partitioning strategies */
#define PARTITION_STRATEGY_LIST 'l' #define PARTITION_STRATEGY_LIST 'l'
#define PARTITION_STRATEGY_RANGE 'r' #define PARTITION_STRATEGY_RANGE 'r'
/* /*
* PartitionBoundSpec - a partition bound specification * PartitionBoundSpec - a partition bound specification
*
* This represents the portion of the partition key space assigned to a
* particular partition. These are stored on disk in pg_class.relpartbound.
*/ */
typedef struct PartitionBoundSpec typedef struct PartitionBoundSpec
{ {
NodeTag type; NodeTag type;
char strategy; char strategy; /* see PARTITION_STRATEGY codes above */
/* List partition values */ /* Partitioning info for LIST strategy: */
List *listdatums; List *listdatums; /* List of Consts (or A_Consts in raw tree) */
/* /* Partitioning info for RANGE strategy: */
* Range partition lower and upper bounds; each member of the lists is a List *lowerdatums; /* List of PartitionRangeDatums */
* PartitionRangeDatum (see below). List *upperdatums; /* List of PartitionRangeDatums */
*/
List *lowerdatums;
List *upperdatums;
int location; int location; /* token location, or -1 if unknown */
} PartitionBoundSpec; } PartitionBoundSpec;
/* /*
* PartitionRangeDatum * PartitionRangeDatum - can be either a value or UNBOUNDED
*
* "value" is an A_Const in raw grammar output, a Const after analysis
*/ */
typedef struct PartitionRangeDatum typedef struct PartitionRangeDatum
{ {
NodeTag type; NodeTag type;
bool infinite; bool infinite; /* true if UNBOUNDED */
Node *value; Node *value; /* null if UNBOUNDED */
int location; int location; /* token location, or -1 if unknown */
} PartitionRangeDatum; } PartitionRangeDatum;
/* /*
* PartitionCmd - ALTER TABLE partition commands * PartitionCmd - info for ALTER TABLE ATTACH/DETACH PARTITION commands
*/ */
typedef struct PartitionCmd typedef struct PartitionCmd
{ {
NodeTag type; NodeTag type;
RangeVar *name; RangeVar *name; /* name of partition to attach/detach */
Node *bound; PartitionBoundSpec *bound; /* FOR VALUES, if attaching */
} PartitionCmd; } PartitionCmd;
/**************************************************************************** /****************************************************************************
...@@ -1969,7 +1977,7 @@ typedef struct CreateStmt ...@@ -1969,7 +1977,7 @@ typedef struct CreateStmt
List *tableElts; /* column definitions (list of ColumnDef) */ List *tableElts; /* column definitions (list of ColumnDef) */
List *inhRelations; /* relations to inherit from (list of List *inhRelations; /* relations to inherit from (list of
* inhRelation) */ * inhRelation) */
Node *partbound; /* FOR VALUES clause */ PartitionBoundSpec *partbound; /* FOR VALUES clause */
PartitionSpec *partspec; /* PARTITION BY clause */ PartitionSpec *partspec; /* PARTITION BY clause */
TypeName *ofTypename; /* OF typename */ TypeName *ofTypename; /* OF typename */
List *constraints; /* constraints (list of Constraint nodes) */ List *constraints; /* constraints (list of Constraint nodes) */
......
...@@ -25,7 +25,7 @@ extern IndexStmt *transformIndexStmt(Oid relid, IndexStmt *stmt, ...@@ -25,7 +25,7 @@ extern IndexStmt *transformIndexStmt(Oid relid, IndexStmt *stmt,
extern void transformRuleStmt(RuleStmt *stmt, const char *queryString, extern void transformRuleStmt(RuleStmt *stmt, const char *queryString,
List **actions, Node **whereClause); List **actions, Node **whereClause);
extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt); extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt);
extern Node *transformPartitionBound(ParseState *pstate, Relation parent, extern PartitionBoundSpec *transformPartitionBound(ParseState *pstate, Relation parent,
Node *bound); PartitionBoundSpec *spec);
#endif /* PARSE_UTILCMD_H */ #endif /* PARSE_UTILCMD_H */
...@@ -274,7 +274,7 @@ CREATE TABLE partitioned ( ...@@ -274,7 +274,7 @@ CREATE TABLE partitioned (
a1 int, a1 int,
a2 int a2 int
) PARTITION BY LIST (a1, a2); -- fail ) PARTITION BY LIST (a1, a2); -- fail
ERROR: cannot list partition using more than one column ERROR: cannot use "list" partition strategy with more than one column
-- unsupported constraint type for partitioned tables -- unsupported constraint type for partitioned tables
CREATE TABLE partitioned ( CREATE TABLE partitioned (
a int PRIMARY KEY a int PRIMARY KEY
...@@ -472,10 +472,31 @@ CREATE TABLE bools ( ...@@ -472,10 +472,31 @@ CREATE TABLE bools (
a bool a bool
) PARTITION BY LIST (a); ) PARTITION BY LIST (a);
CREATE TABLE bools_true PARTITION OF bools FOR VALUES IN (1); CREATE TABLE bools_true PARTITION OF bools FOR VALUES IN (1);
ERROR: specified value cannot be cast to type "boolean" of column "a" ERROR: specified value cannot be cast to type boolean for column "a"
LINE 1: ...REATE TABLE bools_true PARTITION OF bools FOR VALUES IN (1); LINE 1: ...REATE TABLE bools_true PARTITION OF bools FOR VALUES IN (1);
^ ^
DROP TABLE bools; DROP TABLE bools;
-- specified literal can be cast, but cast isn't immutable
CREATE TABLE moneyp (
a money
) PARTITION BY LIST (a);
CREATE TABLE moneyp_10 PARTITION OF moneyp FOR VALUES IN (10);
ERROR: specified value cannot be cast to type money for column "a"
LINE 1: ...EATE TABLE moneyp_10 PARTITION OF moneyp FOR VALUES IN (10);
^
DETAIL: The cast requires a non-immutable conversion.
HINT: Try putting the literal value in single quotes.
CREATE TABLE moneyp_10 PARTITION OF moneyp FOR VALUES IN ('10');
DROP TABLE moneyp;
-- immutable cast should work, though
CREATE TABLE bigintp (
a bigint
) PARTITION BY LIST (a);
CREATE TABLE bigintp_10 PARTITION OF bigintp FOR VALUES IN (10);
-- fails due to overlap:
CREATE TABLE bigintp_10_2 PARTITION OF bigintp FOR VALUES IN ('10');
ERROR: partition "bigintp_10_2" would overlap partition "bigintp_10"
DROP TABLE bigintp;
CREATE TABLE range_parted ( CREATE TABLE range_parted (
a date a date
) PARTITION BY RANGE (a); ) PARTITION BY RANGE (a);
......
...@@ -454,6 +454,23 @@ CREATE TABLE bools ( ...@@ -454,6 +454,23 @@ CREATE TABLE bools (
CREATE TABLE bools_true PARTITION OF bools FOR VALUES IN (1); CREATE TABLE bools_true PARTITION OF bools FOR VALUES IN (1);
DROP TABLE bools; DROP TABLE bools;
-- specified literal can be cast, but cast isn't immutable
CREATE TABLE moneyp (
a money
) PARTITION BY LIST (a);
CREATE TABLE moneyp_10 PARTITION OF moneyp FOR VALUES IN (10);
CREATE TABLE moneyp_10 PARTITION OF moneyp FOR VALUES IN ('10');
DROP TABLE moneyp;
-- immutable cast should work, though
CREATE TABLE bigintp (
a bigint
) PARTITION BY LIST (a);
CREATE TABLE bigintp_10 PARTITION OF bigintp FOR VALUES IN (10);
-- fails due to overlap:
CREATE TABLE bigintp_10_2 PARTITION OF bigintp FOR VALUES IN ('10');
DROP TABLE bigintp;
CREATE TABLE range_parted ( CREATE TABLE range_parted (
a date a date
) PARTITION BY RANGE (a); ) PARTITION BY RANGE (a);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment