aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/ddl.sgml26
-rw-r--r--src/backend/commands/tablecmds.c61
-rw-r--r--src/test/regress/expected/generated.out44
-rw-r--r--src/test/regress/sql/generated.sql22
4 files changed, 146 insertions, 7 deletions
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index aae5d320309..bdfb221bc98 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -324,6 +324,32 @@ CREATE TABLE people (
linkend="sql-createforeigntable"/> for details.
</para>
</listitem>
+ <listitem>
+ <para>For inheritance:</para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ If a parent column is a generated column, a child column must also be
+ a generated column using the same expression. In the definition of
+ the child column, leave off the <literal>GENERATED</literal> clause,
+ as it will be copied from the parent.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ In case of multiple inheritance, if one parent column is a generated
+ column, then all parent columns must be generated columns and with the
+ same expression.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a parent column is not a generated column, a child column may be
+ defined to be a generated column or not.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
</itemizedlist>
</para>
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2fba83504b6..a518b552b3d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -2618,12 +2618,55 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
def->is_local = true;
/* Merge of NOT NULL constraints = OR 'em together */
def->is_not_null |= newdef->is_not_null;
+
+ /*
+ * Check for conflicts related to generated columns.
+ *
+ * If the parent column is generated, the child column must be
+ * unadorned and will be made a generated column. (We could
+ * in theory allow the child column definition specifying the
+ * exact same generation expression, but that's a bit
+ * complicated to implement and doesn't seem very useful.) We
+ * also check that the child column doesn't specify a default
+ * value or identity, which matches the rules for a single
+ * column in parse_util.c.
+ */
+ if (def->generated)
+ {
+ if (newdef->generated)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
+ errmsg("child column \"%s\" specifies generation expression",
+ def->colname),
+ errhint("Omit the generation expression in the definition of the child table column to inherit the generation expression from the parent table.")));
+ if (newdef->raw_default && !newdef->generated)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
+ errmsg("column \"%s\" inherits from generated column but specifies default",
+ def->colname)));
+ if (newdef->identity)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
+ errmsg("column \"%s\" inherits from generated column but specifies identity",
+ def->colname)));
+ }
+ /*
+ * If the parent column is not generated, then take whatever
+ * the child column definition says.
+ */
+ else
+ {
+ if (newdef->generated)
+ def->generated = newdef->generated;
+ }
+
/* If new def has a default, override previous default */
if (newdef->raw_default != NULL)
{
def->raw_default = newdef->raw_default;
def->cooked_default = newdef->cooked_default;
}
+
}
else
{
@@ -2709,11 +2752,19 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
ColumnDef *def = lfirst(entry);
if (def->cooked_default == &bogus_marker)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
- errmsg("column \"%s\" inherits conflicting default values",
- def->colname),
- errhint("To resolve the conflict, specify a default explicitly.")));
+ {
+ if (def->generated)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
+ errmsg("column \"%s\" inherits conflicting generation expressions",
+ def->colname)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
+ errmsg("column \"%s\" inherits conflicting default values",
+ def->colname),
+ errhint("To resolve the conflict, specify a default explicitly.")));
+ }
}
}
diff --git a/src/test/regress/expected/generated.out b/src/test/regress/expected/generated.out
index 30fa320a395..7ccc3c65ed1 100644
--- a/src/test/regress/expected/generated.out
+++ b/src/test/regress/expected/generated.out
@@ -219,12 +219,54 @@ SELECT * FROM gtest1;
4 | 8
(2 rows)
--- test inheritance mismatch
+CREATE TABLE gtest_normal (a int, b int);
+CREATE TABLE gtest_normal_child (a int, b int GENERATED ALWAYS AS (a * 2) STORED) INHERITS (gtest_normal);
+NOTICE: merging column "a" with inherited definition
+NOTICE: merging column "b" with inherited definition
+\d gtest_normal_child
+ Table "public.gtest_normal_child"
+ Column | Type | Collation | Nullable | Default
+--------+---------+-----------+----------+------------------------------------
+ a | integer | | |
+ b | integer | | | generated always as (a * 2) stored
+Inherits: gtest_normal
+
+INSERT INTO gtest_normal (a) VALUES (1);
+INSERT INTO gtest_normal_child (a) VALUES (2);
+SELECT * FROM gtest_normal;
+ a | b
+---+---
+ 1 |
+ 2 | 4
+(2 rows)
+
+-- test inheritance mismatches between parent and child
+CREATE TABLE gtestx (x int, b int GENERATED ALWAYS AS (a * 22) STORED) INHERITS (gtest1); -- error
+NOTICE: merging column "b" with inherited definition
+ERROR: child column "b" specifies generation expression
+HINT: Omit the generation expression in the definition of the child table column to inherit the generation expression from the parent table.
+CREATE TABLE gtestx (x int, b int DEFAULT 10) INHERITS (gtest1); -- error
+NOTICE: merging column "b" with inherited definition
+ERROR: column "b" inherits from generated column but specifies default
+CREATE TABLE gtestx (x int, b int GENERATED ALWAYS AS IDENTITY) INHERITS (gtest1); -- error
+NOTICE: merging column "b" with inherited definition
+ERROR: column "b" inherits from generated column but specifies identity
+-- test multiple inheritance mismatches
CREATE TABLE gtesty (x int, b int);
CREATE TABLE gtest1_2 () INHERITS (gtest1, gtesty); -- error
NOTICE: merging multiple inherited definitions of column "b"
ERROR: inherited column "b" has a generation conflict
DROP TABLE gtesty;
+CREATE TABLE gtesty (x int, b int GENERATED ALWAYS AS (x * 22) STORED);
+CREATE TABLE gtest1_2 () INHERITS (gtest1, gtesty); -- error
+NOTICE: merging multiple inherited definitions of column "b"
+ERROR: column "b" inherits conflicting generation expressions
+DROP TABLE gtesty;
+CREATE TABLE gtesty (x int, b int DEFAULT 55);
+CREATE TABLE gtest1_2 () INHERITS (gtest0, gtesty); -- error
+NOTICE: merging multiple inherited definitions of column "b"
+ERROR: inherited column "b" has a generation conflict
+DROP TABLE gtesty;
-- test stored update
CREATE TABLE gtest3 (a int, b int GENERATED ALWAYS AS (a * 3) STORED);
INSERT INTO gtest3 (a) VALUES (1), (2), (3), (NULL);
diff --git a/src/test/regress/sql/generated.sql b/src/test/regress/sql/generated.sql
index c13ede41075..4cff1279c77 100644
--- a/src/test/regress/sql/generated.sql
+++ b/src/test/regress/sql/generated.sql
@@ -89,11 +89,31 @@ INSERT INTO gtest1_1 VALUES (4);
SELECT * FROM gtest1_1;
SELECT * FROM gtest1;
--- test inheritance mismatch
+CREATE TABLE gtest_normal (a int, b int);
+CREATE TABLE gtest_normal_child (a int, b int GENERATED ALWAYS AS (a * 2) STORED) INHERITS (gtest_normal);
+\d gtest_normal_child
+INSERT INTO gtest_normal (a) VALUES (1);
+INSERT INTO gtest_normal_child (a) VALUES (2);
+SELECT * FROM gtest_normal;
+
+-- test inheritance mismatches between parent and child
+CREATE TABLE gtestx (x int, b int GENERATED ALWAYS AS (a * 22) STORED) INHERITS (gtest1); -- error
+CREATE TABLE gtestx (x int, b int DEFAULT 10) INHERITS (gtest1); -- error
+CREATE TABLE gtestx (x int, b int GENERATED ALWAYS AS IDENTITY) INHERITS (gtest1); -- error
+
+-- test multiple inheritance mismatches
CREATE TABLE gtesty (x int, b int);
CREATE TABLE gtest1_2 () INHERITS (gtest1, gtesty); -- error
DROP TABLE gtesty;
+CREATE TABLE gtesty (x int, b int GENERATED ALWAYS AS (x * 22) STORED);
+CREATE TABLE gtest1_2 () INHERITS (gtest1, gtesty); -- error
+DROP TABLE gtesty;
+
+CREATE TABLE gtesty (x int, b int DEFAULT 55);
+CREATE TABLE gtest1_2 () INHERITS (gtest0, gtesty); -- error
+DROP TABLE gtesty;
+
-- test stored update
CREATE TABLE gtest3 (a int, b int GENERATED ALWAYS AS (a * 3) STORED);
INSERT INTO gtest3 (a) VALUES (1), (2), (3), (NULL);