Skip to content

Commit ca234c3

Browse files
committed
Instead of failing when the constructed name for a sequence,
index, etc is too long, truncate until it fits.
1 parent 4cf595b commit ca234c3

File tree

1 file changed

+92
-85
lines changed

1 file changed

+92
-85
lines changed

src/backend/parser/analyze.c

Lines changed: 92 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Copyright (c) 1994, Regents of the University of California
77
*
8-
* $Id: analyze.c,v 1.109 1999/05/25 22:04:25 momjian Exp $
8+
* $Id: analyze.c,v 1.110 1999/06/05 20:22:30 tgl Exp $
99
*
1010
*-------------------------------------------------------------------------
1111
*/
@@ -410,39 +410,79 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
410410
}
411411

412412
/*
413-
* makeTableName()
414-
* Create a table name from a list of fields.
413+
* makeObjectName()
414+
*
415+
* Create a name for an implicitly created index, sequence, constraint, etc.
416+
*
417+
* The parameters are: the original table name, the original field name, and
418+
* a "type" string (such as "seq" or "pkey"). The field name and/or type
419+
* can be NULL if not relevant.
420+
*
421+
* The result is a palloc'd string.
422+
*
423+
* The basic result we want is "name1_name2_type", omitting "_name2" or
424+
* "_type" when those parameters are NULL. However, we must generate
425+
* a name with less than NAMEDATALEN characters! So, we truncate one or
426+
* both names if necessary to make a short-enough string. The type part
427+
* is never truncated (so it had better be reasonably short).
428+
*
429+
* To reduce the probability of collisions, we might someday add more
430+
* smarts to this routine, like including some "hash" characters computed
431+
* from the truncated characters. Currently it seems best to keep it simple,
432+
* so that the generated names are easily predictable by a person.
415433
*/
416434
static char *
417-
makeTableName(void *elem,...)
435+
makeObjectName(char *name1, char *name2, char *typename)
418436
{
419-
va_list args;
420-
421437
char *name;
422-
char buf[NAMEDATALEN + 1];
423-
424-
buf[0] = '\0';
425-
426-
va_start(args, elem);
427-
428-
name = elem;
429-
while (name != NULL)
438+
int overhead = 0; /* chars needed for type and underscores */
439+
int availchars; /* chars available for name(s) */
440+
int name1chars; /* chars allocated to name1 */
441+
int name2chars; /* chars allocated to name2 */
442+
int ndx;
443+
444+
name1chars = strlen(name1);
445+
if (name2)
430446
{
431-
/* not enough room for next part? then return nothing */
432-
if ((strlen(buf) + strlen(name)) >= (sizeof(buf) - 1))
433-
return NULL;
447+
name2chars = strlen(name2);
448+
overhead++; /* allow for separating underscore */
449+
}
450+
else
451+
name2chars = 0;
452+
if (typename)
453+
overhead += strlen(typename) + 1;
434454

435-
if (strlen(buf) > 0)
436-
strcat(buf, "_");
437-
strcat(buf, name);
455+
availchars = NAMEDATALEN-1 - overhead;
438456

439-
name = va_arg(args, void *);
457+
/* If we must truncate, preferentially truncate the longer name.
458+
* This logic could be expressed without a loop, but it's simple and
459+
* obvious as a loop.
460+
*/
461+
while (name1chars + name2chars > availchars)
462+
{
463+
if (name1chars > name2chars)
464+
name1chars--;
465+
else
466+
name2chars--;
440467
}
441468

442-
va_end(args);
443-
444-
name = palloc(strlen(buf) + 1);
445-
strcpy(name, buf);
469+
/* Now construct the string using the chosen lengths */
470+
name = palloc(name1chars + name2chars + overhead + 1);
471+
strncpy(name, name1, name1chars);
472+
ndx = name1chars;
473+
if (name2)
474+
{
475+
name[ndx++] = '_';
476+
strncpy(name+ndx, name2, name2chars);
477+
ndx += name2chars;
478+
}
479+
if (typename)
480+
{
481+
name[ndx++] = '_';
482+
strcpy(name+ndx, typename);
483+
}
484+
else
485+
name[ndx] = '\0';
446486

447487
return name;
448488
}
@@ -453,36 +493,32 @@ CreateIndexName(char *table_name, char *column_name, char *label, List *indices)
453493
int pass = 0;
454494
char *iname = NULL;
455495
List *ilist;
456-
IndexStmt *index;
457-
char name2[NAMEDATALEN + 1];
496+
char typename[NAMEDATALEN];
497+
498+
/* The type name for makeObjectName is label, or labelN if that's
499+
* necessary to prevent collisions among multiple indexes for the same
500+
* table. Note there is no check for collisions with already-existing
501+
* indexes; this ought to be rethought someday.
502+
*/
503+
strcpy(typename, label);
458504

