aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/allpaths.c26
-rw-r--r--src/backend/optimizer/path/costsize.c63
-rw-r--r--src/backend/optimizer/plan/createplan.c69
-rw-r--r--src/backend/optimizer/plan/planner.c31
-rw-r--r--src/backend/optimizer/plan/setrefs.c20
-rw-r--r--src/backend/optimizer/plan/subselect.c13
-rw-r--r--src/backend/optimizer/util/clauses.c9
-rw-r--r--src/backend/optimizer/util/pathnode.c21
-rw-r--r--src/backend/optimizer/util/plancat.c23
-rw-r--r--src/backend/optimizer/util/relnode.c11
10 files changed, 259 insertions, 27 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 05fe268a318..1d7e20c1e8b 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.149 2006/07/14 14:52:20 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.150 2006/08/02 01:59:45 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -48,6 +48,8 @@ static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte);
static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel,
RangeTblEntry *rte);
+static void set_values_pathlist(PlannerInfo *root, RelOptInfo *rel,
+ RangeTblEntry *rte);
static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist);
static RelOptInfo *make_one_rel_by_joins(PlannerInfo *root, int levels_needed,
List *initial_rels);
@@ -170,6 +172,11 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti)
/* RangeFunction --- generate a separate plan for it */
set_function_pathlist(root, rel, rte);
}
+ else if (rel->rtekind == RTE_VALUES)
+ {
+ /* Values list --- generate a separate plan for it */
+ set_values_pathlist(root, rel, rte);
+ }
else
{
/* Plain relation */
@@ -538,6 +545,23 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
}
/*
+ * set_values_pathlist
+ * Build the (single) access path for a VALUES RTE
+ */
+static void
+set_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
+{
+ /* Mark rel with estimated output rows, width, etc */
+ set_values_size_estimates(root, rel);
+
+ /* Generate appropriate path */
+ add_path(rel, create_valuesscan_path(root, rel));
+
+ /* Select cheapest path (pretty easy in this case...) */
+ set_cheapest(rel);
+}
+
+/*
* make_rel_from_joinlist
* Build access paths using a "joinlist" to guide the join path search.
*
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 5f5e9ec3721..fffa25dd844 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.164 2006/07/26 11:35:56 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.165 2006/08/02 01:59:45 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -775,6 +775,36 @@ cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel)
}
/*
+ * cost_valuesscan
+ * Determines and returns the cost of scanning a VALUES RTE.
+ */
+void
+cost_valuesscan(Path *path, PlannerInfo *root, RelOptInfo *baserel)
+{
+ Cost startup_cost = 0;
+ Cost run_cost = 0;
+ Cost cpu_per_tuple;
+
+ /* Should only be applied to base relations that are values lists */
+ Assert(baserel->relid > 0);
+ Assert(baserel->rtekind == RTE_VALUES);
+
+ /*
+ * For now, estimate list evaluation cost at one operator eval per
+ * list (probably pretty bogus, but is it worth being smarter?)
+ */
+ cpu_per_tuple = cpu_operator_cost;
+
+ /* Add scanning CPU costs */
+ startup_cost += baserel->baserestrictcost.startup;
+ cpu_per_tuple += cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
+ run_cost += cpu_per_tuple * baserel->tuples;
+
+ path->startup_cost = startup_cost;
+ path->total_cost = startup_cost + run_cost;
+}
+
+/*
* cost_sort
* Determines and returns the cost of sorting a relation, including
* the cost of reading the input data.
@@ -2023,6 +2053,37 @@ set_function_size_estimates(PlannerInfo *root, RelOptInfo *rel)
set_baserel_size_estimates(root, rel);
}
+/*
+ * set_values_size_estimates
+ * Set the size estimates for a base relation that is a values list.
+ *
+ * The rel's targetlist and restrictinfo list must have been constructed
+ * already.
+ *
+ * We set the same fields as set_baserel_size_estimates.
+ */
+void
+set_values_size_estimates(PlannerInfo *root, RelOptInfo *rel)
+{
+ RangeTblEntry *rte;
+
+ /* Should only be applied to base relations that are values lists */
+ Assert(rel->relid > 0);
+ rte = rt_fetch(rel->relid, root->parse->rtable);
+ Assert(rte->rtekind == RTE_VALUES);
+
+ /*
+ * Estimate number of rows the values list will return.
+ * We know this precisely based on the list length (well,
+ * barring set-returning functions in list items, but that's
+ * a refinement not catered for anywhere else either).
+ */
+ rel->tuples = list_length(rte->values_lists);
+
+ /* Now estimate number of output rows, etc */
+ set_baserel_size_estimates(root, rel);
+}
+
/*
* set_rel_width
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 7ed718f0b31..ae51505954f 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.215 2006/07/26 00:34:48 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.216 2006/08/02 01:59:45 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -59,6 +59,8 @@ static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root, Path *best_path
List *tlist, List *scan_clauses);
static FunctionScan *create_functionscan_plan(PlannerInfo *root, Path *best_path,
List *tlist, List *scan_clauses);
+static ValuesScan *create_valuesscan_plan(PlannerInfo *root, Path *best_path,
+ List *tlist, List *scan_clauses);
static NestLoop *create_nestloop_plan(PlannerInfo *root, NestPath *best_path,
Plan *outer_plan, Plan *inner_plan);
static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath *best_path,
@@ -95,6 +97,8 @@ static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
List *tidquals);
static FunctionScan *make_functionscan(List *qptlist, List *qpqual,
Index scanrelid);
+static ValuesScan *make_valuesscan(List *qptlist, List *qpqual,
+ Index scanrelid);
static BitmapAnd *make_bitmap_and(List *bitmapplans);
static BitmapOr *make_bitmap_or(List *bitmapplans);
static NestLoop *make_nestloop(List *tlist,
@@ -146,6 +150,7 @@ create_plan(PlannerInfo *root, Path *best_path)
case T_TidScan:
case T_SubqueryScan:
case T_FunctionScan:
+ case T_ValuesScan:
plan = create_scan_plan(root, best_path);
break;
case T_HashJoin:
@@ -262,6 +267,13 @@ create_scan_plan(PlannerInfo *root, Path *best_path)
scan_clauses);
break;
+ case T_ValuesScan:
+ plan = (Plan *) create_valuesscan_plan(root,
+ best_path,
+ tlist,
+ scan_clauses);
+ break;
+
default:
elog(ERROR, "unrecognized node type: %d",
(int) best_path->pathtype);
@@ -315,12 +327,13 @@ use_physical_tlist(RelOptInfo *rel)
int i;
/*
- * We can do this for real relation scans, subquery scans, and function
- * scans (but not for, eg, joins).
+ * We can do this for real relation scans, subquery scans, function
+ * scans, and values scans (but not for, eg, joins).
*/
if (rel->rtekind != RTE_RELATION &&
rel->rtekind != RTE_SUBQUERY &&
- rel->rtekind != RTE_FUNCTION)
+ rel->rtekind != RTE_FUNCTION &&
+ rel->rtekind != RTE_VALUES)
return false;
/*
@@ -365,6 +378,7 @@ disuse_physical_tlist(Plan *plan, Path *path)
case T_TidScan:
case T_SubqueryScan:
case T_FunctionScan:
+ case T_ValuesScan:
plan->targetlist = build_relation_tlist(path->parent);
break;
default:
@@ -1312,6 +1326,35 @@ create_functionscan_plan(PlannerInfo *root, Path *best_path,
return scan_plan;
}
+/*
+ * create_valuesscan_plan
+ * Returns a valuesscan plan for the base relation scanned by 'best_path'
+ * with restriction clauses 'scan_clauses' and targetlist 'tlist'.
+ */
+static ValuesScan *
+create_valuesscan_plan(PlannerInfo *root, Path *best_path,
+ List *tlist, List *scan_clauses)
+{
+ ValuesScan *scan_plan;
+ Index scan_relid = best_path->parent->relid;
+
+ /* it should be a values base rel... */
+ Assert(scan_relid > 0);
+ Assert(best_path->parent->rtekind == RTE_VALUES);
+
+ /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
+ scan_clauses = extract_actual_clauses(scan_clauses, false);
+
+ /* Sort clauses into best execution order */
+ scan_clauses = order_qual_clauses(root, scan_clauses);
+
+ scan_plan = make_valuesscan(tlist, scan_clauses, scan_relid);
+
+ copy_path_costsize(&scan_plan->scan.plan, best_path);
+
+ return scan_plan;
+}
+
/*****************************************************************************
*
* JOIN METHODS
@@ -2123,6 +2166,24 @@ make_functionscan(List *qptlist,
return node;
}
+static ValuesScan *
+make_valuesscan(List *qptlist,
+ List *qpqual,
+ Index scanrelid)
+{
+ ValuesScan *node = makeNode(ValuesScan);
+ Plan *plan = &node->scan.plan;
+
+ /* cost should be inserted by caller */
+ plan->targetlist = qptlist;
+ plan->qual = qpqual;
+ plan->lefttree = NULL;
+ plan->righttree = NULL;
+ node->scan.scanrelid = scanrelid;
+
+ return node;
+}
+
Append *
make_append(List *appendplans, bool isTarget, List *tlist)
{
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index c02f6e195cd..42ae15cd483 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.205 2006/07/26 19:31:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.206 2006/08/02 01:59:46 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -48,9 +48,10 @@ ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */
#define EXPRKIND_QUAL 0
#define EXPRKIND_TARGET 1
#define EXPRKIND_RTFUNC 2
-#define EXPRKIND_LIMIT 3
-#define EXPRKIND_ININFO 4
-#define EXPRKIND_APPINFO 5
+#define EXPRKIND_VALUES 3
+#define EXPRKIND_LIMIT 4
+#define EXPRKIND_ININFO 5
+#define EXPRKIND_APPINFO 6
static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
@@ -295,7 +296,7 @@ subquery_planner(Query *parse, double tuple_fraction,
preprocess_expression(root, (Node *) root->append_rel_list,
EXPRKIND_APPINFO);
- /* Also need to preprocess expressions for function RTEs */
+ /* Also need to preprocess expressions for function and values RTEs */
foreach(l, parse->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
@@ -303,6 +304,10 @@ subquery_planner(Query *parse, double tuple_fraction,
if (rte->rtekind == RTE_FUNCTION)
rte->funcexpr = preprocess_expression(root, rte->funcexpr,
EXPRKIND_RTFUNC);
+ else if (rte->rtekind == RTE_VALUES)
+ rte->values_lists = (List *)
+ preprocess_expression(root, (Node *) rte->values_lists,
+ EXPRKIND_VALUES);
}
/*
@@ -418,8 +423,10 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
* If the query has any join RTEs, replace join alias variables with
* base-relation variables. We must do this before sublink processing,
* else sublinks expanded out from join aliases wouldn't get processed.
+ * We can skip it in VALUES lists, however, since they can't contain
+ * any Vars at all.
*/
- if (root->hasJoinRTEs)
+ if (root->hasJoinRTEs && kind != EXPRKIND_VALUES)
expr = flatten_join_alias_vars(root, expr);
/*
@@ -437,10 +444,14 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
* and we will waste cycles copying the tree. Notice however that we
* still must do it for quals (to get AND/OR flatness); and if we are in a
* subquery we should not assume it will be done only once.
+ *
+ * For VALUES lists we never do this at all, again on the grounds that
+ * we should optimize for one-time evaluation.
*/
- if (root->parse->jointree->fromlist != NIL ||
- kind == EXPRKIND_QUAL ||
- PlannerQueryLevel > 1)
+ if (kind != EXPRKIND_VALUES &&
+ (root->parse->jointree->fromlist != NIL ||
+ kind == EXPRKIND_QUAL ||
+ PlannerQueryLevel > 1))
expr = eval_const_expressions(expr);
/*
@@ -465,7 +476,7 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
* SS_replace_correlation_vars ...
*/
- /* Replace uplevel vars with Param nodes */
+ /* Replace uplevel vars with Param nodes (this IS possible in VALUES) */
if (PlannerQueryLevel > 1)
expr = SS_replace_correlation_vars(expr);
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 2529c42ad95..11ef4765d86 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.122 2006/07/14 14:52:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.123 2006/08/02 01:59:46 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -186,6 +186,18 @@ set_plan_references(Plan *plan, List *rtable)
fix_expr_references(plan, rte->funcexpr);
}
break;
+ case T_ValuesScan:
+ {
+ RangeTblEntry *rte;
+
+ fix_expr_references(plan, (Node *) plan->targetlist);
+ fix_expr_references(plan, (Node *) plan->qual);
+ rte = rt_fetch(((ValuesScan *) plan)->scan.scanrelid,
+ rtable);
+ Assert(rte->rtekind == RTE_VALUES);
+ fix_expr_references(plan, (Node *) rte->values_lists);
+ }
+ break;
case T_NestLoop:
set_join_references((Join *) plan, rtable);
fix_expr_references(plan, (Node *) plan->targetlist);
@@ -522,6 +534,12 @@ adjust_plan_varnos(Plan *plan, int rtoffset)
adjust_expr_varnos((Node *) plan->qual, rtoffset);
/* rte was already fixed by set_subqueryscan_references */
break;
+ case T_ValuesScan:
+ ((ValuesScan *) plan)->scan.scanrelid += rtoffset;
+ adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
+ adjust_expr_varnos((Node *) plan->qual, rtoffset);
+ /* rte was already fixed by set_subqueryscan_references */
+ break;
case T_NestLoop:
adjust_expr_varnos((Node *) plan->targetlist, rtoffset);
adjust_expr_varnos((Node *) plan->qual, rtoffset);
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 0bc9a46c952..95e560478d9 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.110 2006/07/14 14:52:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.111 2006/08/02 01:59:46 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1090,6 +1090,17 @@ finalize_plan(Plan *plan, List *rtable,
}
break;
+ case T_ValuesScan:
+ {
+ RangeTblEntry *rte;
+
+ rte = rt_fetch(((ValuesScan *) plan)->scan.scanrelid,
+ rtable);
+ Assert(rte->rtekind == RTE_VALUES);
+ finalize_primnode((Node *) rte->values_lists, &context);
+ }
+ break;
+
case T_Append:
{
ListCell *l;
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index dfc43149d3a..5570b33f485 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.215 2006/07/27 19:52:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.216 2006/08/02 01:59:46 joe Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -3351,6 +3351,10 @@ range_table_walker(List *rtable,
if (walker(rte->funcexpr, context))
return true;
break;
+ case RTE_VALUES:
+ if (walker(rte->values_lists, context))
+ return true;
+ break;
}
}
return false;
@@ -3917,6 +3921,9 @@ range_table_mutator(List *rtable,
case RTE_FUNCTION:
MUTATE(newrte->funcexpr, rte->funcexpr, Node *);
break;
+ case RTE_VALUES:
+ MUTATE(newrte->values_lists, rte->values_lists, List *);
+ break;
}
newrt = lappend(newrt, newrte);
}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 631d6087d8e..2cc79ed239e 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.131 2006/07/22 15:41:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.132 2006/08/02 01:59:46 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1083,6 +1083,25 @@ create_functionscan_path(PlannerInfo *root, RelOptInfo *rel)
}
/*
+ * create_valuesscan_path
+ * Creates a path corresponding to a scan of a VALUES list,
+ * returning the pathnode.
+ */
+Path *
+create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel)
+{
+ Path *pathnode = makeNode(Path);
+
+ pathnode->pathtype = T_ValuesScan;
+ pathnode->parent = rel;
+ pathnode->pathkeys = NIL; /* result is always unordered */
+
+ cost_valuesscan(pathnode, root, rel);
+
+ return pathnode;
+}
+
+/*
* create_nestloop_path
* Creates a pathnode corresponding to a nestloop join between two
* relations.
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index bafe1b66731..f74faa5c977 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.122 2006/07/31 20:09:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.123 2006/08/02 01:59:46 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -493,9 +493,9 @@ relation_excluded_by_constraints(RelOptInfo *rel, RangeTblEntry *rte)
* For now, we don't apply the physical-tlist optimization when there are
* dropped cols.
*
- * We also support building a "physical" tlist for subqueries and functions,
- * since the same optimization can occur in SubqueryScan and FunctionScan
- * nodes.
+ * We also support building a "physical" tlist for subqueries, functions,
+ * and values lists, since the same optimization can occur in SubqueryScan,
+ * FunctionScan, and ValuesScan nodes.
*/
List *
build_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
@@ -594,6 +594,21 @@ build_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
}
break;
+ case RTE_VALUES:
+ expandRTE(rte, varno, 0, false /* dropped not applicable */ ,
+ NULL, &colvars);
+ foreach(l, colvars)
+ {
+ var = (Var *) lfirst(l);
+
+ tlist = lappend(tlist,
+ makeTargetEntry((Expr *) var,
+ var->varattno,
+ NULL,
+ false));
+ }
+ break;
+
default:
/* caller error */
elog(ERROR, "unsupported RTE kind %d in build_physical_tlist",
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 8d06254a9f4..545b125197c 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.80 2006/07/31 20:09:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.81 2006/08/02 01:59:46 joe Exp $
*
*-------------------------------------------------------------------------
*/
@@ -96,8 +96,13 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
break;
case RTE_SUBQUERY:
case RTE_FUNCTION:
- /* Subquery or function --- set up attr range and arrays */
- /* Note: 0 is included in range to support whole-row Vars */
+ case RTE_VALUES:
+ /*
+ * Subquery, function, or values list --- set up attr range
+ * and arrays
+ *
+ * Note: 0 is included in range to support whole-row Vars
+ */
rel->min_attr = 0;
rel->max_attr = list_length(rte->eref->colnames);
rel->attr_needed = (Relids *)