]> granicus.if.org Git - postgresql/commitdiff
Adjust naming of indexes and their columns per recent discussion.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 23 Dec 2009 02:35:25 +0000 (02:35 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 18affeb098858f141f39a2cc15e9fbac2f54b61c..5c85fcff5ef4a24fa29c0cce765193aca36460d5 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.101 2009/12/07 05:22:21 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.102 2009/12/23 02:35:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 5394d2557eb03e8518a19f8ca0539f289e7032a0..9eb96b7718d189aae1f6576dbb0e10bee1208af0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.326 2009/12/09 21:57:50 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.327 2009/12/23 02:35:18 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -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 05f3bb49691f83a4733bf359d5bae43a3dcf886c..a8c2da66dc3ca764086f71d3f895f76069be0a9d 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.21 2009/12/07 05:22:21 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.22 2009/12/23 02:35:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 00786442b3f35472332505634c27979d62cf3b4a..833114abcf0b08a111beffd0f6ff3e8f12a5bc5b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.188 2009/12/07 05:22:21 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.189 2009/12/23 02:35:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 018f36cef60e9bcdedfa3603e651f756b38a5357..2722a93e074efb3e7b0c29c06b373df8a6159e8a 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.454 2009/12/15 17:57:46 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.455 2009/12/23 02:35:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 2387aaba410b582b34e0062f48c026cdcd40b4eb..e53b4a89e6e4eae5eef94fcff7a7261f55f3d5dc 100644 (file)
@@ -22,7 +22,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.376 2009/12/15 17:57:46 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.377 2009/12/23 02:35:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 cac346464bd15b998e4b56e6fb34a7271a521d07..419c005b5087c64446a89a82a541ef84e6caddda 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.375 2009/12/15 17:57:46 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.376 2009/12/23 02:35:21 tgl Exp $
  *
  * NOTES
  *       Every node type that can appear in stored rules' parsetrees *must*
@@ -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 22449579d0f7372bc2fa8fdf5ddee02e14a4ccb6..7ff46e05cb1c654bf39a2d8fc27dc789f3cebf12 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.697 2009/12/15 17:57:47 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.698 2009/12/23 02:35:22 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -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 ce3f51ca6e5c0009ca054b6c4432506236f062ac..007a3cc6936dba53b029ab211cd47b6b53411717 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.174 2009/10/31 01:41:31 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.175 2009/12/23 02:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 75c8d863dcd8dd6c73983ee88b33018dc84b64ac..f09e78dd8e3ddbaf8d2025ccb52c6159231050ec 100644 (file)
@@ -19,7 +19,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.34 2009/12/22 23:54:17 tgl Exp $
+ *     $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.35 2009/12/23 02:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 a432260058f1308ca11fb878ecc11be9b0f6f223..f2119a530f9568a0615667a14ad05111e7c43750 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/index.h,v 1.78 2009/07/29 20:56:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/index.h,v 1.79 2009/12/23 02:35:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 1b665ff8550ba257cc4a78077d945f7b9cbb4652..2ac7e160fe837fac1b53dbbbf31738257f29e871 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.98 2009/12/07 05:22:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.99 2009/12/23 02:35:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 265c4e2a18acc9296b0b75c04748f91cf2e5ce6c..f93fff3892b729ae3566a58408983f66772e71cb 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.419 2009/12/15 17:57:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.420 2009/12/23 02:35:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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 88aeb31e2f928050bbc7075349f5831ad0fe74d0..9b4202be003985504d201bfec03af5b9590f4e07 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/parse_target.h,v 1.44 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_target.h,v 1.45 2009/12/23 02:35:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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