|
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