* Normally this is always true, but it's false for dropped columns, as well
* as those that were inherited without any local definition. (If we print
* such a column it will mistakenly get pg_attribute.attislocal set to true.)
- * However, in binary_upgrade mode, we must print all such columns anyway and
- * fix the attislocal/attisdropped state later, so as to keep control of the
- * physical column order.
+ * For partitions, it's always true, because we want the partitions to be
+ * created independently and ATTACH PARTITION used afterwards.
+ *
+ * In binary_upgrade mode, we must print all columns and fix the attislocal/
+ * attisdropped state later, so as to keep control of the physical column
+ * order.
*
* This function exists because there are scattered nonobvious places that
* must be kept in sync with this decision.
{
if (dopt->binary_upgrade)
return true;
- return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
+ if (tbinfo->attisdropped[colno])
+ return false;
+ return (tbinfo->attislocal[colno] || tbinfo->ispartition);
}
if (tbinfo->reloftype && !dopt->binary_upgrade)
appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
- /*
- * If the table is a partition, dump it as such; except in the case of
- * a binary upgrade, we dump the table normally and attach it to the
- * parent afterward.
- */
- if (tbinfo->ispartition && !dopt->binary_upgrade)
- {
- TableInfo *parentRel = tbinfo->parents[0];
-
- /*
- * With partitions, unlike inheritance, there can only be one
- * parent.
- */
- if (tbinfo->numParents != 1)
- fatal("invalid number of parents %d for table \"%s\"",
- tbinfo->numParents, tbinfo->dobj.name);
-
- appendPQExpBuffer(q, " PARTITION OF %s",
- fmtQualifiedDumpable(parentRel));
- }
-
if (tbinfo->relkind != RELKIND_MATVIEW)
{
/* Dump the attributes */
*/
if (shouldPrintColumn(dopt, tbinfo, j))
{
+ bool print_default;
+ bool print_notnull;
+
/*
* Default value --- suppress if to be printed separately.
*/
- bool has_default = (tbinfo->attrdefs[j] != NULL &&
- !tbinfo->attrdefs[j]->separate);
+ print_default = (tbinfo->attrdefs[j] != NULL &&
+ !tbinfo->attrdefs[j]->separate);
/*
* Not Null constraint --- suppress if inherited, except
- * in binary-upgrade case where that won't work.
+ * if partition, or in binary-upgrade case where that
+ * won't work.
*/
- bool has_notnull = (tbinfo->notnull[j] &&
- (!tbinfo->inhNotNull[j] ||
- dopt->binary_upgrade));
+ print_notnull = (tbinfo->notnull[j] &&
+ (!tbinfo->inhNotNull[j] ||
+ tbinfo->ispartition || dopt->binary_upgrade));
/*
- * Skip column if fully defined by reloftype or the
- * partition parent.
+ * Skip column if fully defined by reloftype, except in
+ * binary upgrade
*/
- if ((tbinfo->reloftype || tbinfo->ispartition) &&
- !has_default && !has_notnull && !dopt->binary_upgrade)
+ if (tbinfo->reloftype && !print_default && !print_notnull &&
+ !dopt->binary_upgrade)
continue;
/* Format properly if not first attr */
* clean things up later.
*/
appendPQExpBufferStr(q, " INTEGER /* dummy */");
- /* Skip all the rest, too */
+ /* and skip to the next column */
continue;
}
/*
- * Attribute type
- *
- * In binary-upgrade mode, we always include the type. If
- * we aren't in binary-upgrade mode, then we skip the type
- * when creating a typed table ('OF type_name') or a
- * partition ('PARTITION OF'), since the type comes from
- * the parent/partitioned table.
+ * Attribute type; print it except when creating a typed
+ * table ('OF type_name'), but in binary-upgrade mode,
+ * print it in that case too.
*/
- if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
+ if (dopt->binary_upgrade || !tbinfo->reloftype)
{
appendPQExpBuffer(q, " %s",
tbinfo->atttypnames[j]);
}
- if (has_default)
+ if (print_default)
{
if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
}
- if (has_notnull)
+ if (print_notnull)
appendPQExpBufferStr(q, " NOT NULL");
/* Add collation if not default for the type */
/*
* Add non-inherited CHECK constraints, if any.
+ *
+ * For partitions, we need to include check constraints even if
+ * they're not defined locally, because the ALTER TABLE ATTACH
+ * PARTITION that we'll emit later expects the constraint to be
+ * there. (No need to fix conislocal: ATTACH PARTITION does that)
*/
for (j = 0; j < tbinfo->ncheck; j++)
{
ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
- if (constr->separate || !constr->conislocal)
+ if (constr->separate ||
+ (!constr->conislocal && !tbinfo->ispartition))
continue;
if (actual_atts == 0)
if (actual_atts)
appendPQExpBufferStr(q, "\n)");
- else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
- !dopt->binary_upgrade))
+ else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
{
/*
- * We must have a parenthesized attribute list, even though
- * empty, when not using the OF TYPE or PARTITION OF syntax.
+ * No attributes? we must have a parenthesized attribute list,
+ * even though empty, when not using the OF TYPE syntax.
*/
appendPQExpBufferStr(q, " (\n)");
}
- if (tbinfo->ispartition && !dopt->binary_upgrade)
- {
- appendPQExpBufferChar(q, '\n');
- appendPQExpBufferStr(q, tbinfo->partbound);
- }
-
- /* Emit the INHERITS clause, except if this is a partition. */
- if (numParents > 0 &&
- !tbinfo->ispartition &&
+ /*
+ * Emit the INHERITS clause (not for partitions), except in
+ * binary-upgrade mode.
+ */
+ if (numParents > 0 && !tbinfo->ispartition &&
!dopt->binary_upgrade)
{
appendPQExpBufferStr(q, "\nINHERITS (");
}
}
+ /*
+ * Add inherited CHECK constraints, if any.
+ *
+ * For partitions, they were already dumped, and conislocal
+ * doesn't need fixing.
+ */
for (k = 0; k < tbinfo->ncheck; k++)
{
ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
- if (constr->separate || constr->conislocal)
+ if (constr->separate || constr->conislocal || tbinfo->ispartition)
continue;
appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
}
- if (numParents > 0)
+ if (numParents > 0 && !tbinfo->ispartition)
{
- appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
+ appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
for (k = 0; k < numParents; k++)
{
TableInfo *parentRel = parents[k];
- /* In the partitioning case, we alter the parent */
- if (tbinfo->ispartition)
- appendPQExpBuffer(q,
- "ALTER TABLE ONLY %s ATTACH PARTITION ",
- fmtQualifiedDumpable(parentRel));
- else
- appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
- qualrelname);
-
- /* Partition needs specifying the bounds */
- if (tbinfo->ispartition)
- appendPQExpBuffer(q, "%s %s;\n",
- qualrelname,
- tbinfo->partbound);
- else
- appendPQExpBuffer(q, "%s;\n",
- fmtQualifiedDumpable(parentRel));
+ appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT %s;\n",
+ qualrelname,
+ fmtQualifiedDumpable(parentRel));
}
}
}
}
+ /*
+ * For partitioned tables, emit the ATTACH PARTITION clause. Note
+ * that we always want to create partitions this way instead of using
+ * CREATE TABLE .. PARTITION OF, mainly to preserve a possible column
+ * layout discrepancy with the parent, but also to ensure it gets the
+ * correct tablespace setting if it differs from the parent's.
+ */
+ if (tbinfo->ispartition)
+ {
+ /* With partitions there can only be one parent */
+ if (tbinfo->numParents != 1)
+ fatal("invalid number of parents %d for table \"%s\"",
+ tbinfo->numParents, tbinfo->dobj.name);
+
+ /* Perform ALTER TABLE on the parent */
+ appendPQExpBuffer(q,
+ "ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n",
+ fmtQualifiedDumpable(parents[0]),
+ qualrelname, tbinfo->partbound);
+ }
+
/*
* In binary_upgrade mode, arrange to restore the old relfrozenxid and
* relminmxid of all vacuumable relations. (While vacuum.c processes
\QALTER TABLE ONLY dump_test.measurement ATTACH PARTITION dump_test_second_schema.measurement_y2006m2 \E
\QFOR VALUES FROM ('2006-02-01') TO ('2006-03-01');\E\n
/xm,
- like => { binary_upgrade => 1, },
+ like => {
+ %full_runs,
+ role => 1,
+ section_pre_data => 1,
+ binary_upgrade => 1,
+ },
},
'ALTER TABLE test_table CLUSTER ON test_table_pkey' => {
'CREATE TABLE measurement PARTITIONED BY' => {
create_order => 90,
create_sql => 'CREATE TABLE dump_test.measurement (
- city_id int not null,
+ city_id serial not null,
logdate date not null,
- peaktemp int,
+ peaktemp int CHECK (peaktemp >= -460),
unitsales int
) PARTITION BY RANGE (logdate);',
regexp => qr/^
\s+\Qcity_id integer NOT NULL,\E\n
\s+\Qlogdate date NOT NULL,\E\n
\s+\Qpeaktemp integer,\E\n
- \s+\Qunitsales integer\E\n
+ \s+\Qunitsales integer,\E\n
+ \s+\QCONSTRAINT measurement_peaktemp_check CHECK ((peaktemp >= '-460'::integer))\E\n
\)\n
\QPARTITION BY RANGE (logdate);\E\n
/xm,
},
},
- 'CREATE TABLE measurement_y2006m2 PARTITION OF' => {
+ 'Partition measurement_y2006m2 creation' => {
create_order => 91,
create_sql =>
'CREATE TABLE dump_test_second_schema.measurement_y2006m2
)
FOR VALUES FROM (\'2006-02-01\') TO (\'2006-03-01\');',
regexp => qr/^
- \Q-- Name: measurement_y2006m2;\E.*\n
- \Q--\E\n\n
- \QCREATE TABLE dump_test_second_schema.measurement_y2006m2 PARTITION OF dump_test.measurement (\E\n
+ \QCREATE TABLE dump_test_second_schema.measurement_y2006m2 (\E\n
+ \s+\Qcity_id integer DEFAULT nextval('dump_test.measurement_city_id_seq'::regclass) NOT NULL,\E\n
+ \s+\Qlogdate date NOT NULL,\E\n
+ \s+\Qpeaktemp integer,\E\n
+ \s+\Qunitsales integer DEFAULT 0,\E\n
+ \s+\QCONSTRAINT measurement_peaktemp_check CHECK ((peaktemp >= '-460'::integer)),\E\n
\s+\QCONSTRAINT measurement_y2006m2_unitsales_check CHECK ((unitsales >= 0))\E\n
- \)\n
- \QFOR VALUES FROM ('2006-02-01') TO ('2006-03-01');\E\n
+ \);\n
/xm,
like => {
%full_runs,
- role => 1,
section_pre_data => 1,
+ role => 1,
+ binary_upgrade => 1,
},
- unlike => { binary_upgrade => 1, },
},
'CREATE TABLE test_fourth_table_zero_col' => {
unlike => { exclude_dump_test_schema => 1, },
},
+ 'CREATE TABLE test_inheritance_parent' => {
+ create_order => 90,
+ create_sql => 'CREATE TABLE dump_test.test_inheritance_parent (
+ col1 int NOT NULL,
+ col2 int CHECK (col2 >= 42)
+ );',
+ regexp => qr/^
+ \QCREATE TABLE dump_test.test_inheritance_parent (\E\n
+ \s+\Qcol1 integer NOT NULL,\E\n
+ \s+\Qcol2 integer,\E\n
+ \s+\QCONSTRAINT test_inheritance_parent_col2_check CHECK ((col2 >= 42))\E\n
+ \Q);\E\n
+ /xm,
+ like =>
+ { %full_runs, %dump_test_schema_runs, section_pre_data => 1, },
+ unlike => { exclude_dump_test_schema => 1, },
+ },
+
+ 'CREATE TABLE test_inheritance_child' => {
+ create_order => 91,
+ create_sql => 'CREATE TABLE dump_test.test_inheritance_child (
+ col1 int NOT NULL,
+ CONSTRAINT test_inheritance_child CHECK (col2 >= 142857)
+ ) INHERITS (dump_test.test_inheritance_parent);',
+ regexp => qr/^
+ \QCREATE TABLE dump_test.test_inheritance_child (\E\n
+ \s+\Qcol1 integer,\E\n
+ \s+\QCONSTRAINT test_inheritance_child CHECK ((col2 >= 142857))\E\n
+ \)\n
+ \QINHERITS (dump_test.test_inheritance_parent);\E\n
+ /xm,
+ like => {
+ %full_runs, %dump_test_schema_runs, section_pre_data => 1,
+ },
+ unlike => {
+ binary_upgrade => 1,
+ exclude_dump_test_schema => 1,
+ },
+ },
+
'CREATE STATISTICS extended_stats_no_options' => {
create_order => 97,
create_sql => 'CREATE STATISTICS dump_test.test_ext_stats_no_options