@@ -824,6 +824,17 @@ class Frame_cursor : public Sql_alloc
824
824
}
825
825
}
826
826
827
+ /* Clear all sum functions handled by this cursor. */
828
+ void clear_sum_functions ()
829
+ {
830
+ List_iterator_fast<Item_sum> iter_sum_func (sum_functions);
831
+ Item_sum *sum_func;
832
+ while ((sum_func= iter_sum_func++))
833
+ {
834
+ sum_func->clear ();
835
+ }
836
+ }
837
+
827
838
/* Sum functions that this cursor handles. */
828
839
List<Item_sum> sum_functions;
829
840
@@ -1847,17 +1858,6 @@ class Frame_scan_cursor : public Frame_cursor
1847
1858
Table_read_cursor cursor;
1848
1859
ha_rows curr_rownum;
1849
1860
1850
- /* Clear all sum functions handled by this cursor. */
1851
- void clear_sum_functions ()
1852
- {
1853
- List_iterator_fast<Item_sum> iter_sum_func (sum_functions);
1854
- Item_sum *sum_func;
1855
- while ((sum_func= iter_sum_func++))
1856
- {
1857
- sum_func->clear ();
1858
- }
1859
- }
1860
-
1861
1861
/* Scan the rows between the top bound and bottom bound. Add all the values
1862
1862
between them, top bound row and bottom bound row inclusive. */
1863
1863
void compute_values_for_current_row ()
@@ -1883,6 +1883,55 @@ class Frame_scan_cursor : public Frame_cursor
1883
1883
}
1884
1884
};
1885
1885
1886
+ /* A cursor that follows a target cursor. Each time a new row is added,
1887
+ the window functions are cleared and only have the row at which the target
1888
+ is point at added to them.
1889
+ */
1890
+ class Frame_positional_cursor : public Frame_cursor
1891
+ {
1892
+ public:
1893
+ Frame_positional_cursor (const Frame_cursor &position_cursor) :
1894
+ position_cursor (position_cursor) {}
1895
+
1896
+ void init (READ_RECORD *info)
1897
+ {
1898
+ cursor.init (info);
1899
+ }
1900
+
1901
+ void pre_next_partition (ha_rows rownum)
1902
+ {
1903
+ clear_sum_functions ();
1904
+ }
1905
+
1906
+ void next_partition (ha_rows rownum)
1907
+ {
1908
+ cursor.move_to (position_cursor.get_curr_rownum ());
1909
+ add_value_to_items ();
1910
+ }
1911
+
1912
+ void pre_next_row ()
1913
+ {
1914
+ }
1915
+
1916
+ void next_row ()
1917
+ {
1918
+ if (position_cursor.is_outside_computation_bounds ())
1919
+ clear_sum_functions ();
1920
+
1921
+ cursor.move_to (position_cursor.get_curr_rownum ());
1922
+ add_value_to_items ();
1923
+ }
1924
+
1925
+ ha_rows get_curr_rownum () const
1926
+ {
1927
+ return position_cursor.get_curr_rownum ();
1928
+ }
1929
+
1930
+ private:
1931
+ const Frame_cursor &position_cursor;
1932
+ Table_read_cursor cursor;
1933
+ };
1934
+
1886
1935
1887
1936
/*
1888
1937
Get a Frame_cursor for a frame bound. This is a "factory function".
@@ -1990,8 +2039,9 @@ Frame_cursor *get_frame_cursor(THD *thd, Window_spec *spec, bool is_top_bound)
1990
2039
return NULL ;
1991
2040
}
1992
2041
1993
- void add_extra_frame_cursors (THD *thd, Cursor_manager *cursor_manager,
1994
- Item_window_func *window_func)
2042
+ static
2043
+ void add_special_frame_cursors (THD *thd, Cursor_manager *cursor_manager,
2044
+ Item_window_func *window_func)
1995
2045
{
1996
2046
Window_spec *spec= window_func->window_spec ;
1997
2047
Item_sum *item_sum= window_func->window_func ();
@@ -2010,6 +2060,19 @@ void add_extra_frame_cursors(THD *thd, Cursor_manager *cursor_manager,
2010
2060
fc->add_sum_func (item_sum);
2011
2061
cursor_manager->add_cursor (fc);
2012
2062
break ;
2063
+ case Item_sum::FIRST_VALUE_FUNC:
2064
+ fc= get_frame_cursor (thd, spec, true );
2065
+ fc->set_no_action ();
2066
+ cursor_manager->add_cursor (fc);
2067
+ fc= new Frame_positional_cursor (*fc);
2068
+ fc->add_sum_func (item_sum);
2069
+ cursor_manager->add_cursor (fc);
2070
+ break ;
2071
+ case Item_sum::LAST_VALUE_FUNC:
2072
+ fc= get_frame_cursor (thd, spec, false );
2073
+ fc->add_sum_func (item_sum);
2074
+ cursor_manager->add_cursor (fc);
2075
+ break ;
2013
2076
default :
2014
2077
fc= new Frame_unbounded_preceding (
2015
2078
thd, spec->partition_list , spec->order_list );
@@ -2032,6 +2095,8 @@ static bool is_computed_with_remove(Item_sum::Sumfunctype sum_func)
2032
2095
case Item_sum::RANK_FUNC:
2033
2096
case Item_sum::DENSE_RANK_FUNC:
2034
2097
case Item_sum::NTILE_FUNC:
2098
+ case Item_sum::FIRST_VALUE_FUNC:
2099
+ case Item_sum::LAST_VALUE_FUNC:
2035
2100
return false ;
2036
2101
default :
2037
2102
return true ;
@@ -2071,12 +2136,20 @@ void get_window_functions_required_cursors(
2071
2136
2072
2137
/*
2073
2138
If it is not a regular window function that follows frame specifications,
2074
- specific cursors are required. ROW_NUM, RANK, NTILE and others follow
2075
- such rules. Check is_frame_prohibited check for the full list.
2139
+ and/or specific cursors are required. ROW_NUM, RANK, NTILE and others
2140
+ follow such rules. Check is_frame_prohibited check for the full list.
2141
+
2142
+ TODO(cvicentiu) This approach is messy. Every time a function allows
2143
+ computation in a certain way, we have to add an extra method to this
2144
+ factory function. It is better to have window functions output
2145
+ their own cursors, as needed. This way, the logic is bound
2146
+ only to the implementation of said window function. Regular aggregate
2147
+ functions can keep the default frame generating code, overwrite it or
2148
+ add to it.
2076
2149
*/
2077
2150
if (item_win_func->is_frame_prohibited ())
2078
2151
{
2079
- add_extra_frame_cursors (thd, cursor_manager, item_win_func);
2152
+ add_special_frame_cursors (thd, cursor_manager, item_win_func);
2080
2153
cursor_managers->push_back (cursor_manager);
2081
2154
continue ;
2082
2155
}
0 commit comments