diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/bootstrap/bootparse.y | 3 | ||||
-rw-r--r-- | src/backend/catalog/index.c | 22 | ||||
-rw-r--r-- | src/backend/catalog/toasting.c | 3 | ||||
-rw-r--r-- | src/backend/commands/indexcmds.c | 220 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 3 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 3 | ||||
-rw-r--r-- | src/backend/nodes/outfuncs.c | 3 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 5 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 31 | ||||
-rw-r--r-- | src/backend/parser/parse_utilcmd.c | 47 |
10 files changed, 253 insertions, 87 deletions
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 18affeb0988..5c85fcff5ef 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 5394d2557eb..9eb96b7718d 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; @@ -217,12 +220,6 @@ ConstructTupleDescriptor(Relation heapRelation, 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. */ keyType = exprType(indexkey); @@ -269,6 +266,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 05f3bb49691..a8c2da66dc3 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 00786442b3f..833114abcf0 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; @@ -248,36 +250,20 @@ DefineIndex(RangeVar *heapRelation, 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 @@ -1392,6 +1373,147 @@ ChooseRelationName(const char *name1, const char *name2, } /* + * 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 - * * See whether an existing relation has a primary key. diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 018f36cef60..2722a93e074 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 2387aaba410..e53b4a89e6e 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 cac346464bd..419c005b508 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 22449579d0f..7ff46e05cb1 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 ce3f51ca6e5..007a3cc6936 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 75c8d863dcd..f09e78dd8e3 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); /* |