aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-05-28 16:04:02 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-05-28 16:04:02 +0000
commitfc8d970cbcdd6f025475822a4cf01dfda0873226 (patch)
treeca697026dbada6a022dec471191aab5a0ba7eb20 /src/backend/parser
parente5f19598e07e9a0fc0a5c0f18bfac1fe92d21fc5 (diff)
downloadpostgresql-fc8d970cbcdd6f025475822a4cf01dfda0873226.tar.gz
postgresql-fc8d970cbcdd6f025475822a4cf01dfda0873226.zip
Replace functional-index facility with expressional indexes. Any column
of an index can now be a computed expression instead of a simple variable. Restrictions on expressions are the same as for predicates (only immutable functions, no sub-selects). This fixes problems recently introduced with inlining SQL functions, because the inlining transformation is applied to both expression trees so the planner can still match them up. Along the way, improve efficiency of handling index predicates (both predicates and index expressions are now cached by the relcache) and fix 7.3 oversight that didn't record dependencies of predicate expressions.
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; }
;