* update_frameheadpos * make frameheadpos valid for the current row * * Note that frameheadpos is computed without regard for any window exclusion * clause; the current row and/or its peers are considered part of the frame * for this purpose even if they must be excluded later. * * May clobber winstate->temp_slot_2. */
| 1723 | * May clobber winstate->temp_slot_2. |
| 1724 | */ |
| 1725 | static void |
| 1726 | update_frameheadpos(WindowAggState *winstate) |
| 1727 | { |
| 1728 | WindowAgg *node = (WindowAgg *) winstate->ss.ps.plan; |
| 1729 | int frameOptions = winstate->frameOptions; |
| 1730 | MemoryContext oldcontext; |
| 1731 | |
| 1732 | if (winstate->framehead_valid) |
| 1733 | return; /* already known for current row */ |
| 1734 | |
| 1735 | /* We may be called in a short-lived context */ |
| 1736 | oldcontext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_query_memory); |
| 1737 | |
| 1738 | compute_start_end_offsets(winstate); |
| 1739 | |
| 1740 | if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) |
| 1741 | { |
| 1742 | /* In UNBOUNDED PRECEDING mode, frame head is always row 0 */ |
| 1743 | winstate->frameheadpos = 0; |
| 1744 | winstate->framehead_valid = true; |
| 1745 | } |
| 1746 | else if (frameOptions & FRAMEOPTION_START_CURRENT_ROW) |
| 1747 | { |
| 1748 | if (frameOptions & FRAMEOPTION_ROWS) |
| 1749 | { |
| 1750 | /* In ROWS mode, frame head is the same as current */ |
| 1751 | winstate->frameheadpos = winstate->currentpos; |
| 1752 | winstate->framehead_valid = true; |
| 1753 | } |
| 1754 | else if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS)) |
| 1755 | { |
| 1756 | /* If no ORDER BY, all rows are peers with each other */ |
| 1757 | if (node->ordNumCols == 0) |
| 1758 | { |
| 1759 | winstate->frameheadpos = 0; |
| 1760 | winstate->framehead_valid = true; |
| 1761 | MemoryContextSwitchTo(oldcontext); |
| 1762 | return; |
| 1763 | } |
| 1764 | |
| 1765 | /* |
| 1766 | * In RANGE or GROUPS START_CURRENT_ROW mode, frame head is the |
| 1767 | * first row that is a peer of current row. We keep a copy of the |
| 1768 | * last-known frame head row in framehead_slot, and advance as |
| 1769 | * necessary. Note that if we reach end of partition, we will |
| 1770 | * leave frameheadpos = end+1 and framehead_slot empty. |
| 1771 | */ |
| 1772 | tuplestore_select_read_pointer(winstate->buffer, |
| 1773 | winstate->framehead_ptr); |
| 1774 | if (winstate->frameheadpos == 0 && |
| 1775 | TupIsNull(winstate->framehead_slot)) |
| 1776 | { |
| 1777 | /* fetch first row into framehead_slot, if we didn't already */ |
| 1778 | if (!tuplestore_gettupleslot(winstate->buffer, true, true, |
| 1779 | winstate->framehead_slot)) |
| 1780 | elog(ERROR, "unexpected end of tuplestore"); |
| 1781 | } |
| 1782 |
no test coverage detected