diff options
Diffstat (limited to 'src/backend/parser')
| -rw-r--r-- | src/backend/parser/analyze.c | 44 | ||||
| -rw-r--r-- | src/backend/parser/gram.y | 86 |
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; } ; |
