Fix confusion about havingQual vs hasHavingQual in planner.
authorTom Lane <[email protected]>
Tue, 18 Oct 2022 14:44:34 +0000 (10:44 -0400)
committerTom Lane <[email protected]>
Tue, 18 Oct 2022 14:44:34 +0000 (10:44 -0400)
Preprocessing of the HAVING clause will reduce havingQual to NIL
if the clause is constant-TRUE.  This is one case where that
convention is rather unfortunate, because "HAVING TRUE" is not at all
the same as not having any HAVING clause at all.  (Per the SQL spec,
it still forces the query to be grouped.)  The planner deals with this
by having a boolean hasHavingQual that records whether havingQual was
originally nonempty; places that just want to check whether HAVING
was specified are supposed to consult that.

I found three places that got that wrong.  Fortunately, these could
only affect cost estimates not correctness.  It'd be hard even
to demonstrate the errors; for example, the one in allpaths.c would
only matter in a query that has HAVING TRUE but no GROUP BY and no
aggregates, which would require a completely variable-free SELECT
list, making the case probably of only academic interest.  Hence,
while these are worth fixing before someone copies the incorrect
coding somewhere more critical, they don't seem worth back-patching.
I didn't bother trying to devise regression tests, either.

Discussion: https://postgr.es/m/2503888.1666042643@sss.pgh.pa.us

contrib/postgres_fdw/postgres_fdw.c
src/backend/optimizer/path/allpaths.c

index d98709e5e88118dc18a4e1f4b8c4186dca2daddb..8d7500abfbdb9ccd33234128e31a464546f5d301 100644 (file)
@@ -3357,7 +3357,7 @@ estimate_path_cost_size(PlannerInfo *root,
             * Get the retrieved_rows and rows estimates.  If there are HAVING
             * quals, account for their selectivity.
             */
-           if (root->parse->havingQual)
+           if (root->hasHavingQual)
            {
                /* Factor in the selectivity of the remotely-checked quals */
                retrieved_rows =
@@ -3405,7 +3405,7 @@ estimate_path_cost_size(PlannerInfo *root,
            run_cost += cpu_tuple_cost * numGroups;
 
            /* Account for the eval cost of HAVING quals, if any */
-           if (root->parse->havingQual)
+           if (root->hasHavingQual)
            {
                QualCost    remote_cost;
 
index 8fc28007f541d5295f8f7169ebb720f2453c0e2d..4ddaed31a44f24db77325fdf0e20028de384017e 100644 (file)
@@ -2575,7 +2575,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
    if (parse->hasAggs ||
        parse->groupClause ||
        parse->groupingSets ||
-       parse->havingQual ||
+       root->hasHavingQual ||
        parse->distinctClause ||
        parse->sortClause ||
        has_multiple_baserels(root))