aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2004-05-10 22:44:49 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2004-05-10 22:44:49 +0000
commit2f63232d30ca64a8f2684af855230f23a701d371 (patch)
treeb7a7707d1ec9edf368780cd3f4a23755527c5884 /src/backend/optimizer/util
parent9a939886ac782cfee3cd5fdd1c58689163ed84be (diff)
downloadpostgresql-2f63232d30ca64a8f2684af855230f23a701d371.tar.gz
postgresql-2f63232d30ca64a8f2684af855230f23a701d371.zip
Promote row expressions to full-fledged citizens of the expression syntax,
rather than allowing them only in a few special cases as before. In particular you can now pass a ROW() construct to a function that accepts a rowtype parameter. Internal generation of RowExprs fixes a number of corner cases that used to not work very well, such as referencing the whole-row result of a JOIN or subquery. This represents a further step in the work I started a month or so back to make rowtype values into first-class citizens.
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r--src/backend/optimizer/util/clauses.c109
-rw-r--r--src/backend/optimizer/util/var.c53
2 files changed, 95 insertions, 67 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index f653640ee8c..4dabbf50dac 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.169 2004/04/02 23:14:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.170 2004/05/10 22:44:45 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -41,10 +41,6 @@
#include "utils/syscache.h"
-/* note that pg_type.h hardwires size of bool as 1 ... duplicate it */
-#define MAKEBOOLCONST(val,isnull) \
- ((Node *) makeConst(BOOLOID, 1, (Datum) (val), (isnull), true))
-
typedef struct
{
int nargs;
@@ -281,7 +277,7 @@ Expr *
make_ands_explicit(List *andclauses)
{
if (andclauses == NIL)
- return (Expr *) MAKEBOOLCONST(true, false);
+ return (Expr *) makeBoolConst(true, false);
else if (lnext(andclauses) == NIL)
return (Expr *) lfirst(andclauses);
else
@@ -484,6 +480,8 @@ expression_returns_set_walker(Node *node, void *context)
return false;
if (IsA(node, ArrayExpr))
return false;
+ if (IsA(node, RowExpr))
+ return false;
if (IsA(node, CoalesceExpr))
return false;
if (IsA(node, NullIfExpr))
@@ -778,6 +776,8 @@ contain_nonstrict_functions_walker(Node *node, void *context)
if (IsA(node, CaseWhen))
return true;
/* NB: ArrayExpr might someday be nonstrict */
+ if (IsA(node, RowExpr))
+ return true;
if (IsA(node, CoalesceExpr))
return true;
if (IsA(node, NullIfExpr))
@@ -1030,6 +1030,8 @@ set_coercionform_dontcare_walker(Node *node, void *context)
((FuncExpr *) node)->funcformat = COERCE_DONTCARE;
if (IsA(node, RelabelType))
((RelabelType *) node)->relabelformat = COERCE_DONTCARE;
+ if (IsA(node, RowExpr))
+ ((RowExpr *) node)->row_format = COERCE_DONTCARE;
if (IsA(node, CoerceToDomain))
((CoerceToDomain *) node)->coercionformat = COERCE_DONTCARE;
return expression_tree_walker(node, set_coercionform_dontcare_walker,
@@ -1197,11 +1199,11 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
{
/* all nulls? then not distinct */
if (all_null_input)
- return MAKEBOOLCONST(false, false);
+ return makeBoolConst(false, false);
/* one null? then distinct */
if (has_null_input)
- return MAKEBOOLCONST(true, false);
+ return makeBoolConst(true, false);
/* otherwise try to evaluate the '=' operator */
/* (NOT okay to try to inline it, though!) */
@@ -1272,12 +1274,12 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
newargs = simplify_or_arguments(args,
&haveNull, &forceTrue);
if (forceTrue)
- return MAKEBOOLCONST(true, false);
+ return makeBoolConst(true, false);
if (haveNull)
- newargs = lappend(newargs, MAKEBOOLCONST(false, true));
+ newargs = lappend(newargs, makeBoolConst(false, true));
/* If all the inputs are FALSE, result is FALSE */
if (newargs == NIL)
- return MAKEBOOLCONST(false, false);
+ return makeBoolConst(false, false);
/* If only one nonconst-or-NULL input, it's the result */
if (lnext(newargs) == NIL)
return (Node *) lfirst(newargs);
@@ -1293,12 +1295,12 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
newargs = simplify_and_arguments(args,
&haveNull, &forceFalse);
if (forceFalse)
- return MAKEBOOLCONST(false, false);
+ return makeBoolConst(false, false);
if (haveNull)
- newargs = lappend(newargs, MAKEBOOLCONST(false, true));
+ newargs = lappend(newargs, makeBoolConst(false, true));
/* If all the inputs are TRUE, result is TRUE */
if (newargs == NIL)
- return MAKEBOOLCONST(true, false);
+ return makeBoolConst(true, false);
/* If only one nonconst-or-NULL input, it's the result */
if (lnext(newargs) == NIL)
return (Node *) lfirst(newargs);
@@ -1313,9 +1315,9 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
/* NOT NULL => NULL */
if (const_input->constisnull)
- return MAKEBOOLCONST(false, true);
+ return makeBoolConst(false, true);
/* otherwise pretty easy */
- return MAKEBOOLCONST(!DatumGetBool(const_input->constvalue),
+ return makeBoolConst(!DatumGetBool(const_input->constvalue),
false);
}
else if (not_clause((Node *) lfirst(args)))
@@ -1387,7 +1389,6 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
}
if (IsA(node, CaseExpr))
{
-
/*----------
* CASE expressions can be simplified if there are constant
* condition clauses:
@@ -1546,22 +1547,38 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* We can optimize field selection from a whole-row Var into a
* simple Var. (This case won't be generated directly by the
* parser, because ParseComplexProjection short-circuits it. But
- * it can arise while simplifying functions.) If the argument
- * isn't a whole-row Var, just fall through to do generic
- * processing.
+ * it can arise while simplifying functions.) Also, we can
+ * optimize field selection from a RowExpr construct.
*/
FieldSelect *fselect = (FieldSelect *) node;
- Var *argvar = (Var *) fselect->arg;
+ FieldSelect *newfselect;
+ Node *arg;
- if (argvar && IsA(argvar, Var) &&
- argvar->varattno == InvalidAttrNumber)
+ arg = eval_const_expressions_mutator((Node *) fselect->arg,
+ active_fns);
+ if (arg && IsA(arg, Var) &&
+ ((Var *) arg)->varattno == InvalidAttrNumber)
{
- return (Node *) makeVar(argvar->varno,
+ return (Node *) makeVar(((Var *) arg)->varno,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod,
- argvar->varlevelsup);
+ ((Var *) arg)->varlevelsup);
}
+ if (arg && IsA(arg, RowExpr))
+ {
+ RowExpr *rowexpr = (RowExpr *) arg;
+
+ if (fselect->fieldnum > 0 &&
+ fselect->fieldnum <= length(rowexpr->args))
+ return (Node *) nth(fselect->fieldnum - 1, rowexpr->args);
+ }
+ newfselect = makeNode(FieldSelect);
+ newfselect->arg = (Expr *) arg;
+ newfselect->fieldnum = fselect->fieldnum;
+ newfselect->resulttype = fselect->resulttype;
+ newfselect->resulttypmod = fselect->resulttypmod;
+ return (Node *) newfselect;
}
/*
@@ -1759,7 +1776,6 @@ evaluate_function(Oid funcid, Oid result_type, List *args,
bool has_null_input = false;
List *arg;
FuncExpr *newexpr;
- char result_typtype;
/*
* Can't simplify if it returns a set.
@@ -1797,15 +1813,6 @@ evaluate_function(Oid funcid, Oid result_type, List *args,
return NULL;
/*
- * Can't simplify functions returning composite types (mainly because
- * datumCopy() doesn't cope; FIXME someday when we have a saner
- * representation for whole-tuple results).
- */
- result_typtype = get_typtype(funcform->prorettype);
- if (result_typtype == 'c')
- return NULL;
-
- /*
* OK, looks like we can simplify this operator/function.
*
* Build a new FuncExpr node containing the already-simplified arguments.
@@ -1850,7 +1857,6 @@ inline_function(Oid funcid, Oid result_type, List *args,
HeapTuple func_tuple, List *active_fns)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
- char result_typtype;
bool polymorphic = false;
Oid argtypes[FUNC_MAX_ARGS];
char *src;
@@ -1877,21 +1883,6 @@ inline_function(Oid funcid, Oid result_type, List *args,
funcform->pronargs != length(args))
return NULL;
- /*
- * Forget it if declared return type is not base, domain, or
- * polymorphic
- */
- result_typtype = get_typtype(funcform->prorettype);
- if (result_typtype != 'b' &&
- result_typtype != 'd')
- {
- if (funcform->prorettype == ANYARRAYOID ||
- funcform->prorettype == ANYELEMENTOID)
- polymorphic = true;
- else
- return NULL;
- }
-
/* Check for recursive function, and give up trying to expand if so */
if (oidMember(funcid, active_fns))
return NULL;
@@ -1912,6 +1903,10 @@ inline_function(Oid funcid, Oid result_type, List *args,
}
}
+ if (funcform->prorettype == ANYARRAYOID ||
+ funcform->prorettype == ANYELEMENTOID)
+ polymorphic = true;
+
/*
* Setup error traceback support for ereport(). This is so that we
* can finger the function that bad information came from.
@@ -2483,6 +2478,8 @@ expression_tree_walker(Node *node,
break;
case T_ArrayExpr:
return walker(((ArrayExpr *) node)->elements, context);
+ case T_RowExpr:
+ return walker(((RowExpr *) node)->args, context);
case T_CoalesceExpr:
return walker(((CoalesceExpr *) node)->args, context);
case T_NullIfExpr:
@@ -2889,6 +2886,16 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
+ case T_RowExpr:
+ {
+ RowExpr *rowexpr = (RowExpr *) node;
+ RowExpr *newnode;
+
+ FLATCOPY(newnode, rowexpr, RowExpr);
+ MUTATE(newnode->args, rowexpr->args, List *);
+ return (Node *) newnode;
+ }
+ break;
case T_CoalesceExpr:
{
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index dac90809de1..47b1fdbf70e 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.55 2003/11/29 19:51:51 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.56 2004/05/10 22:44:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -192,19 +192,6 @@ contain_var_reference_walker(Node *node,
/*
- * contain_whole_tuple_var
- *
- * Detect whether a parsetree contains any references to the whole
- * tuple of a given rtable entry (ie, a Var with varattno = 0).
- */
-bool
-contain_whole_tuple_var(Node *node, int varno, int levelsup)
-{
- return contain_var_reference(node, varno, InvalidAttrNumber, levelsup);
-}
-
-
-/*
* contain_var_clause
* Recursively scan a clause to discover whether it contains any Var nodes
* (of the current query level).
@@ -486,7 +473,10 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
* flatten_join_alias_vars
* Replace Vars that reference JOIN outputs with references to the original
* relation variables instead. This allows quals involving such vars to be
- * pushed down.
+ * pushed down. Whole-row Vars that reference JOIN relations are expanded
+ * into RowExpr constructs that name the individual output Vars. This
+ * is necessary since we will not scan the JOIN as a base relation, which
+ * is the only way that the executor can directly handle whole-row Vars.
*
* NOTE: this is used on not-yet-planned expressions. We do not expect it
* to be applied directly to a Query node.
@@ -520,8 +510,39 @@ flatten_join_alias_vars_mutator(Node *node,
rte = rt_fetch(var->varno, context->root->rtable);
if (rte->rtekind != RTE_JOIN)
return node;
+ if (var->varattno == InvalidAttrNumber)
+ {
+ /* Must expand whole-row reference */
+ RowExpr *rowexpr;
+ List *fields = NIL;
+ List *l;
+
+ foreach(l, rte->joinaliasvars)
+ {
+ newvar = (Node *) lfirst(l);
+ /*
+ * If we are expanding an alias carried down from an upper
+ * query, must adjust its varlevelsup fields.
+ */
+ if (context->sublevels_up != 0)
+ {
+ newvar = copyObject(newvar);
+ IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
+ }
+ /* Recurse in case join input is itself a join */
+ newvar = flatten_join_alias_vars_mutator(newvar, context);
+ fields = lappend(fields, newvar);
+ }
+ rowexpr = makeNode(RowExpr);
+ rowexpr->args = fields;
+ rowexpr->row_typeid = var->vartype;
+ rowexpr->row_format = COERCE_IMPLICIT_CAST;
+
+ return (Node *) rowexpr;
+ }
+
+ /* Expand join alias reference */
Assert(var->varattno > 0);
- /* Okay, must expand it */
newvar = (Node *) nth(var->varattno - 1, rte->joinaliasvars);
/*