459-
/* use working storage, since we might be trying several possibilities */
460-
strcpy(name2, column_name);
461-
while (iname == NULL)
505+
for (;;)
462506
{
463-
iname = makeTableName(table_name, name2, label, NULL);
464-
/* unable to make a name at all? then quit */
465-
if (iname == NULL)
466-
break;
507+
iname = makeObjectName(table_name, column_name, typename);
467508

468-
ilist = indices;
469-
while (ilist != NIL)
509+
foreach(ilist, indices)
470510
{
471-
index = lfirst(ilist);
511+
IndexStmt *index = lfirst(ilist);
472512
if (strcasecmp(iname, index->idxname) == 0)
473513
break;
474-
475-
ilist = lnext(ilist);
476514
}
477515
/* ran through entire list? then no name conflict found so done */
478516
if (ilist == NIL)
479517
break;
480518

481519
/* the last one conflicted, so try a new name component */
482520
pfree(iname);
483-
iname = NULL;
484-
pass++;
485-
sprintf(name2, "%s_%d", column_name, (pass + 1));
521+
sprintf(typename, "%s%d", label, ++pass);
486522
}
487523

488524
return iname;
@@ -542,12 +578,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
542578
char *cstring;
543579
CreateSeqStmt *sequence;
544580

545-
sname = makeTableName(stmt->relname, column->colname, "seq", NULL);
546-
if (sname == NULL)
547-
elog(ERROR, "CREATE TABLE/SERIAL implicit sequence name must be less than %d characters"
548-
"\n\tSum of lengths of '%s' and '%s' must be less than %d",
549-
NAMEDATALEN, stmt->relname, column->colname, (NAMEDATALEN - 5));
550-
581+
sname = makeObjectName(stmt->relname, column->colname,
582+
"seq");
551583
constraint = makeNode(Constraint);
552584
constraint->contype = CONSTR_DEFAULT;
553585
constraint->name = sname;
@@ -562,11 +594,9 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
562594

563595
constraint = makeNode(Constraint);
564596
constraint->contype = CONSTR_UNIQUE;
565-
constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
566-
if (constraint->name == NULL)
567-
elog(ERROR, "CREATE TABLE/SERIAL implicit index name must be less than %d characters"
568-
"\n\tSum of lengths of '%s' and '%s' must be less than %d",
569-
NAMEDATALEN, stmt->relname, column->colname, (NAMEDATALEN - 5));
597+
constraint->name = makeObjectName(stmt->relname,
598+
column->colname,
599+
"key");
570600
column->constraints = lappend(column->constraints, constraint);
571601

572602
sequence = makeNode(CreateSeqStmt);
@@ -616,23 +646,15 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
616646

617647
case CONSTR_PRIMARY:
618648
if (constraint->name == NULL)
619-
constraint->name = makeTableName(stmt->relname, "pkey", NULL);
620-
if (constraint->name == NULL)
621-
elog(ERROR, "CREATE TABLE/PRIMARY KEY implicit index name must be less than %d characters"
622-
"\n\tLength of '%s' must be less than %d",
623-
NAMEDATALEN, stmt->relname, (NAMEDATALEN - 6));
649+
constraint->name = makeObjectName(stmt->relname, NULL, "pkey");
624650
if (constraint->keys == NIL)
625651
constraint->keys = lappend(constraint->keys, column);
626652
dlist = lappend(dlist, constraint);
627653
break;
628654

