* eval_windowaggregates * evaluate plain aggregates being used as window functions * * This differs from nodeAgg.c in two ways. First, if the window's frame * start position moves, we use the inverse transition function (if it exists) * to remove rows from the transition value. And second, we expect to be * able to call aggregate final functions repeatedly after aggregating more * data on
| 854 | * nodeAgg.c. |
| 855 | */ |
| 856 | static void |
| 857 | eval_windowaggregates(WindowAggState *winstate) |
| 858 | { |
| 859 | WindowStatePerAgg peraggstate; |
| 860 | int wfuncno, |
| 861 | numaggs, |
| 862 | numaggs_restart, |
| 863 | i; |
| 864 | int64 aggregatedupto_nonrestarted; |
| 865 | MemoryContext oldContext; |
| 866 | ExprContext *econtext; |
| 867 | WindowObject agg_winobj; |
| 868 | TupleTableSlot *agg_row_slot; |
| 869 | TupleTableSlot *temp_slot; |
| 870 | bool frame_head_moved_backwards; |
| 871 | bool frame_tail_moved_backwards; |
| 872 | |
| 873 | numaggs = winstate->numaggs; |
| 874 | if (numaggs == 0) |
| 875 | return; /* nothing to do */ |
| 876 | |
| 877 | /* final output execution is in ps_ExprContext */ |
| 878 | econtext = winstate->ss.ps.ps_ExprContext; |
| 879 | agg_winobj = winstate->agg_winobj; |
| 880 | agg_row_slot = winstate->agg_row_slot; |
| 881 | temp_slot = winstate->temp_slot_1; |
| 882 | |
| 883 | /* |
| 884 | * If the window's frame start clause is UNBOUNDED_PRECEDING and no |
| 885 | * exclusion clause is specified, then the window frame consists of a |
| 886 | * contiguous group of rows extending forward from the start of the |
| 887 | * partition, and rows only enter the frame, never exit it, as the current |
| 888 | * row advances forward. This makes it possible to use an incremental |
| 889 | * strategy for evaluating aggregates: we run the transition function for |
| 890 | * each row added to the frame, and run the final function whenever we |
| 891 | * need the current aggregate value. This is considerably more efficient |
| 892 | * than the naive approach of re-running the entire aggregate calculation |
| 893 | * for each current row. It does assume that the final function doesn't |
| 894 | * damage the running transition value, but we have the same assumption in |
| 895 | * nodeAgg.c too (when it rescans an existing hash table). |
| 896 | * |
| 897 | * If the frame start does sometimes move, we can still optimize as above |
| 898 | * whenever successive rows share the same frame head, but if the frame |
| 899 | * head moves beyond the previous head we try to remove those rows using |
| 900 | * the aggregate's inverse transition function. This function restores |
| 901 | * the aggregate's current state to what it would be if the removed row |
| 902 | * had never been aggregated in the first place. Inverse transition |
| 903 | * functions may optionally return NULL, indicating that the function was |
| 904 | * unable to remove the tuple from aggregation. If this happens, or if |
| 905 | * the aggregate doesn't have an inverse transition function at all, we |
| 906 | * must perform the aggregation all over again for all tuples within the |
| 907 | * new frame boundaries. |
| 908 | * |
| 909 | * If there's any exclusion clause, then we may have to aggregate over a |
| 910 | * non-contiguous set of rows, so we punt and recalculate for every row. |
| 911 | * (For some frame end choices, it might be that the frame is always |
| 912 | * contiguous anyway, but that's an optimization to investigate later.) |
| 913 | * |
no test coverage detected