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 */
416434static char *
417- makeTableName ( void * elem ,... )
435+ makeObjectName ( char * name1 , char * name2 , char * typename )
418436{
419- va_list args ;
420-
421437char * 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
447487return name ;
448488}
@@ -453,36 +493,32 @@ CreateIndexName(char *table_name, char *column_name, char *label, List *indices)
453493int pass = 0 ;
454494char * iname = NULL ;
455495List * 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 );
472512if (strcasecmp (iname ,index -> idxname )== 0 )
473513break ;
474-
475- ilist = lnext (ilist );
476514}
477515/* ran through entire list? then no name conflict found so done */
478516if (ilist == NIL )
479517break ;
480518
481519/* the last one conflicted, so try a new name component */
482520pfree (iname );
483- iname = NULL ;
484- pass ++ ;
485- sprintf (name2 ,"%s_%d" ,column_name , (pass + 1 ));
521+ sprintf (typename ,"%s%d" ,label ,++ pass );
486522}
487523
488524return iname ;
@@ -542,12 +578,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
542578char * cstring ;
543579CreateSeqStmt * 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" );
551583constraint = makeNode (Constraint );
552584constraint -> contype = CONSTR_DEFAULT ;
553585constraint -> name = sname ;
@@ -562,11 +594,9 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
562594
563595constraint = makeNode (Constraint );
564596constraint -> 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" );
570600column -> constraints = lappend (column -> constraints ,constraint );
571601
572602sequence = makeNode (CreateSeqStmt );
@@ -616,23 +646,15 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
616646
617647case CONSTR_PRIMARY :
618648if (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" );
624650if (constraint -> keys == NIL )
625651constraint -> keys = lappend (constraint -> keys ,column );
626652dlist = lappend (dlist ,constraint );
627653break ;
628654
629655case CONSTR_UNIQUE :
630656if (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" );
636658if (constraint -> keys == NIL )
637659constraint -> keys = lappend (constraint -> keys ,column );
638660dlist = lappend (dlist ,constraint );
@@ -641,11 +663,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
641663case CONSTR_CHECK :
642664constraints = lappend (constraints ,constraint );
643665if (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 );
649667break ;
650668
651669default :
@@ -663,11 +681,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
663681{
664682case CONSTR_PRIMARY :
665683if (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" );
671685dlist = lappend (dlist ,constraint );
672686break ;
673687
@@ -728,15 +742,9 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
728742}
729743
730744if (constraint -> name != NULL )
731- index -> idxname = constraint -> name ;
745+ index -> idxname = pstrdup ( constraint -> name ) ;
732746else 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" );
740748else
741749index -> idxname = NULL ;
742750
@@ -767,7 +775,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
767775if (constraint -> contype == CONSTR_PRIMARY )
768776column -> is_not_null = TRUE;
769777iparam = makeNode (IndexElem );
770- iparam -> name = strcpy ( palloc ( strlen ( column -> colname ) + 1 ), column -> colname );
778+ iparam -> name = pstrdup ( column -> colname );
771779iparam -> args = NIL ;
772780iparam -> class = NULL ;
773781iparam -> typename = NULL ;
@@ -779,9 +787,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
779787keys = 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
786793ilist = lappend (ilist ,index );
787794dlist = lnext (dlist );