629655
case CONSTR_UNIQUE:
630656
if (constraint->name == NULL)
631-
constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
632-
if (constraint->name == NULL)
633-
elog(ERROR, "CREATE TABLE/UNIQUE implicit index name must be less than %d characters"
634-
"\n\tLength of '%s' must be less than %d",
635-
NAMEDATALEN, stmt->relname, (NAMEDATALEN - 5));
657+
constraint->name = makeObjectName(stmt->relname, column->colname, "key");
636658
if (constraint->keys == NIL)
637659
constraint->keys = lappend(constraint->keys, column);
638660
dlist = lappend(dlist, constraint);
@@ -641,11 +663,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
641663
case CONSTR_CHECK:
642664
constraints = lappend(constraints, constraint);
643665
if (constraint->name == NULL)
644-
constraint->name = makeTableName(stmt->relname, column->colname, NULL);
645-
if (constraint->name == NULL)
646-
elog(ERROR, "CREATE TABLE/CHECK implicit constraint name must be less than %d characters"
647-
"\n\tSum of lengths of '%s' and '%s' must be less than %d",
648-
NAMEDATALEN, stmt->relname, column->colname, (NAMEDATALEN - 1));
666+
constraint->name = makeObjectName(stmt->relname, column->colname, NULL);
649667
break;
650668

651669
default:
@@ -663,11 +681,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
663681
{
664682
case CONSTR_PRIMARY:
665683
if (constraint->name == NULL)
666-
constraint->name = makeTableName(stmt->relname, "pkey", NULL);
667-
if (constraint->name == NULL)
668-
elog(ERROR, "CREATE TABLE/PRIMARY KEY implicit index name must be less than %d characters"
669-
"\n\tLength of '%s' must be less than %d",
670-
NAMEDATALEN, stmt->relname, (NAMEDATALEN - 5));
684+
constraint->name = makeObjectName(stmt->relname, NULL, "pkey");
671685
dlist = lappend(dlist, constraint);
672686
break;
673687

@@ -728,15 +742,9 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
728742
}
729743

730744
if (constraint->name != NULL)
731-
index->idxname = constraint->name;
745+
index->idxname = pstrdup(constraint->name);
732746
else if (constraint->contype == CONSTR_PRIMARY)
733-
{
734-
index->idxname = makeTableName(stmt->relname, "pkey", NULL);
735-
if (index->idxname == NULL)
736-
elog(ERROR, "CREATE TABLE/PRIMARY KEY implicit index name must be less than %d characters"
737-
"\n\tLength of '%s' must be less than %d",
738-
NAMEDATALEN, stmt->relname, (NAMEDATALEN - 5));
739-
}
747+
index->idxname = makeObjectName(stmt->relname, NULL, "pkey");
740748
else
741749
index->idxname = NULL;
742750

@@ -767,7 +775,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
767775
if (constraint->contype == CONSTR_PRIMARY)
768776
column->is_not_null = TRUE;
769777
iparam = makeNode(IndexElem);
770-
iparam->name = strcpy(palloc(strlen(column->colname) + 1), column->colname);
778+
iparam->name = pstrdup(column->colname);
771779
iparam->args = NIL;
772780
iparam->class = NULL;
773781
iparam->typename = NULL;
@@ -779,9 +787,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
779787
keys = lnext(keys);
780788
}
781789

782-
if (index->idxname == NULL)
783-
elog(ERROR, "CREATE TABLE unable to construct implicit index for table '%s'"
784-
"; name too long", stmt->relname);
790+
if (index->idxname == NULL) /* should not happen */
791+
elog(ERROR, "CREATE TABLE: failed to make implicit index name");
785792

786793
ilist = lappend(ilist, index);
787794
dlist = lnext(dlist);

0 commit comments

Comments
 (0)