diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 18affeb098..5c85fcff5e 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -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; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 5394d2557e..9eb96b7718 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -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); diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 05f3bb4969..a8c2da66dc 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -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, diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 00786442b3..833114abcf 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.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 - * diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 018f36cef6..2722a93e07 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -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); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 2387aaba41..e53b4a89e6 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -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); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index cac346464b..419c005b50 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -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); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 22449579d0..7ff46e05cb 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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; diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index ce3f51ca6e..007a3cc693 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -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) { diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 75c8d863dc..f09e78dd8e 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -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); /* diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index a432260058..f2119a530f 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -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, diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 1b665ff855..2ac7e160fe 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -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 */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 265c4e2a18..f93fff3892 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -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 */ diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h index 88aeb31e2f..9b4202be00 100644 --- a/src/include/parser/parse_target.h +++ b/src/include/parser/parse_target.h @@ -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 */ diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 20bf3de3ba..5aff44f23a 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -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); diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out index 33e0edba03..0367f53233 100644 --- a/src/test/regress/expected/foreign_key.out +++ b/src/test/regress/expected/foreign_key.out @@ -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), diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index aa1eb4a4dd..9c83a32f93 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -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) diff --git a/src/test/regress/output/constraints.source b/src/test/regress/output/constraints.source index 8928ca8beb..684394fd83 100644 --- a/src/test/regress/output/constraints.source +++ b/src/test/regress/output/constraints.source @@ -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