summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/sequence.c1
-rw-r--r--src/backend/commands/tablecmds.c99
-rw-r--r--src/backend/nodes/equalfuncs.c1
-rw-r--r--src/backend/nodes/makefuncs.c1
-rw-r--r--src/backend/parser/gram.y4
-rw-r--r--src/backend/parser/parse_utilcmd.c2
-rw-r--r--src/include/nodes/parsenodes.h2
-rw-r--r--src/test/regress/expected/create_table.out26
-rw-r--r--src/test/regress/sql/create_table.sql19
9 files changed, 92 insertions, 63 deletions
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 2f3ee462361..74cb2e61bcd 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -172,7 +172,6 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
coldef->is_local = true;
coldef->is_not_null = true;
coldef->is_from_type = false;
- coldef->is_from_parent = false;
coldef->storage = 0;
coldef->raw_default = NULL;
coldef->cooked_default = NULL;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 971a8721e1c..b4a19771a28 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1650,17 +1650,6 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
MaxHeapAttributeNumber)));
/*
- * In case of a partition, there are no new column definitions, only dummy
- * ColumnDefs created for column constraints. We merge them with the
- * constraints inherited from the parent.
- */
- if (is_partition)
- {
- saved_schema = schema;
- schema = NIL;
- }
-
- /*
* Check for duplicate names in the explicit list of attributes.
*
* Although we might consider merging such entries in the same way that we
@@ -1673,17 +1662,19 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
ListCell *rest = lnext(entry);
ListCell *prev = entry;
- if (coldef->typeName == NULL)
-
+ if (!is_partition && coldef->typeName == NULL)
+ {
/*
* Typed table column option that does not belong to a column from
* the type. This works because the columns from the type come
- * first in the list.
+ * first in the list. (We omit this check for partition column
+ * lists; those are processed separately below.)
*/
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" does not exist",
coldef->colname)));
+ }
while (rest != NULL)
{
@@ -1717,6 +1708,17 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
}
/*
+ * In case of a partition, there are no new column definitions, only dummy
+ * ColumnDefs created for column constraints. Set them aside for now and
+ * process them at the end.
+ */
+ if (is_partition)
+ {
+ saved_schema = schema;
+ schema = NIL;
+ }
+
+ /*
* Scan the parents left-to-right, and merge their attributes to form a
* list of inherited attributes (inhSchema). Also check to see if we need
* to inherit an OID column.
@@ -1931,7 +1933,6 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
def->is_local = false;
def->is_not_null = attribute->attnotnull;
def->is_from_type = false;
- def->is_from_parent = true;
def->storage = attribute->attstorage;
def->raw_default = NULL;
def->cooked_default = NULL;
@@ -2184,59 +2185,51 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
/*
* Now that we have the column definition list for a partition, we can
* check whether the columns referenced in the column constraint specs
- * actually exist. Also, we merge the constraints into the corresponding
- * column definitions.
+ * actually exist. Also, we merge NOT NULL and defaults into each
+ * corresponding column definition.
*/
- if (is_partition && list_length(saved_schema) > 0)
+ if (is_partition)
{
- schema = list_concat(schema, saved_schema);
-
- foreach(entry, schema)
+ foreach(entry, saved_schema)
{
- ColumnDef *coldef = lfirst(entry);
- ListCell *rest = lnext(entry);
- ListCell *prev = entry;
+ ColumnDef *restdef = lfirst(entry);
+ bool found = false;
+ ListCell *l;
- /*
- * Partition column option that does not belong to a column from
- * the parent. This works because the columns from the parent
- * come first in the list (see above).
- */
- if (coldef->typeName == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("column \"%s\" does not exist",
- coldef->colname)));
- while (rest != NULL)
+ foreach(l, schema)
{
- ColumnDef *restdef = lfirst(rest);
- ListCell *next = lnext(rest); /* need to save it in case we
- * delete it */
+ ColumnDef *coldef = lfirst(l);
if (strcmp(coldef->colname, restdef->colname) == 0)
{
+ found = true;
+ coldef->is_not_null |= restdef->is_not_null;
+
/*
- * merge the column options into the column from the
- * parent
+ * Override the parent's default value for this column
+ * (coldef->cooked_default) with the partition's local
+ * definition (restdef->raw_default), if there's one. It
+ * should be physically impossible to get a cooked default
+ * in the local definition or a raw default in the
+ * inherited definition, but make sure they're nulls, for
+ * future-proofing.
*/
- if (coldef->is_from_parent)
+ Assert(restdef->cooked_default == NULL);
+ Assert(coldef->raw_default == NULL);
+ if (restdef->raw_default)
{
- coldef->is_not_null = restdef->is_not_null;
coldef->raw_default = restdef->raw_default;
- coldef->cooked_default = restdef->cooked_default;
- coldef->constraints = restdef->constraints;
- coldef->is_from_parent = false;
- list_delete_cell(schema, rest, prev);
+ coldef->cooked_default = NULL;
}
- else
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_COLUMN),
- errmsg("column \"%s\" specified more than once",
- coldef->colname)));
}
- prev = rest;
- rest = next;
}
+
+ /* complain for constraints on columns not in parent */
+ if (!found)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" does not exist",
+ restdef->colname)));
}
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 68d38fcba1a..c5bb817ba19 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2539,7 +2539,6 @@ _equalColumnDef(const ColumnDef *a, const ColumnDef *b)
COMPARE_SCALAR_FIELD(is_local);
COMPARE_SCALAR_FIELD(is_not_null);
COMPARE_SCALAR_FIELD(is_from_type);
- COMPARE_SCALAR_FIELD(is_from_parent);
COMPARE_SCALAR_FIELD(storage);
COMPARE_NODE_FIELD(raw_default);
COMPARE_NODE_FIELD(cooked_default);
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 0755039da9f..87ffe825304 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -494,7 +494,6 @@ makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid)
n->is_local = true;
n->is_not_null = false;
n->is_from_type = false;
- n->is_from_parent = false;
n->storage = 0;
n->raw_default = NULL;
n->cooked_default = NULL;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 025e82b30fa..a97f51ce37c 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -3240,7 +3240,6 @@ columnDef: ColId Typename create_generic_options ColQualList
n->is_local = true;
n->is_not_null = false;
n->is_from_type = false;
- n->is_from_parent = false;
n->storage = 0;
n->raw_default = NULL;
n->cooked_default = NULL;
@@ -3262,7 +3261,6 @@ columnOptions: ColId ColQualList
n->is_local = true;
n->is_not_null = false;
n->is_from_type = false;
- n->is_from_parent = false;
n->storage = 0;
n->raw_default = NULL;
n->cooked_default = NULL;
@@ -3281,7 +3279,6 @@ columnOptions: ColId ColQualList
n->is_local = true;
n->is_not_null = false;
n->is_from_type = false;
- n->is_from_parent = false;
n->storage = 0;
n->raw_default = NULL;
n->cooked_default = NULL;
@@ -11884,7 +11881,6 @@ TableFuncElement: ColId Typename opt_collate_clause
n->is_local = true;
n->is_not_null = false;
n->is_from_type = false;
- n->is_from_parent = false;
n->storage = 0;
n->raw_default = NULL;
n->cooked_default = NULL;
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index b3367f0cd4b..0a03658e663 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1025,7 +1025,6 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
def->is_local = true;
def->is_not_null = attribute->attnotnull;
def->is_from_type = false;
- def->is_from_parent = false;
def->storage = 0;
def->raw_default = NULL;
def->cooked_default = NULL;
@@ -1293,7 +1292,6 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
n->is_local = true;
n->is_not_null = false;
n->is_from_type = true;
- n->is_from_parent = false;
n->storage = 0;
n->raw_default = NULL;
n->cooked_default = NULL;
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 1f80dfaa85d..57fa4db0d3f 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -642,7 +642,7 @@ typedef struct ColumnDef
bool is_local; /* column has local (non-inherited) def'n */
bool is_not_null; /* NOT NULL constraint specified? */
bool is_from_type; /* column definition came from table type */
- bool is_from_parent; /* column def came from partition parent */
+ bool is_from_parent; /* XXX unused */
char storage; /* attstorage setting, or 0 for default */
Node *raw_default; /* default value (untransformed parse tree) */
Node *cooked_default; /* default value (transformed expr tree) */
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 481510c2bb1..28c9d2df898 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -657,6 +657,32 @@ ERROR: column "c" named in partition key does not exist
CREATE TABLE part_c PARTITION OF parted (b WITH OPTIONS NOT NULL DEFAULT 0) FOR VALUES IN ('c') PARTITION BY RANGE ((b));
-- create a level-2 partition
CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
+-- check that NOT NULL and default value are inherited correctly
+create table parted_notnull_inh_test (a int default 1, b int not null default 0) partition by list (a);
+create table parted_notnull_inh_test1 partition of parted_notnull_inh_test (a not null, b default 1) for values in (1);
+insert into parted_notnull_inh_test (b) values (null);
+ERROR: null value in column "b" violates not-null constraint
+DETAIL: Failing row contains (1, null).
+-- note that while b's default is overriden, a's default is preserved
+\d parted_notnull_inh_test1
+ Table "public.parted_notnull_inh_test1"
+ Column | Type | Collation | Nullable | Default
+--------+---------+-----------+----------+---------
+ a | integer | | not null | 1
+ b | integer | | not null | 1
+Partition of: parted_notnull_inh_test FOR VALUES IN (1)
+
+drop table parted_notnull_inh_test;
+-- check for a conflicting COLLATE clause
+create table parted_collate_must_match (a text collate "C", b text collate "C")
+ partition by range (a);
+-- on the partition key
+create table parted_collate_must_match1 partition of parted_collate_must_match
+ (a collate "POSIX") for values from ('a') to ('m');
+-- on another column
+create table parted_collate_must_match2 partition of parted_collate_must_match
+ (b collate "POSIX") for values from ('m') to ('z');
+drop table parted_collate_must_match;
-- Partition bound in describe output
\d+ part_b
Table "public.part_b"
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index bc6191f4ace..7849139ca15 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -604,6 +604,25 @@ CREATE TABLE part_c PARTITION OF parted (b WITH OPTIONS NOT NULL DEFAULT 0) FOR
-- create a level-2 partition
CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
+-- check that NOT NULL and default value are inherited correctly
+create table parted_notnull_inh_test (a int default 1, b int not null default 0) partition by list (a);
+create table parted_notnull_inh_test1 partition of parted_notnull_inh_test (a not null, b default 1) for values in (1);
+insert into parted_notnull_inh_test (b) values (null);
+-- note that while b's default is overriden, a's default is preserved
+\d parted_notnull_inh_test1
+drop table parted_notnull_inh_test;
+
+-- check for a conflicting COLLATE clause
+create table parted_collate_must_match (a text collate "C", b text collate "C")
+ partition by range (a);
+-- on the partition key
+create table parted_collate_must_match1 partition of parted_collate_must_match
+ (a collate "POSIX") for values from ('a') to ('m');
+-- on another column
+create table parted_collate_must_match2 partition of parted_collate_must_match
+ (b collate "POSIX") for values from ('m') to ('z');
+drop table parted_collate_must_match;
+
-- Partition bound in describe output
\d+ part_b