|
52 | 52 | #include "utils/syscache.h"
|
53 | 53 | #include "utils/typcache.h"
|
54 | 54 |
|
55 |
| -typedef struct |
56 |
| -{ |
57 |
| - PartialAggType allowedtype; |
58 |
| -} partial_agg_context; |
59 | 55 |
|
60 | 56 | typedef struct
|
61 | 57 | {
|
@@ -98,8 +94,6 @@ typedef struct
|
98 | 94 | bool allow_restricted;
|
99 | 95 | } has_parallel_hazard_arg;
|
100 | 96 |
|
101 |
| -static bool aggregates_allow_partial_walker(Node *node, |
102 |
| - partial_agg_context *context); |
103 | 97 | static bool contain_agg_clause_walker(Node *node, void *context);
|
104 | 98 | static bool get_agg_clause_costs_walker(Node *node,
|
105 | 99 | get_agg_clause_costs_context *context);
|
@@ -403,81 +397,6 @@ make_ands_implicit(Expr *clause)
|
403 | 397 | * Aggregate-function clause manipulation
|
404 | 398 | *****************************************************************************/
|
405 | 399 |
|
406 |
| -/* |
407 |
| - * aggregates_allow_partial |
408 |
| - * Recursively search for Aggref clauses and determine the maximum |
409 |
| - * level of partial aggregation which can be supported. |
410 |
| - */ |
411 |
| -PartialAggType |
412 |
| -aggregates_allow_partial(Node *clause) |
413 |
| -{ |
414 |
| - partial_agg_context context; |
415 |
| - |
416 |
| - /* initially any type is okay, until we find Aggrefs which say otherwise */ |
417 |
| - context.allowedtype = PAT_ANY; |
418 |
| - |
419 |
| - if (!aggregates_allow_partial_walker(clause, &context)) |
420 |
| - return context.allowedtype; |
421 |
| - return context.allowedtype; |
422 |
| -} |
423 |
| - |
424 |
| -static bool |
425 |
| -aggregates_allow_partial_walker(Node *node, partial_agg_context *context) |
426 |
| -{ |
427 |
| - if (node == NULL) |
428 |
| - return false; |
429 |
| - if (IsA(node, Aggref)) |
430 |
| - { |
431 |
| - Aggref *aggref = (Aggref *) node; |
432 |
| - HeapTuple aggTuple; |
433 |
| - Form_pg_aggregate aggform; |
434 |
| - |
435 |
| - Assert(aggref->agglevelsup == 0); |
436 |
| - |
437 |
| - /* |
438 |
| - * We can't perform partial aggregation with Aggrefs containing a |
439 |
| - * DISTINCT or ORDER BY clause. |
440 |
| - */ |
441 |
| - if (aggref->aggdistinct || aggref->aggorder) |
442 |
| - { |
443 |
| - context->allowedtype = PAT_DISABLED; |
444 |
| - return true; /* abort search */ |
445 |
| - } |
446 |
| - aggTuple = SearchSysCache1(AGGFNOID, |
447 |
| - ObjectIdGetDatum(aggref->aggfnoid)); |
448 |
| - if (!HeapTupleIsValid(aggTuple)) |
449 |
| - elog(ERROR, "cache lookup failed for aggregate %u", |
450 |
| - aggref->aggfnoid); |
451 |
| - aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple); |
452 |
| - |
453 |
| - /* |
454 |
| - * If there is no combine function, then partial aggregation is not |
455 |
| - * possible. |
456 |
| - */ |
457 |
| - if (!OidIsValid(aggform->aggcombinefn)) |
458 |
| - { |
459 |
| - ReleaseSysCache(aggTuple); |
460 |
| - context->allowedtype = PAT_DISABLED; |
461 |
| - return true; /* abort search */ |
462 |
| - } |
463 |
| - |
464 |
| - /* |
465 |
| - * If we find any aggs with an internal transtype then we must check |
466 |
| - * whether these have serialization/deserialization functions; |
467 |
| - * otherwise, we set the maximum allowed type to PAT_INTERNAL_ONLY. |
468 |
| - */ |
469 |
| - if (aggform->aggtranstype == INTERNALOID && |
470 |
| - (!OidIsValid(aggform->aggserialfn) || |
471 |
| - !OidIsValid(aggform->aggdeserialfn))) |
472 |
| - context->allowedtype = PAT_INTERNAL_ONLY; |
473 |
| - |
474 |
| - ReleaseSysCache(aggTuple); |
475 |
| - return false; /* continue searching */ |
476 |
| - } |
477 |
| - return expression_tree_walker(node, aggregates_allow_partial_walker, |
478 |
| - (void *) context); |
479 |
| -} |
480 |
| - |
481 | 400 | /*
|
482 | 401 | * contain_agg_clause
|
483 | 402 | * Recursively search for Aggref/GroupingFunc nodes within a clause.
|
@@ -529,8 +448,9 @@ contain_agg_clause_walker(Node *node, void *context)
|
529 | 448 | *
|
530 | 449 | * We count the nodes, estimate their execution costs, and estimate the total
|
531 | 450 | * space needed for their transition state values if all are evaluated in
|
532 |
| - * parallel (as would be done in a HashAgg plan). See AggClauseCosts for |
533 |
| - * the exact set of statistics collected. |
| 451 | + * parallel (as would be done in a HashAgg plan). Also, we check whether |
| 452 | + * partial aggregation is feasible. See AggClauseCosts for the exact set |
| 453 | + * of statistics collected. |
534 | 454 | *
|
535 | 455 | * In addition, we mark Aggref nodes with the correct aggtranstype, so
|
536 | 456 | * that that doesn't need to be done repeatedly. (That makes this function's
|
@@ -616,10 +536,40 @@ get_agg_clause_costs_walker(Node *node, get_agg_clause_costs_context *context)
|
616 | 536 | aggref->aggtranstype = aggtranstype;
|
617 | 537 | }
|
618 | 538 |
|
619 |
| - /* count it; note ordered-set aggs always have nonempty aggorder */ |
| 539 | + /* |
| 540 | + * Count it, and check for cases requiring ordered input. Note that |
| 541 | + * ordered-set aggs always have nonempty aggorder. Any ordered-input |
| 542 | + * case also defeats partial aggregation. |
| 543 | + */ |
620 | 544 | costs->numAggs++;
|
621 | 545 | if (aggref->aggorder != NIL || aggref->aggdistinct != NIL)
|
| 546 | + { |
622 | 547 | costs->numOrderedAggs++;
|
| 548 | + costs->hasNonPartial = true; |
| 549 | + } |
| 550 | + |
| 551 | + /* |
| 552 | + * Check whether partial aggregation is feasible, unless we already |
| 553 | + * found out that we can't do it. |
| 554 | + */ |
| 555 | + if (!costs->hasNonPartial) |
| 556 | + { |
| 557 | + /* |
| 558 | + * If there is no combine function, then partial aggregation is |
| 559 | + * not possible. |
| 560 | + */ |
| 561 | + if (!OidIsValid(aggcombinefn)) |
| 562 | + costs->hasNonPartial = true; |
| 563 | + |
| 564 | + /* |
| 565 | + * If we have any aggs with transtype INTERNAL then we must check |
| 566 | + * whether they have serialization/deserialization functions; if |
| 567 | + * not, we can't serialize partial-aggregation results. |
| 568 | + */ |
| 569 | + else if (aggtranstype == INTERNALOID && |
| 570 | + (!OidIsValid(aggserialfn) || !OidIsValid(aggdeserialfn))) |
| 571 | + costs->hasNonSerial = true; |
| 572 | + } |
623 | 573 |
|
624 | 574 | /*
|
625 | 575 | * Add the appropriate component function execution costs to
|
|
0 commit comments