Adjust naming of indexes and their columns per recent discussion.
authorTom Lane <[email protected]>
Wed, 23 Dec 2009 02:35:25 +0000 (02:35 +0000)
committerTom Lane <[email protected]>
Wed, 23 Dec 2009 02:35:25 +0000 (02:35 +0000)
Index expression columns are now named after the FigureColname result for
their expressions, rather than always being "pg_expression_N".  Digits are
appended to this name if needed to make the column name unique within the
index.  (That happens for regular columns too, thus fixing the old problem
that CREATE INDEX fooi ON foo (f1, f1) fails.  Before exclusion indexes
there was no real reason to do such a thing, but now maybe there is.)

Default names for indexes and associated constraints now include the column
names of all their columns, not only the first one as in previous practice.
(Of course, this will be truncated as needed to fit in NAMEDATALEN.  Also,
pkey indexes retain the historical behavior of not naming specific columns
at all.)

An example of the results:

regression=# create table foo (f1 int, f2 text,
regression(# exclude (f1 with =, lower(f2) with =));
NOTICE:  CREATE TABLE / EXCLUDE will create implicit index "foo_f1_lower_exclusion" for table "foo"
CREATE TABLE
regression=# \d foo_f1_lower_exclusion
Index "public.foo_f1_lower_exclusion"
 Column |  Type   | Definition
--------+---------+------------
 f1     | integer | f1
 lower  | text    | lower(f2)
btree, for table "public.foo"

18 files changed:
src/backend/bootstrap/bootparse.y
src/backend/catalog/index.c
src/backend/catalog/toasting.c
src/backend/commands/indexcmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/parser/gram.y
src/backend/parser/parse_target.c
src/backend/parser/parse_utilcmd.c
src/include/catalog/index.h
src/include/commands/defrem.h
src/include/nodes/parsenodes.h
src/include/parser/parse_target.h
src/test/regress/expected/alter_table.out
src/test/regress/expected/foreign_key.out
src/test/regress/expected/inherit.out
src/test/regress/output/constraints.source

index 90cf9659ecfbae5b722e702076fb9013bb9957d4..aec1bd451f0ab91b464ca1400a4cf8b1af986067 100644 (file)
@@ -323,6 +323,7 @@ boot_index_param:
                    IndexElem *n = makeNode(IndexElem);
                    n->name = $1;
                    n->expr = NULL;
+                   n->indexcolname = NULL;
                    n->opclass = list_make1(makeString($2));
                    n->ordering = SORTBY_DEFAULT;
                    n->nulls_ordering = SORTBY_NULLS_DEFAULT;
index a28740bb86a734d4b73225efd50ca44e95bb9230..daf6d099d8f2514f1172e6aa710e0e597befca2a 100644 (file)
@@ -82,6 +82,7 @@ typedef struct
 /* non-export function prototypes */
 static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
                         IndexInfo *indexInfo,
+                        List *indexColNames,
                         Oid accessMethodObjectId,
                         Oid *classObjectId);
 static void InitializeAttributeOids(Relation indexRelation,
@@ -117,10 +118,12 @@ static Oid    IndexGetRelation(Oid indexId);
 static TupleDesc
 ConstructTupleDescriptor(Relation heapRelation,
                         IndexInfo *indexInfo,
+                        List *indexColNames,
                         Oid accessMethodObjectId,
                         Oid *classObjectId)
 {
    int         numatts = indexInfo->ii_NumIndexAttrs;
+   ListCell   *colnames_item = list_head(indexColNames);
    ListCell   *indexpr_item = list_head(indexInfo->ii_Expressions);
    HeapTuple   amtuple;
    Form_pg_am  amform;
@@ -216,12 +219,6 @@ ConstructTupleDescriptor(Relation heapRelation,
            indexkey = (Node *) lfirst(indexpr_item);
            indexpr_item = lnext(indexpr_item);
 
-           /*
-            * Make the attribute's name "pg_expresssion_nnn" (maybe think of
-            * something better later)
-            */
-           sprintf(NameStr(to->attname), "pg_expression_%d", i + 1);
-
            /*
             * Lookup the expression type in pg_type for the type length etc.
             */
@@ -268,6 +265,14 @@ ConstructTupleDescriptor(Relation heapRelation,
         */
        to->attrelid = InvalidOid;
 
+       /*
+        * Set the attribute name as specified by caller.
+        */
+       if (colnames_item == NULL)  /* shouldn't happen */
+           elog(ERROR, "too few entries in colnames list");
+       namestrcpy(&to->attname, (const char *) lfirst(colnames_item));
+       colnames_item = lnext(colnames_item);
+
        /*
         * Check the opclass and index AM to see if either provides a keytype
         * (overriding the attribute type).  Opclass takes precedence.
@@ -494,6 +499,7 @@ UpdateIndexRelation(Oid indexoid,
  *     generate an OID for the index.  During bootstrap this may be
  *     nonzero to specify a preselected OID.
  * indexInfo: same info executor uses to insert into the index
+ * indexColNames: column names to use for index (List of char *)
  * accessMethodObjectId: OID of index AM to use
  * tableSpaceId: OID of tablespace to use
  * classObjectId: array of index opclass OIDs, one per index column
@@ -517,6 +523,7 @@ index_create(Oid heapRelationId,
             const char *indexRelationName,
             Oid indexRelationId,
             IndexInfo *indexInfo,
+            List *indexColNames,
             Oid accessMethodObjectId,
             Oid tableSpaceId,
             Oid *classObjectId,
@@ -629,6 +636,7 @@ index_create(Oid heapRelationId,
     */
    indexTupDesc = ConstructTupleDescriptor(heapRelation,
                                            indexInfo,
+                                           indexColNames,
                                            accessMethodObjectId,
                                            classObjectId);
 
index 81c2cbc0540f5dbcc79bf92dd898d58681dcef4e..dff43a648d864608cb794028d7e439fecc746d84 100644 (file)
@@ -255,6 +255,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 
    toast_idxid = index_create(toast_relid, toast_idxname, toastIndexOid,
                               indexInfo,
+                              list_make2("chunk_id", "chunk_seq"),
                               BTREE_AM_OID,
                               rel->rd_rel->reltablespace,
                               classObjectId, coloptions, (Datum) 0,
index 8ecd03c20b7ee9f80813aef9ca6406e060a30ec1..7700f1c032a6c863f0ebf50af3c9b9c39153d1be 100644 (file)
@@ -67,6 +67,7 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo,
                  bool isconstraint);
 static Oid GetIndexOpClass(List *opclass, Oid attrType,
                char *accessMethodName, Oid accessMethodId);
+static char *ChooseIndexNameAddition(List *colnames);
 static bool relationHasPrimaryKey(Relation rel);
 
 
@@ -128,6 +129,7 @@ DefineIndex(RangeVar *heapRelation,
    Oid         relationId;
    Oid         namespaceId;
    Oid         tablespaceId;
+   List       *indexColNames;
    Relation    rel;
    Relation    indexRelation;
    HeapTuple   tuple;
@@ -247,37 +249,21 @@ DefineIndex(RangeVar *heapRelation,
    if (rel->rd_rel->relisshared)
        tablespaceId = GLOBALTABLESPACE_OID;
 
+   /*
+    * Choose the index column names.
+    */
+   indexColNames = ChooseIndexColumnNames(attributeList);
+
    /*
     * Select name for index if caller didn't specify
     */
    if (indexRelationName == NULL)
-   {
-       if (primary)
-       {
-           indexRelationName = ChooseRelationName(RelationGetRelationName(rel),
-                                                  NULL,
-                                                  "pkey",
-                                                  namespaceId);
-       }
-       else if (exclusionOpNames != NIL)
-       {
-           IndexElem  *iparam = (IndexElem *) linitial(attributeList);
-
-           indexRelationName = ChooseRelationName(RelationGetRelationName(rel),
-                                                  iparam->name,
-                                                  "exclusion",
-                                                  namespaceId);
-       }
-       else
-       {
-           IndexElem  *iparam = (IndexElem *) linitial(attributeList);
-
-           indexRelationName = ChooseRelationName(RelationGetRelationName(rel),
-                                                  iparam->name,
-                                                  "key",
-                                                  namespaceId);
-       }
-   }
+       indexRelationName = ChooseIndexName(RelationGetRelationName(rel),
+                                           namespaceId,
+                                           indexColNames,
+                                           exclusionOpNames,
+                                           primary,
+                                           isconstraint);
 
    /*
     * look up the access method, verify it can handle the requested features
@@ -488,35 +474,30 @@ DefineIndex(RangeVar *heapRelation,
    SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
    heap_close(rel, NoLock);
 
-   if (!concurrent)
-   {
-       indexRelationId =
-           index_create(relationId, indexRelationName, indexRelationId,
-                     indexInfo, accessMethodId, tablespaceId, classObjectId,
-                        coloptions, reloptions, primary,
-                        isconstraint, deferrable, initdeferred,
-                        allowSystemTableMods, skip_build, concurrent);
-
-       return;                 /* We're done, in the standard case */
-   }
-
    /*
-    * For a concurrent build, we next insert the catalog entry and add
-    * constraints.  We don't build the index just yet; we must first make the
-    * catalog entry so that the new index is visible to updating
-    * transactions.  That will prevent them from making incompatible HOT
-    * updates.  The new index will be marked not indisready and not
-    * indisvalid, so that no one else tries to either insert into it or use
-    * it for queries.  We pass skip_build = true to prevent the build.
+    * Make the catalog entries for the index, including constraints.
+    * Then, if not skip_build || concurrent, actually build the index.
     */
    indexRelationId =
        index_create(relationId, indexRelationName, indexRelationId,
-                    indexInfo, accessMethodId, tablespaceId, classObjectId,
+                    indexInfo, indexColNames,
+                    accessMethodId, tablespaceId, classObjectId,
                     coloptions, reloptions, primary,
                     isconstraint, deferrable, initdeferred,
-                    allowSystemTableMods, true, concurrent);
+                    allowSystemTableMods,
+                    skip_build || concurrent,
+                    concurrent);
+
+   if (!concurrent)
+       return;                 /* We're done, in the standard case */
 
    /*
+    * For a concurrent build, it's important to make the catalog entries
+    * visible to other transactions before we start to build the index.
+    * That will prevent them from making incompatible HOT updates.  The new
+    * index will be marked not indisready and not indisvalid, so that no one
+    * else tries to either insert into it or use it for queries.
+    *
     * We must commit our current transaction so that the index becomes
     * visible; then start another.  Note that all the data structures we just
     * built are lost in the commit.  The only data we keep past here are the
@@ -1391,6 +1372,147 @@ ChooseRelationName(const char *name1, const char *name2,
    return relname;
 }
 
+/*
+ * Select the name to be used for an index.
+ *
+ * The argument list is pretty ad-hoc :-(
+ */
+char *
+ChooseIndexName(const char *tabname, Oid namespaceId,
+               List *colnames, List *exclusionOpNames,
+               bool primary, bool isconstraint)
+{
+   char       *indexname;
+
+   if (primary)
+   {
+       /* the primary key's name does not depend on the specific column(s) */
+       indexname = ChooseRelationName(tabname,
+                                      NULL,
+                                      "pkey",
+                                      namespaceId);
+   }
+   else if (exclusionOpNames != NIL)
+   {
+       indexname = ChooseRelationName(tabname,
+                                      ChooseIndexNameAddition(colnames),
+                                      "exclusion",
+                                      namespaceId);
+   }
+   else if (isconstraint)
+   {
+       indexname = ChooseRelationName(tabname,
+                                      ChooseIndexNameAddition(colnames),
+                                      "key",
+                                      namespaceId);
+   }
+   else
+   {
+       indexname = ChooseRelationName(tabname,
+                                      ChooseIndexNameAddition(colnames),
+                                      "idx",
+                                      namespaceId);
+   }
+
+   return indexname;
+}
+
+/*
+ * Generate "name2" for a new index given the list of column names for it
+ * (as produced by ChooseIndexColumnNames).  This will be passed to
+ * ChooseRelationName along with the parent table name and a suitable label.
+ *
+ * We know that less than NAMEDATALEN characters will actually be used,
+ * so we can truncate the result once we've generated that many.
+ */
+static char *
+ChooseIndexNameAddition(List *colnames)
+{
+   char        buf[NAMEDATALEN * 2];
+   int         buflen = 0;
+   ListCell   *lc;
+
+   buf[0] = '\0';
+   foreach(lc, colnames)
+   {
+       const char *name = (const char *) lfirst(lc);
+
+       if (buflen > 0)
+           buf[buflen++] = '_';            /* insert _ between names */
+
+       /*
+        * At this point we have buflen <= NAMEDATALEN.  name should be less
+        * than NAMEDATALEN already, but use strlcpy for paranoia.
+        */
+       strlcpy(buf + buflen, name, NAMEDATALEN);
+       buflen += strlen(buf + buflen);
+       if (buflen >= NAMEDATALEN)
+           break;
+   }
+   return pstrdup(buf);
+}
+
+/*
+ * Select the actual names to be used for the columns of an index, given the
+ * list of IndexElems for the columns.  This is mostly about ensuring the
+ * names are unique so we don't get a conflicting-attribute-names error.
+ *
+ * Returns a List of plain strings (char *, not String nodes).
+ */
+List *
+ChooseIndexColumnNames(List *indexElems)
+{
+   List       *result = NIL;
+   ListCell   *lc;
+
+   foreach(lc, indexElems)
+   {
+       IndexElem  *ielem = (IndexElem *) lfirst(lc);
+       const char *origname;
+       const char *curname;
+       int         i;
+       char        buf[NAMEDATALEN];
+
+       /* Get the preliminary name from the IndexElem */
+       if (ielem->indexcolname)
+           origname = ielem->indexcolname; /* caller-specified name */
+       else if (ielem->name)
+           origname = ielem->name;         /* simple column reference */
+       else
+           origname = "expr";              /* default name for expression */
+
+       /* If it conflicts with any previous column, tweak it */
+       curname = origname;
+       for (i = 1;; i++)
+       {
+           ListCell   *lc2;
+           char        nbuf[32];
+           int         nlen;
+
+           foreach(lc2, result)
+           {
+               if (strcmp(curname, (char *) lfirst(lc2)) == 0)
+                   break;
+           }
+           if (lc2 == NULL)
+               break;          /* found nonconflicting name */
+
+           sprintf(nbuf, "%d", i);
+
+           /* Ensure generated names are shorter than NAMEDATALEN */
+           nlen = pg_mbcliplen(origname, strlen(origname),
+                               NAMEDATALEN - 1 - strlen(nbuf));
+           memcpy(buf, origname, nlen);
+           strcpy(buf + nlen, nbuf);
+           curname = buf;
+       }
+
+       /* And attach to the result list */
+       result = lappend(result, pstrdup(curname));
+   }
+   return result;
+}
+
 /*
  * relationHasPrimaryKey -
  *
index 1c0a5953b4b4935c6af04e0ba0dc1aad5e62ab1b..113e30bc6b807e7ff3b3e655636273c346d9e5bd 100644 (file)
@@ -2121,6 +2121,7 @@ _copyIndexElem(IndexElem *from)
 
    COPY_STRING_FIELD(name);
    COPY_NODE_FIELD(expr);
+   COPY_STRING_FIELD(indexcolname);
    COPY_NODE_FIELD(opclass);
    COPY_SCALAR_FIELD(ordering);
    COPY_SCALAR_FIELD(nulls_ordering);
index 152e407324785e5b773ebcbb693a689737ad45d3..0de81897d7315aafcb49413f6b98341e6f65c8bb 100644 (file)
@@ -2072,6 +2072,7 @@ _equalIndexElem(IndexElem *a, IndexElem *b)
 {
    COMPARE_STRING_FIELD(name);
    COMPARE_NODE_FIELD(expr);
+   COMPARE_STRING_FIELD(indexcolname);
    COMPARE_NODE_FIELD(opclass);
    COMPARE_SCALAR_FIELD(ordering);
    COMPARE_SCALAR_FIELD(nulls_ordering);
index 3eaa4fc2e78aa77ffe87b2bec16ace282de79235..8a83a1fc3ce2fbc703c3400fea3ab7ebab3db643 100644 (file)
@@ -1946,6 +1946,7 @@ _outIndexElem(StringInfo str, IndexElem *node)
 
    WRITE_STRING_FIELD(name);
    WRITE_NODE_FIELD(expr);
+   WRITE_STRING_FIELD(indexcolname);
    WRITE_NODE_FIELD(opclass);
    WRITE_ENUM_FIELD(ordering, SortByDir);
    WRITE_ENUM_FIELD(nulls_ordering, SortByNulls);
index e5b054134867020c77657d2ff378309fd76ac895..a11ba960e81de0c718d193ad4e4b1b3f5adbf057 100644 (file)
@@ -4887,6 +4887,7 @@ index_elem:   ColId opt_class opt_asc_desc opt_nulls_order
                    $$ = makeNode(IndexElem);
                    $$->name = $1;
                    $$->expr = NULL;
+                   $$->indexcolname = NULL;
                    $$->opclass = $2;
                    $$->ordering = $3;
                    $$->nulls_ordering = $4;
@@ -4896,6 +4897,7 @@ index_elem:   ColId opt_class opt_asc_desc opt_nulls_order
                    $$ = makeNode(IndexElem);
                    $$->name = NULL;
                    $$->expr = $1;
+                   $$->indexcolname = NULL;
                    $$->opclass = $2;
                    $$->ordering = $3;
                    $$->nulls_ordering = $4;
@@ -4905,6 +4907,7 @@ index_elem:   ColId opt_class opt_asc_desc opt_nulls_order
                    $$ = makeNode(IndexElem);
                    $$->name = NULL;
                    $$->expr = $2;
+                   $$->indexcolname = NULL;
                    $$->opclass = $4;
                    $$->ordering = $5;
                    $$->nulls_ordering = $6;
index 6883dc32b0cb0f633233a149d1e5516bbcbeb5ea..4bfe393345e9f1788d08044d9c463076548ff1d4 100644 (file)
@@ -1410,13 +1410,40 @@ FigureColname(Node *node)
 {
    char       *name = NULL;
 
-   FigureColnameInternal(node, &name);
+   (void) FigureColnameInternal(node, &name);
    if (name != NULL)
        return name;
    /* default result if we can't guess anything */
    return "?column?";
 }
 
+/*
+ * FigureIndexColname -
+ *   choose the name for an expression column in an index
+ *
+ * This is actually just like FigureColname, except we return NULL if
+ * we can't pick a good name.
+ */
+char *
+FigureIndexColname(Node *node)
+{
+   char       *name = NULL;
+
+   (void) FigureColnameInternal(node, &name);
+   return name;
+}
+
+/*
+ * FigureColnameInternal -
+ *   internal workhorse for FigureColname
+ *
+ * Return value indicates strength of confidence in result:
+ *     0 - no information
+ *     1 - second-best name choice
+ *     2 - good name choice
+ * The return value is actually only used internally.
+ * If the result isn't zero, *name is set to the chosen name.
+ */
 static int
 FigureColnameInternal(Node *node, char **name)
 {
index 4768a3e1b92681c2d6cf4b89631cb5a6c35760b5..839c449d96bc87cef9a330699fe1ab7e8481d59c 100644 (file)
@@ -48,6 +48,7 @@
 #include "parser/parse_clause.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "parser/parse_target.h"
 #include "parser/parse_type.h"
 #include "parser/parse_utilcmd.h"
 #include "parser/parser.h"
@@ -789,34 +790,24 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
 /*
  * chooseIndexName
  *
- * Set name for unnamed index. See also the same logic in DefineIndex.
+ * Compute name for an index.  This must match code in indexcmds.c.
+ *
+ * XXX this is inherently broken because the indexes aren't created
+ * immediately, so we fail to resolve conflicts when the same name is
+ * derived for multiple indexes.  However, that's a reasonably uncommon
+ * situation, so we'll live with it for now.
  */
 static char *
 chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt)
 {
-   Oid namespaceId;
+   Oid         namespaceId;
+   List       *colnames;
 
    namespaceId = RangeVarGetCreationNamespace(relation);
-   if (index_stmt->primary)
-   {
-       /* no need for column list with pkey */
-       return ChooseRelationName(relation->relname, NULL,
-                                 "pkey", namespaceId);
-   }
-   else if (index_stmt->excludeOpNames != NIL)
-   {
-       IndexElem  *iparam = (IndexElem *) linitial(index_stmt->indexParams);
-
-       return ChooseRelationName(relation->relname, iparam->name,
-                                 "exclusion", namespaceId);
-   }
-   else
-   {
-       IndexElem  *iparam = (IndexElem *) linitial(index_stmt->indexParams);
-
-       return ChooseRelationName(relation->relname, iparam->name,
-                                 "key", namespaceId);
-   }
+   colnames = ChooseIndexColumnNames(index_stmt->indexParams);
+   return ChooseIndexName(relation->relname, namespaceId,
+                          colnames, index_stmt->excludeOpNames,
+                          index_stmt->primary, index_stmt->isconstraint);
 }
 
 /*
@@ -828,6 +819,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
                        AttrNumber *attmap)
 {
    Oid         source_relid = RelationGetRelid(source_idx);
+   Form_pg_attribute *attrs = RelationGetDescr(source_idx)->attrs;
    HeapTuple   ht_idxrel;
    HeapTuple   ht_idx;
    Form_pg_class idxrelrec;
@@ -1023,6 +1015,9 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
            keycoltype = exprType(indexkey);
        }
 
+       /* Copy the original index column name */
+       iparam->indexcolname = pstrdup(NameStr(attrs[keyno]->attname));
+
        /* Add the operator class name, if non-default */
        iparam->opclass = get_opclass(indclass->values[keyno], keycoltype);
 
@@ -1416,6 +1411,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
        iparam = makeNode(IndexElem);
        iparam->name = pstrdup(key);
        iparam->expr = NULL;
+       iparam->indexcolname = NULL;
        iparam->opclass = NIL;
        iparam->ordering = SORTBY_DEFAULT;
        iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
@@ -1544,6 +1540,11 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString)
 
        if (ielem->expr)
        {
+           /* Extract preliminary index col name before transforming expr */
+           if (ielem->indexcolname == NULL)
+               ielem->indexcolname = FigureIndexColname(ielem->expr);
+
+           /* Now do parse transformation of the expression */
            ielem->expr = transformExpr(pstate, ielem->expr);
 
            /*
index 7d89f40010f5b6ad8eb3f11959964c661db35626..fddf46a89e16b139ed6f8f4a776981f9f384a192 100644 (file)
@@ -32,6 +32,7 @@ extern Oid index_create(Oid heapRelationId,
             const char *indexRelationName,
             Oid indexRelationId,
             IndexInfo *indexInfo,
+            List *indexColNames,
             Oid accessMethodObjectId,
             Oid tableSpaceId,
             Oid *classObjectId,
index c00896abf5cb371df7a622d0bcb3f09f1cc1ebf8..ad299c36a73bb12da6b6d25451e60c64545f185e 100644 (file)
@@ -45,6 +45,10 @@ 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 namespaceid);
+extern char *ChooseIndexName(const char *tabname, Oid namespaceId,
+                            List *colnames, List *exclusionOpNames,
+                            bool primary, bool isconstraint);
+extern List *ChooseIndexColumnNames(List *indexElems);
 extern Oid GetDefaultOpClass(Oid type_id, Oid am_id);
 
 /* commands/functioncmds.c */
index c36f8e586f6b05cfaf3cb71dfe275574f94a0776..58baa3cdf0fd30e1d9a5e8ea78b6f0eb9410d810 100644 (file)
@@ -501,6 +501,7 @@ typedef struct IndexElem
    NodeTag     type;
    char       *name;           /* name of attribute to index, or NULL */
    Node       *expr;           /* expression to index, or NULL */
+   char       *indexcolname;   /* name for index column; NULL = default */
    List       *opclass;        /* name of desired opclass; NIL = default */
    SortByDir   ordering;       /* ASC/DESC/default */
    SortByNulls nulls_ordering; /* FIRST/LAST/default */
index 2222ccd1f6bdb8fef81a825f58eaeb895a4f3089..cdb8c16c740302e3f1774c3c3be28f96f037ccf9 100644 (file)
@@ -37,5 +37,6 @@ extern List *checkInsertTargets(ParseState *pstate, List *cols,
 extern TupleDesc expandRecordVariable(ParseState *pstate, Var *var,
                     int levelsup);
 extern char *FigureColname(Node *node);
+extern char *FigureIndexColname(Node *node);
 
 #endif   /* PARSE_TARGET_H */
index 20bf3de3bad2580433990051b2f894f31b3207e9..5aff44f23aa8539f868324b052be3fe3344f5d7f 100644 (file)
@@ -159,7 +159,7 @@ CREATE TABLE tmp2 (a int primary key);
 NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "tmp2_pkey" for table "tmp2"
 CREATE TABLE tmp3 (a int, b int);
 CREATE TABLE tmp4 (a int, b int, unique(a,b));
-NOTICE:  CREATE TABLE / UNIQUE will create implicit index "tmp4_a_key" for table "tmp4"
+NOTICE:  CREATE TABLE / UNIQUE will create implicit index "tmp4_a_b_key" for table "tmp4"
 CREATE TABLE tmp5 (a int, b int);
 -- Insert rows into tmp2 (pktable)
 INSERT INTO tmp2 values (1);
index 33e0edba03a351ea5baffca3f982a9425db11efc..0367f532337366df79701d1b963c32b43d9e014d 100644 (file)
@@ -736,7 +736,7 @@ ERROR:  table "fktable_fail2" does not exist
 DROP TABLE PKTABLE;
 -- Test for referencing column number smaller than referenced constraint
 CREATE TABLE PKTABLE (ptest1 int, ptest2 int, UNIQUE(ptest1, ptest2));
-NOTICE:  CREATE TABLE / UNIQUE will create implicit index "pktable_ptest1_key" for table "pktable"
+NOTICE:  CREATE TABLE / UNIQUE will create implicit index "pktable_ptest1_ptest2_key" for table "pktable"
 CREATE TABLE FKTABLE_FAIL1 (ftest1 int REFERENCES pktable(ptest1));
 ERROR:  there is no unique constraint matching given keys for referenced table "pktable"
 DROP TABLE FKTABLE_FAIL1;
@@ -860,7 +860,7 @@ DETAIL:  Key columns "ptest4" and "ptest1" are of incompatible types: inet and i
 create table pktable_base (base1 int not null);
 create table pktable (ptest1 int, primary key(base1), unique(base1, ptest1)) inherits (pktable_base);
 NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "pktable_pkey" for table "pktable"
-NOTICE:  CREATE TABLE / UNIQUE will create implicit index "pktable_base1_key" for table "pktable"
+NOTICE:  CREATE TABLE / UNIQUE will create implicit index "pktable_base1_ptest1_key" for table "pktable"
 create table fktable (ftest1 int references pktable(base1));
 -- now some ins, upd, del
 insert into pktable(base1) values (1);
@@ -1098,7 +1098,7 @@ CREATE TEMP TABLE pktable (
 NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "pktable_pkey" for table "pktable"
 NOTICE:  CREATE TABLE / UNIQUE will create implicit index "pktable_id2_key" for table "pktable"
 NOTICE:  CREATE TABLE / UNIQUE will create implicit index "pktable_id3_key" for table "pktable"
-NOTICE:  CREATE TABLE / UNIQUE will create implicit index "pktable_id1_key" for table "pktable"
+NOTICE:  CREATE TABLE / UNIQUE will create implicit index "pktable_id1_id2_id3_key" for table "pktable"
 CREATE TEMP TABLE fktable (
         x1      INT4 REFERENCES pktable(id1),
         x2      VARCHAR(4) REFERENCES pktable(id2),
index aa1eb4a4ddbfa3f8fbae038b70d39327576caeab..9c83a32f9344f5eec3f91ca07f9737f2165d7f29 100644 (file)
@@ -1031,8 +1031,8 @@ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "t_all_pkey" for
  b      | text |           | extended | B
 Indexes:
     "t_all_pkey" PRIMARY KEY, btree (a)
-    "t_all_b_key" btree (b)
-    "t_all_key" btree ((a || b))
+    "t_all_b_idx" btree (b)
+    "t_all_expr_idx" btree ((a || b))
 Check constraints:
     "t1_a_check" CHECK (length(a) > 2)
 Has OIDs: no
@@ -1040,7 +1040,7 @@ Has OIDs: no
 SELECT c.relname, objsubid, description FROM pg_description, pg_index i, pg_class c WHERE classoid = 'pg_class'::regclass AND objoid = i.indexrelid AND c.oid = i.indexrelid AND i.indrelid = 't_all'::regclass ORDER BY c.relname, objsubid;
    relname   | objsubid | description 
 -------------+----------+-------------
- t_all_b_key |        0 | index b_key
+ t_all_b_idx |        0 | index b_key
  t_all_pkey  |        0 | index pkey
 (2 rows)
 
index 8928ca8beba7b0683bdf53830e12b819729ce1df..684394fd83d2a624e1c5ca5d4c454f05f9c8c251 100644 (file)
@@ -359,12 +359,12 @@ SELECT '' AS five, * FROM UNIQUE_TBL;
 DROP TABLE UNIQUE_TBL;
 CREATE TABLE UNIQUE_TBL (i int, t text,
    UNIQUE(i,t));
-NOTICE:  CREATE TABLE / UNIQUE will create implicit index "unique_tbl_i_key" for table "unique_tbl"
+NOTICE:  CREATE TABLE / UNIQUE will create implicit index "unique_tbl_i_t_key" for table "unique_tbl"
 INSERT INTO UNIQUE_TBL VALUES (1, 'one');
 INSERT INTO UNIQUE_TBL VALUES (2, 'two');
 INSERT INTO UNIQUE_TBL VALUES (1, 'three');
 INSERT INTO UNIQUE_TBL VALUES (1, 'one');
-ERROR:  duplicate key value violates unique constraint "unique_tbl_i_key"
+ERROR:  duplicate key value violates unique constraint "unique_tbl_i_t_key"
 DETAIL:  Key (i, t)=(1, one) already exists.
 INSERT INTO UNIQUE_TBL VALUES (5, 'one');
 INSERT INTO UNIQUE_TBL (t) VALUES ('six');
@@ -523,7 +523,7 @@ CREATE TABLE circles (
     (c1 WITH &&, (c2::circle) WITH ~=)
     WHERE (circle_center(c1) <> '(0,0)')
 );
-NOTICE:  CREATE TABLE / EXCLUDE will create implicit index "circles_c1_exclusion" for table "circles"
+NOTICE:  CREATE TABLE / EXCLUDE will create implicit index "circles_c1_c2_exclusion" for table "circles"
 -- these should succeed because they don't match the index predicate
 INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 5>');
 INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 5>');
@@ -531,7 +531,7 @@ INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 5>');
 INSERT INTO circles VALUES('<(10,10), 10>', '<(0,0), 5>');
 -- fail, overlaps
 INSERT INTO circles VALUES('<(20,20), 10>', '<(0,0), 5>');
-ERROR:  conflicting key value violates exclusion constraint "circles_c1_exclusion"
+ERROR:  conflicting key value violates exclusion constraint "circles_c1_c2_exclusion"
 DETAIL:  Key (c1, (c2::circle))=(<(20,20),10>, <(0,0),5>) conflicts with existing key (c1, (c2::circle))=(<(10,10),10>, <(0,0),5>).
 -- succeed because c1 doesn't overlap
 INSERT INTO circles VALUES('<(20,20), 1>', '<(0,0), 5>');
@@ -540,8 +540,8 @@ INSERT INTO circles VALUES('<(20,20), 10>', '<(1,1), 5>');
 -- should fail on existing data without the WHERE clause
 ALTER TABLE circles ADD EXCLUDE USING gist
   (c1 WITH &&, (c2::circle) WITH ~=);
-NOTICE:  ALTER TABLE / ADD EXCLUDE will create implicit index "circles_c1_exclusion1" for table "circles"
-ERROR:  could not create exclusion constraint "circles_c1_exclusion1"
+NOTICE:  ALTER TABLE / ADD EXCLUDE will create implicit index "circles_c1_c2_exclusion1" for table "circles"
+ERROR:  could not create exclusion constraint "circles_c1_c2_exclusion1"
 DETAIL:  Key (c1, (c2::circle))=(<(0,0),5>, <(0,0),5>) conflicts with key (c1, (c2::circle))=(<(0,0),5>, <(0,0),5>).
 DROP TABLE circles;
 -- Check deferred exclusion constraint