@@ -70,7 +70,7 @@ static Node *convert_testexpr_mutator(Node *node,
70
70
static bool subplan_is_hashable (Plan * plan );
71
71
static bool testexpr_is_hashable (Node * testexpr );
72
72
static bool hash_ok_operator (OpExpr * expr );
73
- static bool simplify_EXISTS_query (Query * query );
73
+ static bool simplify_EXISTS_query (PlannerInfo * root , Query * query );
74
74
static Query * convert_EXISTS_to_ANY (PlannerInfo * root , Query * subselect ,
75
75
Node * * testexpr , List * * paramIds );
76
76
static Node * replace_correlation_vars_mutator (Node * node , PlannerInfo * root );
@@ -452,7 +452,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
452
452
* If it's an EXISTS subplan, we might be able to simplify it.
453
453
*/
454
454
if (subLinkType == EXISTS_SUBLINK )
455
- simple_exists = simplify_EXISTS_query (subquery );
455
+ simple_exists = simplify_EXISTS_query (root , subquery );
456
456
457
457
/*
458
458
* For an EXISTS subplan, tell lower-level planner to expect that only the
@@ -518,7 +518,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
518
518
/* Make a second copy of the original subquery */
519
519
subquery = (Query * ) copyObject (orig_subquery );
520
520
/* and re-simplify */
521
- simple_exists = simplify_EXISTS_query (subquery );
521
+ simple_exists = simplify_EXISTS_query (root , subquery );
522
522
Assert (simple_exists );
523
523
/* See if it can be converted to an ANY query */
524
524
subquery = convert_EXISTS_to_ANY (root , subquery ,
@@ -1359,7 +1359,7 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
1359
1359
* targetlist, we have to fail, because the pullup operation leaves us
1360
1360
* with noplace to evaluate the targetlist.
1361
1361
*/
1362
- if (!simplify_EXISTS_query (subselect ))
1362
+ if (!simplify_EXISTS_query (root , subselect ))
1363
1363
return NULL ;
1364
1364
1365
1365
/*
@@ -1486,13 +1486,14 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
1486
1486
* Returns TRUE if was able to discard the targetlist, else FALSE.
1487
1487
*/
1488
1488
static bool
1489
- simplify_EXISTS_query (Query * query )
1489
+ simplify_EXISTS_query (PlannerInfo * root , Query * query )
1490
1490
{
1491
1491
/*
1492
1492
* We don't try to simplify at all if the query uses set operations,
1493
- * aggregates, modifying CTEs, HAVING, LIMIT/OFFSET, or FOR UPDATE/SHARE;
1494
- * none of these seem likely in normal usage and their possible effects
1495
- * are complex.
1493
+ * aggregates, modifying CTEs, HAVING, OFFSET, or FOR UPDATE/SHARE; none
1494
+ * of these seem likely in normal usage and their possible effects are
1495
+ * complex. (Note: we could ignore an "OFFSET 0" clause, but that
1496
+ * traditionally is used as an optimization fence, so we don't.)
1496
1497
*/
1497
1498
if (query -> commandType != CMD_SELECT ||
1498
1499
query -> setOperations ||
@@ -1501,10 +1502,43 @@ simplify_EXISTS_query(Query *query)
1501
1502
query -> hasModifyingCTE ||
1502
1503
query -> havingQual ||
1503
1504
query -> limitOffset ||
1504
- query -> limitCount ||
1505
1505
query -> rowMarks )
1506
1506
return false;
1507
1507
1508
+ /*
1509
+ * LIMIT with a constant positive (or NULL) value doesn't affect the
1510
+ * semantics of EXISTS, so let's ignore such clauses. This is worth doing
1511
+ * because people accustomed to certain other DBMSes may be in the habit
1512
+ * of writing EXISTS(SELECT ... LIMIT 1) as an optimization. If there's a
1513
+ * LIMIT with anything else as argument, though, we can't simplify.
1514
+ */
1515
+ if (query -> limitCount )
1516
+ {
1517
+ /*
1518
+ * The LIMIT clause has not yet been through eval_const_expressions,
1519
+ * so we have to apply that here. It might seem like this is a waste
1520
+ * of cycles, since the only case plausibly worth worrying about is
1521
+ * "LIMIT 1" ... but what we'll actually see is "LIMIT int8(1::int4)",
1522
+ * so we have to fold constants or we're not going to recognize it.
1523
+ */
1524
+ Node * node = eval_const_expressions (root , query -> limitCount );
1525
+ Const * limit ;
1526
+
1527
+ /* Might as well update the query if we simplified the clause. */
1528
+ query -> limitCount = node ;
1529
+
1530
+ if (!IsA (node , Const ))
1531
+ return false;
1532
+
1533
+ limit = (Const * ) node ;
1534
+ Assert (limit -> consttype == INT8OID );
1535
+ if (!limit -> constisnull && DatumGetInt64 (limit -> constvalue ) <= 0 )
1536
+ return false;
1537
+
1538
+ /* Whether or not the targetlist is safe, we can drop the LIMIT. */
1539
+ query -> limitCount = NULL ;
1540
+ }
1541
+
1508
1542
/*
1509
1543
* Mustn't throw away the targetlist if it contains set-returning
1510
1544
* functions; those could affect whether zero rows are returned!
0 commit comments