summaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/indexcmds.c148
-rw-r--r--src/backend/commands/tablecmds.c74
-rw-r--r--src/backend/commands/typecmds.c24
3 files changed, 165 insertions, 81 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 1fe8e58e58..d141c83c1b 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
*
*
* 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 @@
#include "commands/defrem.h"
#include "commands/tablecmds.h"
#include "executor/executor.h"
+#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "optimizer/prep.h"
-#include "parser/analyze.h"
#include "parser/parsetree.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
@@ -53,8 +53,6 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
static Oid GetIndexOpClass(List *opclass, Oid attrType,
char *accessMethodName, 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);
@@ -159,18 +157,18 @@ DefineIndex(RangeVar *heapRelation,
if (indexRelationName == NULL)
{
if (primary)
- indexRelationName = CreateIndexName(RelationGetRelationName(rel),
- NULL,
- "pkey",
- namespaceId);
+ indexRelationName = ChooseRelationName(RelationGetRelationName(rel),
+ NULL,
+ "pkey",
+ namespaceId);
else
{
IndexElem *iparam = (IndexElem *) linitial(attributeList);
- indexRelationName = CreateIndexName(RelationGetRelationName(rel),
- iparam->name,
- "key",
- namespaceId);
+ indexRelationName = ChooseRelationName(RelationGetRelationName(rel),
+ iparam->name,
+ "key",
+ namespaceId);
}
}
@@ -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 *
-CreateIndexName(const char *table_name, const char *column_name,
- const char *label, Oid inamespace)
+char *
+makeObjectName(const char *name1, const char *name2, const char *label)
{
- int pass = 0;
- char *iname = NULL;
- char typename[NAMEDATALEN];
+ char *name;
+ int overhead = 0; /* chars needed for label 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 (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
- * necessary to prevent collision with existing indexes.
+ * 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.
*/
- 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 (;;)
{
- 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;
/* found a conflict, so try a new name component */
- pfree(iname);
- snprintf(typename, sizeof(typename), "%s%d", label, ++pass);
+ pfree(relname);
+ snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
}
- return iname;
+ return relname;
}
/*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3a95064442..7b0b35840e 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* 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
List *changedConstraintDefs; /* string definitions of same */
List *changedIndexOids; /* OIDs of indexes to rebuild */
List *changedIndexDefs; /* string definitions of same */
- /* Workspace for ATExecAddConstraint */
- int constr_name_ctr;
} AlteredTableInfo;
/* Struct describing one new constraint to check in Phase 3 scan */
@@ -323,46 +321,45 @@ DefineRelation(CreateStmt *stmt, char relkind)
if (old_constraints != NIL)
{
- ConstrCheck *check = (ConstrCheck *) palloc(list_length(old_constraints) *
- sizeof(ConstrCheck));
+ ConstrCheck *check = (ConstrCheck *)
+ palloc0(list_length(old_constraints) * sizeof(ConstrCheck));
int ncheck = 0;
- int constr_name_ctr = 0;
foreach(listptr, old_constraints)
{
Constraint *cdef = (Constraint *) lfirst(listptr);
+ bool dup = false;
if (cdef->contype != CONSTR_CHECK)
continue;
-
- if (cdef->name != NULL)
+ Assert(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)
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_OBJECT),
+ dup = true;
+ break;
+ }
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("duplicate check constraint name \"%s\"",
cdef->name)));
- }
- check[ncheck].ccname = cdef->name;
}
- else
+ if (!dup)
{
- /*
- * Generate a constraint name. NB: this should match the
- * form of names that GenerateConstraintName() may produce
- * 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);
+ check[ncheck].ccname = cdef->name;
+ check[ncheck].ccbin = pstrdup(cdef->cooked_expr);
+ ncheck++;
}
- Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL);
- check[ncheck].ccbin = pstrdup(cdef->cooked_expr);
- ncheck++;
}
if (ncheck > 0)
{
@@ -867,17 +864,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
Node *expr;
cdef->contype = CONSTR_CHECK;
-
- /*
- * 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->name = pstrdup(check[i].ccname);
cdef->raw_expr = NULL;
/* adjust varattnos of ccbin here */
expr = stringToNode(check[i].ccbin);
@@ -3610,10 +3597,11 @@ ATExecAddConstraint(AlteredTableInfo *tab, Relation rel, Node *newConstraint)
}
else
fkconstraint->constr_name =
- GenerateConstraintName(CONSTRAINT_RELATION,
- RelationGetRelid(rel),
- RelationGetNamespace(rel),
- &tab->constr_name_ctr);
+ ChooseConstraintName(RelationGetRelationName(rel),
+ strVal(linitial(fkconstraint->fk_attrs)),
+ "fkey",
+ RelationGetNamespace(rel),
+ NIL);
ATAddForeignKeyConstraint(tab, rel, fkconstraint);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 439ad91cc3..a64617d08d 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
*
*
* 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
* The "DefineFoo" routines take the parse tree and pick out the
@@ -83,7 +83,7 @@ static void domainOwnerCheck(HeapTuple tup, TypeName *typename);
static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
Oid baseTypeOid,
int typMod, Constraint *constr,
- int *counter, char *domainName);
+ char *domainName);
/*
@@ -509,7 +509,6 @@ DefineDomain(CreateDomainStmt *stmt)
Oid basetypeoid;
Oid domainoid;
Form_pg_type baseType;
- int counter = 0;
/* Convert list of names to a name and namespace */
domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
@@ -760,7 +759,7 @@ DefineDomain(CreateDomainStmt *stmt)
case CONSTR_CHECK:
domainAddConstraint(domainoid, domainNamespace,
basetypeoid, stmt->typename->typmod,
- constr, &counter, domainName);
+ constr, domainName);
break;
/* Other constraint types were fully processed above */
@@ -768,6 +767,9 @@ DefineDomain(CreateDomainStmt *stmt)
default:
break;
}
+
+ /* CCI so we can detect duplicate constraint names */
+ CommandCounterIncrement();
}
/*
@@ -1463,7 +1465,6 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
char *ccbin;
Expr *expr;
ExprState *exprstate;
- int counter = 0;
Constraint *constr;
/* Make a TypeName so we can use standard type lookup machinery */
@@ -1547,7 +1548,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
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
@@ -1788,7 +1789,7 @@ domainOwnerCheck(HeapTuple tup, TypeName *typename)
static char *
domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
int typMod, Constraint *constr,
- int *counter, char *domainName)
+ char *domainName)
{
Node *expr;
char *ccsrc;
@@ -1811,10 +1812,11 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
constr->name, domainName)));
}
else
- constr->name = GenerateConstraintName(CONSTRAINT_DOMAIN,
- domainOid,
- domainNamespace,
- counter);
+ constr->name = ChooseConstraintName(domainName,
+ NULL,
+ "check",
+ domainNamespace,
+ NIL);
/*
* Convert the A_EXPR in raw_expr into an EXPR