!1672 exists子查询中存在limit const时可简化忽略

Merge pull request !1672 from 胡正超/subexists
This commit is contained in:
opengauss-bot
2022-07-08 08:37:01 +00:00
committed by Gitee
3 changed files with 94 additions and 6 deletions

View File

@ -100,7 +100,7 @@ static Node* convert_testexpr_mutator(Node* node, convert_testexpr_context* cont
static bool subplan_is_hashable(Plan* plan);
static bool testexpr_is_hashable(Node* testexpr);
static bool hash_ok_operator(OpExpr* expr);
static bool simplify_EXISTS_query(Query* query);
static bool simplify_EXISTS_query(PlannerInfo* root, Query* query);
static Query* convert_EXISTS_to_ANY(PlannerInfo* root, Query* subselect, Node** testexpr, List** paramIds);
static Node* replace_correlation_vars_mutator(Node* node, PlannerInfo* root);
static Node* process_sublinks_mutator(Node* node, process_sublinks_context* context);
@ -604,7 +604,7 @@ static Node* make_subplan(
* If it's an EXISTS subplan, we might be able to simplify it.
*/
if (subLinkType == EXISTS_SUBLINK)
simple_exists = simplify_EXISTS_query(subquery);
simple_exists = simplify_EXISTS_query(root, subquery);
/*
* For an EXISTS subplan, tell lower-level planner to expect that only the
@ -687,7 +687,7 @@ static Node* make_subplan(
/* Make a second copy of the original subquery */
subquery = (Query*)copyObject(orig_subquery);
/* and re-simplify */
simple_exists = simplify_EXISTS_query(subquery);
simple_exists = simplify_EXISTS_query(root, subquery);
if (!simple_exists)
ereport(ERROR,
(errmodule(MOD_OPT),
@ -2156,7 +2156,7 @@ JoinExpr* convert_EXISTS_sublink_to_join(PlannerInfo* root, SubLink* sublink, bo
* targetlist, we have to fail, because the pullup operation leaves us
* with noplace to evaluate the targetlist.
*/
if (!simplify_EXISTS_query(subselect))
if (!simplify_EXISTS_query(root, subselect))
return NULL;
/*
@ -2288,7 +2288,7 @@ JoinExpr* convert_EXISTS_sublink_to_join(PlannerInfo* root, SubLink* sublink, bo
*
* Returns TRUE if was able to discard the targetlist, else FALSE.
*/
static bool simplify_EXISTS_query(Query* query)
static bool simplify_EXISTS_query(PlannerInfo *root, Query* query)
{
/*
* We don't try to simplify at all if the query uses set operations,
@ -2300,9 +2300,42 @@ static bool simplify_EXISTS_query(Query* query)
*/
if (query->commandType != CMD_SELECT || query->setOperations || query->hasAggs || query->groupingSets ||
query->hasWindowFuncs || query->hasModifyingCTE || query->havingQual || query->limitOffset ||
query->limitCount || query->rowMarks)
query->rowMarks)
return false;
/*
* LIMIT with a constant positive (or NULL) value doesn't affect the
* semantics of EXISTS, so let's ignore such clauses. This is worth doing
* because people accustomed to certain other DBMSes may be in the habit
* of writing EXISTS(SELECT ... LIMIT 1) as an optimization. If there's a
* LIMIT with anything else as argument, though, we can't simplify.
*/
if (query->limitCount) {
/*
* The LIMIT clause has not yet been through eval_const_expressions,
* so we have to apply that here. It might seem like this is a waste
* of cycles, since the only case plausibly worth worrying about is
* "LIMIT 1" ... but what we'll actually see is "LIMIT int8(1::int4)",
* so we have to fold constants or we're not going to recognize it.
*/
Node* node = eval_const_expressions(root, query->limitCount);
Const* limit = NULL;
/* Might as well update the query if we simplified the clause. */
query->limitCount = node;
if (!IsA(node, Const))
return false;
limit = (Const*)node;
Assert(limit->consttype == INT8OID);
if (!limit->constisnull && DatumGetInt64(limit->constvalue) <= 0)
return false;
/* Whether or not the targetlist is safe, we can drop the LIMIT. */
query->limitCount = NULL;
}
/*
* Mustn't throw away the targetlist if it contains set-returning
* functions; those could affect whether zero rows are returned!

View File

@ -431,6 +431,48 @@ WHERE 1=0);
1
(6 rows)
--
-- Check EXISTS simplification with LIMIT
--
explain (costs off)
select * from int4_tbl o where exists
(select 1 from int4_tbl i where i.f1=o.f1 limit null);
QUERY PLAN
------------------------------------------
Hash Join
Hash Cond: (o.f1 = i.f1)
-> Seq Scan on int4_tbl o
-> Hash
-> HashAggregate
Group By Key: i.f1
-> Seq Scan on int4_tbl i
(7 rows)
explain (costs off)
select * from int4_tbl o where not exists
(select 1 from int4_tbl i where i.f1=o.f1 limit 1);
QUERY PLAN
------------------------------------
Hash Anti Join
Hash Cond: (o.f1 = i.f1)
-> Seq Scan on int4_tbl o
-> Hash
-> Seq Scan on int4_tbl i
(5 rows)
explain (costs off)
select * from int4_tbl o where exists
(select 1 from int4_tbl i where i.f1=o.f1 limit 0);
QUERY PLAN
--------------------------------------
Seq Scan on int4_tbl o
Filter: (SubPlan 1)
SubPlan 1
-> Limit
-> Seq Scan on int4_tbl i
Filter: (f1 = o.f1)
(6 rows)
drop table if exists location_type cascade;
drop table if exists item_inventory_plan cascade;
NOTICE: drop cascades to view usview03

View File

@ -338,6 +338,19 @@ SELECT 'z'
FROM location_type
WHERE 1=0);
--
-- Check EXISTS simplification with LIMIT
--
explain (costs off)
select * from int4_tbl o where exists
(select 1 from int4_tbl i where i.f1=o.f1 limit null);
explain (costs off)
select * from int4_tbl o where not exists
(select 1 from int4_tbl i where i.f1=o.f1 limit 1);
explain (costs off)
select * from int4_tbl o where exists
(select 1 from int4_tbl i where i.f1=o.f1 limit 0);
drop table if exists location_type cascade;
drop table if exists item_inventory_plan cascade;