Revert "Catalog NOT NULL constraints" and fallout

This reverts commit e056c557ae and minor later fixes thereof.

There's a few problems in this new feature -- most notably regarding
pg_upgrade behavior, but others as well.  This new feature is not in any
way critical on its own, so instead of scrambling to fix it we revert it
and try again in early 17 with these issues in mind.

Discussion: https://postgr.es/m/3801207.1681057430@sss.pgh.pa.us
This commit is contained in:
Alvaro Herrera 2023-04-12 19:29:21 +02:00
parent 8e82db97b0
commit 9ce04b50e1
No known key found for this signature in database
GPG Key ID: 1C20ACB9D5C564AE
42 changed files with 648 additions and 2897 deletions

View File

@ -2552,7 +2552,6 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
<para> <para>
<literal>c</literal> = check constraint, <literal>c</literal> = check constraint,
<literal>f</literal> = foreign key constraint, <literal>f</literal> = foreign key constraint,
<literal>n</literal> = not null constraint,
<literal>p</literal> = primary key constraint, <literal>p</literal> = primary key constraint,
<literal>u</literal> = unique constraint, <literal>u</literal> = unique constraint,
<literal>t</literal> = constraint trigger, <literal>t</literal> = constraint trigger,

View File

@ -117,9 +117,7 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
PRIMARY KEY ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> | PRIMARY KEY ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> |
EXCLUDE [ USING <replaceable class="parameter">index_method</replaceable> ] ( <replaceable class="parameter">exclude_element</replaceable> WITH <replaceable class="parameter">operator</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> [ WHERE ( <replaceable class="parameter">predicate</replaceable> ) ] | EXCLUDE [ USING <replaceable class="parameter">index_method</replaceable> ] ( <replaceable class="parameter">exclude_element</replaceable> WITH <replaceable class="parameter">operator</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> [ WHERE ( <replaceable class="parameter">predicate</replaceable> ) ] |
FOREIGN KEY ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) REFERENCES <replaceable class="parameter">reftable</replaceable> [ ( <replaceable class="parameter">refcolumn</replaceable> [, ... ] ) ] FOREIGN KEY ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) REFERENCES <replaceable class="parameter">reftable</replaceable> [ ( <replaceable class="parameter">refcolumn</replaceable> [, ... ] ) ]
[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE <replaceable class="parameter">referential_action</replaceable> ] [ ON UPDATE <replaceable class="parameter">referential_action</replaceable> ] | [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE <replaceable class="parameter">referential_action</replaceable> ] [ ON UPDATE <replaceable class="parameter">referential_action</replaceable> ] }
NOT NULL <replaceable class="parameter">column_name</replaceable> [ NO INHERIT ]
}
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
<phrase>and <replaceable class="parameter">table_constraint_using_index</replaceable> is:</phrase> <phrase>and <replaceable class="parameter">table_constraint_using_index</replaceable> is:</phrase>
@ -1765,17 +1763,11 @@ ALTER TABLE measurement
<title>Compatibility</title> <title>Compatibility</title>
<para> <para>
The forms <literal>ADD COLUMN</literal> The forms <literal>ADD</literal> (without <literal>USING INDEX</literal>),
<literal>DROP [COLUMN]</literal>, <literal>DROP IDENTITY</literal>, <literal>RESTART</literal>, <literal>DROP [COLUMN]</literal>, <literal>DROP IDENTITY</literal>, <literal>RESTART</literal>,
<literal>SET DEFAULT</literal>, <literal>SET DATA TYPE</literal> (without <literal>USING</literal>), <literal>SET DEFAULT</literal>, <literal>SET DATA TYPE</literal> (without <literal>USING</literal>),
<literal>SET GENERATED</literal>, and <literal>SET <replaceable>sequence_option</replaceable></literal> <literal>SET GENERATED</literal>, and <literal>SET <replaceable>sequence_option</replaceable></literal>
conform with the SQL standard. conform with the SQL standard. The other forms are
The form <literal>ADD <replaceable>table_constraint</replaceable></literal>
conforms with the SQL standard when the <literal>USING INDEX</literal> and
<literal>NOT VALID</literal> clauses are omitted and the constraint type is
one of <literal>UNIQUE</literal>, <literal>PRIMARY KEY</literal>
or <literal>REFERENCES</literal>.
The other forms are
<productname>PostgreSQL</productname> extensions of the SQL standard. <productname>PostgreSQL</productname> extensions of the SQL standard.
Also, the ability to specify more than one manipulation in a single Also, the ability to specify more than one manipulation in a single
<command>ALTER TABLE</command> command is an extension. <command>ALTER TABLE</command> command is an extension.

View File

