mirror of
https://github.com/postgres/postgres.git
synced 2025-10-13 18:28:01 +03:00
Keep track of what RTIs a Result node is scanning.
Result nodes now include an RTI set, which is only non-NULL when they have no subplan, and is taken from the relid set of the RelOptInfo that the Result is generating. ExplainPreScanNode now takes notice of these RTIs, which means that a few things get schema-qualified in the regression tests that previously did not. This makes the output more consistent between cases where some part of the plan tree is replaced by a Result node and those where this does not happen. Likewise, pg_overexplain's EXPLAIN (RANGE_TABLE) now displays the RTIs stored in a Result node just as it already does for other RTI-bearing node types. Result nodes also now include a result_reason, which tells us something about why the Result node was inserted. Using that information, EXPLAIN now emits, where relevant, a "Replaces" line describing the origin of a Result node. The purpose of these changes is to allow code that inspects a Plan tree to understand the origin of Result nodes that appear therein. Discussion: http://postgr.es/m/CA+TgmoYeUZePZWLsSO+1FAN7UPePT_RMEZBKkqYBJVCF1s60=w@mail.gmail.com Reviewed-by: Alexandra Wang <alexandra.wang.oss@gmail.com> Reviewed-by: Richard Guo <guofenglinux@gmail.com> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Junwang Zhao <zhjwpku@gmail.com>
This commit is contained in:
@@ -322,6 +322,7 @@ SET constraint_exclusion = 'on';
|
|||||||
SELECT explain_filter('EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv WHERE a < 0');
|
SELECT explain_filter('EXPLAIN (VERBOSE, COSTS FALSE) SELECT * FROM agg_csv WHERE a < 0');
|
||||||
Result
|
Result
|
||||||
Output: a, b
|
Output: a, b
|
||||||
|
Replaces: Scan on agg_csv
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
|
|
||||||
\t off
|
\t off
|
||||||
|
@@ -44,9 +44,10 @@ EXPLAIN (RANGE_TABLE) SELECT 1;
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
Result (cost=0.00..0.01 rows=1 width=4)
|
Result (cost=0.00..0.01 rows=1 width=4)
|
||||||
|
RTIs: 1
|
||||||
RTI 1 (result):
|
RTI 1 (result):
|
||||||
Eref: "*RESULT*" ()
|
Eref: "*RESULT*" ()
|
||||||
(3 rows)
|
(4 rows)
|
||||||
|
|
||||||
-- Create a partitioned table.
|
-- Create a partitioned table.
|
||||||
CREATE TABLE vegetables (id serial, name text, genus text)
|
CREATE TABLE vegetables (id serial, name text, genus text)
|
||||||
@@ -475,6 +476,7 @@ INSERT INTO vegetables (name, genus) VALUES ('broccoflower', 'brassica');
|
|||||||
Nominal RTI: 1
|
Nominal RTI: 1
|
||||||
Exclude Relation RTI: 0
|
Exclude Relation RTI: 0
|
||||||
-> Result
|
-> Result
|
||||||
|
RTIs: 2
|
||||||
RTI 1 (relation):
|
RTI 1 (relation):
|
||||||
Eref: vegetables (id, name, genus)
|
Eref: vegetables (id, name, genus)
|
||||||
Relation: vegetables
|
Relation: vegetables
|
||||||
@@ -485,5 +487,5 @@ INSERT INTO vegetables (name, genus) VALUES ('broccoflower', 'brassica');
|
|||||||
Eref: "*RESULT*" ()
|
Eref: "*RESULT*" ()
|
||||||
Unprunable RTIs: 1
|
Unprunable RTIs: 1
|
||||||
Result RTIs: 1
|
Result RTIs: 1
|
||||||
(14 rows)
|
(15 rows)
|
||||||
|
|
||||||
|
@@ -236,6 +236,18 @@ overexplain_per_node_hook(PlanState *planstate, List *ancestors,
|
|||||||
((MergeAppend *) plan)->apprelids,
|
((MergeAppend *) plan)->apprelids,
|
||||||
es);
|
es);
|
||||||
break;
|
break;
|
||||||
|
case T_Result:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'relids' is only meaningful when plan->lefttree is NULL,
|
||||||
|
* but if somehow it ends up set when plan->lefttree is not
|
||||||
|
* NULL, print it anyway.
|
||||||
|
*/
|
||||||
|
if (plan->lefttree == NULL ||
|
||||||
|
((Result *) plan)->relids != NULL)
|
||||||
|
overexplain_bitmapset("RTIs",
|
||||||
|
((Result *) plan)->relids,
|
||||||
|
es);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -7159,8 +7159,9 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 < 0;
|
|||||||
Aggregate
|
Aggregate
|
||||||
Output: count(*)
|
Output: count(*)
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on ft1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(4 rows)
|
(5 rows)
|
||||||
|
|
||||||
SELECT count(*) FROM ft1 WHERE c2 < 0;
|
SELECT count(*) FROM ft1 WHERE c2 < 0;
|
||||||
count
|
count
|
||||||
@@ -7203,8 +7204,9 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 >= 0;
|
|||||||
Aggregate
|
Aggregate
|
||||||
Output: count(*)
|
Output: count(*)
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on ft1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(4 rows)
|
(5 rows)
|
||||||
|
|
||||||
SELECT count(*) FROM ft1 WHERE c2 >= 0;
|
SELECT count(*) FROM ft1 WHERE c2 >= 0;
|
||||||
count
|
count
|
||||||
@@ -8032,8 +8034,9 @@ DELETE FROM rem1 WHERE false; -- currently can't be pushed down
|
|||||||
Remote SQL: DELETE FROM public.loc1 WHERE ctid = $1
|
Remote SQL: DELETE FROM public.loc1 WHERE ctid = $1
|
||||||
-> Result
|
-> Result
|
||||||
Output: ctid
|
Output: ctid
|
||||||
|
Replaces: Scan on rem1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
-- Test with statement-level triggers
|
-- Test with statement-level triggers
|
||||||
CREATE TRIGGER trig_stmt_before
|
CREATE TRIGGER trig_stmt_before
|
||||||
|
@@ -147,6 +147,7 @@ static void show_buffer_usage(ExplainState *es, const BufferUsage *usage);
|
|||||||
static void show_wal_usage(ExplainState *es, const WalUsage *usage);
|
static void show_wal_usage(ExplainState *es, const WalUsage *usage);
|
||||||
static void show_memory_counters(ExplainState *es,
|
static void show_memory_counters(ExplainState *es,
|
||||||
const MemoryContextCounters *mem_counters);
|
const MemoryContextCounters *mem_counters);
|
||||||
|
static void show_result_replacement_info(Result *result, ExplainState *es);
|
||||||
static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir,
|
static void ExplainIndexScanDetails(Oid indexid, ScanDirection indexorderdir,
|
||||||
ExplainState *es);
|
ExplainState *es);
|
||||||
static void ExplainScanTarget(Scan *plan, ExplainState *es);
|
static void ExplainScanTarget(Scan *plan, ExplainState *es);
|
||||||
@@ -1229,6 +1230,10 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
|
|||||||
*rels_used = bms_add_members(*rels_used,
|
*rels_used = bms_add_members(*rels_used,
|
||||||
((MergeAppend *) plan)->apprelids);
|
((MergeAppend *) plan)->apprelids);
|
||||||
break;
|
break;
|
||||||
|
case T_Result:
|
||||||
|
*rels_used = bms_add_members(*rels_used,
|
||||||
|
((Result *) plan)->relids);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2232,6 +2237,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
|
|||||||
ancestors, es);
|
ancestors, es);
|
||||||
break;
|
break;
|
||||||
case T_Result:
|
case T_Result:
|
||||||
|
show_result_replacement_info(castNode(Result, plan), es);
|
||||||
show_upper_qual((List *) ((Result *) plan)->resconstantqual,
|
show_upper_qual((List *) ((Result *) plan)->resconstantqual,
|
||||||
"One-Time Filter", planstate, ancestors, es);
|
"One-Time Filter", planstate, ancestors, es);
|
||||||
show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
|
show_upper_qual(plan->qual, "Filter", planstate, ancestors, es);
|
||||||
@@ -4750,6 +4756,102 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
|
|||||||
ExplainCloseGroup("Target Tables", "Target Tables", false, es);
|
ExplainCloseGroup("Target Tables", "Target Tables", false, es);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Explain what a "Result" node replaced.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
show_result_replacement_info(Result *result, ExplainState *es)
|
||||||
|
{
|
||||||
|
StringInfoData buf;
|
||||||
|
int nrels = 0;
|
||||||
|
int rti = -1;
|
||||||
|
bool found_non_result = false;
|
||||||
|
char *replacement_type = "???";
|
||||||
|
|
||||||
|
/* If the Result node has a subplan, it didn't replace anything. */
|
||||||
|
if (result->plan.lefttree != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Gating result nodes should have a subplan, and we don't. */
|
||||||
|
Assert(result->result_type != RESULT_TYPE_GATING);
|
||||||
|
|
||||||
|
switch (result->result_type)
|
||||||
|
{
|
||||||
|
case RESULT_TYPE_GATING:
|
||||||
|
replacement_type = "Gating";
|
||||||
|
break;
|
||||||
|
case RESULT_TYPE_SCAN:
|
||||||
|
replacement_type = "Scan";
|
||||||
|
break;
|
||||||
|
case RESULT_TYPE_JOIN:
|
||||||
|
replacement_type = "Join";
|
||||||
|
break;
|
||||||
|
case RESULT_TYPE_UPPER:
|
||||||
|
/* a small white lie */
|
||||||
|
replacement_type = "Aggregate";
|
||||||
|
break;
|
||||||
|
case RESULT_TYPE_MINMAX:
|
||||||
|
replacement_type = "MinMaxAggregate";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build up a comma-separated list of user-facing names for the range
|
||||||
|
* table entries in the relids set.
|
||||||
|
*/
|
||||||
|
initStringInfo(&buf);
|
||||||
|
while ((rti = bms_next_member(result->relids, rti)) >= 0)
|
||||||
|
{
|
||||||
|
RangeTblEntry *rte = rt_fetch(rti, es->rtable);
|
||||||
|
char *refname;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add_outer_joins_to_relids will add join RTIs to the relids set of a
|
||||||
|
* join; if that join is then replaced with a Result node, we may see
|
||||||
|
* such RTIs here. But we want to completely ignore those here,
|
||||||
|
* because "a LEFT JOIN b ON whatever" is a join between a and b, not
|
||||||
|
* a join between a, b, and an unnamed join.
|
||||||
|
*/
|
||||||
|
if (rte->rtekind == RTE_JOIN)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Count the number of rels that aren't ignored completely. */
|
||||||
|
++nrels;
|
||||||
|
|
||||||
|
/* Work out what reference name to use and add it to the string. */
|
||||||
|
refname = (char *) list_nth(es->rtable_names, rti - 1);
|
||||||
|
if (refname == NULL)
|
||||||
|
refname = rte->eref->aliasname;
|
||||||
|
if (buf.len > 0)
|
||||||
|
appendStringInfoString(&buf, ", ");
|
||||||
|
appendStringInfoString(&buf, refname);
|
||||||
|
|
||||||
|
/* Keep track of whether we see anything other than RTE_RESULT. */
|
||||||
|
if (rte->rtekind != RTE_RESULT)
|
||||||
|
found_non_result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this Result node is because of a single RTE that is RTE_RESULT, it
|
||||||
|
* is not really replacing anything at all, because there's no other
|
||||||
|
* method for implementing a scan of such an RTE, so we don't display the
|
||||||
|
* Replaces line in such cases.
|
||||||
|
*/
|
||||||
|
if (nrels <= 1 && !found_non_result &&
|
||||||
|
result->result_type == RESULT_TYPE_SCAN)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Say what we replaced, with list of rels if available. */
|
||||||
|
if (buf.len == 0)
|
||||||
|
ExplainPropertyText("Replaces", replacement_type, es);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *s = psprintf("%s on %s", replacement_type, buf.data);
|
||||||
|
|
||||||
|
ExplainPropertyText("Replaces", s, es);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Explain the constituent plans of an Append, MergeAppend,
|
* Explain the constituent plans of an Append, MergeAppend,
|
||||||
* BitmapAnd, or BitmapOr node.
|
* BitmapAnd, or BitmapOr node.
|
||||||
|
@@ -99,7 +99,8 @@ static Gather *create_gather_plan(PlannerInfo *root, GatherPath *best_path);
|
|||||||
static Plan *create_projection_plan(PlannerInfo *root,
|
static Plan *create_projection_plan(PlannerInfo *root,
|
||||||
ProjectionPath *best_path,
|
ProjectionPath *best_path,
|
||||||
int flags);
|
int flags);
|
||||||
static Plan *inject_projection_plan(Plan *subplan, List *tlist, bool parallel_safe);
|
static Plan *inject_projection_plan(Plan *subplan, List *tlist,
|
||||||
|
bool parallel_safe);
|
||||||
static Sort *create_sort_plan(PlannerInfo *root, SortPath *best_path, int flags);
|
static Sort *create_sort_plan(PlannerInfo *root, SortPath *best_path, int flags);
|
||||||
static IncrementalSort *create_incrementalsort_plan(PlannerInfo *root,
|
static IncrementalSort *create_incrementalsort_plan(PlannerInfo *root,
|
||||||
IncrementalSortPath *best_path, int flags);
|
IncrementalSortPath *best_path, int flags);
|
||||||
@@ -302,7 +303,10 @@ static SetOp *make_setop(SetOpCmd cmd, SetOpStrategy strategy,
|
|||||||
List *tlist, Plan *lefttree, Plan *righttree,
|
List *tlist, Plan *lefttree, Plan *righttree,
|
||||||
List *groupList, long numGroups);
|
List *groupList, long numGroups);
|
||||||
static LockRows *make_lockrows(Plan *lefttree, List *rowMarks, int epqParam);
|
static LockRows *make_lockrows(Plan *lefttree, List *rowMarks, int epqParam);
|
||||||
static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
|
static Result *make_gating_result(List *tlist, Node *resconstantqual,
|
||||||
|
Plan *subplan);
|
||||||
|
static Result *make_one_row_result(List *tlist, Node *resconstantqual,
|
||||||
|
RelOptInfo *rel);
|
||||||
static ProjectSet *make_project_set(List *tlist, Plan *subplan);
|
static ProjectSet *make_project_set(List *tlist, Plan *subplan);
|
||||||
static ModifyTable *make_modifytable(PlannerInfo *root, Plan *subplan,
|
static ModifyTable *make_modifytable(PlannerInfo *root, Plan *subplan,
|
||||||
CmdType operation, bool canSetTag,
|
CmdType operation, bool canSetTag,
|
||||||
@@ -1012,35 +1016,35 @@ static Plan *
|
|||||||
create_gating_plan(PlannerInfo *root, Path *path, Plan *plan,
|
create_gating_plan(PlannerInfo *root, Path *path, Plan *plan,
|
||||||
List *gating_quals)
|
List *gating_quals)
|
||||||
{
|
{
|
||||||
Plan *gplan;
|
Result *gplan;
|
||||||
Plan *splan;
|
|
||||||
|
|
||||||
Assert(gating_quals);
|
Assert(gating_quals);
|
||||||
|
|
||||||
/*
|
|
||||||
* We might have a trivial Result plan already. Stacking one Result atop
|
|
||||||
* another is silly, so if that applies, just discard the input plan.
|
|
||||||
* (We're assuming its targetlist is uninteresting; it should be either
|
|
||||||
* the same as the result of build_path_tlist, or a simplified version.)
|
|
||||||
*/
|
|
||||||
splan = plan;
|
|
||||||
if (IsA(plan, Result))
|
|
||||||
{
|
|
||||||
Result *rplan = (Result *) plan;
|
|
||||||
|
|
||||||
if (rplan->plan.lefttree == NULL &&
|
|
||||||
rplan->resconstantqual == NULL)
|
|
||||||
splan = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we need a Result node anyway, always return the path's requested
|
* Since we need a Result node anyway, always return the path's requested
|
||||||
* tlist; that's never a wrong choice, even if the parent node didn't ask
|
* tlist; that's never a wrong choice, even if the parent node didn't ask
|
||||||
* for CP_EXACT_TLIST.
|
* for CP_EXACT_TLIST.
|
||||||
*/
|
*/
|
||||||
gplan = (Plan *) make_result(build_path_tlist(root, path),
|
gplan = make_gating_result(build_path_tlist(root, path),
|
||||||
(Node *) gating_quals,
|
(Node *) gating_quals, plan);
|
||||||
splan);
|
|
||||||
|
/*
|
||||||
|
* We might have had a trivial Result plan already. Stacking one Result
|
||||||
|
* atop another is silly, so if that applies, just discard the input plan.
|
||||||
|
* (We're assuming its targetlist is uninteresting; it should be either
|
||||||
|
* the same as the result of build_path_tlist, or a simplified version.
|
||||||
|
* However, we preserve the set of relids that it purports to scan and
|
||||||
|
* attribute that to our replacement Result instead, and likewise for the
|
||||||
|
* result_type.)
|
||||||
|
*/
|
||||||
|
if (IsA(plan, Result))
|
||||||
|
{
|
||||||
|
Result *rplan = (Result *) plan;
|
||||||
|
|
||||||
|
gplan->plan.lefttree = NULL;
|
||||||
|
gplan->relids = rplan->relids;
|
||||||
|
gplan->result_type = rplan->result_type;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Notice that we don't change cost or size estimates when doing gating.
|
* Notice that we don't change cost or size estimates when doing gating.
|
||||||
@@ -1054,12 +1058,12 @@ create_gating_plan(PlannerInfo *root, Path *path, Plan *plan,
|
|||||||
* in most cases we have only a very bad idea of the probability of the
|
* in most cases we have only a very bad idea of the probability of the
|
||||||
* gating qual being true.
|
* gating qual being true.
|
||||||
*/
|
*/
|
||||||
copy_plan_costsize(gplan, plan);
|
copy_plan_costsize(&gplan->plan, plan);
|
||||||
|
|
||||||
/* Gating quals could be unsafe, so better use the Path's safety flag */
|
/* Gating quals could be unsafe, so better use the Path's safety flag */
|
||||||
gplan->parallel_safe = path->parallel_safe;
|
gplan->plan.parallel_safe = path->parallel_safe;
|
||||||
|
|
||||||
return gplan;
|
return &gplan->plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1235,10 +1239,10 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags)
|
|||||||
/* Generate a Result plan with constant-FALSE gating qual */
|
/* Generate a Result plan with constant-FALSE gating qual */
|
||||||
Plan *plan;
|
Plan *plan;
|
||||||
|
|
||||||
plan = (Plan *) make_result(tlist,
|
plan = (Plan *) make_one_row_result(tlist,
|
||||||
(Node *) list_make1(makeBoolConst(false,
|
(Node *) list_make1(makeBoolConst(false,
|
||||||
false)),
|
false)),
|
||||||
NULL);
|
best_path->path.parent);
|
||||||
|
|
||||||
copy_generic_path_info(plan, (Path *) best_path);
|
copy_generic_path_info(plan, (Path *) best_path);
|
||||||
|
|
||||||
@@ -1636,7 +1640,7 @@ create_group_result_plan(PlannerInfo *root, GroupResultPath *best_path)
|
|||||||
/* best_path->quals is just bare clauses */
|
/* best_path->quals is just bare clauses */
|
||||||
quals = order_qual_clauses(root, best_path->quals);
|
quals = order_qual_clauses(root, best_path->quals);
|
||||||
|
|
||||||
plan = make_result(tlist, (Node *) quals, NULL);
|
plan = make_one_row_result(tlist, (Node *) quals, best_path->path.parent);
|
||||||
|
|
||||||
copy_generic_path_info(&plan->plan, (Path *) best_path);
|
copy_generic_path_info(&plan->plan, (Path *) best_path);
|
||||||
|
|
||||||
@@ -1933,8 +1937,7 @@ create_projection_plan(PlannerInfo *root, ProjectionPath *best_path, int flags)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We need a Result node */
|
plan = (Plan *) make_gating_result(tlist, NULL, subplan);
|
||||||
plan = (Plan *) make_result(tlist, NULL, subplan);
|
|
||||||
|
|
||||||
copy_generic_path_info(plan, (Path *) best_path);
|
copy_generic_path_info(plan, (Path *) best_path);
|
||||||
}
|
}
|
||||||
@@ -1958,7 +1961,7 @@ inject_projection_plan(Plan *subplan, List *tlist, bool parallel_safe)
|
|||||||
{
|
{
|
||||||
Plan *plan;
|
Plan *plan;
|
||||||
|
|
||||||
plan = (Plan *) make_result(tlist, NULL, subplan);
|
plan = (Plan *) make_gating_result(tlist, NULL, subplan);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In principle, we should charge tlist eval cost plus cpu_per_tuple per
|
* In principle, we should charge tlist eval cost plus cpu_per_tuple per
|
||||||
@@ -2436,7 +2439,9 @@ create_minmaxagg_plan(PlannerInfo *root, MinMaxAggPath *best_path)
|
|||||||
/* Generate the output plan --- basically just a Result */
|
/* Generate the output plan --- basically just a Result */
|
||||||
tlist = build_path_tlist(root, &best_path->path);
|
tlist = build_path_tlist(root, &best_path->path);
|
||||||
|
|
||||||
plan = make_result(tlist, (Node *) best_path->quals, NULL);
|
plan = make_one_row_result(tlist, (Node *) best_path->quals,
|
||||||
|
best_path->path.parent);
|
||||||
|
plan->result_type = RESULT_TYPE_MINMAX;
|
||||||
|
|
||||||
copy_generic_path_info(&plan->plan, (Path *) best_path);
|
copy_generic_path_info(&plan->plan, (Path *) best_path);
|
||||||
|
|
||||||
@@ -3887,7 +3892,8 @@ create_resultscan_plan(PlannerInfo *root, Path *best_path,
|
|||||||
replace_nestloop_params(root, (Node *) scan_clauses);
|
replace_nestloop_params(root, (Node *) scan_clauses);
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_plan = make_result(tlist, (Node *) scan_clauses, NULL);
|
scan_plan = make_one_row_result(tlist, (Node *) scan_clauses,
|
||||||
|
best_path->parent);
|
||||||
|
|
||||||
copy_generic_path_info(&scan_plan->plan, best_path);
|
copy_generic_path_info(&scan_plan->plan, best_path);
|
||||||
|
|
||||||
@@ -6922,22 +6928,57 @@ make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* make_result
|
* make_gating_result
|
||||||
* Build a Result plan node
|
* Build a Result plan node that performs projection of a subplan, and/or
|
||||||
|
* applies a one time filter (resconstantqual)
|
||||||
*/
|
*/
|
||||||
static Result *
|
static Result *
|
||||||
make_result(List *tlist,
|
make_gating_result(List *tlist,
|
||||||
Node *resconstantqual,
|
Node *resconstantqual,
|
||||||
Plan *subplan)
|
Plan *subplan)
|
||||||
|
{
|
||||||
|
Result *node = makeNode(Result);
|
||||||
|
Plan *plan = &node->plan;
|
||||||
|
|
||||||
|
Assert(subplan != NULL);
|
||||||
|
|
||||||
|
plan->targetlist = tlist;
|
||||||
|
plan->qual = NIL;
|
||||||
|
plan->lefttree = subplan;
|
||||||
|
plan->righttree = NULL;
|
||||||
|
node->result_type = RESULT_TYPE_GATING;
|
||||||
|
node->resconstantqual = resconstantqual;
|
||||||
|
node->relids = NULL;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* make_one_row_result
|
||||||
|
* Build a Result plan node that returns a single row (or possibly no rows,
|
||||||
|
* if the one-time filtered defined by resconstantqual returns false)
|
||||||
|
*
|
||||||
|
* 'rel' should be this path's RelOptInfo. In essence, we're saying that this
|
||||||
|
* Result node generates all the tuples for that RelOptInfo. Note that the same
|
||||||
|
* consideration can never arise in make_gating_result(), because in that case
|
||||||
|
* the tuples are always coming from some subordinate node.
|
||||||
|
*/
|
||||||
|
static Result *
|
||||||
|
make_one_row_result(List *tlist,
|
||||||
|
Node *resconstantqual,
|
||||||
|
RelOptInfo *rel)
|
||||||
{
|
{
|
||||||
Result *node = makeNode(Result);
|
Result *node = makeNode(Result);
|
||||||
Plan *plan = &node->plan;
|
Plan *plan = &node->plan;
|
||||||
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = NIL;
|
plan->qual = NIL;
|
||||||
plan->lefttree = subplan;
|
plan->lefttree = NULL;
|
||||||
plan->righttree = NULL;
|
plan->righttree = NULL;
|
||||||
|
node->result_type = IS_UPPER_REL(rel) ? RESULT_TYPE_UPPER :
|
||||||
|
IS_JOIN_REL(rel) ? RESULT_TYPE_JOIN : RESULT_TYPE_SCAN;
|
||||||
node->resconstantqual = resconstantqual;
|
node->resconstantqual = resconstantqual;
|
||||||
|
node->relids = rel->relids;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@@ -1056,6 +1056,8 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
|
|||||||
/* resconstantqual can't contain any subplan variable refs */
|
/* resconstantqual can't contain any subplan variable refs */
|
||||||
splan->resconstantqual =
|
splan->resconstantqual =
|
||||||
fix_scan_expr(root, splan->resconstantqual, rtoffset, 1);
|
fix_scan_expr(root, splan->resconstantqual, rtoffset, 1);
|
||||||
|
/* adjust the relids set */
|
||||||
|
splan->relids = offset_relid_set(splan->relids, rtoffset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case T_ProjectSet:
|
case T_ProjectSet:
|
||||||
|
@@ -252,6 +252,20 @@ typedef struct Plan
|
|||||||
#define outerPlan(node) (((Plan *)(node))->lefttree)
|
#define outerPlan(node) (((Plan *)(node))->lefttree)
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* ResultType -
|
||||||
|
* Classification of Result nodes
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
typedef enum ResultType
|
||||||
|
{
|
||||||
|
RESULT_TYPE_GATING, /* project or one-time-filter outer plan */
|
||||||
|
RESULT_TYPE_SCAN, /* replace empty scan */
|
||||||
|
RESULT_TYPE_JOIN, /* replace empty join */
|
||||||
|
RESULT_TYPE_UPPER, /* replace degenerate upper rel */
|
||||||
|
RESULT_TYPE_MINMAX /* implement minmax aggregate */
|
||||||
|
} ResultType;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Result node -
|
* Result node -
|
||||||
* If no outer plan, evaluate a variable-free targetlist.
|
* If no outer plan, evaluate a variable-free targetlist.
|
||||||
@@ -261,12 +275,20 @@ typedef struct Plan
|
|||||||
* If resconstantqual isn't NULL, it represents a one-time qualification
|
* If resconstantqual isn't NULL, it represents a one-time qualification
|
||||||
* test (i.e., one that doesn't depend on any variables from the outer plan,
|
* test (i.e., one that doesn't depend on any variables from the outer plan,
|
||||||
* so needs to be evaluated only once).
|
* so needs to be evaluated only once).
|
||||||
|
*
|
||||||
|
* relids identifies the relation for which this Result node is generating the
|
||||||
|
* tuples. When subplan is not NULL, it should be empty: this node is not
|
||||||
|
* generating anything in that case, just acting on tuples generated by the
|
||||||
|
* subplan. Otherwise, it contains the relids of the planner relation that
|
||||||
|
* the Result represents.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef struct Result
|
typedef struct Result
|
||||||
{
|
{
|
||||||
Plan plan;
|
Plan plan;
|
||||||
|
ResultType result_type;
|
||||||
Node *resconstantqual;
|
Node *resconstantqual;
|
||||||
|
Bitmapset *relids;
|
||||||
} Result;
|
} Result;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@@ -959,11 +959,12 @@ explain (costs off)
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan using tenk1_unique1 on tenk1
|
-> Index Only Scan using tenk1_unique1 on tenk1
|
||||||
Index Cond: (unique1 IS NOT NULL)
|
Index Cond: (unique1 IS NOT NULL)
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
select min(unique1) from tenk1;
|
select min(unique1) from tenk1;
|
||||||
min
|
min
|
||||||
@@ -976,11 +977,12 @@ explain (costs off)
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan Backward using tenk1_unique1 on tenk1
|
-> Index Only Scan Backward using tenk1_unique1 on tenk1
|
||||||
Index Cond: (unique1 IS NOT NULL)
|
Index Cond: (unique1 IS NOT NULL)
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
select max(unique1) from tenk1;
|
select max(unique1) from tenk1;
|
||||||
max
|
max
|
||||||
@@ -993,11 +995,12 @@ explain (costs off)
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan Backward using tenk1_unique1 on tenk1
|
-> Index Only Scan Backward using tenk1_unique1 on tenk1
|
||||||
Index Cond: ((unique1 IS NOT NULL) AND (unique1 < 42))
|
Index Cond: ((unique1 IS NOT NULL) AND (unique1 < 42))
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
select max(unique1) from tenk1 where unique1 < 42;
|
select max(unique1) from tenk1 where unique1 < 42;
|
||||||
max
|
max
|
||||||
@@ -1010,11 +1013,12 @@ explain (costs off)
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan Backward using tenk1_unique1 on tenk1
|
-> Index Only Scan Backward using tenk1_unique1 on tenk1
|
||||||
Index Cond: ((unique1 IS NOT NULL) AND (unique1 > 42))
|
Index Cond: ((unique1 IS NOT NULL) AND (unique1 > 42))
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
select max(unique1) from tenk1 where unique1 > 42;
|
select max(unique1) from tenk1 where unique1 > 42;
|
||||||
max
|
max
|
||||||
@@ -1033,11 +1037,12 @@ explain (costs off)
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan Backward using tenk1_unique1 on tenk1
|
-> Index Only Scan Backward using tenk1_unique1 on tenk1
|
||||||
Index Cond: ((unique1 IS NOT NULL) AND (unique1 > 42000))
|
Index Cond: ((unique1 IS NOT NULL) AND (unique1 > 42000))
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
select max(unique1) from tenk1 where unique1 > 42000;
|
select max(unique1) from tenk1 where unique1 > 42000;
|
||||||
max
|
max
|
||||||
@@ -1052,11 +1057,12 @@ explain (costs off)
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan Backward using tenk1_thous_tenthous on tenk1
|
-> Index Only Scan Backward using tenk1_thous_tenthous on tenk1
|
||||||
Index Cond: ((thousand = 33) AND (tenthous IS NOT NULL))
|
Index Cond: ((thousand = 33) AND (tenthous IS NOT NULL))
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
select max(tenthous) from tenk1 where thousand = 33;
|
select max(tenthous) from tenk1 where thousand = 33;
|
||||||
max
|
max
|
||||||
@@ -1069,11 +1075,12 @@ explain (costs off)
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan using tenk1_thous_tenthous on tenk1
|
-> Index Only Scan using tenk1_thous_tenthous on tenk1
|
||||||
Index Cond: ((thousand = 33) AND (tenthous IS NOT NULL))
|
Index Cond: ((thousand = 33) AND (tenthous IS NOT NULL))
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
select min(tenthous) from tenk1 where thousand = 33;
|
select min(tenthous) from tenk1 where thousand = 33;
|
||||||
min
|
min
|
||||||
@@ -1090,11 +1097,12 @@ explain (costs off)
|
|||||||
Seq Scan on int4_tbl
|
Seq Scan on int4_tbl
|
||||||
SubPlan 2
|
SubPlan 2
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan using tenk1_unique1 on tenk1
|
-> Index Only Scan using tenk1_unique1 on tenk1
|
||||||
Index Cond: ((unique1 IS NOT NULL) AND (unique1 > int4_tbl.f1))
|
Index Cond: ((unique1 IS NOT NULL) AND (unique1 > int4_tbl.f1))
|
||||||
(7 rows)
|
(8 rows)
|
||||||
|
|
||||||
select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt
|
select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt
|
||||||
from int4_tbl;
|
from int4_tbl;
|
||||||
@@ -1119,7 +1127,8 @@ explain (costs off)
|
|||||||
-> Index Only Scan Backward using tenk1_unique2 on tenk1
|
-> Index Only Scan Backward using tenk1_unique2 on tenk1
|
||||||
Index Cond: (unique2 IS NOT NULL)
|
Index Cond: (unique2 IS NOT NULL)
|
||||||
-> Result
|
-> Result
|
||||||
(7 rows)
|
Replaces: MinMaxAggregate
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
select distinct max(unique2) from tenk1;
|
select distinct max(unique2) from tenk1;
|
||||||
max
|
max
|
||||||
@@ -1138,7 +1147,8 @@ explain (costs off)
|
|||||||
-> Index Only Scan Backward using tenk1_unique2 on tenk1
|
-> Index Only Scan Backward using tenk1_unique2 on tenk1
|
||||||
Index Cond: (unique2 IS NOT NULL)
|
Index Cond: (unique2 IS NOT NULL)
|
||||||
-> Result
|
-> Result
|
||||||
(7 rows)
|
Replaces: MinMaxAggregate
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
select max(unique2) from tenk1 order by 1;
|
select max(unique2) from tenk1 order by 1;
|
||||||
max
|
max
|
||||||
@@ -1157,7 +1167,8 @@ explain (costs off)
|
|||||||
-> Index Only Scan Backward using tenk1_unique2 on tenk1
|
-> Index Only Scan Backward using tenk1_unique2 on tenk1
|
||||||
Index Cond: (unique2 IS NOT NULL)
|
Index Cond: (unique2 IS NOT NULL)
|
||||||
-> Result
|
-> Result
|
||||||
(7 rows)
|
Replaces: MinMaxAggregate
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
select max(unique2) from tenk1 order by max(unique2);
|
select max(unique2) from tenk1 order by max(unique2);
|
||||||
max
|
max
|
||||||
@@ -1176,7 +1187,8 @@ explain (costs off)
|
|||||||
-> Index Only Scan Backward using tenk1_unique2 on tenk1
|
-> Index Only Scan Backward using tenk1_unique2 on tenk1
|
||||||
Index Cond: (unique2 IS NOT NULL)
|
Index Cond: (unique2 IS NOT NULL)
|
||||||
-> Result
|
-> Result
|
||||||
(7 rows)
|
Replaces: MinMaxAggregate
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
select max(unique2) from tenk1 order by max(unique2)+1;
|
select max(unique2) from tenk1 order by max(unique2)+1;
|
||||||
max
|
max
|
||||||
@@ -1196,7 +1208,8 @@ explain (costs off)
|
|||||||
Index Cond: (unique2 IS NOT NULL)
|
Index Cond: (unique2 IS NOT NULL)
|
||||||
-> ProjectSet
|
-> ProjectSet
|
||||||
-> Result
|
-> Result
|
||||||
(8 rows)
|
Replaces: MinMaxAggregate
|
||||||
|
(9 rows)
|
||||||
|
|
||||||
select max(unique2), generate_series(1,3) as g from tenk1 order by g desc;
|
select max(unique2), generate_series(1,3) as g from tenk1 order by g desc;
|
||||||
max | g
|
max | g
|
||||||
@@ -1212,12 +1225,13 @@ explain (costs off)
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Result
|
-> Result
|
||||||
One-Time Filter: (100 IS NOT NULL)
|
One-Time Filter: (100 IS NOT NULL)
|
||||||
-> Seq Scan on tenk1
|
-> Seq Scan on tenk1
|
||||||
(6 rows)
|
(7 rows)
|
||||||
|
|
||||||
select max(100) from tenk1;
|
select max(100) from tenk1;
|
||||||
max
|
max
|
||||||
@@ -1243,6 +1257,7 @@ explain (costs off)
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
---------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Merge Append
|
-> Merge Append
|
||||||
@@ -1265,7 +1280,7 @@ explain (costs off)
|
|||||||
-> Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest_8
|
-> Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest_8
|
||||||
Index Cond: (f1 IS NOT NULL)
|
Index Cond: (f1 IS NOT NULL)
|
||||||
-> Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest_9
|
-> Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest_9
|
||||||
(23 rows)
|
(24 rows)
|
||||||
|
|
||||||
select min(f1), max(f1) from minmaxtest;
|
select min(f1), max(f1) from minmaxtest;
|
||||||
min | max
|
min | max
|
||||||
@@ -1304,7 +1319,8 @@ explain (costs off)
|
|||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: ((InitPlan 1).col1), ((InitPlan 2).col1)
|
Sort Key: ((InitPlan 1).col1), ((InitPlan 2).col1)
|
||||||
-> Result
|
-> Result
|
||||||
(26 rows)
|
Replaces: MinMaxAggregate
|
||||||
|
(27 rows)
|
||||||
|
|
||||||
select distinct min(f1), max(f1) from minmaxtest;
|
select distinct min(f1), max(f1) from minmaxtest;
|
||||||
min | max
|
min | max
|
||||||
@@ -1334,7 +1350,8 @@ explain (costs off)
|
|||||||
-> Seq Scan on int4_tbl t1
|
-> Seq Scan on int4_tbl t1
|
||||||
Filter: ((f1 IS NOT NULL) AND (f1 = t0.f1))
|
Filter: ((f1 IS NOT NULL) AND (f1 = t0.f1))
|
||||||
-> Result
|
-> Result
|
||||||
(9 rows)
|
Replaces: MinMaxAggregate
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
select f1, (select distinct min(t1.f1) from int4_tbl t1 where t1.f1 = t0.f1)
|
select f1, (select distinct min(t1.f1) from int4_tbl t1 where t1.f1 = t0.f1)
|
||||||
from int4_tbl t0;
|
from int4_tbl t0;
|
||||||
|
@@ -266,27 +266,30 @@ SELECT *
|
|||||||
-- Tests for constant subexpression simplification
|
-- Tests for constant subexpression simplification
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
SELECT * FROM CASE_TBL WHERE NULLIF(1, 2) = 2;
|
SELECT * FROM CASE_TBL WHERE NULLIF(1, 2) = 2;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on case_tbl
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
SELECT * FROM CASE_TBL WHERE NULLIF(1, 1) IS NOT NULL;
|
SELECT * FROM CASE_TBL WHERE NULLIF(1, 1) IS NOT NULL;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on case_tbl
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
SELECT * FROM CASE_TBL WHERE NULLIF(1, null) = 2;
|
SELECT * FROM CASE_TBL WHERE NULLIF(1, null) = 2;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on case_tbl
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Examples of updates involving tables
|
-- Examples of updates involving tables
|
||||||
|
@@ -54,6 +54,14 @@ set jit = off;
|
|||||||
-- enabled.
|
-- enabled.
|
||||||
set track_io_timing = off;
|
set track_io_timing = off;
|
||||||
-- Simple cases
|
-- Simple cases
|
||||||
|
explain (costs off) select 1 as a, 2 as b having false;
|
||||||
|
QUERY PLAN
|
||||||
|
--------------------------
|
||||||
|
Result
|
||||||
|
Replaces: Aggregate
|
||||||
|
One-Time Filter: false
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
select explain_filter('explain select * from int8_tbl i8');
|
select explain_filter('explain select * from int8_tbl i8');
|
||||||
explain_filter
|
explain_filter
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
|
@@ -1570,17 +1570,18 @@ where coalesce(t2.b, 1) = 2 or t1.a is null;
|
|||||||
-- Ensure that the generation expressions are wrapped into PHVs if needed
|
-- Ensure that the generation expressions are wrapped into PHVs if needed
|
||||||
explain (verbose, costs off)
|
explain (verbose, costs off)
|
||||||
select t2.* from gtest32 t1 left join gtest32 t2 on false;
|
select t2.* from gtest32 t1 left join gtest32 t2 on false;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
Nested Loop Left Join
|
Nested Loop Left Join
|
||||||
Output: a, (a * 2), (20), (COALESCE(a, 100)), e
|
Output: t2.a, (t2.a * 2), (20), (COALESCE(t2.a, 100)), t2.e
|
||||||
Join Filter: false
|
Join Filter: false
|
||||||
-> Seq Scan on generated_virtual_tests.gtest32 t1
|
-> Seq Scan on generated_virtual_tests.gtest32 t1
|
||||||
Output: t1.a, t1.b, t1.c, t1.d, t1.e
|
Output: t1.a, t1.b, t1.c, t1.d, t1.e
|
||||||
-> Result
|
-> Result
|
||||||
Output: a, e, 20, COALESCE(a, 100)
|
Output: t2.a, t2.e, 20, COALESCE(t2.a, 100)
|
||||||
|
Replaces: Scan on t2
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(8 rows)
|
(9 rows)
|
||||||
|
|
||||||
select t2.* from gtest32 t1 left join gtest32 t2 on false;
|
select t2.* from gtest32 t1 left join gtest32 t2 on false;
|
||||||
a | b | c | d | e
|
a | b | c | d | e
|
||||||
@@ -1642,20 +1643,22 @@ set constraint_exclusion to on;
|
|||||||
-- should get a dummy Result, not a seq scan
|
-- should get a dummy Result, not a seq scan
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
select * from gtest33 where b < 10;
|
select * from gtest33 where b < 10;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
-----------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on gtest33
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
-- should get a dummy Result, not a seq scan
|
-- should get a dummy Result, not a seq scan
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
select * from gtest33 where b is null;
|
select * from gtest33 where b is null;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
-----------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on gtest33
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
reset constraint_exclusion;
|
reset constraint_exclusion;
|
||||||
drop table gtest33;
|
drop table gtest33;
|
||||||
|
@@ -591,11 +591,12 @@ explain (costs off)
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan using tenk1_unique1 on tenk1
|
-> Index Only Scan using tenk1_unique1 on tenk1
|
||||||
Index Cond: (unique1 IS NOT NULL)
|
Index Cond: (unique1 IS NOT NULL)
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
-- Views with GROUPING SET queries
|
-- Views with GROUPING SET queries
|
||||||
CREATE VIEW gstest_view AS select a, b, grouping(a,b), sum(c), count(*), max(c)
|
CREATE VIEW gstest_view AS select a, b, grouping(a,b), sum(c), count(*), max(c)
|
||||||
|
@@ -580,8 +580,9 @@ update some_tab set a = a + 1 where false;
|
|||||||
Update on public.some_tab
|
Update on public.some_tab
|
||||||
-> Result
|
-> Result
|
||||||
Output: (some_tab.a + 1), NULL::oid, NULL::tid
|
Output: (some_tab.a + 1), NULL::oid, NULL::tid
|
||||||
|
Replaces: Scan on some_tab
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(4 rows)
|
(5 rows)
|
||||||
|
|
||||||
update some_tab set a = a + 1 where false;
|
update some_tab set a = a + 1 where false;
|
||||||
explain (verbose, costs off)
|
explain (verbose, costs off)
|
||||||
@@ -592,8 +593,9 @@ update some_tab set a = a + 1 where false returning b, a;
|
|||||||
Output: some_tab.b, some_tab.a
|
Output: some_tab.b, some_tab.a
|
||||||
-> Result
|
-> Result
|
||||||
Output: (some_tab.a + 1), NULL::oid, NULL::tid
|
Output: (some_tab.a + 1), NULL::oid, NULL::tid
|
||||||
|
Replaces: Scan on some_tab
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
update some_tab set a = a + 1 where false returning b, a;
|
update some_tab set a = a + 1 where false returning b, a;
|
||||||
b | a
|
b | a
|
||||||
@@ -699,8 +701,9 @@ explain update parted_tab set a = 2 where false;
|
|||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
Update on parted_tab (cost=0.00..0.00 rows=0 width=0)
|
Update on parted_tab (cost=0.00..0.00 rows=0 width=0)
|
||||||
-> Result (cost=0.00..0.00 rows=0 width=10)
|
-> Result (cost=0.00..0.00 rows=0 width=10)
|
||||||
|
Replaces: Scan on parted_tab
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(3 rows)
|
(4 rows)
|
||||||
|
|
||||||
drop table parted_tab;
|
drop table parted_tab;
|
||||||
-- Check UPDATE with multi-level partitioned inherited target
|
-- Check UPDATE with multi-level partitioned inherited target
|
||||||
@@ -1756,6 +1759,7 @@ explain (verbose, costs off) select min(1-id) from matest0;
|
|||||||
---------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
Output: (InitPlan 1).col1
|
Output: (InitPlan 1).col1
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
Output: ((1 - matest0.id))
|
Output: ((1 - matest0.id))
|
||||||
@@ -1779,7 +1783,7 @@ explain (verbose, costs off) select min(1-id) from matest0;
|
|||||||
-> Index Scan using matest3i on public.matest3 matest0_4
|
-> Index Scan using matest3i on public.matest3 matest0_4
|
||||||
Output: matest0_4.id, (1 - matest0_4.id)
|
Output: matest0_4.id, (1 - matest0_4.id)
|
||||||
Index Cond: ((1 - matest0_4.id) IS NOT NULL)
|
Index Cond: ((1 - matest0_4.id) IS NOT NULL)
|
||||||
(25 rows)
|
(26 rows)
|
||||||
|
|
||||||
select min(1-id) from matest0;
|
select min(1-id) from matest0;
|
||||||
min
|
min
|
||||||
@@ -1943,6 +1947,7 @@ SELECT min(x) FROM
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------------------------------------
|
--------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Merge Append
|
-> Merge Append
|
||||||
@@ -1951,7 +1956,7 @@ SELECT min(x) FROM
|
|||||||
Index Cond: (unique1 IS NOT NULL)
|
Index Cond: (unique1 IS NOT NULL)
|
||||||
-> Index Only Scan using tenk1_unique2 on tenk1 b
|
-> Index Only Scan using tenk1_unique2 on tenk1 b
|
||||||
Index Cond: (unique2 IS NOT NULL)
|
Index Cond: (unique2 IS NOT NULL)
|
||||||
(9 rows)
|
(10 rows)
|
||||||
|
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
SELECT min(y) FROM
|
SELECT min(y) FROM
|
||||||
@@ -1961,6 +1966,7 @@ SELECT min(y) FROM
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------------------------------------
|
--------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Merge Append
|
-> Merge Append
|
||||||
@@ -1969,7 +1975,7 @@ SELECT min(y) FROM
|
|||||||
Index Cond: (unique1 IS NOT NULL)
|
Index Cond: (unique1 IS NOT NULL)
|
||||||
-> Index Only Scan using tenk1_unique2 on tenk1 b
|
-> Index Only Scan using tenk1_unique2 on tenk1 b
|
||||||
Index Cond: (unique2 IS NOT NULL)
|
Index Cond: (unique2 IS NOT NULL)
|
||||||
(9 rows)
|
(10 rows)
|
||||||
|
|
||||||
-- XXX planner doesn't recognize that index on unique2 is sufficiently sorted
|
-- XXX planner doesn't recognize that index on unique2 is sufficiently sorted
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
@@ -3087,11 +3093,12 @@ explain (costs off) select * from range_list_parted where a between 3 and 23 and
|
|||||||
|
|
||||||
/* Should select no rows because range partition key cannot be null */
|
/* Should select no rows because range partition key cannot be null */
|
||||||
explain (costs off) select * from range_list_parted where a is null;
|
explain (costs off) select * from range_list_parted where a is null;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
---------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on range_list_parted
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
/* Should only select rows from the null-accepting partition */
|
/* Should only select rows from the null-accepting partition */
|
||||||
explain (costs off) select * from range_list_parted where b is null;
|
explain (costs off) select * from range_list_parted where b is null;
|
||||||
@@ -3252,6 +3259,7 @@ explain (costs off) select min(a), max(a) from parted_minmax where b = '12345';
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan using parted_minmax1i on parted_minmax1 parted_minmax
|
-> Index Only Scan using parted_minmax1i on parted_minmax1 parted_minmax
|
||||||
@@ -3260,7 +3268,7 @@ explain (costs off) select min(a), max(a) from parted_minmax where b = '12345';
|
|||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan Backward using parted_minmax1i on parted_minmax1 parted_minmax_1
|
-> Index Only Scan Backward using parted_minmax1i on parted_minmax1 parted_minmax_1
|
||||||
Index Cond: ((a IS NOT NULL) AND (b = '12345'::text))
|
Index Cond: ((a IS NOT NULL) AND (b = '12345'::text))
|
||||||
(9 rows)
|
(10 rows)
|
||||||
|
|
||||||
select min(a), max(a) from parted_minmax where b = '12345';
|
select min(a), max(a) from parted_minmax where b = '12345';
|
||||||
min | max
|
min | max
|
||||||
|
@@ -2264,11 +2264,12 @@ explain (costs off)
|
|||||||
select aa, bb, unique1, unique1
|
select aa, bb, unique1, unique1
|
||||||
from tenk1 right join b_star on aa = unique1
|
from tenk1 right join b_star on aa = unique1
|
||||||
where bb < bb and bb is null;
|
where bb < bb and bb is null;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
-----------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Join on tenk1, b_star
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
select aa, bb, unique1, unique1
|
select aa, bb, unique1, unique1
|
||||||
from tenk1 right join b_star on aa = unique1
|
from tenk1 right join b_star on aa = unique1
|
||||||
@@ -2386,11 +2387,12 @@ order by t1.unique1;
|
|||||||
Index Cond: (unique1 < 10)
|
Index Cond: (unique1 < 10)
|
||||||
SubPlan 2
|
SubPlan 2
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Only Scan using tenk1_unique1 on tenk1
|
-> Index Only Scan using tenk1_unique1 on tenk1
|
||||||
Index Cond: ((unique1 IS NOT NULL) AND (unique1 = t2.unique1))
|
Index Cond: ((unique1 IS NOT NULL) AND (unique1 = t2.unique1))
|
||||||
(19 rows)
|
(20 rows)
|
||||||
|
|
||||||
-- Ensure we get the expected result
|
-- Ensure we get the expected result
|
||||||
select t1.unique1,t2.unique1 from tenk1 t1
|
select t1.unique1,t2.unique1 from tenk1 t1
|
||||||
@@ -2655,8 +2657,8 @@ select * from int8_tbl t1 left join
|
|||||||
(int8_tbl t2 left join int8_tbl t3 full join int8_tbl t4 on false on false)
|
(int8_tbl t2 left join int8_tbl t3 full join int8_tbl t4 on false on false)
|
||||||
left join int8_tbl t5 on t2.q1 = t5.q1
|
left join int8_tbl t5 on t2.q1 = t5.q1
|
||||||
on t2.q2 = 123;
|
on t2.q2 = 123;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------------------
|
----------------------------------------------------
|
||||||
Nested Loop Left Join
|
Nested Loop Left Join
|
||||||
-> Seq Scan on int8_tbl t1
|
-> Seq Scan on int8_tbl t1
|
||||||
-> Materialize
|
-> Materialize
|
||||||
@@ -2667,9 +2669,10 @@ on t2.q2 = 123;
|
|||||||
-> Seq Scan on int8_tbl t2
|
-> Seq Scan on int8_tbl t2
|
||||||
Filter: (q2 = 123)
|
Filter: (q2 = 123)
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Join on t3, t4
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
-> Seq Scan on int8_tbl t5
|
-> Seq Scan on int8_tbl t5
|
||||||
(12 rows)
|
(13 rows)
|
||||||
|
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
select * from int8_tbl t1
|
select * from int8_tbl t1
|
||||||
@@ -4148,9 +4151,9 @@ select * from t t1
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
Nested Loop Left Join
|
Nested Loop Left Join
|
||||||
Output: t1.i, (1), t2.i2, i3, t4.i4
|
Output: t1.i, (1), t2.i2, t3.i3, t4.i4
|
||||||
-> Nested Loop Left Join
|
-> Nested Loop Left Join
|
||||||
Output: t1.i, t2.i2, (1), i3
|
Output: t1.i, t2.i2, (1), t3.i3
|
||||||
Join Filter: false
|
Join Filter: false
|
||||||
-> Hash Left Join
|
-> Hash Left Join
|
||||||
Output: t1.i, t2.i2, (1)
|
Output: t1.i, t2.i2, (1)
|
||||||
@@ -4163,7 +4166,8 @@ select * from t t1
|
|||||||
-> Seq Scan on pg_temp.t t2
|
-> Seq Scan on pg_temp.t t2
|
||||||
Output: t2.i2, 1
|
Output: t2.i2, 1
|
||||||
-> Result
|
-> Result
|
||||||
Output: i3
|
Output: t3.i3
|
||||||
|
Replaces: Scan on t3
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
-> Memoize
|
-> Memoize
|
||||||
Output: t4.i4
|
Output: t4.i4
|
||||||
@@ -4172,7 +4176,7 @@ select * from t t1
|
|||||||
-> Index Only Scan using t_pkey on pg_temp.t t4
|
-> Index Only Scan using t_pkey on pg_temp.t t4
|
||||||
Output: t4.i4
|
Output: t4.i4
|
||||||
Index Cond: (t4.i4 > (1))
|
Index Cond: (t4.i4 > (1))
|
||||||
(25 rows)
|
(26 rows)
|
||||||
|
|
||||||
explain (verbose, costs off)
|
explain (verbose, costs off)
|
||||||
select * from
|
select * from
|
||||||
@@ -4362,8 +4366,9 @@ from int4_tbl t1
|
|||||||
-------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------
|
||||||
Result
|
Result
|
||||||
Output: (current_database())::information_schema.sql_identifier, (c.relname)::information_schema.sql_identifier
|
Output: (current_database())::information_schema.sql_identifier, (c.relname)::information_schema.sql_identifier
|
||||||
|
Replaces: Join on t1, t2, a, c, nc, t, nt, bt, nbt
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(3 rows)
|
(4 rows)
|
||||||
|
|
||||||
-- Test handling of qual pushdown to appendrel members with non-Var outputs
|
-- Test handling of qual pushdown to appendrel members with non-Var outputs
|
||||||
explain (verbose, costs off)
|
explain (verbose, costs off)
|
||||||
@@ -4436,10 +4441,11 @@ select unique1 from tenk1, lateral f_immutable_int4(1) x where x = unique1;
|
|||||||
explain (costs off)
|
explain (costs off)
|
||||||
select unique1 from tenk1, lateral f_immutable_int4(1) x where x in (select 17);
|
select unique1 from tenk1, lateral f_immutable_int4(1) x where x in (select 17);
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
---------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on tenk1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
select unique1, x from tenk1 join f_immutable_int4(1) x on unique1 = x;
|
select unique1, x from tenk1 join f_immutable_int4(1) x on unique1 = x;
|
||||||
@@ -4486,10 +4492,11 @@ select unique1, x from tenk1 full join f_immutable_int4(1) x on unique1 = x;
|
|||||||
explain (costs off)
|
explain (costs off)
|
||||||
select unique1 from tenk1, f_immutable_int4(1) x where x = 42;
|
select unique1 from tenk1, f_immutable_int4(1) x where x = 42;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
---------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on tenk1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
-- test inlining of immutable functions with PlaceHolderVars
|
-- test inlining of immutable functions with PlaceHolderVars
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
@@ -5345,8 +5352,9 @@ left join
|
|||||||
Join Filter: false
|
Join Filter: false
|
||||||
-> Result
|
-> Result
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Join on c, n
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
-- check handling of apparently-commutable outer joins with non-commutable
|
-- check handling of apparently-commutable outer joins with non-commutable
|
||||||
-- joins between them
|
-- joins between them
|
||||||
@@ -5540,12 +5548,13 @@ select 1 from
|
|||||||
right join (select 1 as z) as ss2 on true)
|
right join (select 1 as z) as ss2 on true)
|
||||||
on false,
|
on false,
|
||||||
lateral (select i4.f1, ss1.n from int8_tbl as i8 limit 1) as ss3;
|
lateral (select i4.f1, ss1.n from int8_tbl as i8 limit 1) as ss3;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
-----------------------------------------------
|
||||||
Result
|
Result
|
||||||
Output: 1
|
Output: 1
|
||||||
|
Replaces: Join on i4, ss3, x1, x2, *RESULT*
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(3 rows)
|
(4 rows)
|
||||||
|
|
||||||
select 1 from
|
select 1 from
|
||||||
int4_tbl as i4
|
int4_tbl as i4
|
||||||
@@ -5574,11 +5583,12 @@ select 1 from t t1
|
|||||||
on false
|
on false
|
||||||
where t3.a = coalesce(t5.a,1)) as s2
|
where t3.a = coalesce(t5.a,1)) as s2
|
||||||
on true;
|
on true;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Join on t1, s1, t2, t3, t4, t5
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
rollback;
|
rollback;
|
||||||
--
|
--
|
||||||
@@ -5975,14 +5985,15 @@ from int4_tbl as t1
|
|||||||
inner join int8_tbl as t7 on null)
|
inner join int8_tbl as t7 on null)
|
||||||
on t5.q1 = t7.q2)
|
on t5.q1 = t7.q2)
|
||||||
on false;
|
on false;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------
|
--------------------------------------------------
|
||||||
Nested Loop Left Join
|
Nested Loop Left Join
|
||||||
Join Filter: false
|
Join Filter: false
|
||||||
-> Seq Scan on int4_tbl t1
|
-> Seq Scan on int4_tbl t1
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Join on t2, t3, t4, t5, t7, t6
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
-- variant with Var rather than PHV coming from t6
|
-- variant with Var rather than PHV coming from t6
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
@@ -5997,14 +6008,15 @@ from int4_tbl as t1
|
|||||||
inner join int8_tbl as t7 on null)
|
inner join int8_tbl as t7 on null)
|
||||||
on t5.q1 = t7.q2)
|
on t5.q1 = t7.q2)
|
||||||
on false;
|
on false;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------
|
--------------------------------------------------
|
||||||
Nested Loop Left Join
|
Nested Loop Left Join
|
||||||
Join Filter: false
|
Join Filter: false
|
||||||
-> Seq Scan on int4_tbl t1
|
-> Seq Scan on int4_tbl t1
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Join on t2, t3, t4, t5, t7, t6
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
-- per further discussion of bug #17781
|
-- per further discussion of bug #17781
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
@@ -6054,15 +6066,16 @@ select * from int8_tbl t1 left join
|
|||||||
(int8_tbl t2 inner join int8_tbl t3 on false
|
(int8_tbl t2 inner join int8_tbl t3 on false
|
||||||
left join int8_tbl t4 on t2.q2 = t4.q2)
|
left join int8_tbl t4 on t2.q2 = t4.q2)
|
||||||
on t1.q1 = t2.q1;
|
on t1.q1 = t2.q1;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------
|
--------------------------------------------
|
||||||
Hash Left Join
|
Hash Left Join
|
||||||
Hash Cond: (t1.q1 = q1)
|
Hash Cond: (t1.q1 = t2.q1)
|
||||||
-> Seq Scan on int8_tbl t1
|
-> Seq Scan on int8_tbl t1
|
||||||
-> Hash
|
-> Hash
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Join on t2, t3, t4
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(6 rows)
|
(7 rows)
|
||||||
|
|
||||||
-- deduce constant-false from an EquivalenceClass
|
-- deduce constant-false from an EquivalenceClass
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
@@ -6070,15 +6083,16 @@ select * from int8_tbl t1 left join
|
|||||||
(int8_tbl t2 inner join int8_tbl t3 on (t2.q1-t3.q2) = 0 and (t2.q1-t3.q2) = 1
|
(int8_tbl t2 inner join int8_tbl t3 on (t2.q1-t3.q2) = 0 and (t2.q1-t3.q2) = 1
|
||||||
left join int8_tbl t4 on t2.q2 = t4.q2)
|
left join int8_tbl t4 on t2.q2 = t4.q2)
|
||||||
on t1.q1 = t2.q1;
|
on t1.q1 = t2.q1;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------
|
--------------------------------------------
|
||||||
Hash Left Join
|
Hash Left Join
|
||||||
Hash Cond: (t1.q1 = q1)
|
Hash Cond: (t1.q1 = t2.q1)
|
||||||
-> Seq Scan on int8_tbl t1
|
-> Seq Scan on int8_tbl t1
|
||||||
-> Hash
|
-> Hash
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Join on t2, t3, t4
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(6 rows)
|
(7 rows)
|
||||||
|
|
||||||
-- pseudoconstant based on an outer-level Param
|
-- pseudoconstant based on an outer-level Param
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
@@ -6317,8 +6331,9 @@ select p.* from
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on p
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
select p.* from
|
select p.* from
|
||||||
(parent p left join child c on (p.k = c.k)) join parent x on p.k = x.k
|
(parent p left join child c on (p.k = c.k)) join parent x on p.k = x.k
|
||||||
@@ -6334,8 +6349,9 @@ select p.* from
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Join on p, x
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
-- bug 5255: this is not optimizable by join removal
|
-- bug 5255: this is not optimizable by join removal
|
||||||
begin;
|
begin;
|
||||||
@@ -6400,15 +6416,16 @@ SELECT q2 FROM
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
Nested Loop Left Join
|
Nested Loop Left Join
|
||||||
Output: q2
|
Output: int8_tbl.q2
|
||||||
Join Filter: NULL::boolean
|
Join Filter: NULL::boolean
|
||||||
Filter: (('constant'::text) >= ('constant'::text))
|
Filter: (('constant'::text) >= ('constant'::text))
|
||||||
-> Seq Scan on public.int4_tbl
|
-> Seq Scan on public.int4_tbl
|
||||||
Output: int4_tbl.f1
|
Output: int4_tbl.f1
|
||||||
-> Result
|
-> Result
|
||||||
Output: q2, 'constant'::text
|
Output: int8_tbl.q2, 'constant'::text
|
||||||
|
Replaces: Scan on int8_tbl
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(9 rows)
|
(10 rows)
|
||||||
|
|
||||||
-- join removal bug #17786: check that OR conditions are cleaned up
|
-- join removal bug #17786: check that OR conditions are cleaned up
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
@@ -6427,8 +6444,9 @@ FROM int4_tbl
|
|||||||
Filter: ((tenk1.unique1 = (42)) OR (tenk1.unique2 = (42)))
|
Filter: ((tenk1.unique1 = (42)) OR (tenk1.unique2 = (42)))
|
||||||
-> Seq Scan on tenk1
|
-> Seq Scan on tenk1
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on int8_tbl
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(9 rows)
|
(10 rows)
|
||||||
|
|
||||||
rollback;
|
rollback;
|
||||||
-- another join removal bug: we must clean up correctly when removing a PHV
|
-- another join removal bug: we must clean up correctly when removing a PHV
|
||||||
@@ -6878,8 +6896,9 @@ where q1.x = q2.y;
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on sj
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
-- We can't use a cross-EC generated self join qual because of current logic of
|
-- We can't use a cross-EC generated self join qual because of current logic of
|
||||||
-- the generate_join_implied_equalities routine.
|
-- the generate_join_implied_equalities routine.
|
||||||
@@ -7703,11 +7722,12 @@ select 1 from emp1 full join
|
|||||||
on true
|
on true
|
||||||
where false) s on true
|
where false) s on true
|
||||||
where false;
|
where false;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
----------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Join on emp1, t1, t3
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
select 1 from emp1 full join
|
select 1 from emp1 full join
|
||||||
(select * from emp1 t1 join
|
(select * from emp1 t1 join
|
||||||
@@ -7936,8 +7956,9 @@ where false;
|
|||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
Output: 1
|
Output: 1
|
||||||
|
Replaces: Scan on ss
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(3 rows)
|
(4 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Test LATERAL
|
-- Test LATERAL
|
||||||
@@ -8866,31 +8887,33 @@ select * from int4_tbl t1,
|
|||||||
explain (verbose, costs off)
|
explain (verbose, costs off)
|
||||||
select * from int8_tbl i8 left join lateral
|
select * from int8_tbl i8 left join lateral
|
||||||
(select *, i8.q2 from int4_tbl where false) ss on true;
|
(select *, i8.q2 from int4_tbl where false) ss on true;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------
|
----------------------------------------------
|
||||||
Nested Loop Left Join
|
Nested Loop Left Join
|
||||||
Output: i8.q1, i8.q2, f1, (i8.q2)
|
Output: i8.q1, i8.q2, int4_tbl.f1, (i8.q2)
|
||||||
Join Filter: false
|
Join Filter: false
|
||||||
-> Seq Scan on public.int8_tbl i8
|
-> Seq Scan on public.int8_tbl i8
|
||||||
Output: i8.q1, i8.q2
|
Output: i8.q1, i8.q2
|
||||||
-> Result
|
-> Result
|
||||||
Output: f1, i8.q2
|
Output: int4_tbl.f1, i8.q2
|
||||||
|
Replaces: Scan on int4_tbl
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(8 rows)
|
(9 rows)
|
||||||
|
|
||||||
explain (verbose, costs off)
|
explain (verbose, costs off)
|
||||||
select * from int8_tbl i8 left join lateral
|
select * from int8_tbl i8 left join lateral
|
||||||
(select *, i8.q2 from int4_tbl i1, int4_tbl i2 where false) ss on true;
|
(select *, i8.q2 from int4_tbl i1, int4_tbl i2 where false) ss on true;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
-----------------------------------------
|
-----------------------------------------------
|
||||||
Nested Loop Left Join
|
Nested Loop Left Join
|
||||||
Output: i8.q1, i8.q2, f1, f1, (i8.q2)
|
Output: i8.q1, i8.q2, i1.f1, i2.f1, (i8.q2)
|
||||||
-> Seq Scan on public.int8_tbl i8
|
-> Seq Scan on public.int8_tbl i8
|
||||||
Output: i8.q1, i8.q2
|
Output: i8.q1, i8.q2
|
||||||
-> Result
|
-> Result
|
||||||
Output: f1, f1, i8.q2
|
Output: i1.f1, i2.f1, i8.q2
|
||||||
|
Replaces: Join on i1, i2
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(7 rows)
|
(8 rows)
|
||||||
|
|
||||||
-- check handling of nested appendrels inside LATERAL
|
-- check handling of nested appendrels inside LATERAL
|
||||||
select * from
|
select * from
|
||||||
|
@@ -2426,8 +2426,9 @@ MERGE INTO pa_target t USING pa_source s ON t.tid = s.sid
|
|||||||
Output: t.tid, t.ctid
|
Output: t.tid, t.ctid
|
||||||
-> Result
|
-> Result
|
||||||
Output: t.tid, t.ctid
|
Output: t.tid, t.ctid
|
||||||
|
Replaces: Scan on t
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(12 rows)
|
(13 rows)
|
||||||
|
|
||||||
MERGE INTO pa_target t USING pa_source s ON t.tid = s.sid
|
MERGE INTO pa_target t USING pa_source s ON t.tid = s.sid
|
||||||
WHEN NOT MATCHED THEN INSERT VALUES (s.sid);
|
WHEN NOT MATCHED THEN INSERT VALUES (s.sid);
|
||||||
|
@@ -146,13 +146,14 @@ SELECT c, a, count(*) FROM pagg_tab GROUP BY a, c;
|
|||||||
-- Test when input relation for grouping is dummy
|
-- Test when input relation for grouping is dummy
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT c, sum(a) FROM pagg_tab WHERE 1 = 2 GROUP BY c;
|
SELECT c, sum(a) FROM pagg_tab WHERE 1 = 2 GROUP BY c;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------
|
------------------------------------
|
||||||
HashAggregate
|
HashAggregate
|
||||||
Group Key: c
|
Group Key: c
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on pagg_tab
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(4 rows)
|
(5 rows)
|
||||||
|
|
||||||
SELECT c, sum(a) FROM pagg_tab WHERE 1 = 2 GROUP BY c;
|
SELECT c, sum(a) FROM pagg_tab WHERE 1 = 2 GROUP BY c;
|
||||||
c | sum
|
c | sum
|
||||||
@@ -161,12 +162,13 @@ SELECT c, sum(a) FROM pagg_tab WHERE 1 = 2 GROUP BY c;
|
|||||||
|
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT c, sum(a) FROM pagg_tab WHERE c = 'x' GROUP BY c;
|
SELECT c, sum(a) FROM pagg_tab WHERE c = 'x' GROUP BY c;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------
|
------------------------------------
|
||||||
GroupAggregate
|
GroupAggregate
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on pagg_tab
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(3 rows)
|
(4 rows)
|
||||||
|
|
||||||
SELECT c, sum(a) FROM pagg_tab WHERE c = 'x' GROUP BY c;
|
SELECT c, sum(a) FROM pagg_tab WHERE c = 'x' GROUP BY c;
|
||||||
c | sum
|
c | sum
|
||||||
@@ -804,15 +806,16 @@ SELECT a.x, b.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x < 20) a FULL JOI
|
|||||||
-- Empty join relation because of empty outer side, no partitionwise agg plan
|
-- Empty join relation because of empty outer side, no partitionwise agg plan
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT a.x, a.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x = 1 AND x = 2) a LEFT JOIN pagg_tab2 b ON a.x = b.y GROUP BY a.x, a.y ORDER BY 1, 2;
|
SELECT a.x, a.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x = 1 AND x = 2) a LEFT JOIN pagg_tab2 b ON a.x = b.y GROUP BY a.x, a.y ORDER BY 1, 2;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------
|
----------------------------------------------
|
||||||
GroupAggregate
|
GroupAggregate
|
||||||
Group Key: pagg_tab1.y
|
Group Key: pagg_tab1.y
|
||||||
-> Sort
|
-> Sort
|
||||||
Sort Key: pagg_tab1.y
|
Sort Key: pagg_tab1.y
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Join on b, pagg_tab1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(6 rows)
|
(7 rows)
|
||||||
|
|
||||||
SELECT a.x, a.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x = 1 AND x = 2) a LEFT JOIN pagg_tab2 b ON a.x = b.y GROUP BY a.x, a.y ORDER BY 1, 2;
|
SELECT a.x, a.y, count(*) FROM (SELECT * FROM pagg_tab1 WHERE x = 1 AND x = 2) a LEFT JOIN pagg_tab2 b ON a.x = b.y GROUP BY a.x, a.y ORDER BY 1, 2;
|
||||||
x | y | count
|
x | y | count
|
||||||
|
@@ -1609,26 +1609,28 @@ SELECT avg(t1.a), avg(t2.b), avg(t3.a + t3.b), t1.c, t2.c, t3.c FROM plt1 t1, pl
|
|||||||
-- joins where one of the relations is proven empty
|
-- joins where one of the relations is proven empty
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a = 1 AND t1.a = 2;
|
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a = 1 AND t1.a = 2;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
----------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Join on t1, t2
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 LEFT JOIN prt2 t2 ON t1.a = t2.b;
|
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 LEFT JOIN prt2 t2 ON t1.a = t2.b;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Join on t2, prt1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b, prt1 t3 WHERE t2.b = t3.a;
|
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b, prt1 t3 WHERE t2.b = t3.a;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
Hash Left Join
|
Hash Left Join
|
||||||
Hash Cond: (t2.b = a)
|
Hash Cond: (t2.b = prt1.a)
|
||||||
-> Append
|
-> Append
|
||||||
-> Hash Join
|
-> Hash Join
|
||||||
Hash Cond: (t3_1.a = t2_1.b)
|
Hash Cond: (t3_1.a = t2_1.b)
|
||||||
@@ -1647,17 +1649,18 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1
|
|||||||
-> Seq Scan on prt2_p3 t2_3
|
-> Seq Scan on prt2_p3 t2_3
|
||||||
-> Hash
|
-> Hash
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on prt1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(21 rows)
|
(22 rows)
|
||||||
|
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b;
|
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
Sort
|
Sort
|
||||||
Sort Key: a, t2.b
|
Sort Key: prt1.a, t2.b
|
||||||
-> Hash Left Join
|
-> Hash Left Join
|
||||||
Hash Cond: (t2.b = a)
|
Hash Cond: (t2.b = prt1.a)
|
||||||
-> Append
|
-> Append
|
||||||
-> Seq Scan on prt2_p1 t2_1
|
-> Seq Scan on prt2_p1 t2_1
|
||||||
Filter: (a = 0)
|
Filter: (a = 0)
|
||||||
@@ -1667,8 +1670,9 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1
|
|||||||
Filter: (a = 0)
|
Filter: (a = 0)
|
||||||
-> Hash
|
-> Hash
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on prt1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(14 rows)
|
(15 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- tests for hash partitioned tables.
|
-- tests for hash partitioned tables.
|
||||||
@@ -2242,10 +2246,10 @@ SELECT COUNT(*) FROM prt1_l t1 LEFT JOIN LATERAL
|
|||||||
-- join with one side empty
|
-- join with one side empty
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c;
|
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.b = t2.a AND t1.c = t2.c;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
-------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------
|
||||||
Hash Left Join
|
Hash Left Join
|
||||||
Hash Cond: ((t2.b = a) AND (t2.a = b) AND ((t2.c)::text = (c)::text))
|
Hash Cond: ((t2.b = prt1_l.a) AND (t2.a = prt1_l.b) AND ((t2.c)::text = (prt1_l.c)::text))
|
||||||
-> Append
|
-> Append
|
||||||
-> Seq Scan on prt2_l_p1 t2_1
|
-> Seq Scan on prt2_l_p1 t2_1
|
||||||
-> Seq Scan on prt2_l_p2_p1 t2_2
|
-> Seq Scan on prt2_l_p2_p1 t2_2
|
||||||
@@ -2254,8 +2258,9 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE a = 1 AND a = 2)
|
|||||||
-> Seq Scan on prt2_l_p3_p2 t2_5
|
-> Seq Scan on prt2_l_p3_p2 t2_5
|
||||||
-> Hash
|
-> Hash
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on prt1_l
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(11 rows)
|
(12 rows)
|
||||||
|
|
||||||
-- Test case to verify proper handling of subqueries in a partitioned delete.
|
-- Test case to verify proper handling of subqueries in a partitioned delete.
|
||||||
-- The weird-looking lateral join is just there to force creation of a
|
-- The weird-looking lateral join is just there to force creation of a
|
||||||
|
@@ -627,8 +627,9 @@ explain (costs off) select * from rlp3 where a = 20; /* empty */
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on rlp3
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
-- redundant clauses are eliminated
|
-- redundant clauses are eliminated
|
||||||
explain (costs off) select * from rlp where a > 1 and a = 10; /* only default */
|
explain (costs off) select * from rlp where a > 1 and a = 10; /* only default */
|
||||||
@@ -670,8 +671,9 @@ explain (costs off) select * from rlp where a = 1 and a = 3; /* empty */
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on rlp
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off) select * from rlp where (a = 1 and a = 3) or (a > 1 and a = 15);
|
explain (costs off) select * from rlp where (a = 1 and a = 3) or (a > 1 and a = 15);
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
@@ -1254,25 +1256,28 @@ select * from boolpart where a is not unknown;
|
|||||||
|
|
||||||
-- check that all partitions are pruned when faced with conflicting clauses
|
-- check that all partitions are pruned when faced with conflicting clauses
|
||||||
explain (costs off) select * from boolpart where a is not unknown and a is unknown;
|
explain (costs off) select * from boolpart where a is not unknown and a is unknown;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on boolpart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off) select * from boolpart where a is false and a is unknown;
|
explain (costs off) select * from boolpart where a is false and a is unknown;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on boolpart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off) select * from boolpart where a is true and a is unknown;
|
explain (costs off) select * from boolpart where a is true and a is unknown;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on boolpart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
-- inverse boolean partitioning - a seemingly unlikely design, but we've got
|
-- inverse boolean partitioning - a seemingly unlikely design, but we've got
|
||||||
-- code for it, so we'd better test it.
|
-- code for it, so we'd better test it.
|
||||||
@@ -1568,11 +1573,12 @@ explain (costs off) select * from coercepart where a = any ('{ab,null}');
|
|||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
explain (costs off) select * from coercepart where a = any (null::text[]);
|
explain (costs off) select * from coercepart where a = any (null::text[]);
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on coercepart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off) select * from coercepart where a = all ('{ab}');
|
explain (costs off) select * from coercepart where a = all ('{ab}');
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
@@ -1582,25 +1588,28 @@ explain (costs off) select * from coercepart where a = all ('{ab}');
|
|||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
explain (costs off) select * from coercepart where a = all ('{ab,bc}');
|
explain (costs off) select * from coercepart where a = all ('{ab,bc}');
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on coercepart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off) select * from coercepart where a = all ('{ab,null}');
|
explain (costs off) select * from coercepart where a = all ('{ab,null}');
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on coercepart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off) select * from coercepart where a = all (null::text[]);
|
explain (costs off) select * from coercepart where a = all (null::text[]);
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on coercepart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
drop table coercepart;
|
drop table coercepart;
|
||||||
CREATE TABLE part (a INT, b INT) PARTITION BY LIST (a);
|
CREATE TABLE part (a INT, b INT) PARTITION BY LIST (a);
|
||||||
@@ -1772,8 +1781,9 @@ explain (costs off) select * from lp where a <> 'a' and a is null;
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on lp
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off) select * from lp where (a <> 'a' and a <> 'd') or a is null;
|
explain (costs off) select * from lp where (a <> 'a' and a <> 'd') or a is null;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
@@ -1866,22 +1876,24 @@ create table lparted_by_int2 (a smallint) partition by list (a);
|
|||||||
create table lparted_by_int2_1 partition of lparted_by_int2 for values in (1);
|
create table lparted_by_int2_1 partition of lparted_by_int2 for values in (1);
|
||||||
create table lparted_by_int2_16384 partition of lparted_by_int2 for values in (16384);
|
create table lparted_by_int2_16384 partition of lparted_by_int2 for values in (16384);
|
||||||
explain (costs off) select * from lparted_by_int2 where a = 100_000_000_000_000;
|
explain (costs off) select * from lparted_by_int2 where a = 100_000_000_000_000;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
-------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on lparted_by_int2
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
create table rparted_by_int2 (a smallint) partition by range (a);
|
create table rparted_by_int2 (a smallint) partition by range (a);
|
||||||
create table rparted_by_int2_1 partition of rparted_by_int2 for values from (1) to (10);
|
create table rparted_by_int2_1 partition of rparted_by_int2 for values from (1) to (10);
|
||||||
create table rparted_by_int2_16384 partition of rparted_by_int2 for values from (10) to (16384);
|
create table rparted_by_int2_16384 partition of rparted_by_int2 for values from (10) to (16384);
|
||||||
-- all partitions pruned
|
-- all partitions pruned
|
||||||
explain (costs off) select * from rparted_by_int2 where a > 100_000_000_000_000;
|
explain (costs off) select * from rparted_by_int2 where a > 100_000_000_000_000;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
-------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on rparted_by_int2
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
create table rparted_by_int2_maxvalue partition of rparted_by_int2 for values from (16384) to (maxvalue);
|
create table rparted_by_int2_maxvalue partition of rparted_by_int2 for values from (16384) to (maxvalue);
|
||||||
-- all partitions but rparted_by_int2_maxvalue pruned
|
-- all partitions but rparted_by_int2_maxvalue pruned
|
||||||
@@ -2131,8 +2143,9 @@ explain (costs off) select * from hp where a = 1 and b = 'abcde' and
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on hp
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Test runtime partition pruning
|
-- Test runtime partition pruning
|
||||||
@@ -3390,11 +3403,12 @@ select * from stable_qual_pruning where a < '2000-02-01'::timestamptz;
|
|||||||
explain (analyze, costs off, summary off, timing off, buffers off)
|
explain (analyze, costs off, summary off, timing off, buffers off)
|
||||||
select * from stable_qual_pruning
|
select * from stable_qual_pruning
|
||||||
where a = any(array['2010-02-01', '2020-01-01']::timestamp[]);
|
where a = any(array['2010-02-01', '2020-01-01']::timestamp[]);
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
-----------------------------------
|
-----------------------------------------
|
||||||
Result (actual rows=0.00 loops=1)
|
Result (actual rows=0.00 loops=1)
|
||||||
|
Replaces: Scan on stable_qual_pruning
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (analyze, costs off, summary off, timing off, buffers off)
|
explain (analyze, costs off, summary off, timing off, buffers off)
|
||||||
select * from stable_qual_pruning
|
select * from stable_qual_pruning
|
||||||
@@ -3642,6 +3656,7 @@ explain (analyze, costs off, summary off, timing off, buffers off) select * from
|
|||||||
Sort Key: ma_test.b
|
Sort Key: ma_test.b
|
||||||
InitPlan 2
|
InitPlan 2
|
||||||
-> Result (actual rows=1.00 loops=1)
|
-> Result (actual rows=1.00 loops=1)
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit (actual rows=1.00 loops=1)
|
-> Limit (actual rows=1.00 loops=1)
|
||||||
-> Index Scan using ma_test_p2_b_idx on ma_test_p2 (actual rows=1.00 loops=1)
|
-> Index Scan using ma_test_p2_b_idx on ma_test_p2 (actual rows=1.00 loops=1)
|
||||||
@@ -3656,7 +3671,7 @@ explain (analyze, costs off, summary off, timing off, buffers off) select * from
|
|||||||
-> Index Scan using ma_test_p3_b_idx on ma_test_p3 ma_test_3 (actual rows=10.00 loops=1)
|
-> Index Scan using ma_test_p3_b_idx on ma_test_p3 ma_test_3 (actual rows=10.00 loops=1)
|
||||||
Filter: (a >= (InitPlan 2).col1)
|
Filter: (a >= (InitPlan 2).col1)
|
||||||
Index Searches: 1
|
Index Searches: 1
|
||||||
(18 rows)
|
(19 rows)
|
||||||
|
|
||||||
reset enable_seqscan;
|
reset enable_seqscan;
|
||||||
reset enable_sort;
|
reset enable_sort;
|
||||||
@@ -3678,11 +3693,12 @@ explain (costs off) select * from pp_arrpart where a = '{1}';
|
|||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
explain (costs off) select * from pp_arrpart where a = '{1, 2}';
|
explain (costs off) select * from pp_arrpart where a = '{1, 2}';
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on pp_arrpart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off) select * from pp_arrpart where a in ('{4, 5}', '{1}');
|
explain (costs off) select * from pp_arrpart where a in ('{4, 5}', '{1}');
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
@@ -3764,11 +3780,12 @@ explain (costs off) select * from pp_enumpart where a = 'blue';
|
|||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
explain (costs off) select * from pp_enumpart where a = 'black';
|
explain (costs off) select * from pp_enumpart where a = 'black';
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
---------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on pp_enumpart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
drop table pp_enumpart;
|
drop table pp_enumpart;
|
||||||
drop type pp_colors;
|
drop type pp_colors;
|
||||||
@@ -3785,11 +3802,12 @@ explain (costs off) select * from pp_recpart where a = '(1,1)'::pp_rectype;
|
|||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
explain (costs off) select * from pp_recpart where a = '(1,2)'::pp_rectype;
|
explain (costs off) select * from pp_recpart where a = '(1,2)'::pp_rectype;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on pp_recpart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
drop table pp_recpart;
|
drop table pp_recpart;
|
||||||
drop type pp_rectype;
|
drop type pp_rectype;
|
||||||
@@ -3805,11 +3823,12 @@ explain (costs off) select * from pp_intrangepart where a = '[1,2]'::int4range;
|
|||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
explain (costs off) select * from pp_intrangepart where a = '(1,2)'::int4range;
|
explain (costs off) select * from pp_intrangepart where a = '(1,2)'::int4range;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
-------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on pp_intrangepart
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
drop table pp_intrangepart;
|
drop table pp_intrangepart;
|
||||||
--
|
--
|
||||||
@@ -4125,19 +4144,21 @@ explain (costs off) update listp1 set a = 1 where a = 2;
|
|||||||
-- constraint exclusion enabled
|
-- constraint exclusion enabled
|
||||||
set constraint_exclusion to 'on';
|
set constraint_exclusion to 'on';
|
||||||
explain (costs off) select * from listp1 where a = 2;
|
explain (costs off) select * from listp1 where a = 2;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
----------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on listp1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off) update listp1 set a = 1 where a = 2;
|
explain (costs off) update listp1 set a = 1 where a = 2;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------
|
----------------------------------
|
||||||
Update on listp1
|
Update on listp1
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on listp1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(3 rows)
|
(4 rows)
|
||||||
|
|
||||||
reset constraint_exclusion;
|
reset constraint_exclusion;
|
||||||
reset enable_partition_pruning;
|
reset enable_partition_pruning;
|
||||||
@@ -4524,18 +4545,20 @@ create table hp_contradict_test (a int, b int) partition by hash (a part_test_in
|
|||||||
create table hp_contradict_test_p1 partition of hp_contradict_test for values with (modulus 2, remainder 0);
|
create table hp_contradict_test_p1 partition of hp_contradict_test for values with (modulus 2, remainder 0);
|
||||||
create table hp_contradict_test_p2 partition of hp_contradict_test for values with (modulus 2, remainder 1);
|
create table hp_contradict_test_p2 partition of hp_contradict_test for values with (modulus 2, remainder 1);
|
||||||
explain (costs off) select * from hp_contradict_test where a is null and a === 1 and b === 1;
|
explain (costs off) select * from hp_contradict_test where a is null and a === 1 and b === 1;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
----------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on hp_contradict_test
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
explain (costs off) select * from hp_contradict_test where a === 1 and b === 1 and a is null;
|
explain (costs off) select * from hp_contradict_test where a === 1 and b === 1 and a is null;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
----------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on hp_contradict_test
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
drop table hp_contradict_test;
|
drop table hp_contradict_test;
|
||||||
drop operator class part_test_int4_ops2 using hash;
|
drop operator class part_test_int4_ops2 using hash;
|
||||||
|
@@ -36,8 +36,9 @@ SELECT * FROM pred_tab t WHERE t.a IS NULL;
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on t
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
-- Ensure the IS_NULL qual is not reduced to constant-FALSE on nullable
|
-- Ensure the IS_NULL qual is not reduced to constant-FALSE on nullable
|
||||||
-- columns
|
-- columns
|
||||||
@@ -77,8 +78,9 @@ SELECT * FROM pred_tab t WHERE t.a IS NULL OR t.c IS NULL;
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on t
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
-- Ensure the OR clause is not reduced to constant-FALSE when not all branches
|
-- Ensure the OR clause is not reduced to constant-FALSE when not all branches
|
||||||
-- are provably false
|
-- are provably false
|
||||||
@@ -139,8 +141,9 @@ SELECT * FROM pred_tab t1
|
|||||||
Join Filter: false
|
Join Filter: false
|
||||||
-> Seq Scan on pred_tab t1
|
-> Seq Scan on pred_tab t1
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on t2
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
-- Ensure the IS_NULL qual is not reduced to constant-FALSE when the column is
|
-- Ensure the IS_NULL qual is not reduced to constant-FALSE when the column is
|
||||||
-- nullable by an outer join
|
-- nullable by an outer join
|
||||||
@@ -209,8 +212,9 @@ SELECT * FROM pred_tab t1
|
|||||||
Join Filter: false
|
Join Filter: false
|
||||||
-> Seq Scan on pred_tab t1
|
-> Seq Scan on pred_tab t1
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on t2
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(5 rows)
|
(6 rows)
|
||||||
|
|
||||||
-- Ensure the OR clause is not reduced to constant-FALSE when a column is
|
-- Ensure the OR clause is not reduced to constant-FALSE when a column is
|
||||||
-- made nullable from an outer join
|
-- made nullable from an outer join
|
||||||
@@ -267,17 +271,18 @@ SELECT * FROM pred_tab t1
|
|||||||
LEFT JOIN pred_tab t2 ON EXISTS
|
LEFT JOIN pred_tab t2 ON EXISTS
|
||||||
(SELECT 1 FROM pred_tab t3, pred_tab t4, pred_tab t5, pred_tab t6
|
(SELECT 1 FROM pred_tab t3, pred_tab t4, pred_tab t5, pred_tab t6
|
||||||
WHERE t1.a = t3.a AND t6.a IS NULL);
|
WHERE t1.a = t3.a AND t6.a IS NULL);
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
-------------------------------------
|
--------------------------------------------
|
||||||
Nested Loop Left Join
|
Nested Loop Left Join
|
||||||
Join Filter: (InitPlan 1).col1
|
Join Filter: (InitPlan 1).col1
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Join on t3, t4, t5, t6
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
-> Seq Scan on pred_tab t1
|
-> Seq Scan on pred_tab t1
|
||||||
-> Materialize
|
-> Materialize
|
||||||
-> Seq Scan on pred_tab t2
|
-> Seq Scan on pred_tab t2
|
||||||
(8 rows)
|
(9 rows)
|
||||||
|
|
||||||
DROP TABLE pred_tab;
|
DROP TABLE pred_tab;
|
||||||
-- Validate we handle IS NULL and IS NOT NULL quals correctly with inheritance
|
-- Validate we handle IS NULL and IS NOT NULL quals correctly with inheritance
|
||||||
@@ -418,20 +423,22 @@ SET constraint_exclusion TO ON;
|
|||||||
-- Ensure that we get a dummy plan
|
-- Ensure that we get a dummy plan
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT * FROM pred_tab1, pred_tab2 WHERE pred_tab2.a IS NULL;
|
SELECT * FROM pred_tab1, pred_tab2 WHERE pred_tab2.a IS NULL;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Join on pred_tab1, pred_tab2
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
-- Ensure that we get a dummy plan
|
-- Ensure that we get a dummy plan
|
||||||
EXPLAIN (COSTS OFF)
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT * FROM pred_tab2, pred_tab1 WHERE pred_tab1.a IS NULL OR pred_tab1.b < 2;
|
SELECT * FROM pred_tab2, pred_tab1 WHERE pred_tab1.a IS NULL OR pred_tab1.b < 2;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
------------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Join on pred_tab2, pred_tab1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
RESET constraint_exclusion;
|
RESET constraint_exclusion;
|
||||||
DROP TABLE pred_tab1;
|
DROP TABLE pred_tab1;
|
||||||
|
@@ -3606,8 +3606,9 @@ EXPLAIN (COSTS OFF) SELECT * FROM t1;
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on t1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
SET SESSION AUTHORIZATION regress_rls_bob;
|
SET SESSION AUTHORIZATION regress_rls_bob;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
@@ -3619,8 +3620,9 @@ EXPLAIN (COSTS OFF) SELECT * FROM t1;
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on t1
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- COPY TO/FROM
|
-- COPY TO/FROM
|
||||||
@@ -4524,11 +4526,12 @@ SELECT * FROM rls_tbl WHERE a <<< 1000;
|
|||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
EXPLAIN (COSTS OFF) SELECT * FROM rls_tbl WHERE a <<< 1000 or a <<< 900;
|
EXPLAIN (COSTS OFF) SELECT * FROM rls_tbl WHERE a <<< 1000 or a <<< 900;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
-----------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on rls_tbl
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
RESET SESSION AUTHORIZATION;
|
RESET SESSION AUTHORIZATION;
|
||||||
CREATE TABLE rls_child_tbl () INHERITS (rls_tbl);
|
CREATE TABLE rls_child_tbl () INHERITS (rls_tbl);
|
||||||
|
@@ -1325,8 +1325,9 @@ where false;
|
|||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
Output: (a).f1, (a).f2
|
Output: (a).f1, (a).f2
|
||||||
|
Replaces: Scan on ss
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(3 rows)
|
(4 rows)
|
||||||
|
|
||||||
explain (verbose, costs off)
|
explain (verbose, costs off)
|
||||||
with cte(c) as materialized (select row(1, 2)),
|
with cte(c) as materialized (select row(1, 2)),
|
||||||
@@ -1350,11 +1351,12 @@ where false;
|
|||||||
-----------------------------------
|
-----------------------------------
|
||||||
Result
|
Result
|
||||||
Output: (cte.c).f1
|
Output: (cte.c).f1
|
||||||
|
Replaces: Scan on cte
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
CTE cte
|
CTE cte
|
||||||
-> Result
|
-> Result
|
||||||
Output: '(1,2)'::record
|
Output: '(1,2)'::record
|
||||||
(6 rows)
|
(7 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Tests for component access / FieldSelect
|
-- Tests for component access / FieldSelect
|
||||||
|
@@ -962,10 +962,11 @@ create table list_parted_tbl (a int,b int) partition by list (a);
|
|||||||
create table list_parted_tbl1 partition of list_parted_tbl
|
create table list_parted_tbl1 partition of list_parted_tbl
|
||||||
for values in (1) partition by list(b);
|
for values in (1) partition by list(b);
|
||||||
explain (costs off) select * from list_parted_tbl;
|
explain (costs off) select * from list_parted_tbl;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
-------------------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on list_parted_tbl
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
drop table list_parted_tbl;
|
drop table list_parted_tbl;
|
||||||
|
@@ -1998,17 +1998,18 @@ create temp table json_tab (a int);
|
|||||||
insert into json_tab values (1);
|
insert into json_tab values (1);
|
||||||
explain (verbose, costs off)
|
explain (verbose, costs off)
|
||||||
select * from json_tab t1 left join (select json_array(1, a) from json_tab t2) s on false;
|
select * from json_tab t1 left join (select json_array(1, a) from json_tab t2) s on false;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
---------------------------------------------------
|
------------------------------------------------------
|
||||||
Nested Loop Left Join
|
Nested Loop Left Join
|
||||||
Output: t1.a, (JSON_ARRAY(1, a RETURNING json))
|
Output: t1.a, (JSON_ARRAY(1, t2.a RETURNING json))
|
||||||
Join Filter: false
|
Join Filter: false
|
||||||
-> Seq Scan on pg_temp.json_tab t1
|
-> Seq Scan on pg_temp.json_tab t1
|
||||||
Output: t1.a
|
Output: t1.a
|
||||||
-> Result
|
-> Result
|
||||||
Output: JSON_ARRAY(1, a RETURNING json)
|
Output: JSON_ARRAY(1, t2.a RETURNING json)
|
||||||
|
Replaces: Scan on t2
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(8 rows)
|
(9 rows)
|
||||||
|
|
||||||
select * from json_tab t1 left join (select json_array(1, a) from json_tab t2) s on false;
|
select * from json_tab t1 left join (select json_array(1, a) from json_tab t2) s on false;
|
||||||
a | json_array
|
a | json_array
|
||||||
@@ -2899,12 +2900,13 @@ ON B.hundred in (SELECT min(c.hundred) FROM tenk2 C WHERE c.odd = b.odd);
|
|||||||
-> Subquery Scan on unnamed_subquery
|
-> Subquery Scan on unnamed_subquery
|
||||||
Filter: (b.hundred = unnamed_subquery.min)
|
Filter: (b.hundred = unnamed_subquery.min)
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: MinMaxAggregate
|
||||||
InitPlan 1
|
InitPlan 1
|
||||||
-> Limit
|
-> Limit
|
||||||
-> Index Scan using tenk2_hundred on tenk2 c
|
-> Index Scan using tenk2_hundred on tenk2 c
|
||||||
Index Cond: (hundred IS NOT NULL)
|
Index Cond: (hundred IS NOT NULL)
|
||||||
Filter: (odd = b.odd)
|
Filter: (odd = b.odd)
|
||||||
(16 rows)
|
(17 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Test VALUES to ARRAY (VtA) transformation
|
-- Test VALUES to ARRAY (VtA) transformation
|
||||||
@@ -3067,8 +3069,9 @@ EXPLAIN (COSTS OFF) EXECUTE test(NULL, 3.14, NULL);
|
|||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------
|
--------------------------
|
||||||
Result
|
Result
|
||||||
|
Replaces: Scan on onek
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(2 rows)
|
(3 rows)
|
||||||
|
|
||||||
EXPLAIN (COSTS OFF) EXECUTE test(NULL, 3.14, '-1.5');
|
EXPLAIN (COSTS OFF) EXECUTE test(NULL, 3.14, '-1.5');
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
|
@@ -91,8 +91,9 @@ SELECT unnest(ARRAY[1, 2]) FROM few WHERE false;
|
|||||||
ProjectSet
|
ProjectSet
|
||||||
Output: unnest('{1,2}'::integer[])
|
Output: unnest('{1,2}'::integer[])
|
||||||
-> Result
|
-> Result
|
||||||
|
Replaces: Scan on few
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(4 rows)
|
(5 rows)
|
||||||
|
|
||||||
SELECT unnest(ARRAY[1, 2]) FROM few WHERE false;
|
SELECT unnest(ARRAY[1, 2]) FROM few WHERE false;
|
||||||
unnest
|
unnest
|
||||||
@@ -107,8 +108,9 @@ SELECT * FROM few f1,
|
|||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
Result
|
Result
|
||||||
Output: f1.id, f1.dataa, f1.datab, ss.unnest
|
Output: f1.id, f1.dataa, f1.datab, ss.unnest
|
||||||
|
Replaces: Join on f1, ss
|
||||||
One-Time Filter: false
|
One-Time Filter: false
|
||||||
(3 rows)
|
(4 rows)
|
||||||
|
|
||||||
SELECT * FROM few f1,
|
SELECT * FROM few f1,
|
||||||
(SELECT unnest(ARRAY[1,2]) FROM few f2 WHERE false OFFSET 0) ss;
|
(SELECT unnest(ARRAY[1,2]) FROM few f2 WHERE false OFFSET 0) ss;
|
||||||
|
@@ -61,6 +61,7 @@ set track_io_timing = off;
|
|||||||
|
|
||||||
-- Simple cases
|
-- Simple cases
|
||||||
|
|
||||||
|
explain (costs off) select 1 as a, 2 as b having false;
|
||||||
select explain_filter('explain select * from int8_tbl i8');
|
select explain_filter('explain select * from int8_tbl i8');
|
||||||
select explain_filter('explain (analyze, buffers off) select * from int8_tbl i8');
|
select explain_filter('explain (analyze, buffers off) select * from int8_tbl i8');
|
||||||
select explain_filter('explain (analyze, buffers off, verbose) select * from int8_tbl i8');
|
select explain_filter('explain (analyze, buffers off, verbose) select * from int8_tbl i8');
|
||||||
|
@@ -2568,6 +2568,7 @@ RestrictInfo
|
|||||||
Result
|
Result
|
||||||
ResultRelInfo
|
ResultRelInfo
|
||||||
ResultState
|
ResultState
|
||||||
|
ResultType
|
||||||
RetainDeadTuplesData
|
RetainDeadTuplesData
|
||||||
RetainDeadTuplesPhase
|
RetainDeadTuplesPhase
|
||||||
ReturnSetInfo
|
ReturnSetInfo
|
||||||
|
Reference in New Issue
Block a user