Commit 45616f5b authored by Tom Lane's avatar Tom Lane

Clean up generation of default names for constraints, indexes, and serial

sequences, as per recent discussion.  All these names are now of the
form table_column_type, with digits added if needed to make them unique.
Default constraint names are chosen to be unique across their whole schema,
not just within the parent object, so as to be more SQL-spec-compatible
and make the information schema views more useful.
parent 75db5a66
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.269 2004/06/06 20:30:07 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.270 2004/06/10 17:55:53 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -1488,7 +1488,7 @@ AddRelationRawConstraints(Relation rel, ...@@ -1488,7 +1488,7 @@ AddRelationRawConstraints(Relation rel,
ParseState *pstate; ParseState *pstate;
RangeTblEntry *rte; RangeTblEntry *rte;
int numchecks; int numchecks;
int constr_name_ctr = 0; List *checknames;
ListCell *cell; ListCell *cell;
Node *expr; Node *expr;
CookedConstraint *cooked; CookedConstraint *cooked;
...@@ -1547,6 +1547,7 @@ AddRelationRawConstraints(Relation rel, ...@@ -1547,6 +1547,7 @@ AddRelationRawConstraints(Relation rel,
* Process constraint expressions. * Process constraint expressions.
*/ */
numchecks = numoldchecks; numchecks = numoldchecks;
checknames = NIL;
foreach(cell, rawConstraints) foreach(cell, rawConstraints)
{ {
Constraint *cdef = (Constraint *) lfirst(cell); Constraint *cdef = (Constraint *) lfirst(cell);
...@@ -1556,81 +1557,6 @@ AddRelationRawConstraints(Relation rel, ...@@ -1556,81 +1557,6 @@ AddRelationRawConstraints(Relation rel,
continue; continue;
Assert(cdef->cooked_expr == NULL); Assert(cdef->cooked_expr == NULL);
/* Check name uniqueness, or generate a new name */
if (cdef->name != NULL)
{
ListCell *cell2;
ccname = cdef->name;
/* Check against pre-existing constraints */
if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
RelationGetRelid(rel),
RelationGetNamespace(rel),
ccname))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("constraint \"%s\" for relation \"%s\" already exists",
ccname, RelationGetRelationName(rel))));
/* Check against other new constraints */
/* Needed because we don't do CommandCounterIncrement in loop */
foreach(cell2, rawConstraints)
{
Constraint *cdef2 = (Constraint *) lfirst(cell2);
if (cdef2 == cdef ||
cdef2->contype != CONSTR_CHECK ||
cdef2->raw_expr == NULL ||
cdef2->name == NULL)
continue;
if (strcmp(cdef2->name, ccname) == 0)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("check constraint \"%s\" already exists",
ccname)));
}
}
else
{
bool success;
do
{
ListCell *cell2;
/*
* Generate a name that does not conflict with
* pre-existing constraints, nor with any auto-generated
* names so far.
*/
ccname = GenerateConstraintName(CONSTRAINT_RELATION,
RelationGetRelid(rel),
RelationGetNamespace(rel),
&constr_name_ctr);
/*
* Check against other new constraints, in case the user
* has specified a name that looks like an auto-generated
* name.
*/
success = true;
foreach(cell2, rawConstraints)
{
Constraint *cdef2 = (Constraint *) lfirst(cell2);
if (cdef2 == cdef ||
cdef2->contype != CONSTR_CHECK ||
cdef2->raw_expr == NULL ||
cdef2->name == NULL)
continue;
if (strcmp(cdef2->name, ccname) == 0)
{
success = false;
break;
}
}
} while (!success);
}
/* /*
* Transform raw parsetree to executable expression. * Transform raw parsetree to executable expression.
*/ */
...@@ -1662,6 +1588,73 @@ AddRelationRawConstraints(Relation rel, ...@@ -1662,6 +1588,73 @@ AddRelationRawConstraints(Relation rel,
(errcode(ERRCODE_GROUPING_ERROR), (errcode(ERRCODE_GROUPING_ERROR),
errmsg("cannot use aggregate function in check constraint"))); errmsg("cannot use aggregate function in check constraint")));
/*
* Check name uniqueness, or generate a name if none was given.
*/
if (cdef->name != NULL)
{
ListCell *cell2;
ccname = cdef->name;
/* Check against pre-existing constraints */
if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
RelationGetRelid(rel),
RelationGetNamespace(rel),
ccname))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("constraint \"%s\" for relation \"%s\" already exists",
ccname, RelationGetRelationName(rel))));
/* 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)));
}
}
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, false);
/* eliminate duplicates */
vars = list_union(NIL, vars);
if (list_length(vars) == 1)
colname = get_attname(RelationGetRelid(rel),
((Var *) linitial(vars))->varattno);
else
colname = NULL;
ccname = ChooseConstraintName(RelationGetRelationName(rel),
colname,
"check",
RelationGetNamespace(rel),
checknames);
}
/* save name for future checks */
checknames = lappend(checknames, ccname);
/* /*
* OK, store it. * OK, store it.
*/ */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.19 2003/11/29 19:51:46 pgsql Exp $ * $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.20 2004/06/10 17:55:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/pg_constraint.h" #include "catalog/pg_constraint.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/array.h" #include "utils/array.h"
#include "utils/builtins.h" #include "utils/builtins.h"
...@@ -263,13 +264,19 @@ CreateConstraintEntry(const char *constraintName, ...@@ -263,13 +264,19 @@ CreateConstraintEntry(const char *constraintName,
/* /*
* Test whether given name is currently used as a constraint name * Test whether given name is currently used as a constraint name
* for the given relation. * for the given object (relation or domain).
* *
* NB: Caller should hold exclusive lock on the given relation, else * This is used to decide whether to accept a user-specified constraint name.
* this test is not very meaningful. * It is deliberately not the same test as ChooseConstraintName uses to decide
* whether an auto-generated name is OK: here, we will allow it unless there
* is an identical constraint name in use *on the same object*.
*
* NB: Caller should hold exclusive lock on the given object, else
* this test can be fooled by concurrent additions.
*/ */
bool bool
ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, const char *cname) ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
Oid objNamespace, const char *conname)
{ {
bool found; bool found;
Relation conDesc; Relation conDesc;
...@@ -277,14 +284,14 @@ ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, con ...@@ -277,14 +284,14 @@ ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, con
ScanKeyData skey[2]; ScanKeyData skey[2];
HeapTuple tup; HeapTuple tup;
conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock); conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
found = false; found = false;
ScanKeyInit(&skey[0], ScanKeyInit(&skey[0],
Anum_pg_constraint_conname, Anum_pg_constraint_conname,
BTEqualStrategyNumber, F_NAMEEQ, BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(cname)); CStringGetDatum(conname));
ScanKeyInit(&skey[1], ScanKeyInit(&skey[1],
Anum_pg_constraint_connamespace, Anum_pg_constraint_connamespace,
...@@ -311,101 +318,99 @@ ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, con ...@@ -311,101 +318,99 @@ ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, con
} }
systable_endscan(conscan); systable_endscan(conscan);
heap_close(conDesc, RowExclusiveLock); heap_close(conDesc, AccessShareLock);
return found; return found;
} }
/* /*
* Generate a currently-unused constraint name for the given relation. * Select a nonconflicting name for a new constraint.
*
* The objective here is to choose a name that is unique within the
* specified namespace. Postgres does not require this, but the SQL
* spec does, and some apps depend on it. Therefore we avoid choosing
* default names that so conflict.
*
* name1, name2, and label are used the same way as for makeObjectName(),
* except that the label can't be NULL; digits will be appended to the label
* if needed to create a name that is unique within the specified namespace.
* *
* The passed counter should be initialized to 0 the first time through. * 'others' can be a list of string names already chosen within the current
* If multiple constraint names are to be generated in a single command, * command (but not yet reflected into the catalogs); we will not choose
* pass the new counter value to each successive call, else the same * a duplicate of one of these either.
* name will be generated each time.
* *
* NB: Caller should hold exclusive lock on the given relation, else * Note: it is theoretically possible to get a collision anyway, if someone
* someone else might choose the same name concurrently! * else chooses the same name concurrently. This is fairly unlikely to be
* a problem in practice, especially if one is holding an exclusive lock on
* the relation identified by name1.
*
* Returns a palloc'd string.
*/ */
char * char *
GenerateConstraintName(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, int *counter) ChooseConstraintName(const char *name1, const char *name2,
const char *label, Oid namespace,
List *others)
{ {
bool found; int pass = 0;
char *conname = NULL;
char modlabel[NAMEDATALEN];
Relation conDesc; Relation conDesc;
char *cname; SysScanDesc conscan;
ScanKeyData skey[2];
bool found;
ListCell *l;
cname = (char *) palloc(NAMEDATALEN * sizeof(char)); conDesc = heap_openr(ConstraintRelationName, AccessShareLock);
conDesc = heap_openr(ConstraintRelationName, RowExclusiveLock); /* try the unmodified label first */
StrNCpy(modlabel, label, sizeof(modlabel));
/* Loop until we find a non-conflicting constraint name */ for (;;)
/* We assume there will be one eventually ... */
do
{ {
SysScanDesc conscan; conname = makeObjectName(name1, name2, modlabel);
ScanKeyData skey[2];
HeapTuple tup;
++(*counter);
snprintf(cname, NAMEDATALEN, "$%d", *counter);
/*
* This duplicates ConstraintNameIsUsed() so that we can avoid
* re-opening pg_constraint for each iteration.
*/
found = false; found = false;
ScanKeyInit(&skey[0], foreach(l, others)
Anum_pg_constraint_conname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(cname));
ScanKeyInit(&skey[1],
Anum_pg_constraint_connamespace,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(objNamespace));
conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
SnapshotNow, 2, skey);
while (HeapTupleIsValid(tup = systable_getnext(conscan)))
{ {
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup); if (strcmp((char *) lfirst(l), conname) == 0)
if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
{
found = true;
break;
}
else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
{ {
found = true; found = true;
break; break;
} }
} }
systable_endscan(conscan); if (!found)
} while (found); {
ScanKeyInit(&skey[0],
Anum_pg_constraint_conname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(conname));
heap_close(conDesc, RowExclusiveLock); ScanKeyInit(&skey[1],
Anum_pg_constraint_connamespace,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(namespace));
return cname; conscan = systable_beginscan(conDesc, ConstraintNameNspIndex, true,
} SnapshotNow, 2, skey);
/* found = (HeapTupleIsValid(systable_getnext(conscan)));
* Does the given name look like a generated constraint name?
* systable_endscan(conscan);
* This is a test on the form of the name, *not* on whether it has }
* actually been assigned.
*/ if (!found)
bool break;
ConstraintNameIsGenerated(const char *cname)
{ /* found a conflict, so try a new name component */
if (cname[0] != '$') pfree(conname);
return false; snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
if (strspn(cname + 1, "0123456789") != strlen(cname + 1)) }
return false;
return true; heap_close(conDesc, AccessShareLock);
return conname;
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.120 2004/05/26 04:41:11 neilc Exp $ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.121 2004/06/10 17:55:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -28,10 +28,10 @@ ...@@ -28,10 +28,10 @@
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/tablecmds.h" #include "commands/tablecmds.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/prep.h" #include "optimizer/prep.h"
#include "parser/analyze.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "parser/parse_coerce.h" #include "parser/parse_coerce.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
...@@ -53,8 +53,6 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *classOidP, ...@@ -53,8 +53,6 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
static Oid GetIndexOpClass(List *opclass, Oid attrType, static Oid GetIndexOpClass(List *opclass, Oid attrType,
char *accessMethodName, Oid accessMethodId); char *accessMethodName, Oid accessMethodId);
static Oid GetDefaultOpClass(Oid attrType, Oid accessMethodId); static Oid GetDefaultOpClass(Oid attrType, Oid accessMethodId);
static char *CreateIndexName(const char *table_name, const char *column_name,
const char *label, Oid inamespace);
static bool relationHasPrimaryKey(Relation rel); static bool relationHasPrimaryKey(Relation rel);
...@@ -159,18 +157,18 @@ DefineIndex(RangeVar *heapRelation, ...@@ -159,18 +157,18 @@ DefineIndex(RangeVar *heapRelation,
if (indexRelationName == NULL) if (indexRelationName == NULL)
{ {
if (primary) if (primary)
indexRelationName = CreateIndexName(RelationGetRelationName(rel), indexRelationName = ChooseRelationName(RelationGetRelationName(rel),
NULL, NULL,
"pkey", "pkey",
namespaceId); namespaceId);
else else
{ {
IndexElem *iparam = (IndexElem *) linitial(attributeList); IndexElem *iparam = (IndexElem *) linitial(attributeList);
indexRelationName = CreateIndexName(RelationGetRelationName(rel), indexRelationName = ChooseRelationName(RelationGetRelationName(rel),
iparam->name, iparam->name,
"key", "key",
namespaceId); namespaceId);
} }
} }
...@@ -657,35 +655,131 @@ GetDefaultOpClass(Oid attrType, Oid accessMethodId) ...@@ -657,35 +655,131 @@ GetDefaultOpClass(Oid attrType, Oid accessMethodId)
} }
/* /*
* Select a nonconflicting name for an index. * makeObjectName()
*
* Create a name for an implicitly created index, sequence, constraint, etc.
*
* The parameters are typically: the original table name, the original field
* name, and a "type" string (such as "seq" or "pkey"). The field name
* and/or type can be NULL if not relevant.
*
* The result is a palloc'd string.
*
* The basic result we want is "name1_name2_label", omitting "_name2" or
* "_label" when those parameters are NULL. However, we must generate
* a name with less than NAMEDATALEN characters! So, we truncate one or
* both names if necessary to make a short-enough string. The label part
* is never truncated (so it had better be reasonably short).
*
* The caller is responsible for checking uniqueness of the generated
* name and retrying as needed; retrying will be done by altering the
* "label" string (which is why we never truncate that part).
*/ */
static char * char *
CreateIndexName(const char *table_name, const char *column_name, makeObjectName(const char *name1, const char *name2, const char *label)
const char *label, Oid inamespace)
{ {
int pass = 0; char *name;
char *iname = NULL; int overhead = 0; /* chars needed for label and underscores */
char typename[NAMEDATALEN]; int availchars; /* chars available for name(s) */
int name1chars; /* chars allocated to name1 */
int name2chars; /* chars allocated to name2 */
int ndx;
name1chars = strlen(name1);
if (name2)
{
name2chars = strlen(name2);
overhead++; /* allow for separating underscore */
}
else
name2chars = 0;
if (label)
overhead += strlen(label) + 1;
availchars = NAMEDATALEN - 1 - overhead;
Assert(availchars > 0); /* else caller chose a bad label */
/* /*
* The type name for makeObjectName is label, or labelN if that's * If we must truncate, preferentially truncate the longer name. This
* necessary to prevent collision with existing indexes. * logic could be expressed without a loop, but it's simple and
* obvious as a loop.
*/ */
strncpy(typename, label, sizeof(typename)); while (name1chars + name2chars > availchars)
{
if (name1chars > name2chars)
name1chars--;
else
name2chars--;
}
if (name1)
name1chars = pg_mbcliplen(name1, name1chars, name1chars);
if (name2)
name2chars = pg_mbcliplen(name2, name2chars, name2chars);
/* Now construct the string using the chosen lengths */
name = palloc(name1chars + name2chars + overhead + 1);
memcpy(name, name1, name1chars);
ndx = name1chars;
if (name2)
{
name[ndx++] = '_';
memcpy(name + ndx, name2, name2chars);
ndx += name2chars;
}
if (label)
{
name[ndx++] = '_';
strcpy(name + ndx, label);
}
else
name[ndx] = '\0';
return name;
}
/*
* Select a nonconflicting name for a new relation. This is ordinarily
* used to choose index names (which is why it's here) but it can also
* be used for sequences, or any autogenerated relation kind.
*
* name1, name2, and label are used the same way as for makeObjectName(),
* except that the label can't be NULL; digits will be appended to the label
* if needed to create a name that is unique within the specified namespace.
*
* Note: it is theoretically possible to get a collision anyway, if someone
* else chooses the same name concurrently. This is fairly unlikely to be
* a problem in practice, especially if one is holding an exclusive lock on
* the relation identified by name1. However, if choosing multiple names
* within a single command, you'd better create the new object and do
* CommandCounterIncrement before choosing the next one!
*
* Returns a palloc'd string.
*/
char *
ChooseRelationName(const char *name1, const char *name2,
const char *label, Oid namespace)
{
int pass = 0;
char *relname = NULL;
char modlabel[NAMEDATALEN];
/* try the unmodified label first */
StrNCpy(modlabel, label, sizeof(modlabel));
for (;;) for (;;)
{ {
iname = makeObjectName(table_name, column_name, typename); relname = makeObjectName(name1, name2, modlabel);
if (!OidIsValid(get_relname_relid(iname, inamespace))) if (!OidIsValid(get_relname_relid(relname, namespace)))
break; break;
/* found a conflict, so try a new name component */ /* found a conflict, so try a new name component */
pfree(iname); pfree(relname);
snprintf(typename, sizeof(typename), "%s%d", label, ++pass); snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
} }
return iname; return relname;
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.112 2004/06/06 20:30:07 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.113 2004/06/10 17:55:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -124,8 +124,6 @@ typedef struct AlteredTableInfo ...@@ -124,8 +124,6 @@ typedef struct AlteredTableInfo
List *changedConstraintDefs; /* string definitions of same */ List *changedConstraintDefs; /* string definitions of same */
List *changedIndexOids; /* OIDs of indexes to rebuild */ List *changedIndexOids; /* OIDs of indexes to rebuild */
List *changedIndexDefs; /* string definitions of same */ List *changedIndexDefs; /* string definitions of same */
/* Workspace for ATExecAddConstraint */
int constr_name_ctr;
} AlteredTableInfo; } AlteredTableInfo;
/* Struct describing one new constraint to check in Phase 3 scan */ /* Struct describing one new constraint to check in Phase 3 scan */
...@@ -323,46 +321,45 @@ DefineRelation(CreateStmt *stmt, char relkind) ...@@ -323,46 +321,45 @@ DefineRelation(CreateStmt *stmt, char relkind)
if (old_constraints != NIL) if (old_constraints != NIL)
{ {
ConstrCheck *check = (ConstrCheck *) palloc(list_length(old_constraints) * ConstrCheck *check = (ConstrCheck *)
sizeof(ConstrCheck)); palloc0(list_length(old_constraints) * sizeof(ConstrCheck));
int ncheck = 0; int ncheck = 0;
int constr_name_ctr = 0;
foreach(listptr, old_constraints) foreach(listptr, old_constraints)
{ {
Constraint *cdef = (Constraint *) lfirst(listptr); Constraint *cdef = (Constraint *) lfirst(listptr);
bool dup = false;
if (cdef->contype != CONSTR_CHECK) if (cdef->contype != CONSTR_CHECK)
continue; continue;
Assert(cdef->name != NULL);
if (cdef->name != NULL) Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL);
/*
* In multiple-inheritance situations, it's possible to inherit
* the same grandparent constraint through multiple parents.
* Hence, discard inherited constraints that match as to both
* name and expression. Otherwise, gripe if the names conflict.
*/
for (i = 0; i < ncheck; i++)
{ {
for (i = 0; i < ncheck; i++) if (strcmp(check[i].ccname, cdef->name) != 0)
continue;
if (strcmp(check[i].ccbin, cdef->cooked_expr) == 0)
{ {
if (strcmp(check[i].ccname, cdef->name) == 0) dup = true;
ereport(ERROR, break;
(errcode(ERRCODE_DUPLICATE_OBJECT), }
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("duplicate check constraint name \"%s\"", errmsg("duplicate check constraint name \"%s\"",
cdef->name))); cdef->name)));
}
check[ncheck].ccname = cdef->name;
} }
else if (!dup)
{ {
/* check[ncheck].ccname = cdef->name;
* Generate a constraint name. NB: this should match the check[ncheck].ccbin = pstrdup(cdef->cooked_expr);
* form of names that GenerateConstraintName() may produce ncheck++;
* for names added later. We are assured that there is no
* name conflict, because MergeAttributes() did not pass
* back any names of this form.
*/
check[ncheck].ccname = (char *) palloc(NAMEDATALEN);
snprintf(check[ncheck].ccname, NAMEDATALEN, "$%d",
++constr_name_ctr);
} }
Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL);
check[ncheck].ccbin = pstrdup(cdef->cooked_expr);
ncheck++;
} }
if (ncheck > 0) if (ncheck > 0)
{ {
...@@ -867,17 +864,7 @@ MergeAttributes(List *schema, List *supers, bool istemp, ...@@ -867,17 +864,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
Node *expr; Node *expr;
cdef->contype = CONSTR_CHECK; cdef->contype = CONSTR_CHECK;
cdef->name = pstrdup(check[i].ccname);
/*
* Do not inherit generated constraint names, since they
* might conflict across multiple inheritance parents.
* (But conflicts between user-assigned names will cause
* an error.)
*/
if (ConstraintNameIsGenerated(check[i].ccname))
cdef->name = NULL;
else
cdef->name = pstrdup(check[i].ccname);
cdef->raw_expr = NULL; cdef->raw_expr = NULL;
/* adjust varattnos of ccbin here */ /* adjust varattnos of ccbin here */
expr = stringToNode(check[i].ccbin); expr = stringToNode(check[i].ccbin);
...@@ -3610,10 +3597,11 @@ ATExecAddConstraint(AlteredTableInfo *tab, Relation rel, Node *newConstraint) ...@@ -3610,10 +3597,11 @@ ATExecAddConstraint(AlteredTableInfo *tab, Relation rel, Node *newConstraint)
} }
else else
fkconstraint->constr_name = fkconstraint->constr_name =
GenerateConstraintName(CONSTRAINT_RELATION, ChooseConstraintName(RelationGetRelationName(rel),
RelationGetRelid(rel), strVal(linitial(fkconstraint->fk_attrs)),
RelationGetNamespace(rel), "fkey",
&tab->constr_name_ctr); RelationGetNamespace(rel),
NIL);
ATAddForeignKeyConstraint(tab, rel, fkconstraint); ATAddForeignKeyConstraint(tab, rel, fkconstraint);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.58 2004/06/04 20:35:21 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.59 2004/06/10 17:55:56 tgl Exp $
* *
* DESCRIPTION * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
...@@ -83,7 +83,7 @@ static void domainOwnerCheck(HeapTuple tup, TypeName *typename); ...@@ -83,7 +83,7 @@ static void domainOwnerCheck(HeapTuple tup, TypeName *typename);
static char *domainAddConstraint(Oid domainOid, Oid domainNamespace, static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
Oid baseTypeOid, Oid baseTypeOid,
int typMod, Constraint *constr, int typMod, Constraint *constr,
int *counter, char *domainName); char *domainName);
/* /*
...@@ -509,7 +509,6 @@ DefineDomain(CreateDomainStmt *stmt) ...@@ -509,7 +509,6 @@ DefineDomain(CreateDomainStmt *stmt)
Oid basetypeoid; Oid basetypeoid;
Oid domainoid; Oid domainoid;
Form_pg_type baseType; Form_pg_type baseType;
int counter = 0;
/* Convert list of names to a name and namespace */ /* Convert list of names to a name and namespace */
domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname, domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
...@@ -760,7 +759,7 @@ DefineDomain(CreateDomainStmt *stmt) ...@@ -760,7 +759,7 @@ DefineDomain(CreateDomainStmt *stmt)
case CONSTR_CHECK: case CONSTR_CHECK:
domainAddConstraint(domainoid, domainNamespace, domainAddConstraint(domainoid, domainNamespace,
basetypeoid, stmt->typename->typmod, basetypeoid, stmt->typename->typmod,
constr, &counter, domainName); constr, domainName);
break; break;
/* Other constraint types were fully processed above */ /* Other constraint types were fully processed above */
...@@ -768,6 +767,9 @@ DefineDomain(CreateDomainStmt *stmt) ...@@ -768,6 +767,9 @@ DefineDomain(CreateDomainStmt *stmt)
default: default:
break; break;
} }
/* CCI so we can detect duplicate constraint names */
CommandCounterIncrement();
} }
/* /*
...@@ -1463,7 +1465,6 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) ...@@ -1463,7 +1465,6 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
char *ccbin; char *ccbin;
Expr *expr; Expr *expr;
ExprState *exprstate; ExprState *exprstate;
int counter = 0;
Constraint *constr; Constraint *constr;
/* Make a TypeName so we can use standard type lookup machinery */ /* Make a TypeName so we can use standard type lookup machinery */
...@@ -1547,7 +1548,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint) ...@@ -1547,7 +1548,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace, ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
typTup->typbasetype, typTup->typtypmod, typTup->typbasetype, typTup->typtypmod,
constr, &counter, NameStr(typTup->typname)); constr, NameStr(typTup->typname));
/* /*
* Test all values stored in the attributes based on the domain the * Test all values stored in the attributes based on the domain the
...@@ -1788,7 +1789,7 @@ domainOwnerCheck(HeapTuple tup, TypeName *typename) ...@@ -1788,7 +1789,7 @@ domainOwnerCheck(HeapTuple tup, TypeName *typename)
static char * static char *
domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
int typMod, Constraint *constr, int typMod, Constraint *constr,
int *counter, char *domainName) char *domainName)
{ {
Node *expr; Node *expr;
char *ccsrc; char *ccsrc;
...@@ -1811,10 +1812,11 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, ...@@ -1811,10 +1812,11 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
constr->name, domainName))); constr->name, domainName)));
} }
else else
constr->name = GenerateConstraintName(CONSTRAINT_DOMAIN, constr->name = ChooseConstraintName(domainName,
domainOid, NULL,
domainNamespace, "check",
counter); domainNamespace,
NIL);
/* /*
* Convert the A_EXPR in raw_expr into an EXPR * Convert the A_EXPR in raw_expr into an EXPR
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.304 2004/06/09 19:08:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.305 2004/06/10 17:55:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_index.h" #include "catalog/pg_index.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "commands/prepare.h" #include "commands/prepare.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
...@@ -45,7 +46,6 @@ ...@@ -45,7 +46,6 @@
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "mb/pg_wchar.h"
/* State shared by transformCreateSchemaStmt and its subroutines */ /* State shared by transformCreateSchemaStmt and its subroutines */
...@@ -703,90 +703,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, ...@@ -703,90 +703,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
return qry; return qry;
} }
/*
* makeObjectName()
*
* Create a name for an implicitly created index, sequence, constraint, etc.
*
* The parameters are: the original table name, the original field name, and
* a "type" string (such as "seq" or "pkey"). The field name and/or type
* can be NULL if not relevant.
*
* The result is a palloc'd string.
*
* The basic result we want is "name1_name2_type", omitting "_name2" or
* "_type" when those parameters are NULL. However, we must generate
* a name with less than NAMEDATALEN characters! So, we truncate one or
* both names if necessary to make a short-enough string. The type part
* is never truncated (so it had better be reasonably short).
*
* To reduce the probability of collisions, we might someday add more
* smarts to this routine, like including some "hash" characters computed
* from the truncated characters. Currently it seems best to keep it simple,
* so that the generated names are easily predictable by a person.
*/
char *
makeObjectName(const char *name1, const char *name2, const char *typename)
{
char *name;
int overhead = 0; /* chars needed for type and underscores */
int availchars; /* chars available for name(s) */
int name1chars; /* chars allocated to name1 */
int name2chars; /* chars allocated to name2 */
int ndx;
name1chars = strlen(name1);
if (name2)
{
name2chars = strlen(name2);
overhead++; /* allow for separating underscore */
}
else
name2chars = 0;
if (typename)
overhead += strlen(typename) + 1;
availchars = NAMEDATALEN - 1 - overhead;
/*
* If we must truncate, preferentially truncate the longer name. This
* logic could be expressed without a loop, but it's simple and
* obvious as a loop.
*/
while (name1chars + name2chars > availchars)
{
if (name1chars > name2chars)
name1chars--;
else
name2chars--;
}
if (name1)
name1chars = pg_mbcliplen(name1, name1chars, name1chars);
if (name2)
name2chars = pg_mbcliplen(name2, name2chars, name2chars);
/* Now construct the string using the chosen lengths */
name = palloc(name1chars + name2chars + overhead + 1);
strncpy(name, name1, name1chars);
ndx = name1chars;
if (name2)
{
name[ndx++] = '_';
strncpy(name + ndx, name2, name2chars);
ndx += name2chars;
}
if (typename)
{
name[ndx++] = '_';
strcpy(name + ndx, typename);
}
else
name[ndx] = '\0';
return name;
}
/* /*
* transformCreateStmt - * transformCreateStmt -
* transforms the "create table" statement * transforms the "create table" statement
...@@ -919,21 +835,34 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, ...@@ -919,21 +835,34 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
/* Special actions for SERIAL pseudo-types */ /* Special actions for SERIAL pseudo-types */
if (is_serial) if (is_serial)
{ {
char *sname; Oid snamespaceid;
char *snamespace; char *snamespace;
char *sname;
char *qstring; char *qstring;
A_Const *snamenode; A_Const *snamenode;
FuncCall *funccallnode; FuncCall *funccallnode;
CreateSeqStmt *seqstmt; CreateSeqStmt *seqstmt;
/* /*
* Determine name and namespace to use for the sequence. * Determine namespace and name to use for the sequence.
*
* Although we use ChooseRelationName, it's not guaranteed that
* the selected sequence name won't conflict; given sufficiently
* long field names, two different serial columns in the same table
* could be assigned the same sequence name, and we'd not notice
* since we aren't creating the sequence quite yet. In practice
* this seems quite unlikely to be a problem, especially since
* few people would need two serial columns in one table.
*/ */
sname = makeObjectName(cxt->relation->relname, column->colname, "seq"); snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
snamespace = get_namespace_name(RangeVarGetCreationNamespace(cxt->relation)); snamespace = get_namespace_name(snamespaceid);
sname = ChooseRelationName(cxt->relation->relname,
column->colname,
"seq",
snamespaceid);
ereport(NOTICE, ereport(NOTICE,
(errmsg("%s will create implicit sequence \"%s\" for \"serial\" column \"%s.%s\"", (errmsg("%s will create implicit sequence \"%s\" for serial column \"%s.%s\"",
cxt->stmtType, sname, cxt->stmtType, sname,
cxt->relation->relname, column->colname))); cxt->relation->relname, column->colname)));
...@@ -975,7 +904,6 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, ...@@ -975,7 +904,6 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
constraint = makeNode(Constraint); constraint = makeNode(Constraint);
constraint->contype = CONSTR_DEFAULT; constraint->contype = CONSTR_DEFAULT;
constraint->name = sname;
constraint->raw_expr = (Node *) funccallnode; constraint->raw_expr = (Node *) funccallnode;
constraint->cooked_expr = NULL; constraint->cooked_expr = NULL;
constraint->keys = NIL; constraint->keys = NIL;
...@@ -1044,30 +972,13 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, ...@@ -1044,30 +972,13 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
break; break;
case CONSTR_PRIMARY: case CONSTR_PRIMARY:
if (constraint->name == NULL)
constraint->name = makeObjectName(cxt->relation->relname,
NULL,
"pkey");
if (constraint->keys == NIL)
constraint->keys = list_make1(makeString(column->colname));
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
break;
case CONSTR_UNIQUE: case CONSTR_UNIQUE:
if (constraint->name == NULL)
constraint->name = makeObjectName(cxt->relation->relname,
column->colname,
"key");
if (constraint->keys == NIL) if (constraint->keys == NIL)
constraint->keys = list_make1(makeString(column->colname)); constraint->keys = list_make1(makeString(column->colname));
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
break; break;
case CONSTR_CHECK: case CONSTR_CHECK:
if (constraint->name == NULL)
constraint->name = makeObjectName(cxt->relation->relname,
column->colname,
NULL);
cxt->ckconstraints = lappend(cxt->ckconstraints, constraint); cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
break; break;
...@@ -1093,13 +1004,6 @@ transformTableConstraint(ParseState *pstate, CreateStmtContext *cxt, ...@@ -1093,13 +1004,6 @@ transformTableConstraint(ParseState *pstate, CreateStmtContext *cxt,
switch (constraint->contype) switch (constraint->contype)
{ {
case CONSTR_PRIMARY: case CONSTR_PRIMARY:
if (constraint->name == NULL)
constraint->name = makeObjectName(cxt->relation->relname,
NULL,
"pkey");
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
break;
case CONSTR_UNIQUE: case CONSTR_UNIQUE:
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.10 2003/11/29 22:40:58 pgsql Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.11 2004/06/10 17:55:59 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -141,15 +141,14 @@ typedef FormData_pg_constraint *Form_pg_constraint; ...@@ -141,15 +141,14 @@ typedef FormData_pg_constraint *Form_pg_constraint;
*/ */
/* /*
* Used for constraint support functions where the * Identify constraint type for lookup purposes
* and conrelid, contypid columns being looked up
*/ */
typedef enum CONSTRAINTCATEGORY typedef enum ConstraintCategory
{ {
CONSTRAINT_RELATION, CONSTRAINT_RELATION,
CONSTRAINT_DOMAIN, CONSTRAINT_DOMAIN,
CONSTRAINT_ASSERTION CONSTRAINT_ASSERTION /* for future expansion */
} CONSTRAINTCATEGORY; } ConstraintCategory;
/* /*
* prototypes for functions in pg_constraint.c * prototypes for functions in pg_constraint.c
...@@ -176,10 +175,10 @@ extern Oid CreateConstraintEntry(const char *constraintName, ...@@ -176,10 +175,10 @@ extern Oid CreateConstraintEntry(const char *constraintName,
extern void RemoveConstraintById(Oid conId); extern void RemoveConstraintById(Oid conId);
extern bool ConstraintNameIsUsed(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, extern bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
const char *cname); Oid objNamespace, const char *conname);
extern char *GenerateConstraintName(CONSTRAINTCATEGORY conCat, Oid objId, Oid objNamespace, extern char *ChooseConstraintName(const char *name1, const char *name2,
int *counter); const char *label, Oid namespace,
extern bool ConstraintNameIsGenerated(const char *cname); List *others);
#endif /* PG_CONSTRAINT_H */ #endif /* PG_CONSTRAINT_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.56 2004/05/14 16:11:25 tgl Exp $ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.57 2004/06/10 17:55:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -35,6 +35,10 @@ extern void RemoveIndex(RangeVar *relation, DropBehavior behavior); ...@@ -35,6 +35,10 @@ extern void RemoveIndex(RangeVar *relation, DropBehavior behavior);
extern void ReindexIndex(RangeVar *indexRelation, bool force); extern void ReindexIndex(RangeVar *indexRelation, bool force);
extern void ReindexTable(RangeVar *relation, bool force); extern void ReindexTable(RangeVar *relation, bool force);
extern void ReindexDatabase(const char *databaseName, bool force, bool all); extern void ReindexDatabase(const char *databaseName, bool force, bool all);
extern char *makeObjectName(const char *name1, const char *name2,
const char *label);
extern char *ChooseRelationName(const char *name1, const char *name2,
const char *label, Oid namespace);
/* commands/functioncmds.c */ /* commands/functioncmds.c */
extern void CreateFunction(CreateFunctionStmt *stmt); extern void CreateFunction(CreateFunctionStmt *stmt);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.26 2004/05/05 04:48:47 tgl Exp $ * $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.27 2004/06/10 17:56:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,10 +21,6 @@ extern List *parse_analyze_varparams(Node *parseTree, Oid **paramTypes, ...@@ -21,10 +21,6 @@ extern List *parse_analyze_varparams(Node *parseTree, Oid **paramTypes,
int *numParams); int *numParams);
extern List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState); extern List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState);
extern List *analyzeCreateSchemaStmt(CreateSchemaStmt *stmt); extern List *analyzeCreateSchemaStmt(CreateSchemaStmt *stmt);
extern char *makeObjectName(const char *name1, const char *name2,
const char *typename);
extern void CheckSelectForUpdate(Query *qry); extern void CheckSelectForUpdate(Query *qry);
#endif /* ANALYZE_H */ #endif /* ANALYZE_H */
...@@ -194,27 +194,27 @@ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "pktable_pkey" fo ...@@ -194,27 +194,27 @@ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "pktable_pkey" fo
CREATE TEMP TABLE FKTABLE (ftest1 inet); CREATE TEMP TABLE FKTABLE (ftest1 inet);
-- This next should fail, because inet=int does not exist -- This next should fail, because inet=int does not exist
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable; ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
ERROR: foreign key constraint "$1" cannot be implemented ERROR: foreign key constraint "fktable_ftest1_fkey" cannot be implemented
DETAIL: Key columns "ftest1" and "ptest1" are of incompatible types: inet and integer. DETAIL: Key columns "ftest1" and "ptest1" are of incompatible types: inet and integer.
-- This should also fail for the same reason, but here we -- This should also fail for the same reason, but here we
-- give the column name -- give the column name
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1); ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
ERROR: foreign key constraint "$1" cannot be implemented ERROR: foreign key constraint "fktable_ftest1_fkey" cannot be implemented
DETAIL: Key columns "ftest1" and "ptest1" are of incompatible types: inet and integer. DETAIL: Key columns "ftest1" and "ptest1" are of incompatible types: inet and integer.
-- This should succeed, even though they are different types -- This should succeed, even though they are different types
-- because varchar=int does exist -- because varchar=int does exist
DROP TABLE FKTABLE; DROP TABLE FKTABLE;
CREATE TEMP TABLE FKTABLE (ftest1 varchar); CREATE TEMP TABLE FKTABLE (ftest1 varchar);
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable; ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
WARNING: foreign key constraint "$1" will require costly sequential scans WARNING: foreign key constraint "fktable_ftest1_fkey" will require costly sequential scans
DETAIL: Key columns "ftest1" and "ptest1" are of different types: character varying and integer. DETAIL: Key columns "ftest1" and "ptest1" are of different types: character varying and integer.
-- As should this -- As should this
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1); ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
WARNING: foreign key constraint "$2" will require costly sequential scans WARNING: foreign key constraint "fktable_ftest1_fkey1" will require costly sequential scans
DETAIL: Key columns "ftest1" and "ptest1" are of different types: character varying and integer. DETAIL: Key columns "ftest1" and "ptest1" are of different types: character varying and integer.
DROP TABLE pktable cascade; DROP TABLE pktable cascade;
NOTICE: drop cascades to constraint $2 on table fktable NOTICE: drop cascades to constraint fktable_ftest1_fkey1 on table fktable
NOTICE: drop cascades to constraint $1 on table fktable NOTICE: drop cascades to constraint fktable_ftest1_fkey on table fktable
DROP TABLE fktable; DROP TABLE fktable;
CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 inet, CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 inet,
PRIMARY KEY(ptest1, ptest2)); PRIMARY KEY(ptest1, ptest2));
...@@ -222,26 +222,26 @@ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "pktable_pkey" fo ...@@ -222,26 +222,26 @@ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "pktable_pkey" fo
-- This should fail, because we just chose really odd types -- This should fail, because we just chose really odd types
CREATE TEMP TABLE FKTABLE (ftest1 cidr, ftest2 timestamp); CREATE TEMP TABLE FKTABLE (ftest1 cidr, ftest2 timestamp);
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable; ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) references pktable;
ERROR: foreign key constraint "$1" cannot be implemented ERROR: foreign key constraint "fktable_ftest1_fkey" cannot be implemented
DETAIL: Key columns "ftest1" and "ptest1" are of incompatible types: cidr and integer. DETAIL: Key columns "ftest1" and "ptest1" are of incompatible types: cidr and integer.
DROP TABLE FKTABLE; DROP TABLE FKTABLE;
-- Again, so should this... -- Again, so should this...
CREATE TEMP TABLE FKTABLE (ftest1 cidr, ftest2 timestamp); CREATE TEMP TABLE FKTABLE (ftest1 cidr, ftest2 timestamp);
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
references pktable(ptest1, ptest2); references pktable(ptest1, ptest2);
ERROR: foreign key constraint "$1" cannot be implemented ERROR: foreign key constraint "fktable_ftest1_fkey" cannot be implemented
DETAIL: Key columns "ftest1" and "ptest1" are of incompatible types: cidr and integer. DETAIL: Key columns "ftest1" and "ptest1" are of incompatible types: cidr and integer.
DROP TABLE FKTABLE; DROP TABLE FKTABLE;
-- This fails because we mixed up the column ordering -- This fails because we mixed up the column ordering
CREATE TEMP TABLE FKTABLE (ftest1 int, ftest2 inet); CREATE TEMP TABLE FKTABLE (ftest1 int, ftest2 inet);
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2) ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
references pktable(ptest2, ptest1); references pktable(ptest2, ptest1);
ERROR: foreign key constraint "$1" cannot be implemented ERROR: foreign key constraint "fktable_ftest1_fkey" cannot be implemented
DETAIL: Key columns "ftest1" and "ptest2" are of incompatible types: integer and inet. DETAIL: Key columns "ftest1" and "ptest2" are of incompatible types: integer and inet.
-- As does this... -- As does this...
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest2, ftest1) ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest2, ftest1)
references pktable(ptest1, ptest2); references pktable(ptest1, ptest2);
ERROR: foreign key constraint "$1" cannot be implemented ERROR: foreign key constraint "fktable_ftest2_fkey" cannot be implemented
DETAIL: Key columns "ftest2" and "ptest1" are of incompatible types: inet and integer. DETAIL: Key columns "ftest2" and "ptest1" are of incompatible types: inet and integer.
-- temp tables should go away by themselves, need not drop them. -- temp tables should go away by themselves, need not drop them.
-- test check constraint adding -- test check constraint adding
...@@ -284,7 +284,7 @@ create table atacc1 (test int check (test>3), test2 int); ...@@ -284,7 +284,7 @@ create table atacc1 (test int check (test>3), test2 int);
alter table atacc1 add check (test2>test); alter table atacc1 add check (test2>test);
-- should fail for $2 -- should fail for $2
insert into atacc1 (test2, test) values (3, 4); insert into atacc1 (test2, test) values (3, 4);
ERROR: new row for relation "atacc1" violates check constraint "$1" ERROR: new row for relation "atacc1" violates check constraint "atacc1_check"
drop table atacc1; drop table atacc1;
-- inheritance related tests -- inheritance related tests
create table atacc1 (test int); create table atacc1 (test int);
...@@ -1081,7 +1081,7 @@ alter table p1 add column f2 text; ...@@ -1081,7 +1081,7 @@ alter table p1 add column f2 text;
NOTICE: merging definition of column "f2" for child "c1" NOTICE: merging definition of column "f2" for child "c1"
insert into p1 values (1,2,'abc'); insert into p1 values (1,2,'abc');
insert into c1 values(11,'xyz',33,0); -- should fail insert into c1 values(11,'xyz',33,0); -- should fail
ERROR: new row for relation "c1" violates check constraint "p1_a1" ERROR: new row for relation "c1" violates check constraint "c1_a1_check"
insert into c1 values(11,'xyz',33,22); insert into c1 values(11,'xyz',33,22);
select * from p1; select * from p1;
f1 | a1 | f2 f1 | a1 | f2
...@@ -1100,7 +1100,7 @@ select * from p1; ...@@ -1100,7 +1100,7 @@ select * from p1;
drop table p1 cascade; drop table p1 cascade;
NOTICE: drop cascades to table c1 NOTICE: drop cascades to table c1
NOTICE: drop cascades to constraint p1_a1 on table c1 NOTICE: drop cascades to constraint c1_a1_check on table c1
-- test that operations with a dropped column do not try to reference -- test that operations with a dropped column do not try to reference
-- its datatype -- its datatype
create domain mytype as text; create domain mytype as text;
...@@ -1148,7 +1148,7 @@ ERROR: column "f1" cannot be cast to type "pg_catalog.int4" ...@@ -1148,7 +1148,7 @@ ERROR: column "f1" cannot be cast to type "pg_catalog.int4"
alter table foo alter f1 TYPE varchar(10); alter table foo alter f1 TYPE varchar(10);
create table anothertab (atcol1 serial8, atcol2 boolean, create table anothertab (atcol1 serial8, atcol2 boolean,
constraint anothertab_chk check (atcol1 <= 3)); constraint anothertab_chk check (atcol1 <= 3));
NOTICE: CREATE TABLE will create implicit sequence "anothertab_atcol1_seq" for "serial" column "anothertab.atcol1" NOTICE: CREATE TABLE will create implicit sequence "anothertab_atcol1_seq" for serial column "anothertab.atcol1"
insert into anothertab (atcol1, atcol2) values (default, true); insert into anothertab (atcol1, atcol2) values (default, true);
insert into anothertab (atcol1, atcol2) values (default, false); insert into anothertab (atcol1, atcol2) values (default, false);
select * from anothertab; select * from anothertab;
......
...@@ -3,14 +3,14 @@ ...@@ -3,14 +3,14 @@
-- --
CREATE TABLE clstr_tst_s (rf_a SERIAL PRIMARY KEY, CREATE TABLE clstr_tst_s (rf_a SERIAL PRIMARY KEY,
b INT); b INT);
NOTICE: CREATE TABLE will create implicit sequence "clstr_tst_s_rf_a_seq" for "serial" column "clstr_tst_s.rf_a" NOTICE: CREATE TABLE will create implicit sequence "clstr_tst_s_rf_a_seq" for serial column "clstr_tst_s.rf_a"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "clstr_tst_s_pkey" for table "clstr_tst_s" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "clstr_tst_s_pkey" for table "clstr_tst_s"
CREATE TABLE clstr_tst (a SERIAL PRIMARY KEY, CREATE TABLE clstr_tst (a SERIAL PRIMARY KEY,
b INT, b INT,
c TEXT, c TEXT,
d TEXT, d TEXT,
CONSTRAINT clstr_tst_con FOREIGN KEY (b) REFERENCES clstr_tst_s); CONSTRAINT clstr_tst_con FOREIGN KEY (b) REFERENCES clstr_tst_s);
NOTICE: CREATE TABLE will create implicit sequence "clstr_tst_a_seq" for "serial" column "clstr_tst.a" NOTICE: CREATE TABLE will create implicit sequence "clstr_tst_a_seq" for serial column "clstr_tst.a"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "clstr_tst_pkey" for table "clstr_tst" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "clstr_tst_pkey" for table "clstr_tst"
CREATE INDEX clstr_tst_b ON clstr_tst (b); CREATE INDEX clstr_tst_b ON clstr_tst (b);
CREATE INDEX clstr_tst_c ON clstr_tst (c); CREATE INDEX clstr_tst_c ON clstr_tst (c);
...@@ -303,10 +303,10 @@ SELECT pg_class.relname FROM pg_index, pg_class, pg_class AS pg_class_2 ...@@ -303,10 +303,10 @@ SELECT pg_class.relname FROM pg_index, pg_class, pg_class AS pg_class_2
WHERE pg_class.oid=indexrelid WHERE pg_class.oid=indexrelid
AND indrelid=pg_class_2.oid AND indrelid=pg_class_2.oid
AND pg_class_2.relname = 'clstr_tst' AND pg_class_2.relname = 'clstr_tst'
AND indisclustered; AND indisclustered;
relname relname
--------- ---------
(0 rows) (0 rows)
-- Verify that clustering all tables does in fact cluster the right ones -- Verify that clustering all tables does in fact cluster the right ones
CREATE USER clstr_user; CREATE USER clstr_user;
......
...@@ -5,7 +5,7 @@ CREATE TABLE x ( ...@@ -5,7 +5,7 @@ CREATE TABLE x (
d text, d text,
e text e text
); );
NOTICE: CREATE TABLE will create implicit sequence "x_a_seq" for "serial" column "x.a" NOTICE: CREATE TABLE will create implicit sequence "x_a_seq" for serial column "x.a"
CREATE FUNCTION fn_x_before () RETURNS TRIGGER AS ' CREATE FUNCTION fn_x_before () RETURNS TRIGGER AS '
BEGIN BEGIN
NEW.e := ''before trigger fired''::text; NEW.e := ''before trigger fired''::text;
...@@ -191,6 +191,6 @@ COPY y TO stdout WITH CSV FORCE QUOTE col2 ESCAPE '\\'; ...@@ -191,6 +191,6 @@ COPY y TO stdout WITH CSV FORCE QUOTE col2 ESCAPE '\\';
"Jackson, Sam","\\h" "Jackson, Sam","\\h"
"It is \"perfect\"."," " "It is \"perfect\"."," "
"", "",
DROP TABLE x; DROP TABLE x, y;
DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_before();
DROP FUNCTION fn_x_after(); DROP FUNCTION fn_x_after();
...@@ -116,7 +116,7 @@ INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c'); -- Good ...@@ -116,7 +116,7 @@ INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c'); -- Good
insert into nulltest values ('a', 'b', 'c', 'd', NULL); insert into nulltest values ('a', 'b', 'c', 'd', NULL);
ERROR: domain dcheck does not allow null values ERROR: domain dcheck does not allow null values
insert into nulltest values ('a', 'b', 'c', 'd', 'a'); insert into nulltest values ('a', 'b', 'c', 'd', 'a');
ERROR: new row for relation "nulltest" violates check constraint "nulltest_col5" ERROR: new row for relation "nulltest" violates check constraint "nulltest_col5_check"
INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd'); INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd');
ERROR: domain dnotnull does not allow null values ERROR: domain dnotnull does not allow null values
INSERT INTO nulltest values ('a', NULL, 'c', 'd', 'c'); INSERT INTO nulltest values ('a', NULL, 'c', 'd', 'c');
...@@ -130,7 +130,7 @@ ERROR: domain dcheck does not allow null values ...@@ -130,7 +130,7 @@ ERROR: domain dcheck does not allow null values
CONTEXT: COPY nulltest, line 1: "a b \N d \N" CONTEXT: COPY nulltest, line 1: "a b \N d \N"
-- Last row is bad -- Last row is bad
COPY nulltest FROM stdin; COPY nulltest FROM stdin;
ERROR: new row for relation "nulltest" violates check constraint "nulltest_col5" ERROR: new row for relation "nulltest" violates check constraint "nulltest_col5_check"
CONTEXT: COPY nulltest, line 3: "a b c \N a" CONTEXT: COPY nulltest, line 3: "a b c \N a"
select * from nulltest; select * from nulltest;
col1 | col2 | col3 | col4 | col5 col1 | col2 | col3 | col4 | col5
...@@ -251,13 +251,13 @@ ERROR: column "col1" of table "domcontest" contains values that violate the new ...@@ -251,13 +251,13 @@ ERROR: column "col1" of table "domcontest" contains values that violate the new
alter domain con add constraint t check (VALUE < 34); alter domain con add constraint t check (VALUE < 34);
alter domain con add check (VALUE > 0); alter domain con add check (VALUE > 0);
insert into domcontest values (-5); -- fails insert into domcontest values (-5); -- fails
ERROR: value for domain con violates check constraint "$1" ERROR: value for domain con violates check constraint "con_check"
insert into domcontest values (42); -- fails insert into domcontest values (42); -- fails
ERROR: value for domain con violates check constraint "t" ERROR: value for domain con violates check constraint "t"
insert into domcontest values (5); insert into domcontest values (5);
alter domain con drop constraint t; alter domain con drop constraint t;
insert into domcontest values (-5); --fails insert into domcontest values (-5); --fails
ERROR: value for domain con violates check constraint "$1" ERROR: value for domain con violates check constraint "con_check"
insert into domcontest values (42); insert into domcontest values (42);
-- Confirm ALTER DOMAIN with RULES. -- Confirm ALTER DOMAIN with RULES.
create table domtab (col1 integer); create table domtab (col1 integer);
......
This diff is collapsed.
...@@ -9,7 +9,7 @@ CREATE SCHEMA test_schema_1 ...@@ -9,7 +9,7 @@ CREATE SCHEMA test_schema_1
a serial, a serial,
b int UNIQUE b int UNIQUE
); );
NOTICE: CREATE TABLE will create implicit sequence "abc_a_seq" for "serial" column "abc.a" NOTICE: CREATE TABLE will create implicit sequence "abc_a_seq" for serial column "abc.a"
NOTICE: CREATE TABLE / UNIQUE will create implicit index "abc_b_key" for table "abc" NOTICE: CREATE TABLE / UNIQUE will create implicit index "abc_b_key" for table "abc"
-- verify that the objects were created -- verify that the objects were created
SELECT COUNT(*) FROM pg_class WHERE relnamespace = SELECT COUNT(*) FROM pg_class WHERE relnamespace =
......
...@@ -1408,10 +1408,10 @@ insert into rule_and_refint_t3 values (1, 11, 12, 'row2'); ...@@ -1408,10 +1408,10 @@ insert into rule_and_refint_t3 values (1, 11, 12, 'row2');
insert into rule_and_refint_t3 values (1, 12, 11, 'row3'); insert into rule_and_refint_t3 values (1, 12, 11, 'row3');
insert into rule_and_refint_t3 values (1, 12, 12, 'row4'); insert into rule_and_refint_t3 values (1, 12, 12, 'row4');
insert into rule_and_refint_t3 values (1, 11, 13, 'row5'); insert into rule_and_refint_t3 values (1, 11, 13, 'row5');
ERROR: insert or update on table "rule_and_refint_t3" violates foreign key constraint "$2" ERROR: insert or update on table "rule_and_refint_t3" violates foreign key constraint "rule_and_refint_t3_id3a_fkey1"
DETAIL: Key (id3a,id3c)=(1,13) is not present in table "rule_and_refint_t2". DETAIL: Key (id3a,id3c)=(1,13) is not present in table "rule_and_refint_t2".
insert into rule_and_refint_t3 values (1, 13, 11, 'row6'); insert into rule_and_refint_t3 values (1, 13, 11, 'row6');
ERROR: insert or update on table "rule_and_refint_t3" violates foreign key constraint "$1" ERROR: insert or update on table "rule_and_refint_t3" violates foreign key constraint "rule_and_refint_t3_id3a_fkey"
DETAIL: Key (id3a,id3b)=(1,13) is not present in table "rule_and_refint_t1". DETAIL: Key (id3a,id3b)=(1,13) is not present in table "rule_and_refint_t1".
create rule rule_and_refint_t3_ins as on insert to rule_and_refint_t3 create rule rule_and_refint_t3_ins as on insert to rule_and_refint_t3
where (exists (select 1 from rule_and_refint_t3 where (exists (select 1 from rule_and_refint_t3
...@@ -1423,8 +1423,8 @@ create rule rule_and_refint_t3_ins as on insert to rule_and_refint_t3 ...@@ -1423,8 +1423,8 @@ create rule rule_and_refint_t3_ins as on insert to rule_and_refint_t3
and (rule_and_refint_t3.id3b = new.id3b)) and (rule_and_refint_t3.id3b = new.id3b))
and (rule_and_refint_t3.id3c = new.id3c)); and (rule_and_refint_t3.id3c = new.id3c));
insert into rule_and_refint_t3 values (1, 11, 13, 'row7'); insert into rule_and_refint_t3 values (1, 11, 13, 'row7');
ERROR: insert or update on table "rule_and_refint_t3" violates foreign key constraint "$2" ERROR: insert or update on table "rule_and_refint_t3" violates foreign key constraint "rule_and_refint_t3_id3a_fkey1"
DETAIL: Key (id3a,id3c)=(1,13) is not present in table "rule_and_refint_t2". DETAIL: Key (id3a,id3c)=(1,13) is not present in table "rule_and_refint_t2".
insert into rule_and_refint_t3 values (1, 13, 11, 'row8'); insert into rule_and_refint_t3 values (1, 13, 11, 'row8');
ERROR: insert or update on table "rule_and_refint_t3" violates foreign key constraint "$1" ERROR: insert or update on table "rule_and_refint_t3" violates foreign key constraint "rule_and_refint_t3_id3a_fkey"
DETAIL: Key (id3a,id3b)=(1,13) is not present in table "rule_and_refint_t1". DETAIL: Key (id3a,id3b)=(1,13) is not present in table "rule_and_refint_t1".
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
--- ---
CREATE TABLE serialTest (f1 text, f2 serial); CREATE TABLE serialTest (f1 text, f2 serial);
NOTICE: CREATE TABLE will create implicit sequence "serialtest_f2_seq" for "serial" column "serialtest.f2" NOTICE: CREATE TABLE will create implicit sequence "serialtest_f2_seq" for serial column "serialtest.f2"
INSERT INTO serialTest VALUES ('foo'); INSERT INTO serialTest VALUES ('foo');
INSERT INTO serialTest VALUES ('bar'); INSERT INTO serialTest VALUES ('bar');
......
...@@ -41,7 +41,7 @@ SELECT * FROM truncate_a; ...@@ -41,7 +41,7 @@ SELECT * FROM truncate_a;
TRUNCATE truncate_a; TRUNCATE truncate_a;
ERROR: cannot truncate a table referenced in a foreign key constraint ERROR: cannot truncate a table referenced in a foreign key constraint
DETAIL: Table "truncate_b" references "truncate_a" via foreign key constraint "$1". DETAIL: Table "truncate_b" references "truncate_a" via foreign key constraint "truncate_b_col1_fkey".
SELECT * FROM truncate_a; SELECT * FROM truncate_a;
col1 col1
------ ------
......
...@@ -127,7 +127,7 @@ INSERT INTO INSERT_TBL(y) VALUES ('Y'); ...@@ -127,7 +127,7 @@ INSERT INTO INSERT_TBL(y) VALUES ('Y');
ERROR: new row for relation "insert_tbl" violates check constraint "insert_con" ERROR: new row for relation "insert_tbl" violates check constraint "insert_con"
INSERT INTO INSERT_TBL(y) VALUES ('Y'); INSERT INTO INSERT_TBL(y) VALUES ('Y');
INSERT INTO INSERT_TBL(x,z) VALUES (1, -2); INSERT INTO INSERT_TBL(x,z) VALUES (1, -2);
ERROR: new row for relation "insert_tbl" violates check constraint "$1" ERROR: new row for relation "insert_tbl" violates check constraint "insert_tbl_check"
INSERT INTO INSERT_TBL(z,x) VALUES (-7, 7); INSERT INTO INSERT_TBL(z,x) VALUES (-7, 7);
INSERT INTO INSERT_TBL VALUES (5, 'check failed', -5); INSERT INTO INSERT_TBL VALUES (5, 'check failed', -5);
ERROR: new row for relation "insert_tbl" violates check constraint "insert_con" ERROR: new row for relation "insert_tbl" violates check constraint "insert_con"
...@@ -143,7 +143,7 @@ SELECT '' AS four, * FROM INSERT_TBL; ...@@ -143,7 +143,7 @@ SELECT '' AS four, * FROM INSERT_TBL;
(4 rows) (4 rows)
INSERT INTO INSERT_TBL(y,z) VALUES ('check failed', 4); INSERT INTO INSERT_TBL(y,z) VALUES ('check failed', 4);
ERROR: new row for relation "insert_tbl" violates check constraint "$1" ERROR: new row for relation "insert_tbl" violates check constraint "insert_tbl_check"
INSERT INTO INSERT_TBL(x,y) VALUES (5, 'check failed'); INSERT INTO INSERT_TBL(x,y) VALUES (5, 'check failed');
ERROR: new row for relation "insert_tbl" violates check constraint "insert_con" ERROR: new row for relation "insert_tbl" violates check constraint "insert_con"
INSERT INTO INSERT_TBL(x,y) VALUES (5, '!check failed'); INSERT INTO INSERT_TBL(x,y) VALUES (5, '!check failed');
...@@ -197,9 +197,9 @@ CREATE TABLE INSERT_CHILD (cx INT default 42, ...@@ -197,9 +197,9 @@ CREATE TABLE INSERT_CHILD (cx INT default 42,
INHERITS (INSERT_TBL); INHERITS (INSERT_TBL);
INSERT INTO INSERT_CHILD(x,z,cy) VALUES (7,-7,11); INSERT INTO INSERT_CHILD(x,z,cy) VALUES (7,-7,11);
INSERT INTO INSERT_CHILD(x,z,cy) VALUES (7,-7,6); INSERT INTO INSERT_CHILD(x,z,cy) VALUES (7,-7,6);
ERROR: new row for relation "insert_child" violates check constraint "insert_child_cy" ERROR: new row for relation "insert_child" violates check constraint "insert_child_check"
INSERT INTO INSERT_CHILD(x,z,cy) VALUES (6,-7,7); INSERT INTO INSERT_CHILD(x,z,cy) VALUES (6,-7,7);
ERROR: new row for relation "insert_child" violates check constraint "$1" ERROR: new row for relation "insert_child" violates check constraint "insert_tbl_check"
INSERT INTO INSERT_CHILD(x,y,z,cy) VALUES (6,'check failed',-6,7); INSERT INTO INSERT_CHILD(x,y,z,cy) VALUES (6,'check failed',-6,7);
ERROR: new row for relation "insert_child" violates check constraint "insert_con" ERROR: new row for relation "insert_child" violates check constraint "insert_con"
SELECT * FROM INSERT_CHILD; SELECT * FROM INSERT_CHILD;
......
...@@ -129,6 +129,6 @@ COPY y TO stdout WITH CSV; ...@@ -129,6 +129,6 @@ COPY y TO stdout WITH CSV;
COPY y TO stdout WITH CSV QUOTE '''' DELIMITER '|'; COPY y TO stdout WITH CSV QUOTE '''' DELIMITER '|';
COPY y TO stdout WITH CSV FORCE QUOTE col2 ESCAPE '\\'; COPY y TO stdout WITH CSV FORCE QUOTE col2 ESCAPE '\\';
DROP TABLE x; DROP TABLE x, y;
DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_before();
DROP FUNCTION fn_x_after(); DROP FUNCTION fn_x_after();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment