summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c44
-rw-r--r--src/backend/parser/gram.y86
2 files changed, 68 insertions, 62 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index b7fc22c46be..79b36caad75 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.271 2003/05/06 00:20:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.272 2003/05/28 16:03:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1311,8 +1311,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
/* OK, add it to the index definition */
iparam = makeNode(IndexElem);
iparam->name = pstrdup(key);
- iparam->funcname = NIL;
- iparam->args = NIL;
+ iparam->expr = NULL;
iparam->opclass = NIL;
index->indexParams = lappend(index->indexParams, iparam);
}
@@ -1386,11 +1385,13 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
if (index->idxname == NULL && index->indexParams != NIL)
{
- iparam = lfirst(index->indexParams);
+ iparam = (IndexElem *) lfirst(index->indexParams);
+ /* we should never see an expression item here */
+ Assert(iparam->expr == NULL);
index->idxname = CreateIndexName(cxt->relation->relname,
- iparam->name ? iparam->name :
- strVal(llast(iparam->funcname)),
- "key", cxt->alist);
+ iparam->name,
+ "key",
+ cxt->alist);
}
if (index->idxname == NULL) /* should not happen */
elog(ERROR, "%s: failed to make implicit index name",
@@ -1454,7 +1455,8 @@ static Query *
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
{
Query *qry;
- RangeTblEntry *rte;
+ RangeTblEntry *rte = NULL;
+ List *l;
qry = makeNode(Query);
qry->commandType = CMD_UTILITY;
@@ -1477,6 +1479,32 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
}
+ /* take care of any index expressions */
+ foreach(l, stmt->indexParams)
+ {
+ IndexElem *ielem = (IndexElem *) lfirst(l);
+
+ if (ielem->expr)
+ {
+ /* Set up rtable as for predicate, see notes above */
+ if (rte == NULL)
+ {
+ rte = addRangeTableEntry(pstate, stmt->relation, NULL,
+ false, true);
+ /* no to join list, yes to namespace */
+ addRTEtoQuery(pstate, rte, false, true);
+ }
+ 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))
+ elog(ERROR, "index expression may not return a set");
+ }
+ }
+
qry->hasSubLinks = pstate->p_hasSubLinks;
stmt->rangetable = pstate->p_rtable;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0a7ae361f49..681738253bb 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.414 2003/05/15 16:35:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.415 2003/05/28 16:03:57 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -210,7 +210,7 @@ static void doNegateFloat(Value *v);
oper_argtypes RuleActionList RuleActionMulti
opt_column_list columnList opt_name_list
sort_clause opt_sort_clause sortby_list index_params
- index_list name_list from_clause from_list opt_array_bounds
+ name_list from_clause from_list opt_array_bounds
qualified_name_list any_name any_name_list
any_operator expr_list dotted_name attrs
target_list update_target_list insert_column_list
@@ -276,7 +276,7 @@ static void doNegateFloat(Value *v);
%type <columnref> columnref
%type <alias> alias_clause
%type <sortgroupby> sortby
-%type <ielem> index_elem func_index
+%type <ielem> index_elem
%type <node> table_ref
%type <jexpr> joined_table
%type <range> relation_expr
@@ -408,7 +408,7 @@ static void doNegateFloat(Value *v);
%token UNIONJOIN
/* Special keywords, not in the query language - see the "lex" file */
-%token <str> IDENT FCONST SCONST NCONST BCONST XCONST Op
+%token <str> IDENT FCONST SCONST BCONST XCONST Op
%token <ival> ICONST PARAM
/* precedence: lowest to highest */
@@ -2932,7 +2932,7 @@ function_with_argtypes:
*
* QUERY:
* create index <indexname> on <relname>
- * [ using <access> ] "(" (<col> with <op>)+ ")"
+ * [ using <access> ] "(" ( <col> [ using <opclass> ] )+ ")"
* [ where <predicate> ]
*
*****************************************************************************/
@@ -2958,70 +2958,48 @@ index_opt_unique:
access_method_clause:
USING access_method { $$ = $2; }
- /* If btree changes as our default, update pg_get_indexdef() */
| /*EMPTY*/ { $$ = DEFAULT_INDEX_TYPE; }
;
-index_params:
- index_list { $$ = $1; }
- | func_index { $$ = makeList1($1); }
+index_params: index_elem { $$ = makeList1($1); }
+ | index_params ',' index_elem { $$ = lappend($1, $3); }
;
-index_list: index_elem { $$ = makeList1($1); }
- | index_list ',' index_elem { $$ = lappend($1, $3); }
- ;
-
-func_index: func_name '(' name_list ')' opt_class
+/*
+ * Index attributes can be either simple column references, or arbitrary
+ * expressions in parens. For backwards-compatibility reasons, we allow
+ * an expression that's just a function call to be written without parens.
+ */
+index_elem: attr_name opt_class
+ {
+ $$ = makeNode(IndexElem);
+ $$->name = $1;
+ $$->expr = NULL;
+ $$->opclass = $2;
+ }
+ | func_name '(' expr_list ')' opt_class
{
+ FuncCall *n = makeNode(FuncCall);
+ n->funcname = $1;
+ n->args = $3;
+ n->agg_star = FALSE;
+ n->agg_distinct = FALSE;
+
$$ = makeNode(IndexElem);
$$->name = NULL;
- $$->funcname = $1;
- $$->args = $3;
+ $$->expr = (Node *)n;
$$->opclass = $5;
}
- ;
-
-index_elem: attr_name opt_class
+ | '(' a_expr ')' opt_class
{
$$ = makeNode(IndexElem);
- $$->name = $1;
- $$->funcname = NIL;
- $$->args = NIL;
- $$->opclass = $2;
+ $$->name = NULL;
+ $$->expr = $2;
+ $$->opclass = $4;
}
;
-opt_class: any_name
- {
- /*
- * Release 7.0 removed network_ops, timespan_ops, and
- * datetime_ops, so we suppress it from being passed to
- * the parser so the default *_ops is used. This can be
- * removed in some later release. bjm 2000/02/07
- *
- * Release 7.1 removes lztext_ops, so suppress that too
- * for a while. tgl 2000/07/30
- *
- * Release 7.2 renames timestamp_ops to timestamptz_ops,
- * so suppress that too for awhile. I'm starting to
- * think we need a better approach. tgl 2000/10/01
- */
- if (length($1) == 1)
- {
- char *claname = strVal(lfirst($1));
-
- if (strcmp(claname, "network_ops") != 0 &&
- strcmp(claname, "timespan_ops") != 0 &&
- strcmp(claname, "datetime_ops") != 0 &&
- strcmp(claname, "lztext_ops") != 0 &&
- strcmp(claname, "timestamp_ops") != 0)
- $$ = $1;
- else
- $$ = NIL;
- }
- else
- $$ = $1;
- }
+opt_class: any_name { $$ = $1; }
| USING any_name { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;