@ -77,7 +77,6 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
[ CONSTRAINT <replaceable class="parameter">constraint_name</replaceable> ] [ CONSTRAINT <replaceable class="parameter">constraint_name</replaceable> ]
{ CHECK ( <replaceable class="parameter">expression</replaceable> ) [ NO INHERIT ] | { CHECK ( <replaceable class="parameter">expression</replaceable> ) [ NO INHERIT ] |
NOT NULL <replaceable class="parameter">column_name</replaceable> |
UNIQUE [ NULLS [ NOT ] DISTINCT ] ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> | UNIQUE [ NULLS [ NOT ] DISTINCT ] ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> |
PRIMARY KEY ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> | PRIMARY KEY ( <replaceable class="parameter">column_name</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> |
EXCLUDE [ USING <replaceable class="parameter">index_method</replaceable> ] ( <replaceable class="parameter">exclude_element</replaceable> WITH <replaceable class="parameter">operator</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> [ WHERE ( <replaceable class="parameter">predicate</replaceable> ) ] | EXCLUDE [ USING <replaceable class="parameter">index_method</replaceable> ] ( <replaceable class="parameter">exclude_element</replaceable> WITH <replaceable class="parameter">operator</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> [ WHERE ( <replaceable class="parameter">predicate</replaceable> ) ] |
@ -2315,6 +2314,13 @@ CREATE TABLE cities_partdef
constraint, and index names must be unique across all relations within constraint, and index names must be unique across all relations within
the same schema. the same schema.
</para> </para>
<para>
Currently, <productname>PostgreSQL</productname> does not record names
for <literal>NOT NULL</literal> constraints at all, so they are not
subject to the uniqueness restriction. This might change in a future
release.
</para>
</refsect2> </refsect2>
<refsect2> <refsect2>

View File

@ -2160,57 +2160,6 @@ StoreRelCheck(Relation rel, const char *ccname, Node *expr,
return constrOid; return constrOid;
} }
/*
* Store a NOT NULL constraint for the given relation
*
* The OID of the new constraint is returned.
*/
static Oid
StoreRelNotNull(Relation rel, const char *nnname, AttrNumber attnum,
bool is_validated, bool is_local, int inhcount,
bool is_no_inherit)
{
int16 attNos;
Oid constrOid;
/* We only ever store one column per constraint */
attNos = attnum;
constrOid =
CreateConstraintEntry(nnname,
RelationGetNamespace(rel),
CONSTRAINT_NOTNULL,
false,
false,
is_validated,
InvalidOid,
RelationGetRelid(rel),
&attNos,
1,
1,
InvalidOid, /* not a domain constraint */
InvalidOid, /* no associated index */
InvalidOid, /* Foreign key fields */
NULL,
NULL,
NULL,
NULL,
0,
' ',
' ',
NULL,
0,
' ',
NULL, /* not an exclusion constraint */
NULL,
NULL,
is_local,
inhcount,
is_no_inherit,
false);
return constrOid;
}
/* /*
* Store defaults and constraints (passed as a list of CookedConstraint). * Store defaults and constraints (passed as a list of CookedConstraint).
* *
@ -2255,14 +2204,6 @@ StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal)
is_internal); is_internal);
numchecks++; numchecks++;
break; break;
case CONSTR_NOTNULL:
con->conoid =
StoreRelNotNull(rel, con->name, con->attnum,
!con->skip_validation, con->is_local,
con->inhcount, con->is_no_inherit);
break;
default: default:
elog(ERROR, "unrecognized constraint type: %d", elog(ERROR, "unrecognized constraint type: %d",
(int) con->contype); (int) con->contype);
@ -2318,7 +2259,6 @@ AddRelationNewConstraints(Relation rel,
ParseNamespaceItem *nsitem; ParseNamespaceItem *nsitem;
int numchecks; int numchecks;
List *checknames; List *checknames;
List *nnnames;
ListCell *cell; ListCell *cell;
Node *expr; Node *expr;
CookedConstraint *cooked; CookedConstraint *cooked;
@ -2404,179 +2344,130 @@ AddRelationNewConstraints(Relation rel,
*/ */
numchecks = numoldchecks; numchecks = numoldchecks;
checknames = NIL; checknames = NIL;
nnnames = NIL;
foreach(cell, newConstraints) foreach(cell, newConstraints)
{ {
Constraint *cdef = (Constraint *) lfirst(cell); Constraint *cdef = (Constraint *) lfirst(cell);
char *ccname;
Oid constrOid; Oid constrOid;
if (cdef->contype == CONSTR_CHECK) if (cdef->contype != CONSTR_CHECK)
continue;
if (cdef->raw_expr != NULL)
{ {
char *ccname; Assert(cdef->cooked_expr == NULL);
/* /*
* XXX Should we detect the case with CHECK (foo IS NOT NULL) and * Transform raw parsetree to executable expression, and verify
* handle it as a NOT NULL constraint? * it's valid as a CHECK constraint.
*/ */
expr = cookConstraint(pstate, cdef->raw_expr,
if (cdef->raw_expr != NULL) RelationGetRelationName(rel));
{
Assert(cdef->cooked_expr == NULL);
/*
* Transform raw parsetree to executable expression, and
* verify it's valid as a CHECK constraint.
*/
expr = cookConstraint(pstate, cdef->raw_expr,
RelationGetRelationName(rel));
}
else
{
Assert(cdef->cooked_expr != NULL);
/*
* Here, we assume the parser will only pass us valid CHECK
* expressions, so we do no particular checking.
*/
expr = stringToNode(cdef->cooked_expr);
}
/*
* Check name uniqueness, or generate a name if none was given.
*/
if (cdef->conname != NULL)
{
ListCell *cell2;
ccname = cdef->conname;
/* Check against other new constraints */
/* Needed because we don't do CommandCounterIncrement in loop */
foreach(cell2, checknames)
{
if (strcmp((char *) lfirst(cell2), ccname) == 0)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("check constraint \"%s\" already exists",
ccname)));
}
/* save name for future checks */
checknames = lappend(checknames, ccname);
/*
* Check against pre-existing constraints. If we are allowed
* to merge with an existing constraint, there's no more to do
* here. (We omit the duplicate constraint from the result,
* which is what ATAddCheckConstraint wants.)
*/
if (MergeWithExistingConstraint(rel, ccname, expr,
allow_merge, is_local,
cdef->initially_valid,
cdef->is_no_inherit))
continue;
}
else
{
/*
* When generating a name, we want to create "tab_col_check"
* for a column constraint and "tab_check" for a table
* constraint. We no longer have any info about the syntactic
* positioning of the constraint phrase, so we approximate
* this by seeing whether the expression references more than
* one column. (If the user played by the rules, the result
* is the same...)
*
* Note: pull_var_clause() doesn't descend into sublinks, but
* we eliminated those above; and anyway this only needs to be
* an approximate answer.
*/
List *vars;
char *colname;
vars = pull_var_clause(expr, 0);
/* eliminate duplicates */
vars = list_union(NIL, vars);
if (list_length(vars) == 1)
colname = get_attname(RelationGetRelid(rel),
((Var *) linitial(vars))->varattno,
true);
else
colname = NULL;
ccname = ChooseConstraintName(RelationGetRelationName(rel),
colname,
"check",
RelationGetNamespace(rel),
checknames);
/* save name for future checks */
checknames = lappend(checknames, ccname);
}
/*
* OK, store it.
*/
constrOid =
StoreRelCheck(rel, ccname, expr, cdef->initially_valid, is_local,
is_local ? 0 : 1, cdef->is_no_inherit, is_internal);
numchecks++;
cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
cooked->contype = CONSTR_CHECK;
cooked->conoid = constrOid;
cooked->name = ccname;
cooked->attnum = 0;
cooked->expr = expr;
cooked->skip_validation = cdef->skip_validation;
cooked->is_local = is_local;
cooked->inhcount = is_local ? 0 : 1;
cooked->is_no_inherit = cdef->is_no_inherit;
cookedConstraints = lappend(cookedConstraints, cooked);
} }
else if (cdef->contype == CONSTR_NOTNULL) else
{ {
CookedConstraint *nncooked; Assert(cdef->cooked_expr != NULL);
AttrNumber colnum;
char *nnname;
colnum = get_attnum(RelationGetRelid(rel), /*
cdef->colname); * Here, we assume the parser will only pass us valid CHECK
if (colnum == InvalidAttrNumber) * expressions, so we do no particular checking.
elog(ERROR, "invalid column name \"%s\"", cdef->colname); */
expr = stringToNode(cdef->cooked_expr);
if (cdef->conname)
nnname = cdef->conname; /* verify clash? */
else
nnname = ChooseConstraintName(RelationGetRelationName(rel),
cdef->colname,
"not_null",
RelationGetNamespace(rel),
nnnames);
nnnames = lappend(nnnames, nnname);
constrOid =
StoreRelNotNull(rel, nnname, colnum,
cdef->initially_valid,
is_local,
is_local ? 0 : 1,
cdef->is_no_inherit);
nncooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
nncooked->contype = CONSTR_NOTNULL;
nncooked->conoid = constrOid;
nncooked->name = nnname;
nncooked->attnum = colnum;
nncooked->expr = NULL;
nncooked->skip_validation = cdef->skip_validation;
nncooked->is_local = is_local;
nncooked->inhcount = is_local ? 0 : 1;
nncooked->is_no_inherit = cdef->is_no_inherit;
cookedConstraints = lappend(cookedConstraints, nncooked);
} }
/*
* Check name uniqueness, or generate a name if none was given.
*/
if (cdef->conname != NULL)
{
ListCell *cell2;
ccname = cdef->conname;
/* Check against other new constraints */
/* Needed because we don't do CommandCounterIncrement in loop */
foreach(cell2, checknames)
{
if (strcmp((char *) lfirst(cell2), ccname) == 0)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("check constraint \"%s\" already exists",
ccname)));
}
/* save name for future checks */
checknames = lappend(checknames, ccname);
/*
* Check against pre-existing constraints. If we are allowed to
* merge with an existing constraint, there's no more to do here.
* (We omit the duplicate constraint from the result, which is
* what ATAddCheckConstraint wants.)
*/
if (MergeWithExistingConstraint(rel, ccname, expr,
allow_merge, is_local,
cdef->initially_valid,
cdef->is_no_inherit))
continue;
}
else
{
/*
* When generating a name, we want to create "tab_col_check" for a
* column constraint and "tab_check" for a table constraint. We
* no longer have any info about the syntactic positioning of the
* constraint phrase, so we approximate this by seeing whether the
* expression references more than one column. (If the user
* played by the rules, the result is the same...)
*
* Note: pull_var_clause() doesn't descend into sublinks, but we
* eliminated those above; and anyway this only needs to be an
* approximate answer.
*/
List *vars;
char *colname;
vars = pull_var_clause(expr, 0);
/* eliminate duplicates */
vars = list_union(NIL, vars);
if (list_length(vars) == 1)
colname = get_attname(RelationGetRelid(rel),
((Var *) linitial(vars))->varattno,
true);
else
colname = NULL;
ccname = ChooseConstraintName(RelationGetRelationName(rel),
colname,
"check",
RelationGetNamespace(rel),
checknames);
/* save name for future checks */
checknames = lappend(checknames, ccname);
}
/*
* OK, store it.
*/
constrOid =
StoreRelCheck(rel, ccname, expr, cdef->initially_valid, is_local,
is_local ? 0 : 1, cdef->is_no_inherit, is_internal);
numchecks++;
cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
cooked->contype = CONSTR_CHECK;
cooked->conoid = constrOid;
cooked->name = ccname;
cooked->attnum = 0;
cooked->expr = expr;
cooked->skip_validation = cdef->skip_validation;
cooked->is_local = is_local;
cooked->inhcount = is_local ? 0 : 1;
cooked->is_no_inherit = cdef->is_no_inherit;
cookedConstraints = lappend(cookedConstraints, cooked);
} }
/* /*
@ -2746,190 +2637,6 @@ MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr,
return found; return found;
} }
/* list_sort comparator to sort CookedConstraint by attnum */
static int
list_cookedconstr_attnum_cmp(const ListCell *p1, const ListCell *p2)
{
AttrNumber v1 = ((CookedConstraint *) lfirst(p1))->attnum;
AttrNumber v2 = ((CookedConstraint *) lfirst(p2))->attnum;
if (v1 < v2)
return -1;
if (v1 > v2)
return 1;
return 0;
}
/*
* Create the NOT NULL constraints for the relation
*
* These come from two sources: the 'constraints' list (of Constraint) is
* specified directly by the user; the 'old_notnulls' list (of
* CookedConstraint) comes from inheritance. We create one constraint
* for each column, giving priority to user-specified ones, and setting
* inhcount according to how many parents cause each column to get a
* NOT NULL constraint. If a user-specified name clashes with another
* user-specified name, an error is raised.
*
* Note that inherited constraints have two shapes: those coming from another
* NOT NULL constraint in the parent, which have a name already, and those
* coming from a PRIMARY KEY in the parent, which don't. Any name specified
* in a parent is disregarded in case of a conflict.
*
* Returns a list of AttrNumber for columns that need to have the attnotnull
* flag set.
*/
List *
AddRelationNotNullConstraints(Relation rel, List *constraints,
List *old_notnulls)
{
List *nnnames = NIL;
List *givennames = NIL;
List *nncols = NIL;
ListCell *lc;
/*
* First, create all NOT NULLs that are directly specified by the user.
* Note that inheritance might have given us another source for each, so
* we must scan the old_notnulls list and increment inhcount for each
* element with identical attnum. We delete from there any element that
* we process.
*/
foreach(lc, constraints)
{
Constraint *constr = lfirst_node(Constraint, lc);
AttrNumber attnum;
char *conname;
bool is_local = true;
int inhcount = 0;
ListCell *lc2;
attnum = get_attnum(RelationGetRelid(rel), constr->colname);
foreach(lc2, old_notnulls)
{
CookedConstraint *old = (CookedConstraint *) lfirst(lc2);
if (old->attnum == attnum)
{
inhcount++;
old_notnulls = foreach_delete_current(old_notnulls, lc2);
}
}
/*
* Determine a constraint name, which may have been specified by the
* user, or raise an error if a conflict exists with another
* user-specified name.
*/
if (constr->conname)
{
foreach(lc2, givennames)
{
if (strcmp(lfirst(lc2), conname) == 0)
ereport(ERROR,
errmsg("constraint name \"%s\" is already in use in relation \"%s\"",
constr->conname,
RelationGetRelationName(rel)));
}
conname = constr->conname;
givennames = lappend(givennames, conname);
}
else
conname = ChooseConstraintName(RelationGetRelationName(rel),
get_attname(RelationGetRelid(rel),
attnum, false),
"not_null",
RelationGetNamespace(rel),
nnnames);
nnnames = lappend(nnnames, conname);
StoreRelNotNull(rel, conname,
attnum, true, is_local,
inhcount, constr->is_no_inherit);
nncols = lappend_int(nncols, attnum);
}
/*
* If any column remains in the additional_notnulls list, we must create a
* NOT NULL constraint marked not-local. Because multiple parents could
* specify a NOT NULL for the same column, we must count how many there
* are and set inhcount accordingly, deleting elements we've already
* processed.
*
* We don't use foreach() here because we have two nested loops over the
* cooked constraint list, with possible element deletions in the inner one.
* If we used foreach_delete_current() it could only fix up the state of one
* of the loops, so it seems cleaner to use looping over list indexes for
* both loops. Note that any deletion will happen beyond where the outer
* loop is, so its index never needs adjustment.
*/
list_sort(old_notnulls, list_cookedconstr_attnum_cmp);
for (int outerpos = 0; outerpos < list_length(old_notnulls); outerpos++)
{
CookedConstraint *cooked;
char *conname = NULL;
int inhcount = 1;
ListCell *lc2;
cooked = (CookedConstraint *) list_nth(old_notnulls, outerpos);
/* We just preserve the first constraint name we come across, if any */
if (conname == NULL && cooked->name)
conname = cooked->name;
for (int restpos = outerpos + 1; restpos < list_length(old_notnulls);)
{
CookedConstraint *other;
other = (CookedConstraint *) list_nth(old_notnulls, restpos);
if (other->attnum == cooked->attnum)
{
if (conname == NULL && other->name)
conname = other->name;
inhcount++;
old_notnulls = list_delete_nth_cell(old_notnulls, restpos);
}
else
restpos++;
}
/* If we got a name, make sure it isn't one we've already used */
if (conname != NULL)
{
foreach(lc2, nnnames)
{
if (strcmp(lfirst(lc2), conname) == 0)
{
conname = NULL;
break;
}
}
}
/* and choose a name, if needed */
if (conname == NULL)
conname = ChooseConstraintName(RelationGetRelationName(rel),
get_attname(RelationGetRelid(rel),
cooked->attnum, false),
"not_null",
RelationGetNamespace(rel),
nnnames);
nnnames = lappend(nnnames, conname);
StoreRelNotNull(rel, conname, cooked->attnum, true,
false, inhcount,
cooked->is_no_inherit);
nncols = lappend_int(nncols, cooked->attnum);
}
return nncols;
}
/* /*
* Update the count of constraints in the relation's pg_class tuple. * Update the count of constraints in the relation's pg_class tuple.
* *

View File

@ -562,103 +562,6 @@ ChooseConstraintName(const char *name1, const char *name2,
return conname; return conname;
} }
/*
* Find and return the pg_constraint tuple that implements a validated
* NOT NULL constraint for the given column of the given relation.
*
* XXX This would be easier if we had pg_attribute.notnullconstr with the OID
* of the constraint that implements the NOT NULL constraint for that column.
* I'm not sure it's worth the catalog bloat and de-normalization, however.
*/
HeapTuple
findNotNullConstraintAttnum(Relation rel, AttrNumber attnum)
{
Relation pg_constraint;
HeapTuple conTup,
retval = NULL;
SysScanDesc scan;
ScanKeyData key;
pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
ScanKeyInit(&key,
Anum_pg_constraint_conrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
true, NULL, 1, &key);
while (HeapTupleIsValid(conTup = systable_getnext(scan)))
{
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(conTup);
AttrNumber conkey;
/*
* We're looking for a NOTNULL constraint that's marked validated,
* with the column we're looking for as the sole element in conkey.
*/
if (con->contype != CONSTRAINT_NOTNULL)
continue;
if (!con->convalidated)
continue;
conkey = extractNotNullColumn(conTup);
if (conkey != attnum)
continue;
/* Found it */
retval = heap_copytuple(conTup);
break;
}
systable_endscan(scan);
table_close(pg_constraint, AccessShareLock);
return retval;
}
/*
* Find and return the pg_constraint tuple that implements a validated
* NOT NULL constraint for the given column of the given relation.
*/
HeapTuple
findNotNullConstraint(Relation rel, const char *colname)
{
AttrNumber attnum = get_attnum(RelationGetRelid(rel), colname);
return findNotNullConstraintAttnum(rel, attnum);
}
/*
* Given a pg_constraint tuple for a NOT NULL constraint, return the column
* number it is for.
*/
AttrNumber
extractNotNullColumn(HeapTuple constrTup)
{
AttrNumber colnum;
Datum adatum;
ArrayType *arr;
/* only tuples for CHECK constraints should be given */
Assert(((Form_pg_constraint) GETSTRUCT(constrTup))->contype == CONSTRAINT_NOTNULL);
adatum = SysCacheGetAttrNotNull(CONSTROID, constrTup,
Anum_pg_constraint_conkey);
arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
if (ARR_NDIM(arr) != 1 ||
ARR_HASNULL(arr) ||
ARR_ELEMTYPE(arr) != INT2OID ||
ARR_DIMS(arr)[0] != 1)
elog(ERROR, "conkey is not a 1-D smallint array");
memcpy(&colnum, ARR_DATA_PTR(arr), sizeof(AttrNumber));
if ((Pointer) arr != DatumGetPointer(adatum))
pfree(arr); /* free de-toasted copy, if any */
return colnum;
}
/* /*
* Delete a single constraint record. * Delete a single constraint record.
*/ */

File diff suppressed because it is too large Load Diff

View File

@ -717,10 +717,6 @@ _outConstraint(StringInfo str, const Constraint *node)
case CONSTR_NOTNULL: case CONSTR_NOTNULL:
appendStringInfoString(str, "NOT_NULL"); appendStringInfoString(str, "NOT_NULL");
WRITE_BOOL_FIELD(is_no_inherit);
WRITE_STRING_FIELD(colname);
WRITE_BOOL_FIELD(skip_validation);
WRITE_BOOL_FIELD(initially_valid);
break; break;
case CONSTR_DEFAULT: case CONSTR_DEFAULT:

View File

@ -390,14 +390,8 @@ _readConstraint(void)
switch (local_node->contype) switch (local_node->contype)
{ {
case CONSTR_NULL: case CONSTR_NULL:
/* no extra fields */
break;
case CONSTR_NOTNULL: case CONSTR_NOTNULL:
READ_BOOL_FIELD(is_no_inherit); /* no extra fields */
READ_STRING_FIELD(colname);
READ_BOOL_FIELD(skip_validation);
READ_BOOL_FIELD(initially_valid);
break; break;
case CONSTR_DEFAULT: case CONSTR_DEFAULT:

View File

@ -1644,8 +1644,6 @@ relation_excluded_by_constraints(PlannerInfo *root,
* Currently, attnotnull constraints must be treated as NO INHERIT unless * Currently, attnotnull constraints must be treated as NO INHERIT unless
* this is a partitioned table. In future we might track their * this is a partitioned table. In future we might track their
* inheritance status more accurately, allowing this to be refined. * inheritance status more accurately, allowing this to be refined.
*
* XXX do we need/want to change this?
*/ */
include_notnull = (!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE); include_notnull = (!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE);

View File

@ -4099,19 +4099,6 @@ ConstraintElem:
n->initially_valid = !n->skip_validation; n->initially_valid = !n->skip_validation;
$$ = (Node *) n; $$ = (Node *) n;
} }
| NOT NULL_P ColId ConstraintAttributeSpec
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_NOTNULL;
n->location = @1;
n->colname = $3;
processCASbits($4, @4, "NOT NULL",
NULL, NULL, NULL,
&n->is_no_inherit, yyscanner);
n->initially_valid = !n->skip_validation;
$$ = (Node *) n;
}
| UNIQUE opt_unique_null_treatment '(' columnList ')' opt_c_include opt_definition OptConsTableSpace | UNIQUE opt_unique_null_treatment '(' columnList ')' opt_c_include opt_definition OptConsTableSpace
ConstraintAttributeSpec ConstraintAttributeSpec
{ {

View File

@ -83,7 +83,6 @@ typedef struct
List *ckconstraints; /* CHECK constraints */ List *ckconstraints; /* CHECK constraints */
List *fkconstraints; /* FOREIGN KEY constraints */ List *fkconstraints; /* FOREIGN KEY constraints */
List *ixconstraints; /* index-creating constraints */ List *ixconstraints; /* index-creating constraints */
List *nnconstraints; /* NOT NULL constraints */
List *likeclauses; /* LIKE clauses that need post-processing */ List *likeclauses; /* LIKE clauses that need post-processing */
List *extstats; /* cloned extended statistics */ List *extstats; /* cloned extended statistics */
List *blist; /* "before list" of things to do before List *blist; /* "before list" of things to do before
@ -245,7 +244,6 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
cxt.ckconstraints = NIL; cxt.ckconstraints = NIL;
cxt.fkconstraints = NIL; cxt.fkconstraints = NIL;
cxt.ixconstraints = NIL; cxt.ixconstraints = NIL;
cxt.nnconstraints = NIL;
cxt.likeclauses = NIL; cxt.likeclauses = NIL;
cxt.extstats = NIL; cxt.extstats = NIL;
cxt.blist = NIL; cxt.blist = NIL;
@ -350,7 +348,6 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
*/ */
stmt->tableElts = cxt.columns; stmt->tableElts = cxt.columns;
stmt->constraints = cxt.ckconstraints; stmt->constraints = cxt.ckconstraints;
stmt->nnconstraints = cxt.nnconstraints;
result = lappend(cxt.blist, stmt); result = lappend(cxt.blist, stmt);
result = list_concat(result, cxt.alist); result = list_concat(result, cxt.alist);
@ -540,7 +537,6 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
bool saw_default; bool saw_default;
bool saw_identity; bool saw_identity;
bool saw_generated; bool saw_generated;
bool need_notnull = false;
ListCell *clist; ListCell *clist;
cxt->columns = lappend(cxt->columns, column); cxt->columns = lappend(cxt->columns, column);
@ -638,8 +634,10 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
constraint->cooked_expr = NULL; constraint->cooked_expr = NULL;
column->constraints = lappend(column->constraints, constraint); column->constraints = lappend(column->constraints, constraint);
/* have a NOT NULL constraint added later */ constraint = makeNode(Constraint);
need_notnull = true; constraint->contype = CONSTR_NOTNULL;
constraint->location = -1;
column->constraints = lappend(column->constraints, constraint);
} }
/* Process column constraints, if any... */ /* Process column constraints, if any... */
@ -657,7 +655,7 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
switch (constraint->contype) switch (constraint->contype)
{ {
case CONSTR_NULL: case CONSTR_NULL:
if ((saw_nullable && column->is_not_null) || need_notnull) if (saw_nullable && column->is_not_null)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"", errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
@ -669,58 +667,15 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
break; break;
case CONSTR_NOTNULL: case CONSTR_NOTNULL:
if (saw_nullable && !column->is_not_null)
/* ereport(ERROR,
* For NOT NULL declarations, we need to mark the column as (errcode(ERRCODE_SYNTAX_ERROR),
* not nullable, and set things up to have a CHECK constraint errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
* created. Also, duplicate NOT NULL declarations are not column->colname, cxt->relation->relname),
* allowed. parser_errposition(cxt->pstate,
*/ constraint->location)));
if (saw_nullable) column->is_not_null = true;
{ saw_nullable = true;
if (!column->is_not_null)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
column->colname, cxt->relation->relname),
parser_errposition(cxt->pstate,
constraint->location)));
else
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("redundant NOT NULL declarations for column \"%s\" of table \"%s\"",
column->colname, cxt->relation->relname),
parser_errposition(cxt->pstate,
constraint->location));
}
/*
* If this is the first time we see this column being marked
* not null, keep track to later add a NOT NULL constraint.
*/
if (!column->is_not_null)
{
Constraint *notnull;
column->is_not_null = true;
saw_nullable = true;
notnull = makeNode(Constraint);
notnull->contype = CONSTR_NOTNULL;
notnull->conname = constraint->conname;
notnull->deferrable = false;
notnull->initdeferred = false;
notnull->location = -1;
notnull->colname = column->colname;
notnull->skip_validation = false;
notnull->initially_valid = true;
cxt->nnconstraints = lappend(cxt->nnconstraints, notnull);
/* Don't need this anymore, if we had it */
need_notnull = false;
}
break; break;
case CONSTR_DEFAULT: case CONSTR_DEFAULT:
@ -770,19 +725,16 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
column->identity = constraint->generated_when; column->identity = constraint->generated_when;
saw_identity = true; saw_identity = true;
/* /* An identity column is implicitly NOT NULL */
* Identity columns are always NOT NULL, but we may have a if (saw_nullable && !column->is_not_null)
* constraint already.
*/
if (!saw_nullable)
need_notnull = true;
else if (!column->is_not_null)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"", errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
column->colname, cxt->relation->relname), column->colname, cxt->relation->relname),
parser_errposition(cxt->pstate, parser_errposition(cxt->pstate,
constraint->location))); constraint->location)));
column->is_not_null = true;
saw_nullable = true;
break; break;
} }
@ -806,11 +758,6 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
case CONSTR_CHECK: case CONSTR_CHECK:
cxt->ckconstraints = lappend(cxt->ckconstraints, constraint); cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
/*
* XXX If the user says CHECK (IS NOT NULL), should we turn
* that into a regular NOT NULL constraint?
*/
break; break;
case CONSTR_PRIMARY: case CONSTR_PRIMARY:
@ -893,29 +840,6 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
constraint->location))); constraint->location)));
} }
/*
* If we need a NOT NULL constraint for SERIAL or IDENTITY, and one was
* not explicitly specified, add one now.
*/
if (need_notnull && !(saw_nullable && column->is_not_null))
{
Constraint *notnull;
column->is_not_null = true;
notnull = makeNode(Constraint);
notnull->contype = CONSTR_NOTNULL;
notnull->conname = NULL;
notnull->deferrable = false;
notnull->initdeferred = false;
notnull->location = -1;
notnull->colname = column->colname;
notnull->skip_validation = false;
notnull->initially_valid = true;
cxt->nnconstraints = lappend(cxt->nnconstraints, notnull);
}
/* /*
* If needed, generate ALTER FOREIGN TABLE ALTER COLUMN statement to add * If needed, generate ALTER FOREIGN TABLE ALTER COLUMN statement to add
* per-column foreign data wrapper options to this column after creation. * per-column foreign data wrapper options to this column after creation.
@ -991,10 +915,6 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
cxt->ckconstraints = lappend(cxt->ckconstraints, constraint); cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
break; break;
case CONSTR_NOTNULL:
cxt->nnconstraints = lappend(cxt->nnconstraints, constraint);
break;
case CONSTR_FOREIGN: case CONSTR_FOREIGN:
if (cxt->isforeign) if (cxt->isforeign)
ereport(ERROR, ereport(ERROR,
@ -1006,6 +926,7 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
break; break;
case CONSTR_NULL: case CONSTR_NULL:
case CONSTR_NOTNULL:
case CONSTR_DEFAULT: case CONSTR_DEFAULT:
case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_DEFERRABLE:
case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE:
@ -1041,7 +962,6 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
AclResult aclresult; AclResult aclresult;
char *comment; char *comment;
ParseCallbackState pcbstate; ParseCallbackState pcbstate;
bool process_notnull_constraints = false;
setup_parser_errposition_callback(&pcbstate, cxt->pstate, setup_parser_errposition_callback(&pcbstate, cxt->pstate,
table_like_clause->relation->location); table_like_clause->relation->location);
@ -1123,8 +1043,6 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
def->inhcount = 0; def->inhcount = 0;
def->is_local = true; def->is_local = true;
def->is_not_null = attribute->attnotnull; def->is_not_null = attribute->attnotnull;
if (attribute->attnotnull)
process_notnull_constraints = true;
def->is_from_type = false; def->is_from_type = false;
def->storage = 0; def->storage = 0;
def->raw_default = NULL; def->raw_default = NULL;
@ -1206,19 +1124,14 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
* we don't yet know what column numbers the copied columns will have in * we don't yet know what column numbers the copied columns will have in
* the finished table. If any of those options are specified, add the * the finished table. If any of those options are specified, add the
* LIKE clause to cxt->likeclauses so that expandTableLikeClause will be * LIKE clause to cxt->likeclauses so that expandTableLikeClause will be
* called after we do know that; in addition, do that if there are any NOT * called after we do know that. Also, remember the relation OID so that
* NULL constraints, because those must be propagated even if not
* explicitly requested.
*
* In order for this to work, we remember the relation OID so that
* expandTableLikeClause is certain to open the same table. * expandTableLikeClause is certain to open the same table.
*/ */
if ((table_like_clause->options & if (table_like_clause->options &
(CREATE_TABLE_LIKE_DEFAULTS | (CREATE_TABLE_LIKE_DEFAULTS |
CREATE_TABLE_LIKE_GENERATED | CREATE_TABLE_LIKE_GENERATED |
CREATE_TABLE_LIKE_CONSTRAINTS | CREATE_TABLE_LIKE_CONSTRAINTS |
CREATE_TABLE_LIKE_INDEXES)) || CREATE_TABLE_LIKE_INDEXES))
process_notnull_constraints)
{ {
table_like_clause->relationOid = RelationGetRelid(relation); table_like_clause->relationOid = RelationGetRelid(relation);
cxt->likeclauses = lappend(cxt->likeclauses, table_like_clause); cxt->likeclauses = lappend(cxt->likeclauses, table_like_clause);
@ -1290,7 +1203,6 @@ expandTableLikeClause(RangeVar *heapRel, TableLikeClause *table_like_clause)
TupleConstr *constr; TupleConstr *constr;
AttrMap *attmap; AttrMap *attmap;
char *comment; char *comment;
ListCell *lc;
/* /*
* Open the relation referenced by the LIKE clause. We should still have * Open the relation referenced by the LIKE clause. We should still have
@ -1470,20 +1382,6 @@ expandTableLikeClause(RangeVar *heapRel, TableLikeClause *table_like_clause)
} }
} }
/*
* Copy NOT NULL constraints, too (these do not require any option to have
* been given).
*/
foreach(lc, RelationGetNotNullConstraints(relation, false))
{
AlterTableCmd *atsubcmd;
atsubcmd = makeNode(AlterTableCmd);
atsubcmd->subtype = AT_AddConstraint;
atsubcmd->def = (Node *) lfirst_node(Constraint, lc);
atsubcmds = lappend(atsubcmds, atsubcmd);
}
/* /*
* If we generated any ALTER TABLE actions above, wrap them into a single * If we generated any ALTER TABLE actions above, wrap them into a single
* ALTER TABLE command. Stick it at the front of the result, so it runs * ALTER TABLE command. Stick it at the front of the result, so it runs
@ -2161,12 +2059,10 @@ transformIndexConstraints(CreateStmtContext *cxt)
ListCell *lc; ListCell *lc;
/* /*
* Run through the constraints that need to generate an index, and do so. * Run through the constraints that need to generate an index. For PRIMARY
* * KEY, mark each column as NOT NULL and create an index. For UNIQUE or
* For PRIMARY KEY, in addition we set each column's attnotnull flag true. * EXCLUDE, create an index as for PRIMARY KEY, but do not insist on NOT
* We do not create a separate CHECK (IS NOT NULL) constraint, as that * NULL.
* would be redundant: the PRIMARY KEY constraint itself fulfills that
* role. Other constraint types don't need any NOT NULL markings.
*/ */
foreach(lc, cxt->ixconstraints) foreach(lc, cxt->ixconstraints)
{ {
@ -2240,7 +2136,9 @@ transformIndexConstraints(CreateStmtContext *cxt)
} }
/* /*
* Now append all the IndexStmts to cxt->alist. * Now append all the IndexStmts to cxt->alist. If we generated an ALTER
* TABLE SET NOT NULL statement to support a primary key, it's already in
* cxt->alist.
*/ */
cxt->alist = list_concat(cxt->alist, finalindexlist); cxt->alist = list_concat(cxt->alist, finalindexlist);
} }
@ -2248,10 +2146,12 @@ transformIndexConstraints(CreateStmtContext *cxt)
/* /*
* transformIndexConstraint * transformIndexConstraint
* Transform one UNIQUE, PRIMARY KEY, or EXCLUDE constraint for * Transform one UNIQUE, PRIMARY KEY, or EXCLUDE constraint for
* transformIndexConstraints. An IndexStmt is returned. * transformIndexConstraints.
* *
* For a PRIMARY KEY constraint, we additionally force the columns to be * We return an IndexStmt. For a PRIMARY KEY constraint, we additionally
* marked as NOT NULL, without producing a CHECK (IS NOT NULL) constraint. * produce NOT NULL constraints, either by marking ColumnDefs in cxt->columns
* as is_not_null or by adding an ALTER TABLE SET NOT NULL command to
* cxt->alist.
*/ */
static IndexStmt * static IndexStmt *
transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt) transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
@ -2517,6 +2417,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
{ {
char *key = strVal(lfirst(lc)); char *key = strVal(lfirst(lc));
bool found = false; bool found = false;
bool forced_not_null = false;
ColumnDef *column = NULL; ColumnDef *column = NULL;
ListCell *columns; ListCell *columns;
IndexElem *iparam; IndexElem *iparam;
@ -2537,14 +2438,13 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
* column is defined in the new table. For PRIMARY KEY, we * column is defined in the new table. For PRIMARY KEY, we
* can apply the NOT NULL constraint cheaply here ... unless * can apply the NOT NULL constraint cheaply here ... unless
* the column is marked is_from_type, in which case marking it * the column is marked is_from_type, in which case marking it
* here would be ineffective (see MergeAttributes). Note that * here would be ineffective (see MergeAttributes).
* this isn't effective in ALTER TABLE either, unless the
* column is being added in the same command.
*/ */
if (constraint->contype == CONSTR_PRIMARY && if (constraint->contype == CONSTR_PRIMARY &&
!column->is_from_type) !column->is_from_type)
{ {
column->is_not_null = true; column->is_not_null = true;
forced_not_null = true;
} }
} }
else if (SystemAttributeByName(key) != NULL) else if (SystemAttributeByName(key) != NULL)
@ -2587,6 +2487,14 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
if (strcmp(key, inhname) == 0) if (strcmp(key, inhname) == 0)
{ {
found = true; found = true;
/*
* It's tempting to set forced_not_null if the
* parent column is already NOT NULL, but that
* seems unsafe because the column's NOT NULL
* marking might disappear between now and
* execution. Do the runtime check to be safe.
*/
break; break;
} }
} }
@ -2640,11 +2548,15 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
iparam->nulls_ordering = SORTBY_NULLS_DEFAULT; iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
index->indexParams = lappend(index->indexParams, iparam); index->indexParams = lappend(index->indexParams, iparam);
if (constraint->contype == CONSTR_PRIMARY) /*
* For a primary-key column, also create an item for ALTER TABLE
* SET NOT NULL if we couldn't ensure it via is_not_null above.
*/
if (constraint->contype == CONSTR_PRIMARY && !forced_not_null)
{ {
AlterTableCmd *notnullcmd = makeNode(AlterTableCmd); AlterTableCmd *notnullcmd = makeNode(AlterTableCmd);
notnullcmd->subtype = AT_SetAttNotNull; notnullcmd->subtype = AT_SetNotNull;
notnullcmd->name = pstrdup(key); notnullcmd->name = pstrdup(key);
notnullcmds = lappend(notnullcmds, notnullcmd); notnullcmds = lappend(notnullcmds, notnullcmd);
} }
@ -3416,7 +3328,6 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
cxt.isalter = true; cxt.isalter = true;
cxt.columns = NIL; cxt.columns = NIL;
cxt.ckconstraints = NIL; cxt.ckconstraints = NIL;
cxt.nnconstraints = NIL;
cxt.fkconstraints = NIL; cxt.fkconstraints = NIL;
cxt.ixconstraints = NIL; cxt.ixconstraints = NIL;
cxt.likeclauses = NIL; cxt.likeclauses = NIL;
@ -3660,8 +3571,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
/* /*
* We assume here that cxt.alist contains only IndexStmts and possibly * We assume here that cxt.alist contains only IndexStmts and possibly
* AT_SetAttNotNull statements generated from primary key constraints. * ALTER TABLE SET NOT NULL statements generated from primary key
* We absorb the subcommands of the latter directly. * constraints. We absorb the subcommands of the latter directly.
*/ */
if (IsA(istmt, IndexStmt)) if (IsA(istmt, IndexStmt))
{ {
@ -3689,21 +3600,14 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
{ {
newcmd = makeNode(AlterTableCmd); newcmd = makeNode(AlterTableCmd);
newcmd->subtype = AT_AddConstraint; newcmd->subtype = AT_AddConstraint;
newcmd->def = (Node *) lfirst_node(Constraint, l); newcmd->def = (Node *) lfirst(l);
newcmds = lappend(newcmds, newcmd); newcmds = lappend(newcmds, newcmd);
} }
foreach(l, cxt.fkconstraints) foreach(l, cxt.fkconstraints)
{ {
newcmd = makeNode(AlterTableCmd); newcmd = makeNode(AlterTableCmd);
newcmd->subtype = AT_AddConstraint; newcmd->subtype = AT_AddConstraint;
newcmd->def = (Node *) lfirst_node(Constraint, l); newcmd->def = (Node *) lfirst(l);
newcmds = lappend(newcmds, newcmd);
}
foreach(l, cxt.nnconstraints)
{
newcmd = makeNode(AlterTableCmd);
newcmd->subtype = AT_AddConstraint;
newcmd->def = (Node *) lfirst_node(Constraint, l);
newcmds = lappend(newcmds, newcmd); newcmds = lappend(newcmds, newcmd);
} }

View File

@ -2472,20 +2472,6 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
conForm->connoinherit ? " NO INHERIT" : ""); conForm->connoinherit ? " NO INHERIT" : "");
break; break;
} }
case CONSTRAINT_NOTNULL:
{
AttrNumber attnum;
attnum = extractNotNullColumn(tup);
appendStringInfo(&buf, "NOT NULL %s",
quote_identifier(get_attname(conForm->conrelid,
attnum, false)));
if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
appendStringInfoString(&buf, " NO INHERIT");
break;
}
case CONSTRAINT_TRIGGER: case CONSTRAINT_TRIGGER:
/* /*

View File

@ -82,8 +82,7 @@ static catalogid_hash *catalogIdHash = NULL;
static void flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables, static void flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
InhInfo *inhinfo, int numInherits); InhInfo *inhinfo, int numInherits);
static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables); static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
static void flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
int numTables);
static int strInArray(const char *pattern, char **arr, int arr_size); static int strInArray(const char *pattern, char **arr, int arr_size);
static IndxInfo *findIndexByOid(Oid oid); static IndxInfo *findIndexByOid(Oid oid);
@ -227,7 +226,7 @@ getSchemaData(Archive *fout, int *numTablesPtr)
getTableAttrs(fout, tblinfo, numTables); getTableAttrs(fout, tblinfo, numTables);
pg_log_info("flagging inherited columns in subtables"); pg_log_info("flagging inherited columns in subtables");
flagInhAttrs(fout, fout->dopt, tblinfo, numTables); flagInhAttrs(fout->dopt, tblinfo, numTables);
pg_log_info("reading partitioning data"); pg_log_info("reading partitioning data");
getPartitioningInfo(fout); getPartitioningInfo(fout);
@ -472,8 +471,7 @@ flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
* What we need to do here is: * What we need to do here is:
* *
* - Detect child columns that inherit NOT NULL bits from their parents, so * - Detect child columns that inherit NOT NULL bits from their parents, so
* that we needn't specify that again for the child. (Versions >= 16 no * that we needn't specify that again for the child.
* longer need this.)
* *
* - Detect child columns that have DEFAULT NULL when their parents had some * - Detect child columns that have DEFAULT NULL when their parents had some
* non-null default. In this case, we make up a dummy AttrDefInfo object so * non-null default. In this case, we make up a dummy AttrDefInfo object so
@ -493,7 +491,7 @@ flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
* modifies tblinfo * modifies tblinfo
*/ */
static void static void
flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables) flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
{ {
int i, int i,
j, j,
@ -574,9 +572,8 @@ flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables
} }
} }
/* In versions < 16, remember if we found inherited NOT NULL */ /* Remember if we found inherited NOT NULL */
if (fout->remoteVersion < 160000) tbinfo->inhNotNull[j] = foundNotNull;
tbinfo->localNotNull[j] = !foundNotNull;
/* /*
* Manufacture a DEFAULT NULL clause if necessary. This breaks * Manufacture a DEFAULT NULL clause if necessary. This breaks

View File

@ -601,7 +601,6 @@ RestoreArchive(Archive *AHX)
if (strcmp(te->desc, "CONSTRAINT") == 0 || if (strcmp(te->desc, "CONSTRAINT") == 0 ||
strcmp(te->desc, "CHECK CONSTRAINT") == 0 || strcmp(te->desc, "CHECK CONSTRAINT") == 0 ||
strcmp(te->desc, "NOT NULL CONSTRAINT") == 0 ||
strcmp(te->desc, "FK CONSTRAINT") == 0) strcmp(te->desc, "FK CONSTRAINT") == 0)
strcpy(buffer, "DROP CONSTRAINT"); strcpy(buffer, "DROP CONSTRAINT");
else else
@ -3512,7 +3511,6 @@ _getObjectDescription(PQExpBuffer buf, const TocEntry *te)
/* these object types don't have separate owners */ /* these object types don't have separate owners */
else if (strcmp(type, "CAST") == 0 || else if (strcmp(type, "CAST") == 0 ||
strcmp(type, "CHECK CONSTRAINT") == 0 || strcmp(type, "CHECK CONSTRAINT") == 0 ||
strcmp(type, "NOT NULL CONSTRAINT") == 0 ||
strcmp(type, "CONSTRAINT") == 0 || strcmp(type, "CONSTRAINT") == 0 ||
strcmp(type, "DATABASE PROPERTIES") == 0 || strcmp(type, "DATABASE PROPERTIES") == 0 ||
strcmp(type, "DEFAULT") == 0 || strcmp(type, "DEFAULT") == 0 ||

View File

@ -8372,7 +8372,6 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
PQExpBuffer q = createPQExpBuffer(); PQExpBuffer q = createPQExpBuffer();
PQExpBuffer tbloids = createPQExpBuffer(); PQExpBuffer tbloids = createPQExpBuffer();
PQExpBuffer checkoids = createPQExpBuffer(); PQExpBuffer checkoids = createPQExpBuffer();
PQExpBuffer defaultoids = createPQExpBuffer();
PGresult *res; PGresult *res;
int ntups; int ntups;
int curtblindx; int curtblindx;
@ -8390,7 +8389,6 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
int i_attalign; int i_attalign;
int i_attislocal; int i_attislocal;
int i_attnotnull; int i_attnotnull;
int i_localnotnull;
int i_attoptions; int i_attoptions;
int i_attcollation; int i_attcollation;
int i_attcompression; int i_attcompression;
@ -8400,17 +8398,16 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
/* /*
* We want to perform just one query against pg_attribute, and then just * We want to perform just one query against pg_attribute, and then just
* one against pg_attrdef (for DEFAULTs) and two against pg_constraint * one against pg_attrdef (for DEFAULTs) and one against pg_constraint
* (for CHECK constraints and for NOT NULL constraints). However, we * (for CHECK constraints). However, we mustn't try to select every row
* mustn't try to select every row of those catalogs and then sort it out * of those catalogs and then sort it out on the client side, because some
* on the client side, because some of the server-side functions we need * of the server-side functions we need would be unsafe to apply to tables
* would be unsafe to apply to tables we don't have lock on. Hence, we * we don't have lock on. Hence, we build an array of the OIDs of tables
* build an array of the OIDs of tables we care about (and now have lock * we care about (and now have lock on!), and use a WHERE clause to
* on!), and use a WHERE clause to constrain which rows are selected. * constrain which rows are selected.
*/ */
appendPQExpBufferChar(tbloids, '{'); appendPQExpBufferChar(tbloids, '{');
appendPQExpBufferChar(checkoids, '{'); appendPQExpBufferChar(checkoids, '{');
appendPQExpBufferChar(defaultoids, '{');
for (int i = 0; i < numTables; i++) for (int i = 0; i < numTables; i++)
{ {
TableInfo *tbinfo = &tblinfo[i]; TableInfo *tbinfo = &tblinfo[i];
@ -8454,6 +8451,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
"a.attstattarget,\n" "a.attstattarget,\n"
"a.attstorage,\n" "a.attstorage,\n"
"t.typstorage,\n" "t.typstorage,\n"
"a.attnotnull,\n"
"a.atthasdef,\n" "a.atthasdef,\n"
"a.attisdropped,\n" "a.attisdropped,\n"
"a.attlen,\n" "a.attlen,\n"
@ -8470,21 +8468,6 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
"ORDER BY option_name" "ORDER BY option_name"
"), E',\n ') AS attfdwoptions,\n"); "), E',\n ') AS attfdwoptions,\n");
/*
* Write out NOT NULL. In 16 and up we have to read pg_constraint, and we
* only print it for constraints that aren't connoinherit. A NULL result
* means there's no contype='n' row for the column, so we mustn't print
* anything then either. We also track conislocal so that we can handle
* the case of partitioned tables and binary upgrade especially.
*/
if (fout->remoteVersion >= 160000)
appendPQExpBufferStr(q,
"co.connoinherit IS NOT NULL AS attnotnull,\n"
"coalesce(co.conislocal, false) AS local_notnull,\n");
else
appendPQExpBufferStr(q,
"a.attnotnull, false AS local_notnull,\n");
if (fout->remoteVersion >= 140000) if (fout->remoteVersion >= 140000)
appendPQExpBufferStr(q, appendPQExpBufferStr(q,
"a.attcompression AS attcompression,\n"); "a.attcompression AS attcompression,\n");
@ -8519,20 +8502,11 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
"FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
"JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) " "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
"LEFT JOIN pg_catalog.pg_type t " "LEFT JOIN pg_catalog.pg_type t "
"ON (a.atttypid = t.oid)\n", "ON (a.atttypid = t.oid)\n"
"WHERE a.attnum > 0::pg_catalog.int2\n"
"ORDER BY a.attrelid, a.attnum",
tbloids->data); tbloids->data);
/* in 16, need pg_constraint for NOT NULLs */
if (fout->remoteVersion >= 160000)
appendPQExpBufferStr(q,
" LEFT JOIN pg_catalog.pg_constraint co ON "
"(a.attrelid = co.conrelid\n"
" AND co.contype = 'n' AND "
"co.conkey = array[a.attnum])\n");
appendPQExpBufferStr(q,
"WHERE a.attnum > 0::pg_catalog.int2\n"
"ORDER BY a.attrelid, a.attnum");
res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK); res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
ntups = PQntuples(res); ntups = PQntuples(res);
@ -8551,7 +8525,6 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
i_attalign = PQfnumber(res, "attalign"); i_attalign = PQfnumber(res, "attalign");
i_attislocal = PQfnumber(res, "attislocal"); i_attislocal = PQfnumber(res, "attislocal");
i_attnotnull = PQfnumber(res, "attnotnull"); i_attnotnull = PQfnumber(res, "attnotnull");
i_localnotnull = PQfnumber(res, "local_notnull");
i_attoptions = PQfnumber(res, "attoptions"); i_attoptions = PQfnumber(res, "attoptions");
i_attcollation = PQfnumber(res, "attcollation"); i_attcollation = PQfnumber(res, "attcollation");
i_attcompression = PQfnumber(res, "attcompression"); i_attcompression = PQfnumber(res, "attcompression");
@ -8560,8 +8533,8 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
i_atthasdef = PQfnumber(res, "atthasdef"); i_atthasdef = PQfnumber(res, "atthasdef");
/* Within the next loop, we'll accumulate OIDs of tables with defaults */ /* Within the next loop, we'll accumulate OIDs of tables with defaults */
resetPQExpBuffer(defaultoids); resetPQExpBuffer(tbloids);
appendPQExpBufferChar(defaultoids, '{'); appendPQExpBufferChar(tbloids, '{');
/* /*
* Outer loop iterates once per table, not once per row. Incrementing of * Outer loop iterates once per table, not once per row. Incrementing of
@ -8617,7 +8590,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *)); tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *)); tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
tbinfo->notnull = (bool *) pg_malloc(numatts * sizeof(bool)); tbinfo->notnull = (bool *) pg_malloc(numatts * sizeof(bool));
tbinfo->localNotNull = (bool *) pg_malloc(numatts * sizeof(bool)); tbinfo->inhNotNull = (bool *) pg_malloc(numatts * sizeof(bool));
tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *)); tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
hasdefaults = false; hasdefaults = false;
@ -8639,7 +8612,6 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign)); tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't'); tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
tbinfo->notnull[j] = (PQgetvalue(res, r, i_attnotnull)[0] == 't'); tbinfo->notnull[j] = (PQgetvalue(res, r, i_attnotnull)[0] == 't');
tbinfo->localNotNull[j] = (PQgetvalue(res, r, i_localnotnull)[0] == 't');
tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions)); tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation)); tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression)); tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
@ -8648,14 +8620,16 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
tbinfo->attrdefs[j] = NULL; /* fix below */ tbinfo->attrdefs[j] = NULL; /* fix below */
if (PQgetvalue(res, r, i_atthasdef)[0] == 't') if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
hasdefaults = true; hasdefaults = true;
/* these flags will be set in flagInhAttrs() */
tbinfo->inhNotNull[j] = false;
} }
if (hasdefaults) if (hasdefaults)
{ {
/* Collect OIDs of interesting tables that have defaults */ /* Collect OIDs of interesting tables that have defaults */
if (defaultoids->len > 1) /* do we have more than the '{'? */ if (tbloids->len > 1) /* do we have more than the '{'? */
appendPQExpBufferChar(defaultoids, ','); appendPQExpBufferChar(tbloids, ',');
appendPQExpBuffer(defaultoids, "%u", tbinfo->dobj.catId.oid); appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
} }
} }
@ -8665,7 +8639,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
* Now get info about column defaults. This is skipped for a data-only * Now get info about column defaults. This is skipped for a data-only
* dump, as it is only needed for table schemas. * dump, as it is only needed for table schemas.
*/ */
if (!dopt->dataOnly && defaultoids->len > 1) if (!dopt->dataOnly && tbloids->len > 1)
{ {
AttrDefInfo *attrdefs; AttrDefInfo *attrdefs;
int numDefaults; int numDefaults;
@ -8673,14 +8647,14 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
pg_log_info("finding table default expressions"); pg_log_info("finding table default expressions");
appendPQExpBufferChar(defaultoids, '}'); appendPQExpBufferChar(tbloids, '}');
printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, " printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
"pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n" "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
"FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n" "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
"JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n" "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
"ORDER BY a.adrelid, a.adnum", "ORDER BY a.adrelid, a.adnum",
defaultoids->data); tbloids->data);
res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK); res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
@ -8923,112 +8897,9 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
PQclear(res); PQclear(res);
} }
/*
* Get info about table NOT NULL constraints. This is skipped for a
* data-only dump, as it is only needed for table schemas.
*
* Optimizing for tables that have no NOT NULL constraint seems
* pointless, so we don't try.
*/
if (!dopt->dataOnly)
{
ConstraintInfo *constrs;
int numConstrs;
int i_tableoid;
int i_oid;
int i_conrelid;
int i_conname;
int i_condef;
int i_conislocal;
pg_log_info("finding table not null constraints");
/*
* Only constraints marked connoinherit need to be handled here;
* the normal constraints are instead handled by writing NOT NULL
* when each column is defined.
*/
resetPQExpBuffer(q);
appendPQExpBuffer(q,
"SELECT co.tableoid, co.oid, conrelid, conname, "
"pg_catalog.pg_get_constraintdef(co.oid) AS condef,\n"
" conislocal, coninhcount, connoinherit "
"FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
"JOIN pg_catalog.pg_constraint co ON (src.tbloid = co.conrelid)\n"
"JOIN pg_catalog.pg_class c ON (conrelid = c.oid)\n"
"WHERE contype = 'n' AND connoinherit\n"
"ORDER BY co.conrelid, co.conname",
tbloids->data);
res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
numConstrs = PQntuples(res);
constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
i_tableoid = PQfnumber(res, "tableoid");
i_oid = PQfnumber(res, "oid");
i_conrelid = PQfnumber(res, "conrelid");
i_conname = PQfnumber(res, "conname");
i_condef = PQfnumber(res, "condef");
i_conislocal = PQfnumber(res, "conislocal");
/* As above, this loop iterates once per table, not once per row */
curtblindx = -1;
for (int j = 0; j < numConstrs;)
{
Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
TableInfo *tbinfo = NULL;
int numcons;
/* Count rows for this table */
for (numcons = 1; numcons < numConstrs - j; numcons++)
if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
break;
/*
* Locate the associated TableInfo; we rely on tblinfo[] being in
* OID order.
*/
while (++curtblindx < numTables)
{
tbinfo = &tblinfo[curtblindx];
if (tbinfo->dobj.catId.oid == conrelid)
break;
}
if (curtblindx >= numTables)
pg_fatal("unrecognized table OID %u", conrelid);
for (int c = 0; c < numcons; c++, j++)
{
constrs[j].dobj.objType = DO_CONSTRAINT;
constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
AssignDumpId(&constrs[j].dobj);
constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
constrs[j].dobj.namespace = tbinfo->dobj.namespace;
constrs[j].contable = tbinfo;
constrs[j].condomain = NULL;
constrs[j].contype = 'n';
constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
constrs[j].confrelid = InvalidOid;
constrs[j].conindex = 0;
constrs[j].condeferrable = false;
constrs[j].condeferred = false;
constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
constrs[j].separate = true;
constrs[j].dobj.dump = tbinfo->dobj.dump;
}
}
PQclear(res);
}
destroyPQExpBuffer(q); destroyPQExpBuffer(q);
destroyPQExpBuffer(tbloids); destroyPQExpBuffer(tbloids);
destroyPQExpBuffer(checkoids); destroyPQExpBuffer(checkoids);
destroyPQExpBuffer(defaultoids);
} }
/* /*
@ -15701,12 +15572,12 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
!tbinfo->attrdefs[j]->separate); !tbinfo->attrdefs[j]->separate);
/* /*
* Not Null constraint --- suppress unless it is locally * Not Null constraint --- suppress if inherited, except
* defined, except if partition, or in binary-upgrade case * if partition, or in binary-upgrade case where that
* where that won't work. * won't work.
*/ */
print_notnull = (tbinfo->notnull[j] && print_notnull = (tbinfo->notnull[j] &&
(tbinfo->localNotNull[j] || (!tbinfo->inhNotNull[j] ||
tbinfo->ispartition || dopt->binary_upgrade)); tbinfo->ispartition || dopt->binary_upgrade));
/* /*
@ -16099,8 +15970,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
* we have to mark it separately. * we have to mark it separately.
*/ */
if (!shouldPrintColumn(dopt, tbinfo, j) && if (!shouldPrintColumn(dopt, tbinfo, j) &&
tbinfo->notnull[j] && tbinfo->localNotNull[j] && tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
tbinfo->ispartition)
appendPQExpBuffer(q, appendPQExpBuffer(q,
"ALTER %sTABLE ONLY %s ALTER COLUMN %s SET NOT NULL;\n", "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET NOT NULL;\n",
foreign, qualrelname, foreign, qualrelname,
@ -16925,31 +16795,6 @@ dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
.createStmt = q->data, .createStmt = q->data,
.dropStmt = delq->data)); .dropStmt = delq->data));
} }
else if (coninfo->contype == 'n')
{
appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
fmtQualifiedDumpable(tbinfo));
appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
fmtId(coninfo->dobj.name),
coninfo->condef);
appendPQExpBuffer(delq, "ALTER %sTABLE %s\n", foreign,
fmtQualifiedDumpable(tbinfo));
appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
fmtId(coninfo->dobj.name));
tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
ARCHIVE_OPTS(.tag = tag,
.namespace = tbinfo->dobj.namespace->dobj.name,
.owner = tbinfo->rolname,
.description = "NOT NULL CONSTRAINT",
.section = SECTION_POST_DATA,
.createStmt = q->data,
.dropStmt = delq->data));
}
else if (coninfo->contype == 'c' && tbinfo) else if (coninfo->contype == 'c' && tbinfo)
{ {
/* CHECK constraint on a table */ /* CHECK constraint on a table */

View File

@ -345,7 +345,7 @@ typedef struct _tableInfo
char **attfdwoptions; /* per-attribute fdw options */ char **attfdwoptions; /* per-attribute fdw options */
char **attmissingval; /* per attribute missing value */ char **attmissingval; /* per attribute missing value */
bool *notnull; /* NOT NULL constraints on attributes */ bool *notnull; /* NOT NULL constraints on attributes */
bool *localNotNull; /* true if NOT NULL has local definition */ bool *inhNotNull; /* true if NOT NULL is inherited */
struct _attrDefInfo **attrdefs; /* DEFAULT expressions */ struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
struct _constraintInfo *checkexprs; /* CHECK constraints */ struct _constraintInfo *checkexprs; /* CHECK constraints */
bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */ bool needs_override; /* has GENERATED ALWAYS AS IDENTITY */

View File

@ -3115,7 +3115,7 @@ my %tests = (
);', );',
regexp => qr/^ regexp => qr/^
\QCREATE TABLE dump_test.fk_reference_test_table (\E \QCREATE TABLE dump_test.fk_reference_test_table (\E
\n\s+\Qcol1 integer\E \n\s+\Qcol1 integer NOT NULL\E
\n\); \n\);
/xm, /xm,
like => like =>
@ -3507,7 +3507,7 @@ my %tests = (
);', );',
regexp => qr/^ regexp => qr/^
\QCREATE TABLE dump_test.test_table_generated (\E\n \QCREATE TABLE dump_test.test_table_generated (\E\n
\s+\Qcol1 integer,\E\n \s+\Qcol1 integer NOT NULL,\E\n
\s+\Qcol2 integer GENERATED ALWAYS AS ((col1 * 2)) STORED\E\n \s+\Qcol2 integer GENERATED ALWAYS AS ((col1 * 2)) STORED\E\n
\); \);
/xms, /xms,
@ -3621,7 +3621,7 @@ my %tests = (
) INHERITS (dump_test.test_inheritance_parent);', ) INHERITS (dump_test.test_inheritance_parent);',
regexp => qr/^ regexp => qr/^
\QCREATE TABLE dump_test.test_inheritance_child (\E\n \QCREATE TABLE dump_test.test_inheritance_child (\E\n
\s+\Qcol1 integer NOT NULL,\E\n \s+\Qcol1 integer,\E\n
\s+\QCONSTRAINT test_inheritance_child CHECK ((col2 >= 142857))\E\n \s+\QCONSTRAINT test_inheritance_child CHECK ((col2 >= 142857))\E\n
\)\n \)\n
\QINHERITS (dump_test.test_inheritance_parent);\E\n \QINHERITS (dump_test.test_inheritance_parent);\E\n

View File

@ -57,6 +57,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 202304075 #define CATALOG_VERSION_NO 202304111
#endif #endif

View File

@ -34,10 +34,10 @@ typedef struct RawColumnDefault
typedef struct CookedConstraint typedef struct CookedConstraint
{ {
ConstrType contype; /* CONSTR_DEFAULT, CONSTR_CHECK, CONSTR_NOTNULL */ ConstrType contype; /* CONSTR_DEFAULT or CONSTR_CHECK */
Oid conoid; /* constr OID if created, otherwise Invalid */ Oid conoid; /* constr OID if created, otherwise Invalid */
char *name; /* name, or NULL if none */ char *name; /* name, or NULL if none */
AttrNumber attnum; /* which attr (only for NOTNULL, DEFAULT) */ AttrNumber attnum; /* which attr (only for DEFAULT) */
Node *expr; /* transformed default or check expr */ Node *expr; /* transformed default or check expr */
bool skip_validation; /* skip validation? (only for CHECK) */ bool skip_validation; /* skip validation? (only for CHECK) */
bool is_local; /* constraint has local (non-inherited) def */ bool is_local; /* constraint has local (non-inherited) def */
@ -113,9 +113,6 @@ extern List *AddRelationNewConstraints(Relation rel,
bool is_local, bool is_local,
bool is_internal, bool is_internal,
const char *queryString); const char *queryString);
extern List *AddRelationNotNullConstraints(Relation rel,
List *constraints,
List *additional_notnulls);
extern void RelationClearMissing(Relation rel); extern void RelationClearMissing(Relation rel);
extern void SetAttrMissing(Oid relid, char *attname, char *value); extern void SetAttrMissing(Oid relid, char *attname, char *value);

View File

@ -181,7 +181,6 @@ DECLARE_ARRAY_FOREIGN_KEY((confrelid, confkey), pg_attribute, (attrelid, attnum)
/* Valid values for contype */ /* Valid values for contype */
#define CONSTRAINT_CHECK 'c' #define CONSTRAINT_CHECK 'c'
#define CONSTRAINT_FOREIGN 'f' #define CONSTRAINT_FOREIGN 'f'
#define CONSTRAINT_NOTNULL 'n'
#define CONSTRAINT_PRIMARY 'p' #define CONSTRAINT_PRIMARY 'p'
#define CONSTRAINT_UNIQUE 'u' #define CONSTRAINT_UNIQUE 'u'
#define CONSTRAINT_TRIGGER 't' #define CONSTRAINT_TRIGGER 't'
@ -238,6 +237,9 @@ extern Oid CreateConstraintEntry(const char *constraintName,
bool conNoInherit, bool conNoInherit,
bool is_internal); bool is_internal);
extern void RemoveConstraintById(Oid conId);
extern void RenameConstraintById(Oid conId, const char *newname);
extern bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, extern bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
const char *conname); const char *conname);
extern bool ConstraintNameExists(const char *conname, Oid namespaceid); extern bool ConstraintNameExists(const char *conname, Oid namespaceid);
@ -245,13 +247,6 @@ extern char *ChooseConstraintName(const char *name1, const char *name2,
const char *label, Oid namespaceid, const char *label, Oid namespaceid,
List *others); List *others);
extern HeapTuple findNotNullConstraintAttnum(Relation rel, AttrNumber attnum);
extern HeapTuple findNotNullConstraint(Relation rel, const char *colname);
extern AttrNumber extractNotNullColumn(HeapTuple constrTup);
extern void RemoveConstraintById(Oid conId);
extern void RenameConstraintById(Oid conId, const char *newname);
extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
Oid newNspId, bool isType, ObjectAddresses *objsMoved); Oid newNspId, bool isType, ObjectAddresses *objsMoved);
extern void ConstraintSetParentConstraint(Oid childConstrId, extern void ConstraintSetParentConstraint(Oid childConstrId,

View File

@ -73,8 +73,6 @@ extern ObjectAddress renameatt(RenameStmt *stmt);
extern ObjectAddress RenameConstraint(RenameStmt *stmt); extern ObjectAddress RenameConstraint(RenameStmt *stmt);
extern List *RelationGetNotNullConstraints(Relation relation, bool cooked);
extern ObjectAddress RenameRelation(RenameStmt *stmt); extern ObjectAddress RenameRelation(RenameStmt *stmt);
extern void RenameRelationInternal(Oid myrelid, extern void RenameRelationInternal(Oid myrelid,

View File

@ -2177,7 +2177,6 @@ typedef enum AlterTableType
AT_CookedColumnDefault, /* add a pre-cooked column default */ AT_CookedColumnDefault, /* add a pre-cooked column default */
AT_DropNotNull, /* alter column drop not null */ AT_DropNotNull, /* alter column drop not null */
AT_SetNotNull, /* alter column set not null */ AT_SetNotNull, /* alter column set not null */
AT_SetAttNotNull, /* set attnotnull w/o a constraint */
AT_DropExpression, /* alter column drop expression */ AT_DropExpression, /* alter column drop expression */
AT_CheckNotNull, /* check column is already marked not null */ AT_CheckNotNull, /* check column is already marked not null */
AT_SetStatistics, /* alter column set statistics */ AT_SetStatistics, /* alter column set statistics */
@ -2463,11 +2462,10 @@ typedef struct VariableShowStmt
* Create Table Statement * Create Table Statement
* *
* NOTE: in the raw gram.y output, ColumnDef and Constraint nodes are * NOTE: in the raw gram.y output, ColumnDef and Constraint nodes are
* intermixed in tableElts, and constraints and notnullcols are NIL. After * intermixed in tableElts, and constraints is NIL. After parse analysis,
* parse analysis, tableElts contains just ColumnDefs, notnullcols has been * tableElts contains just ColumnDefs, and constraints contains just
* filled with not-nullable column names from various sources, and constraints * Constraint nodes (in fact, only CONSTR_CHECK nodes, in the present
* contains just Constraint nodes (in fact, only CONSTR_CHECK nodes, in the * implementation).
* present implementation).
* ---------------------- * ----------------------
*/ */
@ -2482,7 +2480,6 @@ typedef struct CreateStmt
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) */
List *nnconstraints; /* NOT NULL constraints (ditto) */
List *options; /* options from WITH clause */ List *options; /* options from WITH clause */
OnCommitAction oncommit; /* what do we do at COMMIT? */ OnCommitAction oncommit; /* what do we do at COMMIT? */
char *tablespacename; /* table space to use, or NULL */ char *tablespacename; /* table space to use, or NULL */
@ -2571,9 +2568,6 @@ typedef struct Constraint
char *cooked_expr; /* expr, as nodeToString representation */ char *cooked_expr; /* expr, as nodeToString representation */
char generated_when; /* ALWAYS or BY DEFAULT */ char generated_when; /* ALWAYS or BY DEFAULT */
/* Fields used for "raw" NOT NULL constraints: */
char *colname; /* column it applies to */
/* Fields used for unique constraints (UNIQUE and PRIMARY KEY): */ /* Fields used for unique constraints (UNIQUE and PRIMARY KEY): */
bool nulls_not_distinct; /* null treatment for UNIQUE constraints */ bool nulls_not_distinct; /* null treatment for UNIQUE constraints */
List *keys; /* String nodes naming referenced key List *keys; /* String nodes naming referenced key

View File

@ -28,7 +28,6 @@ ALTER TABLE parent ADD COLUMN b serial;
NOTICE: DDL test: type simple, tag CREATE SEQUENCE NOTICE: DDL test: type simple, tag CREATE SEQUENCE
NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type ADD COLUMN (and recurse) desc column b of table parent NOTICE: subcommand: type ADD COLUMN (and recurse) desc column b of table parent
NOTICE: subcommand: type ADD CONSTRAINT (and recurse) desc constraint parent_b_not_null on table parent
NOTICE: DDL test: type simple, tag ALTER SEQUENCE NOTICE: DDL test: type simple, tag ALTER SEQUENCE
ALTER TABLE parent RENAME COLUMN b TO c; ALTER TABLE parent RENAME COLUMN b TO c;
NOTICE: DDL test: type simple, tag ALTER TABLE NOTICE: DDL test: type simple, tag ALTER TABLE
@ -58,18 +57,24 @@ NOTICE: subcommand: type DETACH PARTITION desc table part2
DROP TABLE part2; DROP TABLE part2;
ALTER TABLE part ADD PRIMARY KEY (a); ALTER TABLE part ADD PRIMARY KEY (a);
NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET ATTNOTNULL desc <NULL> NOTICE: subcommand: type SET NOT NULL desc column a of table part
NOTICE: subcommand: type SET ATTNOTNULL desc <NULL> NOTICE: subcommand: type SET NOT NULL desc column a of table part1
NOTICE: subcommand: type ADD INDEX desc index part_pkey NOTICE: subcommand: type ADD INDEX desc index part_pkey
ALTER TABLE parent ALTER COLUMN a SET NOT NULL; ALTER TABLE parent ALTER COLUMN a SET NOT NULL;
NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET NOT NULL (and recurse) desc constraint parent_a_not_null on table parent NOTICE: subcommand: type SET NOT NULL desc column a of table parent
NOTICE: subcommand: type SET NOT NULL desc column a of table child
NOTICE: subcommand: type SET NOT NULL desc column a of table grandchild
ALTER TABLE parent ALTER COLUMN a DROP NOT NULL; ALTER TABLE parent ALTER COLUMN a DROP NOT NULL;
NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type DROP NOT NULL (and recurse) desc column a of table parent NOTICE: subcommand: type DROP NOT NULL desc column a of table parent
NOTICE: subcommand: type DROP NOT NULL desc column a of table child
NOTICE: subcommand: type DROP NOT NULL desc column a of table grandchild
ALTER TABLE parent ALTER COLUMN a SET NOT NULL; ALTER TABLE parent ALTER COLUMN a SET NOT NULL;
NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET NOT NULL (and recurse) desc constraint parent_a_not_null on table parent NOTICE: subcommand: type SET NOT NULL desc column a of table parent
NOTICE: subcommand: type SET NOT NULL desc column a of table child
NOTICE: subcommand: type SET NOT NULL desc column a of table grandchild
ALTER TABLE parent ALTER COLUMN a ADD GENERATED ALWAYS AS IDENTITY; ALTER TABLE parent ALTER COLUMN a ADD GENERATED ALWAYS AS IDENTITY;
NOTICE: DDL test: type simple, tag CREATE SEQUENCE NOTICE: DDL test: type simple, tag CREATE SEQUENCE
NOTICE: DDL test: type simple, tag ALTER SEQUENCE NOTICE: DDL test: type simple, tag ALTER SEQUENCE
@ -111,7 +116,6 @@ NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type ALTER COLUMN SET TYPE desc column c of table parent NOTICE: subcommand: type ALTER COLUMN SET TYPE desc column c of table parent
NOTICE: subcommand: type ALTER COLUMN SET TYPE desc column c of table child NOTICE: subcommand: type ALTER COLUMN SET TYPE desc column c of table child
NOTICE: subcommand: type ALTER COLUMN SET TYPE desc column c of table grandchild NOTICE: subcommand: type ALTER COLUMN SET TYPE desc column c of table grandchild
NOTICE: subcommand: type (re) ADD CONSTRAINT desc constraint parent_b_not_null on table parent
NOTICE: subcommand: type (re) ADD STATS desc statistics object parent_stat NOTICE: subcommand: type (re) ADD STATS desc statistics object parent_stat
ALTER TABLE parent ALTER COLUMN c SET DEFAULT 0; ALTER TABLE parent ALTER COLUMN c SET DEFAULT 0;
NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: DDL test: type alter table, tag ALTER TABLE

View File

@ -54,8 +54,6 @@ NOTICE: DDL test: type simple, tag CREATE SEQUENCE
NOTICE: DDL test: type simple, tag CREATE SEQUENCE NOTICE: DDL test: type simple, tag CREATE SEQUENCE
NOTICE: DDL test: type simple, tag CREATE SEQUENCE NOTICE: DDL test: type simple, tag CREATE SEQUENCE
NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE TABLE
NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET ATTNOTNULL desc <NULL>
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
NOTICE: DDL test: type simple, tag ALTER SEQUENCE NOTICE: DDL test: type simple, tag ALTER SEQUENCE
@ -76,8 +74,6 @@ CREATE TABLE IF NOT EXISTS fkey_table (
EXCLUDE USING btree (check_col_2 WITH =) EXCLUDE USING btree (check_col_2 WITH =)
); );
NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE TABLE
NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET ATTNOTNULL desc <NULL>
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: DDL test: type alter table, tag ALTER TABLE
@ -90,7 +86,7 @@ CREATE TABLE employees OF employee_type (
); );
NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE TABLE
NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET ATTNOTNULL desc <NULL> NOTICE: subcommand: type SET NOT NULL desc column name of table employees
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
-- Inheritance -- Inheritance
CREATE TABLE person ( CREATE TABLE person (
@ -100,8 +96,6 @@ CREATE TABLE person (
location point location point
); );
NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE TABLE
NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET ATTNOTNULL desc <NULL>
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
CREATE TABLE emp ( CREATE TABLE emp (
salary int4, salary int4,
@ -134,10 +128,6 @@ CREATE TABLE like_datatype_table (
EXCLUDING ALL EXCLUDING ALL
); );
NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE TABLE
NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type ADD CONSTRAINT (and recurse) desc constraint datatype_table_id_big_not_null on table like_datatype_table
NOTICE: subcommand: type ADD CONSTRAINT (and recurse) desc constraint datatype_table_id_not_null on table like_datatype_table
NOTICE: subcommand: type ADD CONSTRAINT (and recurse) desc constraint datatype_table_is_small_not_null on table like_datatype_table
CREATE TABLE like_fkey_table ( CREATE TABLE like_fkey_table (
LIKE fkey_table LIKE fkey_table
INCLUDING DEFAULTS INCLUDING DEFAULTS
@ -147,11 +137,6 @@ CREATE TABLE like_fkey_table (
NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE TABLE
NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type ALTER COLUMN SET DEFAULT (precooked) desc column id of table like_fkey_table NOTICE: subcommand: type ALTER COLUMN SET DEFAULT (precooked) desc column id of table like_fkey_table
NOTICE: subcommand: type ADD CONSTRAINT (and recurse) desc constraint fkey_table_big_id_not_null on table like_fkey_table
NOTICE: subcommand: type ADD CONSTRAINT (and recurse) desc constraint fkey_table_check_col_1_not_null on table like_fkey_table
NOTICE: subcommand: type ADD CONSTRAINT (and recurse) desc constraint fkey_table_check_col_2_not_null on table like_fkey_table
NOTICE: subcommand: type ADD CONSTRAINT (and recurse) desc constraint fkey_table_datatype_id_not_null on table like_fkey_table
NOTICE: subcommand: type ADD CONSTRAINT (and recurse) desc constraint fkey_table_id_not_null on table like_fkey_table
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
-- Volatile table types -- Volatile table types
@ -159,29 +144,21 @@ CREATE UNLOGGED TABLE unlogged_table (
id INT PRIMARY KEY id INT PRIMARY KEY
); );
NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE TABLE
NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET ATTNOTNULL desc <NULL>
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
CREATE TEMP TABLE temp_table ( CREATE TEMP TABLE temp_table (
id INT PRIMARY KEY id INT PRIMARY KEY
); );
NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE TABLE
NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET ATTNOTNULL desc <NULL>
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
CREATE TEMP TABLE temp_table_commit_delete ( CREATE TEMP TABLE temp_table_commit_delete (
id INT PRIMARY KEY id INT PRIMARY KEY
) )
ON COMMIT DELETE ROWS; ON COMMIT DELETE ROWS;
NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE TABLE
NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET ATTNOTNULL desc <NULL>
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX
CREATE TEMP TABLE temp_table_commit_drop ( CREATE TEMP TABLE temp_table_commit_drop (
id INT PRIMARY KEY id INT PRIMARY KEY
) )
ON COMMIT DROP; ON COMMIT DROP;
NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE TABLE
NOTICE: DDL test: type alter table, tag ALTER TABLE
NOTICE: subcommand: type SET ATTNOTNULL desc <NULL>
NOTICE: DDL test: type simple, tag CREATE INDEX NOTICE: DDL test: type simple, tag CREATE INDEX

View File

@ -129,9 +129,6 @@ get_altertable_subcmdinfo(PG_FUNCTION_ARGS)
case AT_SetNotNull: case AT_SetNotNull:
strtype = "SET NOT NULL"; strtype = "SET NOT NULL";
break; break;
case AT_SetAttNotNull:
strtype = "SET ATTNOTNULL";
break;
case AT_DropExpression: case AT_DropExpression:
strtype = "DROP EXPRESSION"; strtype = "DROP EXPRESSION";
break; break;
@ -321,7 +318,6 @@ get_altertable_subcmdinfo(PG_FUNCTION_ARGS)
if (OidIsValid(sub->address.objectId)) if (OidIsValid(sub->address.objectId))
{ {
char *objdesc; char *objdesc;
objdesc = getObjectDescription((const ObjectAddress *) &sub->address, false); objdesc = getObjectDescription((const ObjectAddress *) &sub->address, false);
values[1] = CStringGetTextDatum(objdesc); values[1] = CStringGetTextDatum(objdesc);
} }

View File

@ -1119,13 +1119,9 @@ ERROR: relation "non_existent" does not exist
create table atacc1 (test int not null); create table atacc1 (test int not null);
alter table atacc1 add constraint "atacc1_pkey" primary key (test); alter table atacc1 add constraint "atacc1_pkey" primary key (test);
alter table atacc1 alter column test drop not null; alter table atacc1 alter column test drop not null;
ERROR: column "test" is in a primary key
alter table atacc1 drop constraint "atacc1_pkey"; alter table atacc1 drop constraint "atacc1_pkey";
\d atacc1 alter table atacc1 alter column test drop not null;
Table "public.atacc1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
test | integer | | |
insert into atacc1 values (null); insert into atacc1 values (null);
alter table atacc1 alter test set not null; alter table atacc1 alter test set not null;
ERROR: column "test" of relation "atacc1" contains null values ERROR: column "test" of relation "atacc1" contains null values
@ -1195,10 +1191,23 @@ alter table parent alter a drop not null;
insert into parent values (NULL); insert into parent values (NULL);
insert into child (a, b) values (NULL, 'foo'); insert into child (a, b) values (NULL, 'foo');
alter table only parent alter a set not null; alter table only parent alter a set not null;
ERROR: cannot add constraint only to table with inheritance children ERROR: column "a" of relation "parent" contains null values
HINT: Do not specify the ONLY keyword.
alter table child alter a set not null; alter table child alter a set not null;
ERROR: column "a" of relation "child" contains null values ERROR: column "a" of relation "child" contains null values
delete from parent;
alter table only parent alter a set not null;
insert into parent values (NULL);
ERROR: null value in column "a" of relation "parent" violates not-null constraint
DETAIL: Failing row contains (null).
alter table child alter a set not null;
insert into child (a, b) values (NULL, 'foo');
ERROR: null value in column "a" of relation "child" violates not-null constraint
DETAIL: Failing row contains (null, foo).
delete from child;
alter table child alter a set not null;
insert into child (a, b) values (NULL, 'foo');
ERROR: null value in column "a" of relation "child" violates not-null constraint
DETAIL: Failing row contains (null, foo).
drop table child; drop table child;
drop table parent; drop table parent;
-- test setting and removing default values -- test setting and removing default values
@ -3825,28 +3834,6 @@ Referenced by:
TABLE "ataddindex" CONSTRAINT "ataddindex_ref_id_fkey" FOREIGN KEY (ref_id) REFERENCES ataddindex(id) TABLE "ataddindex" CONSTRAINT "ataddindex_ref_id_fkey" FOREIGN KEY (ref_id) REFERENCES ataddindex(id)
DROP TABLE ataddindex; DROP TABLE ataddindex;
CREATE TABLE atnotnull1 ();
ALTER TABLE atnotnull1
ADD COLUMN a INT,
ALTER a SET NOT NULL;
ALTER TABLE atnotnull1
ADD COLUMN b INT,
ADD NOT NULL b;
ALTER TABLE atnotnull1
ADD COLUMN c INT,
ADD PRIMARY KEY (c);
SELECT conrelid::regclass, conname, contype, conkey,
(SELECT attname FROM pg_attribute WHERE attrelid = conrelid AND attnum = conkey[1]),
coninhcount, conislocal
FROM pg_constraint WHERE contype IN ('n','p') AND
conrelid IN ('atnotnull1'::regclass);
conrelid | conname | contype | conkey | attname | coninhcount | conislocal
------------+-----------------------+---------+--------+---------+-------------+------------
atnotnull1 | atnotnull1_a_not_null | n | {1} | a | 0 | t
atnotnull1 | atnotnull1_b_not_null | n | {2} | b | 0 | t
atnotnull1 | atnotnull1_pkey | p | {3} | c | 0 | t
(3 rows)
-- unsupported constraint types for partitioned tables -- unsupported constraint types for partitioned tables
CREATE TABLE partitioned ( CREATE TABLE partitioned (
a int, a int,
@ -4368,7 +4355,8 @@ ERROR: cannot alter inherited column "b"
-- cannot add/drop NOT NULL or check constraints to *only* the parent, when -- cannot add/drop NOT NULL or check constraints to *only* the parent, when
-- partitions exist -- partitions exist
ALTER TABLE ONLY list_parted2 ALTER b SET NOT NULL; ALTER TABLE ONLY list_parted2 ALTER b SET NOT NULL;
ERROR: cannot add constraint to only the partitioned table when partitions exist ERROR: constraint must be added to child tables too
DETAIL: Column "b" of relation "part_2" is not already NOT NULL.
HINT: Do not specify the ONLY keyword. HINT: Do not specify the ONLY keyword.
ALTER TABLE ONLY list_parted2 ADD CONSTRAINT check_b CHECK (b <> 'zz'); ALTER TABLE ONLY list_parted2 ADD CONSTRAINT check_b CHECK (b <> 'zz');
ERROR: constraint must be added to child tables too ERROR: constraint must be added to child tables too

View File

@ -247,12 +247,11 @@ ERROR: insert or update on table "clstr_tst" violates foreign key constraint "c
DETAIL: Key (b)=(1111) is not present in table "clstr_tst_s". DETAIL: Key (b)=(1111) is not present in table "clstr_tst_s".
SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass
ORDER BY 1; ORDER BY 1;
conname conname
---------------------- ----------------
clstr_tst_a_not_null
clstr_tst_con clstr_tst_con
clstr_tst_pkey clstr_tst_pkey
(3 rows) (2 rows)
SELECT relname, relkind, SELECT relname, relkind,
EXISTS(SELECT 1 FROM pg_class WHERE oid = c.reltoastrelid) AS hastoast EXISTS(SELECT 1 FROM pg_class WHERE oid = c.reltoastrelid) AS hastoast

View File

@ -288,28 +288,6 @@ ERROR: new row for relation "atacc1" violates check constraint "atacc1_test2_ch
DETAIL: Failing row contains (null, 3). DETAIL: Failing row contains (null, 3).
DROP TABLE ATACC1 CASCADE; DROP TABLE ATACC1 CASCADE;
NOTICE: drop cascades to table atacc2 NOTICE: drop cascades to table atacc2
-- NOT NULL NO INHERIT
CREATE TABLE ATACC1 (a int, not null a no inherit);
CREATE TABLE ATACC2 () INHERITS (ATACC1);
\d ATACC2
Table "public.atacc2"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
Inherits: atacc1
DROP TABLE ATACC1, ATACC2;
CREATE TABLE ATACC1 (a int);
ALTER TABLE ATACC1 ADD NOT NULL a NO INHERIT;
CREATE TABLE ATACC2 () INHERITS (ATACC1);
\d ATACC2
Table "public.atacc2"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
Inherits: atacc1
DROP TABLE ATACC1, ATACC2;
-- --
-- Check constraints on INSERT INTO -- Check constraints on INSERT INTO
-- --
@ -776,98 +754,6 @@ ALTER TABLE deferred_excl ADD EXCLUDE (f1 WITH =);
ERROR: could not create exclusion constraint "deferred_excl_f1_excl" ERROR: could not create exclusion constraint "deferred_excl_f1_excl"
DETAIL: Key (f1)=(3) conflicts with key (f1)=(3). DETAIL: Key (f1)=(3) conflicts with key (f1)=(3).
DROP TABLE deferred_excl; DROP TABLE deferred_excl;
-- verify constraints created for NOT NULL clauses
CREATE TABLE notnull_tbl1 (a INTEGER NOT NULL);
\d notnull_tbl1
Table "public.notnull_tbl1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | not null |
select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
conname | contype | conkey
-------------------------+---------+--------
notnull_tbl1_a_not_null | n | {1}
(1 row)
-- DROP NOT NULL gets rid of both the attnotnull flag and the constraint itself
ALTER TABLE notnull_tbl1 ALTER a DROP NOT NULL;
\d notnull_tbl1
Table "public.notnull_tbl1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
conname | contype | conkey
---------+---------+--------
(0 rows)
-- SET NOT NULL puts both back
ALTER TABLE notnull_tbl1 ALTER a SET NOT NULL;
\d notnull_tbl1
Table "public.notnull_tbl1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | not null |
select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
conname | contype | conkey
-------------------------+---------+--------
notnull_tbl1_a_not_null | n | {1}
(1 row)
-- Doing it twice doesn't create a redundant constraint
ALTER TABLE notnull_tbl1 ALTER a SET NOT NULL;
select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
conname | contype | conkey
-------------------------+---------+--------
notnull_tbl1_a_not_null | n | {1}
(1 row)
-- Using the "table constraint" syntax also works
ALTER TABLE notnull_tbl1 ALTER a DROP NOT NULL;
ALTER TABLE notnull_tbl1 ADD CONSTRAINT foobar NOT NULL a;
\d notnull_tbl1
Table "public.notnull_tbl1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | not null |
select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
conname | contype | conkey
---------+---------+--------
foobar | n | {1}
(1 row)
DROP TABLE notnull_tbl1;
CREATE TABLE notnull_tbl2 (a INTEGER PRIMARY KEY);
ALTER TABLE notnull_tbl2 ALTER a DROP NOT NULL;
ERROR: column "a" is in a primary key
CREATE TABLE notnull_tbl3 (a INTEGER NOT NULL, CHECK (a IS NOT NULL));
ALTER TABLE notnull_tbl3 ALTER A DROP NOT NULL;
ALTER TABLE notnull_tbl3 ADD b int, ADD CONSTRAINT pk PRIMARY KEY (a, b);
\d notnull_tbl3
Table "public.notnull_tbl3"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | not null |
b | integer | | not null |
Indexes:
"pk" PRIMARY KEY, btree (a, b)
Check constraints:
"notnull_tbl3_a_check" CHECK (a IS NOT NULL)
ALTER TABLE notnull_tbl3 DROP CONSTRAINT pk;
\d notnull_tbl3
Table "public.notnull_tbl3"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
b | integer | | |
Check constraints:
"notnull_tbl3_a_check" CHECK (a IS NOT NULL)
-- Comments -- Comments
-- Setup a low-level role to enforce non-superuser checks. -- Setup a low-level role to enforce non-superuser checks.
CREATE ROLE regress_constraint_comments; CREATE ROLE regress_constraint_comments;

View File

@ -766,24 +766,22 @@ CREATE TABLE part_b PARTITION OF parted (
) FOR VALUES IN ('b'); ) FOR VALUES IN ('b');
NOTICE: merging constraint "check_a" with inherited definition NOTICE: merging constraint "check_a" with inherited definition
-- conislocal should be false for any merged constraints, true otherwise -- conislocal should be false for any merged constraints, true otherwise
SELECT conname, conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass ORDER BY coninhcount DESC, conname; SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass ORDER BY conislocal, coninhcount;
conname | conislocal | coninhcount conislocal | coninhcount
-------------------+------------+------------- ------------+-------------
check_a | f | 1 f | 1
part_b_b_not_null | t | 1 t | 0
check_b | t | 0 (2 rows)
(3 rows)
-- Once check_b is added to the parent, it should be made non-local for part_b -- Once check_b is added to the parent, it should be made non-local for part_b
ALTER TABLE parted ADD CONSTRAINT check_b CHECK (b >= 0); ALTER TABLE parted ADD CONSTRAINT check_b CHECK (b >= 0);
NOTICE: merging constraint "check_b" with inherited definition NOTICE: merging constraint "check_b" with inherited definition
SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass ORDER BY coninhcount DESC, conname; SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass;
conislocal | coninhcount conislocal | coninhcount
------------+------------- ------------+-------------
f | 1 f | 1
f | 1 f | 1
t | 1 (2 rows)
(3 rows)
-- Neither check_a nor check_b are droppable from part_b -- Neither check_a nor check_b are droppable from part_b
ALTER TABLE part_b DROP CONSTRAINT check_a; ALTER TABLE part_b DROP CONSTRAINT check_a;
@ -794,11 +792,10 @@ ERROR: cannot drop inherited constraint "check_b" of relation "part_b"
-- traditional inheritance where they will be left behind, because they would -- traditional inheritance where they will be left behind, because they would
-- be local constraints. -- be local constraints.
ALTER TABLE parted DROP CONSTRAINT check_a, DROP CONSTRAINT check_b; ALTER TABLE parted DROP CONSTRAINT check_a, DROP CONSTRAINT check_b;
SELECT conname, conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass ORDER BY coninhcount; SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass;
conname | conislocal | coninhcount conislocal | coninhcount
-------------------+------------+------------- ------------+-------------
part_b_b_not_null | t | 1 (0 rows)
(1 row)
-- specify PARTITION BY for a partition -- specify PARTITION BY for a partition
CREATE TABLE fail_part_col_not_found PARTITION OF parted FOR VALUES IN ('c') PARTITION BY RANGE (c); CREATE TABLE fail_part_col_not_found PARTITION OF parted FOR VALUES IN ('c') PARTITION BY RANGE (c);

View File

@ -408,7 +408,6 @@ NOTICE: END: command_tag=CREATE SCHEMA type=schema identity=evttrig
NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.one_col_a_seq NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.one_col_a_seq
NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.one_col_c_seq NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.one_col_c_seq
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.one NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.one
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.one
NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_pkey NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_pkey
NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_a_seq NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_a_seq
NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_c_seq NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_c_seq
@ -423,7 +422,6 @@ CREATE TABLE evttrig.parted (
id int PRIMARY KEY) id int PRIMARY KEY)
PARTITION BY RANGE (id); PARTITION BY RANGE (id);
NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.parted NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.parted
NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.parted
NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.parted_pkey NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.parted_pkey
CREATE TABLE evttrig.part_1_10 PARTITION OF evttrig.parted (id) CREATE TABLE evttrig.part_1_10 PARTITION OF evttrig.parted (id)
FOR VALUES FROM (1) TO (10); FOR VALUES FROM (1) TO (10);

View File

@ -1652,12 +1652,11 @@ SELECT relname, conname, contype, conislocal, coninhcount, connoinherit
FROM pg_class AS pc JOIN pg_constraint AS pgc ON (conrelid = pc.oid) FROM pg_class AS pc JOIN pg_constraint AS pgc ON (conrelid = pc.oid)
WHERE pc.relname = 'fd_pt1' WHERE pc.relname = 'fd_pt1'
ORDER BY 1,2; ORDER BY 1,2;
relname | conname | contype | conislocal | coninhcount | connoinherit relname | conname | contype | conislocal | coninhcount | connoinherit
---------+--------------------+---------+------------+-------------+-------------- ---------+------------+---------+------------+-------------+--------------
fd_pt1 | fd_pt1_c1_not_null | n | t | 0 | f fd_pt1 | fd_pt1chk1 | c | t | 0 | t
fd_pt1 | fd_pt1chk1 | c | t | 0 | t fd_pt1 | fd_pt1chk2 | c | t | 0 | f
fd_pt1 | fd_pt1chk2 | c | t | 0 | f (2 rows)
(3 rows)
-- child does not inherit NO INHERIT constraints -- child does not inherit NO INHERIT constraints
\d+ fd_pt1 \d+ fd_pt1

View File

@ -2036,19 +2036,13 @@ ORDER BY co.contype, cr.relname, co.conname, p.conname;
part33_self_fk | parted_self_fk_id_abc_fkey | f | t | parted_self_fk_id_abc_fkey | t | parted_self_fk part33_self_fk | parted_self_fk_id_abc_fkey | f | t | parted_self_fk_id_abc_fkey | t | parted_self_fk
part3_self_fk | parted_self_fk_id_abc_fkey | f | t | parted_self_fk_id_abc_fkey | t | parted_self_fk part3_self_fk | parted_self_fk_id_abc_fkey | f | t | parted_self_fk_id_abc_fkey | t | parted_self_fk
parted_self_fk | parted_self_fk_id_abc_fkey | f | t | | | parted_self_fk parted_self_fk | parted_self_fk_id_abc_fkey | f | t | | | parted_self_fk
part1_self_fk | part1_self_fk_id_not_null | n | t | | |
part2_self_fk | parted_self_fk_id_not_null | n | t | | |
part32_self_fk | part3_self_fk_id_not_null | n | t | | |
part33_self_fk | part33_self_fk_id_not_null | n | t | | |
part3_self_fk | part3_self_fk_id_not_null | n | t | | |
parted_self_fk | parted_self_fk_id_not_null | n | t | | |
part1_self_fk | part1_self_fk_pkey | p | t | parted_self_fk_pkey | t | part1_self_fk | part1_self_fk_pkey | p | t | parted_self_fk_pkey | t |
part2_self_fk | part2_self_fk_pkey | p | t | parted_self_fk_pkey | t | part2_self_fk | part2_self_fk_pkey | p | t | parted_self_fk_pkey | t |
part32_self_fk | part32_self_fk_pkey | p | t | part3_self_fk_pkey | t | part32_self_fk | part32_self_fk_pkey | p | t | part3_self_fk_pkey | t |
part33_self_fk | part33_self_fk_pkey | p | t | part3_self_fk_pkey | t | part33_self_fk | part33_self_fk_pkey | p | t | part3_self_fk_pkey | t |
part3_self_fk | part3_self_fk_pkey | p | t | parted_self_fk_pkey | t | part3_self_fk | part3_self_fk_pkey | p | t | parted_self_fk_pkey | t |
parted_self_fk | parted_self_fk_pkey | p | t | | | parted_self_fk | parted_self_fk_pkey | p | t | | |
(18 rows) (12 rows)
-- detach and re-attach multiple times just to ensure everything is kosher -- detach and re-attach multiple times just to ensure everything is kosher
ALTER TABLE parted_self_fk DETACH PARTITION part2_self_fk; ALTER TABLE parted_self_fk DETACH PARTITION part2_self_fk;
@ -2071,19 +2065,13 @@ ORDER BY co.contype, cr.relname, co.conname, p.conname;
part33_self_fk | parted_self_fk_id_abc_fkey | f | t | parted_self_fk_id_abc_fkey | t | parted_self_fk part33_self_fk | parted_self_fk_id_abc_fkey | f | t | parted_self_fk_id_abc_fkey | t | parted_self_fk
part3_self_fk | parted_self_fk_id_abc_fkey | f | t | parted_self_fk_id_abc_fkey | t | parted_self_fk part3_self_fk | parted_self_fk_id_abc_fkey | f | t | parted_self_fk_id_abc_fkey | t | parted_self_fk
parted_self_fk | parted_self_fk_id_abc_fkey | f | t | | | parted_self_fk parted_self_fk | parted_self_fk_id_abc_fkey | f | t | | | parted_self_fk
part1_self_fk | part1_self_fk_id_not_null | n | t | | |
part2_self_fk | parted_self_fk_id_not_null | n | t | | |
part32_self_fk | part3_self_fk_id_not_null | n | t | | |
part33_self_fk | part33_self_fk_id_not_null | n | t | | |
part3_self_fk | part3_self_fk_id_not_null | n | t | | |
parted_self_fk | parted_self_fk_id_not_null | n | t | | |
part1_self_fk | part1_self_fk_pkey | p | t | parted_self_fk_pkey | t | part1_self_fk | part1_self_fk_pkey | p | t | parted_self_fk_pkey | t |
part2_self_fk | part2_self_fk_pkey | p | t | parted_self_fk_pkey | t | part2_self_fk | part2_self_fk_pkey | p | t | parted_self_fk_pkey | t |
part32_self_fk | part32_self_fk_pkey | p | t | part3_self_fk_pkey | t | part32_self_fk | part32_self_fk_pkey | p | t | part3_self_fk_pkey | t |
part33_self_fk | part33_self_fk_pkey | p | t | part3_self_fk_pkey | t | part33_self_fk | part33_self_fk_pkey | p | t | part3_self_fk_pkey | t |
part3_self_fk | part3_self_fk_pkey | p | t | parted_self_fk_pkey | t | part3_self_fk | part3_self_fk_pkey | p | t | parted_self_fk_pkey | t |
parted_self_fk | parted_self_fk_pkey | p | t | | | parted_self_fk | parted_self_fk_pkey | p | t | | |
(18 rows) (12 rows)
-- Leave this table around, for pg_upgrade/pg_dump tests -- Leave this table around, for pg_upgrade/pg_dump tests
-- Test creating a constraint at the parent that already exists in partitions. -- Test creating a constraint at the parent that already exists in partitions.

View File

@ -1065,18 +1065,16 @@ create table idxpart3 (b int not null, a int not null);
alter table idxpart attach partition idxpart3 for values from (20, 20) to (30, 30); alter table idxpart attach partition idxpart3 for values from (20, 20) to (30, 30);
select conname, contype, conrelid::regclass, conindid::regclass, conkey select conname, contype, conrelid::regclass, conindid::regclass, conkey
from pg_constraint where conrelid::regclass::text like 'idxpart%' from pg_constraint where conrelid::regclass::text like 'idxpart%'
order by conrelid::regclass::text, conname; order by conname;
conname | contype | conrelid | conindid | conkey conname | contype | conrelid | conindid | conkey
---------------------+---------+-----------+----------------+-------- ----------------+---------+-----------+----------------+--------
idxpart_pkey | p | idxpart | idxpart_pkey | {1,2} idxpart1_pkey | p | idxpart1 | idxpart1_pkey | {1,2}
idxpart1_pkey | p | idxpart1 | idxpart1_pkey | {1,2} idxpart21_pkey | p | idxpart21 | idxpart21_pkey | {1,2}
idxpart2_pkey | p | idxpart2 | idxpart2_pkey | {1,2} idxpart22_pkey | p | idxpart22 | idxpart22_pkey | {1,2}
idxpart21_pkey | p | idxpart21 | idxpart21_pkey | {1,2} idxpart2_pkey | p | idxpart2 | idxpart2_pkey | {1,2}
idxpart22_pkey | p | idxpart22 | idxpart22_pkey | {1,2} idxpart3_pkey | p | idxpart3 | idxpart3_pkey | {2,1}
idxpart3_a_not_null | n | idxpart3 | - | {2} idxpart_pkey | p | idxpart | idxpart_pkey | {1,2}
idxpart3_b_not_null | n | idxpart3 | - | {1} (6 rows)
idxpart3_pkey | p | idxpart3 | idxpart3_pkey | {2,1}
(8 rows)
drop table idxpart; drop table idxpart;
-- Verify that multi-layer partitioning honors the requirement that all -- Verify that multi-layer partitioning honors the requirement that all
@ -1209,21 +1207,12 @@ create table idxpart (a int) partition by range (a);
create table idxpart0 (like idxpart); create table idxpart0 (like idxpart);
alter table idxpart0 add unique (a); alter table idxpart0 add unique (a);
alter table idxpart attach partition idxpart0 default; alter table idxpart attach partition idxpart0 default;
alter table only idxpart add primary key (a); -- works, but idxpart0.a is nullable alter table only idxpart add primary key (a); -- fail, no NOT NULL constraint
\d idxpart0 ERROR: constraint must be added to child tables too
Table "public.idxpart0" DETAIL: Column "a" of relation "idxpart0" is not already NOT NULL.
Column | Type | Collation | Nullable | Default HINT: Do not specify the ONLY keyword.
--------+---------+-----------+----------+---------
a | integer | | |
Partition of: idxpart DEFAULT
Indexes:
"idxpart0_a_key" UNIQUE CONSTRAINT, btree (a)
alter index idxpart_pkey attach partition idxpart0_a_key; -- fails, lacks NOT NULL
ERROR: invalid primary key definition
DETAIL: Column "a" of relation "idxpart0" is not marked NOT NULL.
alter table idxpart0 alter column a set not null; alter table idxpart0 alter column a set not null;
alter index idxpart_pkey attach partition idxpart0_a_key; alter table only idxpart add primary key (a); -- now it works
alter table idxpart0 alter column a drop not null; -- fail, pkey needs it alter table idxpart0 alter column a drop not null; -- fail, pkey needs it
ERROR: column "a" is marked NOT NULL in parent table ERROR: column "a" is marked NOT NULL in parent table
drop table idxpart; drop table idxpart;

View File

@ -1847,414 +1847,6 @@ select * from cnullparent where f1 = 2;
drop table cnullparent cascade; drop table cnullparent cascade;
NOTICE: drop cascades to table cnullchild NOTICE: drop cascades to table cnullchild
-- --
-- Test inheritance of NOT NULL constraints
--
create table pp1 (f1 int);
create table cc1 (f2 text, f3 int) inherits (pp1);
\d cc1
Table "public.cc1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
f1 | integer | | |
f2 | text | | |
f3 | integer | | |
Inherits: pp1
create table cc2(f4 float) inherits(pp1,cc1);
NOTICE: merging multiple inherited definitions of column "f1"
\d cc2
Table "public.cc2"
Column | Type | Collation | Nullable | Default
--------+------------------+-----------+----------+---------
f1 | integer | | |
f2 | text | | |
f3 | integer | | |
f4 | double precision | | |
Inherits: pp1,
cc1
-- named NOT NULL constraint
alter table cc1 add column a2 int constraint nn not null;
\d cc1
Table "public.cc1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
f1 | integer | | |
f2 | text | | |
f3 | integer | | |
a2 | integer | | not null |
Inherits: pp1
Number of child tables: 1 (Use \d+ to list them.)
\d cc2
Table "public.cc2"
Column | Type | Collation | Nullable | Default
--------+------------------+-----------+----------+---------
f1 | integer | | |
f2 | text | | |
f3 | integer | | |
f4 | double precision | | |
a2 | integer | | not null |
Inherits: pp1,
cc1
alter table pp1 alter column f1 set not null;
\d pp1
Table "public.pp1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
f1 | integer | | not null |
Number of child tables: 2 (Use \d+ to list them.)
\d cc1
Table "public.cc1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
f1 | integer | | not null |
f2 | text | | |
f3 | integer | | |
a2 | integer | | not null |
Inherits: pp1
Number of child tables: 1 (Use \d+ to list them.)
\d cc2
Table "public.cc2"
Column | Type | Collation | Nullable | Default
--------+------------------+-----------+----------+---------
f1 | integer | | not null |
f2 | text | | |
f3 | integer | | |
f4 | double precision | | |
a2 | integer | | not null |
Inherits: pp1,
cc1
-- have a look at pg_constraint
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('pp1'::regclass, 'cc1'::regclass, 'cc2'::regclass)
order by 2, 1;
conrelid | conname | contype | conkey | attname | coninhcount | conislocal
----------+-----------------+---------+--------+---------+-------------+------------
cc1 | nn | n | {4} | a2 | 0 | t
cc2 | nn | n | {5} | a2 | 1 | f
pp1 | pp1_f1_not_null | n | {1} | f1 | 0 | t
cc1 | pp1_f1_not_null | n | {1} | f1 | 1 | f
cc2 | pp1_f1_not_null | n | {1} | f1 | 1 | f
(5 rows)
-- remove constraint from cc2: no dice, it's inherited
alter table cc2 alter column a2 drop not null;
ERROR: cannot drop inherited constraint "nn" of relation "cc2"
-- remove constraint cc1, should succeed
alter table cc1 alter column a2 drop not null;
-- have a look at pg_constraint
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('pp1'::regclass, 'cc1'::regclass, 'cc2'::regclass)
order by 2, 1;
conrelid | conname | contype | conkey | attname | coninhcount | conislocal
----------+-----------------+---------+--------+---------+-------------+------------
pp1 | pp1_f1_not_null | n | {1} | f1 | 0 | t
cc1 | pp1_f1_not_null | n | {1} | f1 | 1 | f
cc2 | pp1_f1_not_null | n | {1} | f1 | 1 | f
(3 rows)
-- same for cc2
alter table cc2 alter column f1 drop not null;
ERROR: cannot drop inherited constraint "pp1_f1_not_null" of relation "cc2"
-- remove from cc1, should fail again
alter table cc1 alter column f1 drop not null;
ERROR: cannot drop inherited constraint "pp1_f1_not_null" of relation "cc1"
-- remove from pp1, should succeed
alter table pp1 alter column f1 drop not null;
-- have a look at pg_constraint
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('pp1'::regclass, 'cc1'::regclass, 'cc2'::regclass)
order by 2, 1;
conrelid | conname | contype | conkey | attname | coninhcount | conislocal
----------+---------+---------+--------+---------+-------------+------------
(0 rows)
drop table pp1 cascade;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table cc1
drop cascades to table cc2
\d cc1
\d cc2
-- test "dropping" a not null constraint that's also inherited
create table inh_parent (a int not null);
create table inh_child (a int not null) inherits (inh_parent);
NOTICE: merging column "a" with inherited definition
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal, connoinherit
from pg_constraint where contype in ('n','p') and
conrelid in ('inh_child'::regclass, 'inh_parent'::regclass)
order by 1, 2;
conrelid | conname | contype | conkey | attname | coninhcount | conislocal | connoinherit
------------+-----------------------+---------+--------+---------+-------------+------------+--------------
inh_parent | inh_parent_a_not_null | n | {1} | a | 0 | t | f
inh_child | inh_child_a_not_null | n | {1} | a | 1 | t | f
(2 rows)
alter table inh_child alter a drop not null;
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal, connoinherit
from pg_constraint where contype in ('n','p') and
conrelid in ('inh_child'::regclass, 'inh_parent'::regclass)
order by 1, 2;
conrelid | conname | contype | conkey | attname | coninhcount | conislocal | connoinherit
------------+-----------------------+---------+--------+---------+-------------+------------+--------------
inh_parent | inh_parent_a_not_null | n | {1} | a | 0 | t | f
inh_child | inh_child_a_not_null | n | {1} | a | 1 | f | f
(2 rows)
alter table inh_parent alter a drop not null;
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal, connoinherit
from pg_constraint where contype in ('n','p') and
conrelid in ('inh_child'::regclass, 'inh_parent'::regclass)
order by 1, 2;
conrelid | conname | contype | conkey | attname | coninhcount | conislocal | connoinherit
----------+---------+---------+--------+---------+-------------+------------+--------------
(0 rows)
drop table inh_parent, inh_child;
-- NOT NULL NO INHERIT
create table inh_parent(a int);
create table inh_child() inherits (inh_parent);
alter table inh_parent add not null a no inherit;
create table inh_child2() inherits (inh_parent);
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal, connoinherit
from pg_constraint where contype = 'n' and
conrelid in ('inh_parent'::regclass, 'inh_child'::regclass, 'inh_child2'::regclass)
order by 2, 1;
conrelid | conname | contype | conkey | attname | coninhcount | conislocal | connoinherit
------------+-----------------------+---------+--------+---------+-------------+------------+--------------
inh_parent | inh_parent_a_not_null | n | {1} | a | 0 | t | t
(1 row)
\d inh_parent
Table "public.inh_parent"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | not null |
Number of child tables: 2 (Use \d+ to list them.)
\d inh_child
Table "public.inh_child"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
Inherits: inh_parent
\d inh_child2
Table "public.inh_child2"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
Inherits: inh_parent
drop table inh_parent, inh_child, inh_child2;
--
-- test inherit/deinherit
--
create table inh_parent(f1 int);
create table inh_child1(f1 int not null);
create table inh_child2(f1 int);
-- inh_child1 should have not null constraint
alter table inh_child1 inherit inh_parent;
-- should fail, missing NOT NULL constraint
alter table inh_child2 inherit inh_child1;
ERROR: column "f1" in child table must be marked NOT NULL
alter table inh_child2 alter column f1 set not null;
alter table inh_child2 inherit inh_child1;
-- add NOT NULL constraint recursively
alter table inh_parent alter column f1 set not null;
\d inh_parent
Table "public.inh_parent"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
f1 | integer | | not null |
Number of child tables: 1 (Use \d+ to list them.)
\d inh_child1
Table "public.inh_child1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
f1 | integer | | not null |
Inherits: inh_parent
Number of child tables: 1 (Use \d+ to list them.)
\d inh_child2
Table "public.inh_child2"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
f1 | integer | | not null |
Inherits: inh_child1
select conrelid::regclass, conname, contype, coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('inh_parent'::regclass, 'inh_child1'::regclass, 'inh_child2'::regclass)
order by 2, 1;
conrelid | conname | contype | coninhcount | conislocal
------------+------------------------+---------+-------------+------------
inh_child1 | inh_child1_f1_not_null | n | 1 | t
inh_child2 | inh_child2_f1_not_null | n | 1 | t
inh_parent | inh_parent_f1_not_null | n | 0 | t
(3 rows)
--
-- test deinherit procedure
--
-- deinherit inh_child1
alter table inh_child1 no inherit inh_parent;
\d inh_parent
Table "public.inh_parent"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
f1 | integer | | not null |
\d inh_child1
Table "public.inh_child1"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
f1 | integer | | not null |
Number of child tables: 1 (Use \d+ to list them.)
\d inh_child2
Table "public.inh_child2"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
f1 | integer | | not null |
Inherits: inh_child1
select conrelid::regclass, conname, contype, coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('inh_parent'::regclass, 'inh_child1'::regclass, 'inh_child2'::regclass)
order by 2, 1;
conrelid | conname | contype | coninhcount | conislocal
------------+------------------------+---------+-------------+------------
inh_child1 | inh_child1_f1_not_null | n | 0 | t
inh_child2 | inh_child2_f1_not_null | n | 1 | t
inh_parent | inh_parent_f1_not_null | n | 0 | t
(3 rows)
-- test inhcount of inh_child2, should fail
alter table inh_child2 alter f1 drop not null;
-- should succeed
drop table inh_parent;
drop table inh_child1 cascade;
NOTICE: drop cascades to table inh_child2
--
-- test multi inheritance tree
--
create table inh_parent(f1 int not null);
create table c1() inherits(inh_parent);
create table c2() inherits(inh_parent);
create table d1() inherits(c1, c2);
NOTICE: merging multiple inherited definitions of column "f1"
-- show constraint info
select conrelid::regclass, conname, contype, coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('inh_parent'::regclass, 'c1'::regclass, 'c2'::regclass, 'd1'::regclass)
order by 2, 1;
conrelid | conname | contype | coninhcount | conislocal
------------+------------------------+---------+-------------+------------
inh_parent | inh_parent_f1_not_null | n | 0 | t
c1 | inh_parent_f1_not_null | n | 1 | f
c2 | inh_parent_f1_not_null | n | 1 | f
d1 | inh_parent_f1_not_null | n | 2 | f
(4 rows)
drop table inh_parent cascade;
NOTICE: drop cascades to 3 other objects
DETAIL: drop cascades to table c1
drop cascades to table c2
drop cascades to table d1
-- test child table with inherited columns and
-- with explicitly specified not null constraints
create table inh_parent_1(f1 int);
create table inh_parent_2(f2 text);
create table inh_child(f1 int not null, f2 text not null) inherits(inh_parent_1, inh_parent_2);
NOTICE: merging column "f1" with inherited definition
NOTICE: merging column "f2" with inherited definition
-- show constraint info
select conrelid::regclass, conname, contype, coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('inh_parent_1'::regclass, 'inh_parent_2'::regclass, 'inh_child'::regclass)
order by 2, 1;
conrelid | conname | contype | coninhcount | conislocal
-----------+-----------------------+---------+-------------+------------
inh_child | inh_child_f1_not_null | n | 0 | t
inh_child | inh_child_f2_not_null | n | 0 | t
(2 rows)
-- also drops inh_child table
drop table inh_parent_1 cascade;
NOTICE: drop cascades to table inh_child
drop table inh_parent_2;
-- test multi layer inheritance tree
create table inh_p1(f1 int not null);
create table inh_p2(f1 int not null);
create table inh_p3(f2 int);
create table inh_p4(f1 int not null, f3 text not null);
create table inh_multiparent() inherits(inh_p1, inh_p2, inh_p3, inh_p4);
NOTICE: merging multiple inherited definitions of column "f1"
NOTICE: merging multiple inherited definitions of column "f1"
-- constraint on f1 should have three parents
select conrelid::regclass, contype, conname,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid::regclass in ('inh_p1', 'inh_p2', 'inh_p3', 'inh_p4',
'inh_multiparent')
order by conrelid::regclass::text, conname;
conrelid | contype | conname | attname | coninhcount | conislocal
-----------------+---------+--------------------+---------+-------------+------------
inh_multiparent | n | inh_p1_f1_not_null | f1 | 3 | f
inh_multiparent | n | inh_p4_f3_not_null | f3 | 1 | f
inh_p1 | n | inh_p1_f1_not_null | f1 | 0 | t
inh_p2 | n | inh_p2_f1_not_null | f1 | 0 | t
inh_p4 | n | inh_p4_f1_not_null | f1 | 0 | t
inh_p4 | n | inh_p4_f3_not_null | f3 | 0 | t
(6 rows)
create table inh_multiparent2 (a int not null, f1 int) inherits(inh_p3, inh_multiparent);
NOTICE: merging multiple inherited definitions of column "f2"
NOTICE: merging column "f1" with inherited definition
select conrelid::regclass, contype, conname,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid::regclass in ('inh_p3', 'inh_multiparent', 'inh_multiparent2')
order by conrelid::regclass::text, conname;
conrelid | contype | conname | attname | coninhcount | conislocal
------------------+---------+-----------------------------+---------+-------------+------------
inh_multiparent | n | inh_p1_f1_not_null | f1 | 3 | f
inh_multiparent | n | inh_p4_f3_not_null | f3 | 1 | f
inh_multiparent2 | n | inh_multiparent2_a_not_null | a | 0 | t
inh_multiparent2 | n | inh_p1_f1_not_null | f1 | 1 | f
inh_multiparent2 | n | inh_p4_f3_not_null | f3 | 1 | f
(5 rows)
drop table inh_p1, inh_p2, inh_p3, inh_p4 cascade;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table inh_multiparent
drop cascades to table inh_multiparent2
--
-- Check use of temporary tables with inheritance trees -- Check use of temporary tables with inheritance trees
-- --
create table inh_perm_parent (a1 int); create table inh_perm_parent (a1 int);

View File

@ -263,21 +263,8 @@ Indexes:
"test_replica_identity4_pkey" PRIMARY KEY, btree (id) REPLICA IDENTITY "test_replica_identity4_pkey" PRIMARY KEY, btree (id) REPLICA IDENTITY
Partitions: test_replica_identity4_1 FOR VALUES IN (1) Partitions: test_replica_identity4_1 FOR VALUES IN (1)
-- Dropping the primary key is not allowed if that would leave the replica
-- identity as nullable
CREATE TABLE test_replica_identity5 (a int not null, b int, c int,
PRIMARY KEY (b, c));
CREATE UNIQUE INDEX test_replica_identity5_a_b_key ON test_replica_identity5 (a, b);
ALTER TABLE test_replica_identity5 REPLICA IDENTITY USING INDEX test_replica_identity5_a_b_key;
ALTER TABLE test_replica_identity5 DROP CONSTRAINT test_replica_identity5_pkey;
ERROR: column "b" is in index used as replica identity
ALTER TABLE test_replica_identity5 ALTER b SET NOT NULL;
ALTER TABLE test_replica_identity5 DROP CONSTRAINT test_replica_identity5_pkey;
ALTER TABLE test_replica_identity5 ALTER b DROP NOT NULL;
ERROR: column "b" is in index used as replica identity
DROP TABLE test_replica_identity; DROP TABLE test_replica_identity;
DROP TABLE test_replica_identity2; DROP TABLE test_replica_identity2;
DROP TABLE test_replica_identity3; DROP TABLE test_replica_identity3;
DROP TABLE test_replica_identity4; DROP TABLE test_replica_identity4;
DROP TABLE test_replica_identity5;
DROP TABLE test_replica_identity_othertable; DROP TABLE test_replica_identity_othertable;

View File

@ -121,8 +121,7 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion tr
# ---------- # ----------
test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain compression memoize stats test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain compression memoize stats
# event_trigger depends on create_am and cannot run concurrently with # event_trigger cannot run concurrently with any test that runs DDL
# any test that runs DDL
# oidjoins is read-only, though, and should run late for best coverage # oidjoins is read-only, though, and should run late for best coverage
test: event_trigger oidjoins test: event_trigger oidjoins

View File

@ -852,7 +852,7 @@ create table atacc1 (test int not null);
alter table atacc1 add constraint "atacc1_pkey" primary key (test); alter table atacc1 add constraint "atacc1_pkey" primary key (test);
alter table atacc1 alter column test drop not null; alter table atacc1 alter column test drop not null;
alter table atacc1 drop constraint "atacc1_pkey"; alter table atacc1 drop constraint "atacc1_pkey";
\d atacc1 alter table atacc1 alter column test drop not null;
insert into atacc1 values (null); insert into atacc1 values (null);
alter table atacc1 alter test set not null; alter table atacc1 alter test set not null;
delete from atacc1; delete from atacc1;
@ -917,6 +917,14 @@ insert into parent values (NULL);
insert into child (a, b) values (NULL, 'foo'); insert into child (a, b) values (NULL, 'foo');
alter table only parent alter a set not null; alter table only parent alter a set not null;
alter table child alter a set not null; alter table child alter a set not null;
delete from parent;
alter table only parent alter a set not null;
insert into parent values (NULL);
alter table child alter a set not null;
insert into child (a, b) values (NULL, 'foo');
delete from child;
alter table child alter a set not null;
insert into child (a, b) values (NULL, 'foo');
drop table child; drop table child;
drop table parent; drop table parent;
@ -2334,22 +2342,6 @@ ALTER TABLE ataddindex
\d ataddindex \d ataddindex
DROP TABLE ataddindex; DROP TABLE ataddindex;
CREATE TABLE atnotnull1 ();
ALTER TABLE atnotnull1
ADD COLUMN a INT,
ALTER a SET NOT NULL;
ALTER TABLE atnotnull1
ADD COLUMN b INT,
ADD NOT NULL b;
ALTER TABLE atnotnull1
ADD COLUMN c INT,
ADD PRIMARY KEY (c);
SELECT conrelid::regclass, conname, contype, conkey,
(SELECT attname FROM pg_attribute WHERE attrelid = conrelid AND attnum = conkey[1]),
coninhcount, conislocal
FROM pg_constraint WHERE contype IN ('n','p') AND
conrelid IN ('atnotnull1'::regclass);
-- unsupported constraint types for partitioned tables -- unsupported constraint types for partitioned tables
CREATE TABLE partitioned ( CREATE TABLE partitioned (
a int, a int,

View File

@ -196,17 +196,6 @@ INSERT INTO ATACC2 (TEST2) VALUES (3);
INSERT INTO ATACC1 (TEST2) VALUES (3); INSERT INTO ATACC1 (TEST2) VALUES (3);
DROP TABLE ATACC1 CASCADE; DROP TABLE ATACC1 CASCADE;
-- NOT NULL NO INHERIT
CREATE TABLE ATACC1 (a int, not null a no inherit);
CREATE TABLE ATACC2 () INHERITS (ATACC1);
\d ATACC2
DROP TABLE ATACC1, ATACC2;
CREATE TABLE ATACC1 (a int);
ALTER TABLE ATACC1 ADD NOT NULL a NO INHERIT;
CREATE TABLE ATACC2 () INHERITS (ATACC1);
\d ATACC2
DROP TABLE ATACC1, ATACC2;
-- --
-- Check constraints on INSERT INTO -- Check constraints on INSERT INTO
-- --
@ -567,38 +556,6 @@ ALTER TABLE deferred_excl ADD EXCLUDE (f1 WITH =);
DROP TABLE deferred_excl; DROP TABLE deferred_excl;
-- verify constraints created for NOT NULL clauses
CREATE TABLE notnull_tbl1 (a INTEGER NOT NULL);
\d notnull_tbl1
select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
-- DROP NOT NULL gets rid of both the attnotnull flag and the constraint itself
ALTER TABLE notnull_tbl1 ALTER a DROP NOT NULL;
\d notnull_tbl1
select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
-- SET NOT NULL puts both back
ALTER TABLE notnull_tbl1 ALTER a SET NOT NULL;
\d notnull_tbl1
select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
-- Doing it twice doesn't create a redundant constraint
ALTER TABLE notnull_tbl1 ALTER a SET NOT NULL;
select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
-- Using the "table constraint" syntax also works
ALTER TABLE notnull_tbl1 ALTER a DROP NOT NULL;
ALTER TABLE notnull_tbl1 ADD CONSTRAINT foobar NOT NULL a;
\d notnull_tbl1
select conname, contype, conkey from pg_constraint where conrelid = 'notnull_tbl1'::regclass;
DROP TABLE notnull_tbl1;
CREATE TABLE notnull_tbl2 (a INTEGER PRIMARY KEY);
ALTER TABLE notnull_tbl2 ALTER a DROP NOT NULL;
CREATE TABLE notnull_tbl3 (a INTEGER NOT NULL, CHECK (a IS NOT NULL));
ALTER TABLE notnull_tbl3 ALTER A DROP NOT NULL;
ALTER TABLE notnull_tbl3 ADD b int, ADD CONSTRAINT pk PRIMARY KEY (a, b);
\d notnull_tbl3
ALTER TABLE notnull_tbl3 DROP CONSTRAINT pk;
\d notnull_tbl3
-- Comments -- Comments
-- Setup a low-level role to enforce non-superuser checks. -- Setup a low-level role to enforce non-superuser checks.
CREATE ROLE regress_constraint_comments; CREATE ROLE regress_constraint_comments;

View File

@ -532,11 +532,11 @@ CREATE TABLE part_b PARTITION OF parted (
CONSTRAINT check_b CHECK (b >= 0) CONSTRAINT check_b CHECK (b >= 0)
) FOR VALUES IN ('b'); ) FOR VALUES IN ('b');
-- conislocal should be false for any merged constraints, true otherwise -- conislocal should be false for any merged constraints, true otherwise
SELECT conname, conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass ORDER BY coninhcount DESC, conname; SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass ORDER BY conislocal, coninhcount;
-- Once check_b is added to the parent, it should be made non-local for part_b -- Once check_b is added to the parent, it should be made non-local for part_b
ALTER TABLE parted ADD CONSTRAINT check_b CHECK (b >= 0); ALTER TABLE parted ADD CONSTRAINT check_b CHECK (b >= 0);
SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass ORDER BY coninhcount DESC, conname; SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass;
-- Neither check_a nor check_b are droppable from part_b -- Neither check_a nor check_b are droppable from part_b
ALTER TABLE part_b DROP CONSTRAINT check_a; ALTER TABLE part_b DROP CONSTRAINT check_a;
@ -546,7 +546,7 @@ ALTER TABLE part_b DROP CONSTRAINT check_b;
-- traditional inheritance where they will be left behind, because they would -- traditional inheritance where they will be left behind, because they would
-- be local constraints. -- be local constraints.
ALTER TABLE parted DROP CONSTRAINT check_a, DROP CONSTRAINT check_b; ALTER TABLE parted DROP CONSTRAINT check_a, DROP CONSTRAINT check_b;
SELECT conname, conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass ORDER BY coninhcount; SELECT conislocal, coninhcount FROM pg_constraint WHERE conrelid = 'part_b'::regclass;
-- specify PARTITION BY for a partition -- specify PARTITION BY for a partition
CREATE TABLE fail_part_col_not_found PARTITION OF parted FOR VALUES IN ('c') PARTITION BY RANGE (c); CREATE TABLE fail_part_col_not_found PARTITION OF parted FOR VALUES IN ('c') PARTITION BY RANGE (c);

View File

@ -522,7 +522,7 @@ create table idxpart3 (b int not null, a int not null);
alter table idxpart attach partition idxpart3 for values from (20, 20) to (30, 30); alter table idxpart attach partition idxpart3 for values from (20, 20) to (30, 30);
select conname, contype, conrelid::regclass, conindid::regclass, conkey select conname, contype, conrelid::regclass, conindid::regclass, conkey
from pg_constraint where conrelid::regclass::text like 'idxpart%' from pg_constraint where conrelid::regclass::text like 'idxpart%'
order by conrelid::regclass::text, conname; order by conname;
drop table idxpart; drop table idxpart;
-- Verify that multi-layer partitioning honors the requirement that all -- Verify that multi-layer partitioning honors the requirement that all
@ -620,11 +620,9 @@ create table idxpart (a int) partition by range (a);
create table idxpart0 (like idxpart); create table idxpart0 (like idxpart);
alter table idxpart0 add unique (a); alter table idxpart0 add unique (a);
alter table idxpart attach partition idxpart0 default; alter table idxpart attach partition idxpart0 default;
alter table only idxpart add primary key (a); -- works, but idxpart0.a is nullable alter table only idxpart add primary key (a); -- fail, no NOT NULL constraint
\d idxpart0
alter index idxpart_pkey attach partition idxpart0_a_key; -- fails, lacks NOT NULL
alter table idxpart0 alter column a set not null; alter table idxpart0 alter column a set not null;
alter index idxpart_pkey attach partition idxpart0_a_key; alter table only idxpart add primary key (a); -- now it works
alter table idxpart0 alter column a drop not null; -- fail, pkey needs it alter table idxpart0 alter column a drop not null; -- fail, pkey needs it
drop table idxpart; drop table idxpart;

View File

@ -679,217 +679,6 @@ select * from cnullparent;
select * from cnullparent where f1 = 2; select * from cnullparent where f1 = 2;
drop table cnullparent cascade; drop table cnullparent cascade;
--
-- Test inheritance of NOT NULL constraints
--
create table pp1 (f1 int);
create table cc1 (f2 text, f3 int) inherits (pp1);
\d cc1
create table cc2(f4 float) inherits(pp1,cc1);
\d cc2
-- named NOT NULL constraint
alter table cc1 add column a2 int constraint nn not null;
\d cc1
\d cc2
alter table pp1 alter column f1 set not null;
\d pp1
\d cc1
\d cc2
-- have a look at pg_constraint
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('pp1'::regclass, 'cc1'::regclass, 'cc2'::regclass)
order by 2, 1;
-- remove constraint from cc2: no dice, it's inherited
alter table cc2 alter column a2 drop not null;
-- remove constraint cc1, should succeed
alter table cc1 alter column a2 drop not null;
-- have a look at pg_constraint
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('pp1'::regclass, 'cc1'::regclass, 'cc2'::regclass)
order by 2, 1;
-- same for cc2
alter table cc2 alter column f1 drop not null;
-- remove from cc1, should fail again
alter table cc1 alter column f1 drop not null;
-- remove from pp1, should succeed
alter table pp1 alter column f1 drop not null;
-- have a look at pg_constraint
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('pp1'::regclass, 'cc1'::regclass, 'cc2'::regclass)
order by 2, 1;
drop table pp1 cascade;
\d cc1
\d cc2
-- test "dropping" a not null constraint that's also inherited
create table inh_parent (a int not null);
create table inh_child (a int not null) inherits (inh_parent);
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal, connoinherit
from pg_constraint where contype in ('n','p') and
conrelid in ('inh_child'::regclass, 'inh_parent'::regclass)
order by 1, 2;
alter table inh_child alter a drop not null;
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal, connoinherit
from pg_constraint where contype in ('n','p') and
conrelid in ('inh_child'::regclass, 'inh_parent'::regclass)
order by 1, 2;
alter table inh_parent alter a drop not null;
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal, connoinherit
from pg_constraint where contype in ('n','p') and
conrelid in ('inh_child'::regclass, 'inh_parent'::regclass)
order by 1, 2;
drop table inh_parent, inh_child;
-- NOT NULL NO INHERIT
create table inh_parent(a int);
create table inh_child() inherits (inh_parent);
alter table inh_parent add not null a no inherit;
create table inh_child2() inherits (inh_parent);
select conrelid::regclass, conname, contype, conkey,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal, connoinherit
from pg_constraint where contype = 'n' and
conrelid in ('inh_parent'::regclass, 'inh_child'::regclass, 'inh_child2'::regclass)
order by 2, 1;
\d inh_parent
\d inh_child
\d inh_child2
drop table inh_parent, inh_child, inh_child2;
--
-- test inherit/deinherit
--
create table inh_parent(f1 int);
create table inh_child1(f1 int not null);
create table inh_child2(f1 int);
-- inh_child1 should have not null constraint
alter table inh_child1 inherit inh_parent;
-- should fail, missing NOT NULL constraint
alter table inh_child2 inherit inh_child1;
alter table inh_child2 alter column f1 set not null;
alter table inh_child2 inherit inh_child1;
-- add NOT NULL constraint recursively
alter table inh_parent alter column f1 set not null;
\d inh_parent
\d inh_child1
\d inh_child2
select conrelid::regclass, conname, contype, coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('inh_parent'::regclass, 'inh_child1'::regclass, 'inh_child2'::regclass)
order by 2, 1;
--
-- test deinherit procedure
--
-- deinherit inh_child1
alter table inh_child1 no inherit inh_parent;
\d inh_parent
\d inh_child1
\d inh_child2
select conrelid::regclass, conname, contype, coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('inh_parent'::regclass, 'inh_child1'::regclass, 'inh_child2'::regclass)
order by 2, 1;
-- test inhcount of inh_child2, should fail
alter table inh_child2 alter f1 drop not null;
-- should succeed
drop table inh_parent;
drop table inh_child1 cascade;
--
-- test multi inheritance tree
--
create table inh_parent(f1 int not null);
create table c1() inherits(inh_parent);
create table c2() inherits(inh_parent);
create table d1() inherits(c1, c2);
-- show constraint info
select conrelid::regclass, conname, contype, coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('inh_parent'::regclass, 'c1'::regclass, 'c2'::regclass, 'd1'::regclass)
order by 2, 1;
drop table inh_parent cascade;
-- test child table with inherited columns and
-- with explicitly specified not null constraints
create table inh_parent_1(f1 int);
create table inh_parent_2(f2 text);
create table inh_child(f1 int not null, f2 text not null) inherits(inh_parent_1, inh_parent_2);
-- show constraint info
select conrelid::regclass, conname, contype, coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid in ('inh_parent_1'::regclass, 'inh_parent_2'::regclass, 'inh_child'::regclass)
order by 2, 1;
-- also drops inh_child table
drop table inh_parent_1 cascade;
drop table inh_parent_2;
-- test multi layer inheritance tree
create table inh_p1(f1 int not null);
create table inh_p2(f1 int not null);
create table inh_p3(f2 int);
create table inh_p4(f1 int not null, f3 text not null);
create table inh_multiparent() inherits(inh_p1, inh_p2, inh_p3, inh_p4);
-- constraint on f1 should have three parents
select conrelid::regclass, contype, conname,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid::regclass in ('inh_p1', 'inh_p2', 'inh_p3', 'inh_p4',
'inh_multiparent')
order by conrelid::regclass::text, conname;
create table inh_multiparent2 (a int not null, f1 int) inherits(inh_p3, inh_multiparent);
select conrelid::regclass, contype, conname,
(select attname from pg_attribute where attrelid = conrelid and attnum = conkey[1]),
coninhcount, conislocal
from pg_constraint where contype = 'n' and
conrelid::regclass in ('inh_p3', 'inh_multiparent', 'inh_multiparent2')
order by conrelid::regclass::text, conname;
drop table inh_p1, inh_p2, inh_p3, inh_p4 cascade;
-- --
-- Check use of temporary tables with inheritance trees -- Check use of temporary tables with inheritance trees
-- --

View File

@ -117,20 +117,8 @@ ALTER INDEX test_replica_identity4_pkey
ATTACH PARTITION test_replica_identity4_1_pkey; ATTACH PARTITION test_replica_identity4_1_pkey;
\d+ test_replica_identity4 \d+ test_replica_identity4
-- Dropping the primary key is not allowed if that would leave the replica
-- identity as nullable
CREATE TABLE test_replica_identity5 (a int not null, b int, c int,
PRIMARY KEY (b, c));
CREATE UNIQUE INDEX test_replica_identity5_a_b_key ON test_replica_identity5 (a, b);
ALTER TABLE test_replica_identity5 REPLICA IDENTITY USING INDEX test_replica_identity5_a_b_key;
ALTER TABLE test_replica_identity5 DROP CONSTRAINT test_replica_identity5_pkey;
ALTER TABLE test_replica_identity5 ALTER b SET NOT NULL;
ALTER TABLE test_replica_identity5 DROP CONSTRAINT test_replica_identity5_pkey;
ALTER TABLE test_replica_identity5 ALTER b DROP NOT NULL;
DROP TABLE test_replica_identity; DROP TABLE test_replica_identity;
DROP TABLE test_replica_identity2; DROP TABLE test_replica_identity2;
DROP TABLE test_replica_identity3; DROP TABLE test_replica_identity3;
DROP TABLE test_replica_identity4; DROP TABLE test_replica_identity4;
DROP TABLE test_replica_identity5;
DROP TABLE test_replica_identity_othertable; DROP TABLE test_replica_identity_othertable;