index-naming-1.patch
text/x-patch
Filename: index-naming-1.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/bootstrap/bootparse.y | 2 | 1 |
| src/backend/catalog/index.c | 4 | 2 |
| src/backend/commands/indexcmds.c | 69 | 20 |
| src/backend/nodes/copyfuncs.c | 2 | 1 |
| src/backend/nodes/equalfuncs.c | 2 | 1 |
| src/backend/nodes/outfuncs.c | 2 | 1 |
| src/backend/parser/gram.y | 6 | 3 |
| src/backend/parser/parse_target.c | 27 | 0 |
| src/backend/parser/parse_utilcmd.c | 45 | 19 |
| src/include/commands/defrem.h | 1 | 0 |
| src/include/nodes/parsenodes.h | 9 | 3 |
| src/include/parser/parse_target.h | 1 | 0 |
Index: src/backend/bootstrap/bootparse.y
===================================================================
RCS file: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v
retrieving revision 1.101
diff -c -r1.101 bootparse.y
*** src/backend/bootstrap/bootparse.y 7 Dec 2009 05:22:21 -0000 1.101
--- src/backend/bootstrap/bootparse.y 21 Dec 2009 02:47:04 -0000
***************
*** 322,328 ****
{
IndexElem *n = makeNode(IndexElem);
n->name = $1;
! n->expr = NULL;
n->opclass = list_make1(makeString($2));
n->ordering = SORTBY_DEFAULT;
n->nulls_ordering = SORTBY_NULLS_DEFAULT;
--- 322,329 ----
{
IndexElem *n = makeNode(IndexElem);
n->name = $1;
! n->iexpr = NULL;
! n->iexprname = NULL;
n->opclass = list_make1(makeString($2));
n->ordering = SORTBY_DEFAULT;
n->nulls_ordering = SORTBY_NULLS_DEFAULT;
Index: src/backend/catalog/index.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/index.c,v
retrieving revision 1.326
diff -c -r1.326 index.c
*** src/backend/catalog/index.c 9 Dec 2009 21:57:50 -0000 1.326
--- src/backend/catalog/index.c 21 Dec 2009 02:47:04 -0000
***************
*** 217,224 ****
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);
--- 217,226 ----
indexpr_item = lnext(indexpr_item);
/*
! * Make the attribute's name "pg_expression_nnn" (maybe think of
! * something better later? we're kind of locked in now, though,
! * because pg_dump exposes these names when dumping comments on
! * index columns)
*/
sprintf(NameStr(to->attname), "pg_expression_%d", i + 1);
Index: src/backend/commands/indexcmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v
retrieving revision 1.188
diff -c -r1.188 indexcmds.c
*** src/backend/commands/indexcmds.c 7 Dec 2009 05:22:21 -0000 1.188
--- src/backend/commands/indexcmds.c 21 Dec 2009 02:47:05 -0000
***************
*** 252,282 ****
*/
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);
}
}
/*
--- 252,288 ----
*/
if (indexRelationName == NULL)
{
+ char *tabname = RelationGetRelationName(rel);
+
if (primary)
{
! /* the pkey name does not depend on the specific column(s) */
! indexRelationName = ChooseRelationName(tabname,
NULL,
"pkey",
namespaceId);
}
else if (exclusionOpNames != NIL)
{
! indexRelationName = ChooseRelationName(tabname,
! ChooseIndexNameAddition(attributeList),
"exclusion",
namespaceId);
}
! else if (isconstraint)
{
! indexRelationName = ChooseRelationName(tabname,
! ChooseIndexNameAddition(attributeList),
"key",
namespaceId);
}
+ else
+ {
+ indexRelationName = ChooseRelationName(tabname,
+ ChooseIndexNameAddition(attributeList),
+ "idx",
+ namespaceId);
+ }
}
/*
***************
*** 884,890 ****
HeapTuple atttuple;
Form_pg_attribute attform;
! Assert(attribute->expr == NULL);
atttuple = SearchSysCacheAttName(relId, attribute->name);
if (!HeapTupleIsValid(atttuple))
{
--- 890,896 ----
HeapTuple atttuple;
Form_pg_attribute attform;
! Assert(attribute->iexpr == NULL);
atttuple = SearchSysCacheAttName(relId, attribute->name);
if (!HeapTupleIsValid(atttuple))
{
***************
*** 905,915 ****
atttype = attform->atttypid;
ReleaseSysCache(atttuple);
}
! else if (attribute->expr && IsA(attribute->expr, Var) &&
! ((Var *) attribute->expr)->varattno != InvalidAttrNumber)
{
/* Tricky tricky, he wrote (column) ... treat as simple attr */
! Var *var = (Var *) attribute->expr;
indexInfo->ii_KeyAttrNumbers[attn] = var->varattno;
atttype = get_atttype(relId, var->varattno);
--- 911,921 ----
atttype = attform->atttypid;
ReleaseSysCache(atttuple);
}
! else if (attribute->iexpr && IsA(attribute->iexpr, Var) &&
! ((Var *) attribute->iexpr)->varattno != InvalidAttrNumber)
{
/* Tricky tricky, he wrote (column) ... treat as simple attr */
! Var *var = (Var *) attribute->iexpr;
indexInfo->ii_KeyAttrNumbers[attn] = var->varattno;
atttype = get_atttype(relId, var->varattno);
***************
*** 917,938 ****
else
{
/* Index expression */
! Assert(attribute->expr != NULL);
indexInfo->ii_KeyAttrNumbers[attn] = 0; /* marks expression */
indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
! attribute->expr);
! atttype = exprType(attribute->expr);
/*
* We don't currently support generation of an actual query plan
* for an index expression, only simple scalar expressions; hence
* these restrictions.
*/
! if (contain_subplans(attribute->expr))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use subquery in index expression")));
! if (contain_agg_clause(attribute->expr))
ereport(ERROR,
(errcode(ERRCODE_GROUPING_ERROR),
errmsg("cannot use aggregate function in index expression")));
--- 923,944 ----
else
{
/* Index expression */
! Assert(attribute->iexpr != NULL);
indexInfo->ii_KeyAttrNumbers[attn] = 0; /* marks expression */
indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
! attribute->iexpr);
! atttype = exprType(attribute->iexpr);
/*
* We don't currently support generation of an actual query plan
* for an index expression, only simple scalar expressions; hence
* these restrictions.
*/
! if (contain_subplans(attribute->iexpr))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use subquery in index expression")));
! if (contain_agg_clause(attribute->iexpr))
ereport(ERROR,
(errcode(ERRCODE_GROUPING_ERROR),
errmsg("cannot use aggregate function in index expression")));
***************
*** 942,948 ****
* if you aren't going to get the same result for the same data
* every time, it's not clear what the index entries mean at all.
*/
! if (contain_mutable_functions(attribute->expr))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("functions in index expression must be marked IMMUTABLE")));
--- 948,954 ----
* if you aren't going to get the same result for the same data
* every time, it's not clear what the index entries mean at all.
*/
! if (contain_mutable_functions(attribute->iexpr))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("functions in index expression must be marked IMMUTABLE")));
***************
*** 1392,1397 ****
--- 1398,1446 ----
}
/*
+ * Generate "name2" for a new index given the list of IndexElems for it.
+ * 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.
+ */
+ char *
+ ChooseIndexNameAddition(List *indexElems)
+ {
+ char buf[NAMEDATALEN * 2];
+ int buflen = 0;
+ ListCell *lc;
+
+ buf[0] = '\0';
+ foreach(lc, indexElems)
+ {
+ IndexElem *ielem = (IndexElem *) lfirst(lc);
+ const char *name;
+
+ if (ielem->name)
+ name = ielem->name; /* simple column reference */
+ else if (ielem->iexprname)
+ name = ielem->iexprname; /* expression */
+ else
+ name = "expr"; /* default name for expression */
+
+ 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);
+ }
+
+ /*
* relationHasPrimaryKey -
*
* See whether an existing relation has a primary key.
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.454
diff -c -r1.454 copyfuncs.c
*** src/backend/nodes/copyfuncs.c 15 Dec 2009 17:57:46 -0000 1.454
--- src/backend/nodes/copyfuncs.c 21 Dec 2009 02:47:05 -0000
***************
*** 2120,2126 ****
IndexElem *newnode = makeNode(IndexElem);
COPY_STRING_FIELD(name);
! COPY_NODE_FIELD(expr);
COPY_NODE_FIELD(opclass);
COPY_SCALAR_FIELD(ordering);
COPY_SCALAR_FIELD(nulls_ordering);
--- 2120,2127 ----
IndexElem *newnode = makeNode(IndexElem);
COPY_STRING_FIELD(name);
! COPY_NODE_FIELD(iexpr);
! COPY_STRING_FIELD(iexprname);
COPY_NODE_FIELD(opclass);
COPY_SCALAR_FIELD(ordering);
COPY_SCALAR_FIELD(nulls_ordering);
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.376
diff -c -r1.376 equalfuncs.c
*** src/backend/nodes/equalfuncs.c 15 Dec 2009 17:57:46 -0000 1.376
--- src/backend/nodes/equalfuncs.c 21 Dec 2009 02:47:05 -0000
***************
*** 2071,2077 ****
_equalIndexElem(IndexElem *a, IndexElem *b)
{
COMPARE_STRING_FIELD(name);
! COMPARE_NODE_FIELD(expr);
COMPARE_NODE_FIELD(opclass);
COMPARE_SCALAR_FIELD(ordering);
COMPARE_SCALAR_FIELD(nulls_ordering);
--- 2071,2078 ----
_equalIndexElem(IndexElem *a, IndexElem *b)
{
COMPARE_STRING_FIELD(name);
! COMPARE_NODE_FIELD(iexpr);
! COMPARE_STRING_FIELD(iexprname);
COMPARE_NODE_FIELD(opclass);
COMPARE_SCALAR_FIELD(ordering);
COMPARE_SCALAR_FIELD(nulls_ordering);
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v
retrieving revision 1.375
diff -c -r1.375 outfuncs.c
*** src/backend/nodes/outfuncs.c 15 Dec 2009 17:57:46 -0000 1.375
--- src/backend/nodes/outfuncs.c 21 Dec 2009 02:47:05 -0000
***************
*** 1945,1951 ****
WRITE_NODE_TYPE("INDEXELEM");
WRITE_STRING_FIELD(name);
! WRITE_NODE_FIELD(expr);
WRITE_NODE_FIELD(opclass);
WRITE_ENUM_FIELD(ordering, SortByDir);
WRITE_ENUM_FIELD(nulls_ordering, SortByNulls);
--- 1945,1952 ----
WRITE_NODE_TYPE("INDEXELEM");
WRITE_STRING_FIELD(name);
! WRITE_NODE_FIELD(iexpr);
! WRITE_STRING_FIELD(iexprname);
WRITE_NODE_FIELD(opclass);
WRITE_ENUM_FIELD(ordering, SortByDir);
WRITE_ENUM_FIELD(nulls_ordering, SortByNulls);
Index: src/backend/parser/gram.y
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.697
diff -c -r2.697 gram.y
*** src/backend/parser/gram.y 15 Dec 2009 17:57:47 -0000 2.697
--- src/backend/parser/gram.y 21 Dec 2009 02:47:05 -0000
***************
*** 4886,4892 ****
{
$$ = makeNode(IndexElem);
$$->name = $1;
! $$->expr = NULL;
$$->opclass = $2;
$$->ordering = $3;
$$->nulls_ordering = $4;
--- 4886,4893 ----
{
$$ = makeNode(IndexElem);
$$->name = $1;
! $$->iexpr = NULL;
! $$->iexprname = NULL;
$$->opclass = $2;
$$->ordering = $3;
$$->nulls_ordering = $4;
***************
*** 4895,4901 ****
{
$$ = makeNode(IndexElem);
$$->name = NULL;
! $$->expr = $1;
$$->opclass = $2;
$$->ordering = $3;
$$->nulls_ordering = $4;
--- 4896,4903 ----
{
$$ = makeNode(IndexElem);
$$->name = NULL;
! $$->iexpr = $1;
! $$->iexprname = NULL;
$$->opclass = $2;
$$->ordering = $3;
$$->nulls_ordering = $4;
***************
*** 4904,4910 ****
{
$$ = makeNode(IndexElem);
$$->name = NULL;
! $$->expr = $2;
$$->opclass = $4;
$$->ordering = $5;
$$->nulls_ordering = $6;
--- 4906,4913 ----
{
$$ = makeNode(IndexElem);
$$->name = NULL;
! $$->iexpr = $2;
! $$->iexprname = NULL;
$$->opclass = $4;
$$->ordering = $5;
$$->nulls_ordering = $6;
Index: src/backend/parser/parse_target.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/parse_target.c,v
retrieving revision 1.174
diff -c -r1.174 parse_target.c
*** src/backend/parser/parse_target.c 31 Oct 2009 01:41:31 -0000 1.174
--- src/backend/parser/parse_target.c 21 Dec 2009 02:47:05 -0000
***************
*** 1417,1422 ****
--- 1417,1449 ----
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;
+
+ 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: src/backend/parser/parse_utilcmd.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/parse_utilcmd.c,v
retrieving revision 2.33
diff -c -r2.33 parse_utilcmd.c
*** src/backend/parser/parse_utilcmd.c 20 Dec 2009 18:28:14 -0000 2.33
--- src/backend/parser/parse_utilcmd.c 21 Dec 2009 02:47:05 -0000
***************
*** 48,53 ****
--- 48,54 ----
#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"
***************
*** 750,756 ****
int colno;
comment = GetComment(parent_index_oid, RelationRelationId, 0);
!
if (comment != NULL)
{
/*
--- 751,757 ----
int colno;
comment = GetComment(parent_index_oid, RelationRelationId, 0);
!
if (comment != NULL)
{
/*
***************
*** 827,858 ****
* chooseIndexName
*
* Set name for unnamed index. See also the same logic in DefineIndex.
*/
static char *
chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt)
{
Oid namespaceId;
!
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);
}
}
--- 828,872 ----
* chooseIndexName
*
* Set name for unnamed index. See also the same logic in DefineIndex.
+ *
+ * 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.
*/
static char *
chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt)
{
Oid namespaceId;
!
namespaceId = RangeVarGetCreationNamespace(relation);
if (index_stmt->primary)
{
! /* the pkey name does not depend on the specific column(s) */
! return ChooseRelationName(relation->relname,
! NULL,
! "pkey",
! namespaceId);
}
else if (index_stmt->excludeOpNames != NIL)
{
! return ChooseRelationName(relation->relname,
! ChooseIndexNameAddition(index_stmt->indexParams),
! "exclusion",
! namespaceId);
! }
! else if (index_stmt->isconstraint)
! {
! return ChooseRelationName(relation->relname,
! ChooseIndexNameAddition(index_stmt->indexParams),
! "key",
! namespaceId);
}
else
{
! return ChooseRelationName(relation->relname,
! ChooseIndexNameAddition(index_stmt->indexParams),
! "idx",
! namespaceId);
}
}
***************
*** 1039,1045 ****
keycoltype = get_atttype(indrelid, attnum);
iparam->name = attname;
! iparam->expr = NULL;
}
else
{
--- 1053,1060 ----
keycoltype = get_atttype(indrelid, attnum);
iparam->name = attname;
! iparam->iexpr = NULL;
! iparam->iexprname = NULL;
}
else
{
***************
*** 1055,1061 ****
change_varattnos_of_a_node(indexkey, attmap);
iparam->name = NULL;
! iparam->expr = indexkey;
keycoltype = exprType(indexkey);
}
--- 1070,1082 ----
change_varattnos_of_a_node(indexkey, attmap);
iparam->name = NULL;
! iparam->iexpr = indexkey;
!
! /*
! * Unfortunately, we have no good way to extract a name from
! * the already-transformed index expression; so punt.
! */
! iparam->iexprname = NULL;
keycoltype = exprType(indexkey);
}
***************
*** 1452,1458 ****
/* OK, add it to the index definition */
iparam = makeNode(IndexElem);
iparam->name = pstrdup(key);
! iparam->expr = NULL;
iparam->opclass = NIL;
iparam->ordering = SORTBY_DEFAULT;
iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
--- 1473,1480 ----
/* OK, add it to the index definition */
iparam = makeNode(IndexElem);
iparam->name = pstrdup(key);
! iparam->iexpr = NULL;
! iparam->iexprname = NULL;
iparam->opclass = NIL;
iparam->ordering = SORTBY_DEFAULT;
iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
***************
*** 1579,1594 ****
{
IndexElem *ielem = (IndexElem *) lfirst(l);
! if (ielem->expr)
{
! ielem->expr = transformExpr(pstate, ielem->expr);
/*
* We check only that the result type is legitimate; this is for
* consistency with what transformWhereClause() checks for the
* predicate. DefineIndex() will make more checks.
*/
! if (expression_returns_set(ielem->expr))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("index expression cannot return a set")));
--- 1601,1620 ----
{
IndexElem *ielem = (IndexElem *) lfirst(l);
! if (ielem->iexpr)
{
! /* Extract index column name before transforming expr */
! ielem->iexprname = FigureIndexColname(ielem->iexpr);
!
! /* Now do parse transformation of the expression */
! ielem->iexpr = transformExpr(pstate, ielem->iexpr);
/*
* We check only that the result type is legitimate; this is for
* consistency with what transformWhereClause() checks for the
* predicate. DefineIndex() will make more checks.
*/
! if (expression_returns_set(ielem->iexpr))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("index expression cannot return a set")));
Index: src/include/commands/defrem.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/commands/defrem.h,v
retrieving revision 1.98
diff -c -r1.98 defrem.h
*** src/include/commands/defrem.h 7 Dec 2009 05:22:23 -0000 1.98
--- src/include/commands/defrem.h 21 Dec 2009 02:47:05 -0000
***************
*** 45,50 ****
--- 45,51 ----
const char *label);
extern char *ChooseRelationName(const char *name1, const char *name2,
const char *label, Oid namespaceid);
+ extern char *ChooseIndexNameAddition(List *indexElems);
extern Oid GetDefaultOpClass(Oid type_id, Oid am_id);
/* commands/functioncmds.c */
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.419
diff -c -r1.419 parsenodes.h
*** src/include/nodes/parsenodes.h 15 Dec 2009 17:57:47 -0000 1.419
--- src/include/nodes/parsenodes.h 21 Dec 2009 02:47:06 -0000
***************
*** 493,506 ****
* IndexElem - index parameters (used in CREATE INDEX)
*
* For a plain index attribute, 'name' is the name of the table column to
! * index, and 'expr' is NULL. For an index expression, 'name' is NULL and
! * 'expr' is the expression tree.
*/
typedef struct IndexElem
{
NodeTag type;
char *name; /* name of attribute to index, or NULL */
! Node *expr; /* expression to index, or NULL */
List *opclass; /* name of desired opclass; NIL = default */
SortByDir ordering; /* ASC/DESC/default */
SortByNulls nulls_ordering; /* FIRST/LAST/default */
--- 493,512 ----
* IndexElem - index parameters (used in CREATE INDEX)
*
* For a plain index attribute, 'name' is the name of the table column to
! * index, and 'iexpr' is NULL. For an index expression, 'name' is NULL and
! * 'iexpr' is the expression tree.
! *
! * 'iexprname' is a name extracted from 'iexpr', or NULL for none/default.
! * We need this field because the FigureColname machinery only works on
! * not-yet-transformed expression trees, so we can't get it from iexpr
! * after parse transformation.
*/
typedef struct IndexElem
{
NodeTag type;
char *name; /* name of attribute to index, or NULL */
! Node *iexpr; /* expression to index, or NULL */
! char *iexprname; /* name extracted from iexpr, or NULL */
List *opclass; /* name of desired opclass; NIL = default */
SortByDir ordering; /* ASC/DESC/default */
SortByNulls nulls_ordering; /* FIRST/LAST/default */
Index: src/include/parser/parse_target.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/parser/parse_target.h,v
retrieving revision 1.44
diff -c -r1.44 parse_target.h
*** src/include/parser/parse_target.h 1 Jan 2009 17:24:00 -0000 1.44
--- src/include/parser/parse_target.h 21 Dec 2009 02:47:06 -0000
***************
*** 37,41 ****
--- 37,42 ----
extern TupleDesc expandRecordVariable(ParseState *pstate, Var *var,
int levelsup);
extern char *FigureColname(Node *node);
+ extern char *FigureIndexColname(Node *node);
#endif /* PARSE_TARGET_H */