mirror of
https://github.com/postgres/postgres.git
synced 2025-08-27 07:42:10 +03:00
Add support for multi-row VALUES clauses as part of INSERT statements
(e.g. "INSERT ... VALUES (...), (...), ...") and elsewhere as allowed by the spec. (e.g. similar to a FROM clause subselect). initdb required. Joe Conway and Tom Lane.
This commit is contained in:
@@ -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 */
|
||||
@@ -537,6 +544,23 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
|
||||
set_cheapest(rel);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
@@ -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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -774,6 +774,36 @@ cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel)
|
||||
path->total_cost = startup_cost + run_cost;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -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
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1082,6 +1082,25 @@ create_functionscan_path(PlannerInfo *root, RelOptInfo *rel)
|
||||
return pathnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@@ -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",
|
||||
|
@@ -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 *)
|
||||
|
Reference in New Issue
Block a user