1/*
2 Copyright (c) 2016,2017 MariaDB
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17#ifndef ITEM_WINDOWFUNC_INCLUDED
18#define ITEM_WINDOWFUNC_INCLUDED
19
20#include "item.h"
21
22class Window_spec;
23
24
25int test_if_group_changed(List<Cached_item> &list);
26
27
28/* A wrapper around test_if_group_changed */
29class Group_bound_tracker
30{
31public:
32
33 Group_bound_tracker(THD *thd, SQL_I_List<ORDER> *list)
34 {
35 for (ORDER *curr = list->first; curr; curr=curr->next)
36 {
37 Cached_item *tmp= new_Cached_item(thd, curr->item[0], TRUE);
38 group_fields.push_back(tmp);
39 }
40 }
41
42 void init()
43 {
44 first_check= true;
45 }
46
47 void cleanup()
48 {
49 group_fields.empty();
50 }
51
52 /*
53 Check if the current row is in a different group than the previous row
54 this function was called for.
55 XXX: Side-effect: The new row's group becomes the current row's group.
56
57 Returns true if there is a change between the current_group and the cached
58 value, or if it is the first check after a call to init.
59 */
60 bool check_if_next_group()
61 {
62 if (test_if_group_changed(group_fields) > -1 || first_check)
63 {
64 first_check= false;
65 return true;
66 }
67 return false;
68 }
69
70 /*
71 Check if the current row is in a different group than the previous row
72 check_if_next_group was called for.
73
74 Compares the groups without the additional side effect of updating the
75 current cached values.
76 */
77 int compare_with_cache()
78 {
79 List_iterator<Cached_item> li(group_fields);
80 Cached_item *ptr;
81 int res;
82 while ((ptr= li++))
83 {
84 if ((res= ptr->cmp_read_only()))
85 return res;
86 }
87 return 0;
88 }
89
90private:
91 List<Cached_item> group_fields;
92 /*
93 During the first check_if_next_group, the list of cached_items is not
94 initialized. The compare function will return that the items match if
95 the field's value is the same as the Cached_item's default value (0).
96 This flag makes sure that we always return true during the first check.
97
98 XXX This is better to be implemented within test_if_group_changed, but
99 since it is used in other parts of the codebase, we keep it here for now.
100 */
101 bool first_check;
102};
103
104/*
105 ROW_NUMBER() OVER (...)
106
107 @detail
108 - This is a Window function (not just an aggregate)
109 - It can be computed by doing one pass over select output, provided
110 the output is sorted according to the window definition.
111*/
112
113class Item_sum_row_number: public Item_sum_int
114{
115 longlong count;
116
117public:
118
119 Item_sum_row_number(THD *thd)
120 : Item_sum_int(thd), count(0) {}
121
122 void clear()
123 {
124 count= 0;
125 }
126
127 bool add()
128 {
129 count++;
130 return false;
131 }
132
133 void update_field() {}
134
135 enum Sumfunctype sum_func() const
136 {
137 return ROW_NUMBER_FUNC;
138 }
139
140 longlong val_int()
141 {
142 return count;
143 }
144 const char*func_name() const
145 {
146 return "row_number";
147 }
148
149 Item *get_copy(THD *thd)
150 { return get_item_copy<Item_sum_row_number>(thd, this); }
151};
152
153
154/*
155 RANK() OVER (...) Windowing function
156
157 @detail
158 - This is a Window function (not just an aggregate)
159 - It can be computed by doing one pass over select output, provided
160 the output is sorted according to the window definition.
161
162 The function is defined as:
163
164 "The rank of row R is defined as 1 (one) plus the number of rows that
165 precede R and are not peers of R"
166
167 "This implies that if two or more rows are not distinct with respect to
168 the window ordering, then there will be one or more"
169*/
170
171class Item_sum_rank: public Item_sum_int
172{
173protected:
174 longlong row_number; // just ROW_NUMBER()
175 longlong cur_rank; // current value
176
177 Group_bound_tracker *peer_tracker;
178public:
179
180 Item_sum_rank(THD *thd) : Item_sum_int(thd), peer_tracker(NULL) {}
181
182 void clear()
183 {
184 /* This is called on partition start */
185 cur_rank= 1;
186 row_number= 0;
187 }
188
189 bool add();
190
191 longlong val_int()
192 {
193 return cur_rank;
194 }
195
196 void update_field() {}
197 /*
198 void reset_field();
199 TODO: ^^ what does this do ? It is not called ever?
200 */
201
202 enum Sumfunctype sum_func () const
203 {
204 return RANK_FUNC;
205 }
206
207 const char*func_name() const
208 {
209 return "rank";
210 }
211
212 void setup_window_func(THD *thd, Window_spec *window_spec);
213
214 void cleanup()
215 {
216 if (peer_tracker)
217 {
218 peer_tracker->cleanup();
219 delete peer_tracker;
220 peer_tracker= NULL;
221 }
222 Item_sum_int::cleanup();
223 }
224 Item *get_copy(THD *thd)
225 { return get_item_copy<Item_sum_rank>(thd, this); }
226};
227
228
229/*
230 DENSE_RANK() OVER (...) Windowing function
231
232 @detail
233 - This is a Window function (not just an aggregate)
234 - It can be computed by doing one pass over select output, provided
235 the output is sorted according to the window definition.
236
237 The function is defined as:
238
239 "If DENSE_RANK is specified, then the rank of row R is defined as the
240 number of rows preceding and including R that are distinct with respect
241 to the window ordering"
242
243 "This implies that there are no gaps in the sequential rank numbering of
244 rows in each window partition."
245*/
246
247
248class Item_sum_dense_rank: public Item_sum_int
249{
250 longlong dense_rank;
251 bool first_add;
252 Group_bound_tracker *peer_tracker;
253 public:
254 /*
255 XXX(cvicentiu) This class could potentially be implemented in the rank
256 class, with a switch for the DENSE case.
257 */
258 void clear()
259 {
260 dense_rank= 0;
261 first_add= true;
262 }
263 bool add();
264 void update_field() {}
265 longlong val_int()
266 {
267 return dense_rank;
268 }
269
270 Item_sum_dense_rank(THD *thd)
271 : Item_sum_int(thd), dense_rank(0), first_add(true), peer_tracker(NULL) {}
272 enum Sumfunctype sum_func () const
273 {
274 return DENSE_RANK_FUNC;
275 }
276
277 const char*func_name() const
278 {
279 return "dense_rank";
280 }
281
282 void setup_window_func(THD *thd, Window_spec *window_spec);
283
284 void cleanup()
285 {
286 if (peer_tracker)
287 {
288 peer_tracker->cleanup();
289 delete peer_tracker;
290 peer_tracker= NULL;
291 }
292 Item_sum_int::cleanup();
293 }
294 Item *get_copy(THD *thd)
295 { return get_item_copy<Item_sum_dense_rank>(thd, this); }
296};
297
298class Item_sum_hybrid_simple : public Item_sum,
299 public Type_handler_hybrid_field_type
300{
301 public:
302 Item_sum_hybrid_simple(THD *thd, Item *arg):
303 Item_sum(thd, arg),
304 Type_handler_hybrid_field_type(&type_handler_longlong),
305 value(NULL)
306 { collation.set(&my_charset_bin); }
307
308 Item_sum_hybrid_simple(THD *thd, Item *arg1, Item *arg2):
309 Item_sum(thd, arg1, arg2),
310 Type_handler_hybrid_field_type(&type_handler_longlong),
311 value(NULL)
312 { collation.set(&my_charset_bin); }
313
314 bool add();
315 bool fix_fields(THD *, Item **);
316 void setup_hybrid(THD *thd, Item *item);
317 double val_real();
318 longlong val_int();
319 my_decimal *val_decimal(my_decimal *);
320 void reset_field();
321 String *val_str(String *);
322 bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
323 const Type_handler *type_handler() const
324 { return Type_handler_hybrid_field_type::type_handler(); }
325 void update_field();
326 Field *create_tmp_field(bool group, TABLE *table);
327 void clear()
328 {
329 value->clear();
330 null_value= 1;
331 }
332
333 private:
334 Item_cache *value;
335};
336
337/*
338 This item will remember the first value added to it. It will not update
339 the value unless it is cleared.
340*/
341class Item_sum_first_value : public Item_sum_hybrid_simple
342{
343 public:
344 Item_sum_first_value(THD* thd, Item* arg_expr) :
345 Item_sum_hybrid_simple(thd, arg_expr) {}
346
347
348 enum Sumfunctype sum_func () const
349 {
350 return FIRST_VALUE_FUNC;
351 }
352
353 const char*func_name() const
354 {
355 return "first_value";
356 }
357
358 Item *get_copy(THD *thd)
359 { return get_item_copy<Item_sum_first_value>(thd, this); }
360};
361
362/*
363 This item will remember the last value added to it.
364
365 This item does not support removal, and can be cleared only by calling
366 clear().
367*/
368class Item_sum_last_value : public Item_sum_hybrid_simple
369{
370 public:
371 Item_sum_last_value(THD* thd, Item* arg_expr) :
372 Item_sum_hybrid_simple(thd, arg_expr) {}
373
374 enum Sumfunctype sum_func() const
375 {
376 return LAST_VALUE_FUNC;
377 }
378
379 const char*func_name() const
380 {
381 return "last_value";
382 }
383
384 Item *get_copy(THD *thd)
385 { return get_item_copy<Item_sum_last_value>(thd, this); }
386};
387
388class Item_sum_nth_value : public Item_sum_hybrid_simple
389{
390 public:
391 Item_sum_nth_value(THD *thd, Item *arg_expr, Item* offset_expr) :
392 Item_sum_hybrid_simple(thd, arg_expr, offset_expr) {}
393
394 enum Sumfunctype sum_func() const
395 {
396 return NTH_VALUE_FUNC;
397 }
398
399 const char*func_name() const
400 {
401 return "nth_value";
402 }
403
404 Item *get_copy(THD *thd)
405 { return get_item_copy<Item_sum_nth_value>(thd, this); }
406};
407
408class Item_sum_lead : public Item_sum_hybrid_simple
409{
410 public:
411 Item_sum_lead(THD *thd, Item *arg_expr, Item* offset_expr) :
412 Item_sum_hybrid_simple(thd, arg_expr, offset_expr) {}
413
414 enum Sumfunctype sum_func() const
415 {
416 return LEAD_FUNC;
417 }
418
419 const char*func_name() const
420 {
421 return "lead";
422 }
423
424 Item *get_copy(THD *thd)
425 { return get_item_copy<Item_sum_lead>(thd, this); }
426};
427
428class Item_sum_lag : public Item_sum_hybrid_simple
429{
430 public:
431 Item_sum_lag(THD *thd, Item *arg_expr, Item* offset_expr) :
432 Item_sum_hybrid_simple(thd, arg_expr, offset_expr) {}
433
434 enum Sumfunctype sum_func() const
435 {
436 return LAG_FUNC;
437 }
438
439 const char*func_name() const
440 {
441 return "lag";
442 }
443
444 Item *get_copy(THD *thd)
445 { return get_item_copy<Item_sum_lag>(thd, this); }
446};
447
448/*
449 A base window function (aggregate) that also holds a counter for the number
450 of rows.
451*/
452class Item_sum_window_with_row_count : public Item_sum_num
453{
454 public:
455 Item_sum_window_with_row_count(THD *thd) : Item_sum_num(thd),
456 partition_row_count_(0) {}
457
458 Item_sum_window_with_row_count(THD *thd, Item *arg) :
459 Item_sum_num(thd, arg), partition_row_count_(0) {};
460
461 void set_row_count(ulonglong count) { partition_row_count_ = count; }
462
463 protected:
464 longlong get_row_count() { return partition_row_count_; }
465 private:
466 ulonglong partition_row_count_;
467};
468
469/*
470 @detail
471 "The relative rank of a row R is defined as (RK-1)/(NR-1), where RK is
472 defined to be the RANK of R and NR is defined to be the number of rows in
473 the window partition of R."
474
475 Computation of this function requires two passes:
476 - First pass to find #rows in the partition
477 This is held within the row_count context.
478 - Second pass to compute rank of current row and the value of the function
479*/
480class Item_sum_percent_rank: public Item_sum_window_with_row_count
481{
482 public:
483 Item_sum_percent_rank(THD *thd)
484 : Item_sum_window_with_row_count(thd), cur_rank(1), peer_tracker(NULL) {}
485
486 longlong val_int()
487 {
488 /*
489 Percent rank is a real value so calling the integer value should never
490 happen. It makes no sense as it gets truncated to either 0 or 1.
491 */
492 DBUG_ASSERT(0);
493 return 0;
494 }
495
496 double val_real()
497 {
498 /*
499 We can not get the real value without knowing the number of rows
500 in the partition. Don't divide by 0.
501 */
502 ulonglong partition_rows = get_row_count();
503 null_value= partition_rows > 0 ? false : true;
504
505 return partition_rows > 1 ?
506 static_cast<double>(cur_rank - 1) / (partition_rows - 1) : 0;
507 }
508
509 enum Sumfunctype sum_func () const
510 {
511 return PERCENT_RANK_FUNC;
512 }
513
514 const char*func_name() const
515 {
516 return "percent_rank";
517 }
518
519 void update_field() {}
520
521 void clear()
522 {
523 cur_rank= 1;
524 row_number= 0;
525 }
526 bool add();
527 const Type_handler *type_handler() const { return &type_handler_double; }
528
529 void fix_length_and_dec()
530 {
531 decimals = 10; // TODO-cvicentiu find out how many decimals the standard
532 // requires.
533 }
534
535 void setup_window_func(THD *thd, Window_spec *window_spec);
536 Item *get_copy(THD *thd)
537 { return get_item_copy<Item_sum_percent_rank>(thd, this); }
538
539 private:
540 longlong cur_rank; // Current rank of the current row.
541 longlong row_number; // Value if this were ROW_NUMBER() function.
542
543 Group_bound_tracker *peer_tracker;
544
545 void cleanup()
546 {
547 if (peer_tracker)
548 {
549 peer_tracker->cleanup();
550 delete peer_tracker;
551 peer_tracker= NULL;
552 }
553 Item_sum_num::cleanup();
554 }
555};
556
557
558
559
560/*
561 @detail
562 "The relative rank of a row R is defined as NP/NR, where
563 - NP is defined to be the number of rows preceding or peer with R in the
564 window ordering of the window partition of R
565 - NR is defined to be the number of rows in the window partition of R.
566
567 Just like with Item_sum_percent_rank, computation of this function requires
568 two passes.
569*/
570
571class Item_sum_cume_dist: public Item_sum_window_with_row_count
572{
573 public:
574 Item_sum_cume_dist(THD *thd) : Item_sum_window_with_row_count(thd),
575 current_row_count_(0) {}
576
577 Item_sum_cume_dist(THD *thd, Item *arg) : Item_sum_window_with_row_count(thd,arg),
578 current_row_count_(0) {}
579
580 double val_real()
581 {
582 if (get_row_count() == 0)
583 {
584 null_value= true;
585 return 0;
586 }
587 ulonglong partition_row_count= get_row_count();
588 null_value= false;
589 return static_cast<double>(current_row_count_) / partition_row_count;
590 }
591
592 bool add()
593 {
594 current_row_count_++;
595 return false;
596 }
597
598 enum Sumfunctype sum_func() const
599 {
600 return CUME_DIST_FUNC;
601 }
602
603 void clear()
604 {
605 current_row_count_= 0;
606 set_row_count(0);
607 }
608
609 const char*func_name() const
610 {
611 return "cume_dist";
612 }
613
614 void update_field() {}
615 const Type_handler *type_handler() const { return &type_handler_double; }
616
617 void fix_length_and_dec()
618 {
619 decimals = 10; // TODO-cvicentiu find out how many decimals the standard
620 // requires.
621 }
622
623 Item *get_copy(THD *thd)
624 { return get_item_copy<Item_sum_cume_dist>(thd, this); }
625
626 ulonglong get_row_number()
627 {
628 return current_row_count_ ;
629 }
630
631 private:
632 ulonglong current_row_count_;
633};
634
635class Item_sum_ntile : public Item_sum_window_with_row_count
636{
637 public:
638 Item_sum_ntile(THD* thd, Item* num_quantiles_expr) :
639 Item_sum_window_with_row_count(thd, num_quantiles_expr),
640 current_row_count_(0) {};
641
642 double val_real()
643 {
644 return (double) val_int();
645 }
646
647 longlong val_int()
648 {
649 if (get_row_count() == 0)
650 {
651 null_value= true;
652 return 0;
653 }
654
655 longlong num_quantiles= get_num_quantiles();
656
657 if (num_quantiles <= 0) {
658 my_error(ER_INVALID_NTILE_ARGUMENT, MYF(0));
659 return true;
660 }
661
662 null_value= false;
663 ulonglong quantile_size = get_row_count() / num_quantiles;
664 ulonglong extra_rows = get_row_count() - quantile_size * num_quantiles;
665
666 if (current_row_count_ <= extra_rows * (quantile_size + 1))
667 return (current_row_count_ - 1) / (quantile_size + 1) + 1;
668
669 return (current_row_count_ - 1 - extra_rows) / quantile_size + 1;
670 }
671
672 bool add()
673 {
674 current_row_count_++;
675 return false;
676 }
677
678 enum Sumfunctype sum_func() const
679 {
680 return NTILE_FUNC;
681 }
682
683 void clear()
684 {
685 current_row_count_= 0;
686 set_row_count(0);
687 }
688
689 const char*func_name() const
690 {
691 return "ntile";
692 }
693
694 void update_field() {}
695
696 const Type_handler *type_handler() const { return &type_handler_longlong; }
697
698 Item *get_copy(THD *thd)
699 { return get_item_copy<Item_sum_ntile>(thd, this); }
700
701 private:
702 longlong get_num_quantiles() { return args[0]->val_int(); }
703 ulong current_row_count_;
704};
705
706class Item_sum_percentile_disc : public Item_sum_cume_dist,
707 public Type_handler_hybrid_field_type
708{
709public:
710 Item_sum_percentile_disc(THD *thd, Item* arg) : Item_sum_cume_dist(thd, arg),
711 Type_handler_hybrid_field_type(&type_handler_longlong),
712 value(NULL), val_calculated(FALSE), first_call(TRUE),
713 prev_value(0), order_item(NULL){}
714
715 double val_real()
716 {
717 if (get_row_count() == 0 || get_arg(0)->is_null())
718 {
719 null_value= true;
720 return 0;
721 }
722 null_value= false;
723 return value->val_real();
724 }
725
726 longlong val_int()
727 {
728 if (get_row_count() == 0 || get_arg(0)->is_null())
729 {
730 null_value= true;
731 return 0;
732 }
733 null_value= false;
734 return value->val_int();
735 }
736
737 my_decimal* val_decimal(my_decimal* dec)
738 {
739 if (get_row_count() == 0 || get_arg(0)->is_null())
740 {
741 null_value= true;
742 return 0;
743 }
744 null_value= false;
745 return value->val_decimal(dec);
746 }
747
748 String* val_str(String *str)
749 {
750 if (get_row_count() == 0 || get_arg(0)->is_null())
751 {
752 null_value= true;
753 return 0;
754 }
755 null_value= false;
756 return value->val_str(str);
757 }
758
759 bool add()
760 {
761 Item *arg= get_arg(0);
762 if (arg->is_null())
763 return false;
764
765 if (first_call)
766 {
767 prev_value= arg->val_real();
768 if (prev_value > 1 || prev_value < 0)
769 {
770 my_error(ER_ARGUMENT_OUT_OF_RANGE, MYF(0), func_name());
771 return true;
772 }
773 first_call= false;
774 }
775
776 double arg_val= arg->val_real();
777
778 if (prev_value != arg_val)
779 {
780 my_error(ER_ARGUMENT_NOT_CONSTANT, MYF(0), func_name());
781 return true;
782 }
783
784 if (val_calculated)
785 return false;
786
787 value->store(order_item);
788 value->cache_value();
789 if (value->null_value)
790 return false;
791
792 Item_sum_cume_dist::add();
793 double val= Item_sum_cume_dist::val_real();
794
795 if (val >= prev_value && !val_calculated)
796 val_calculated= true;
797 return false;
798 }
799
800 enum Sumfunctype sum_func() const
801 {
802 return PERCENTILE_DISC_FUNC;
803 }
804
805 void clear()
806 {
807 val_calculated= false;
808 first_call= true;
809 value->clear();
810 Item_sum_cume_dist::clear();
811 }
812
813 const char*func_name() const
814 {
815 return "percentile_disc";
816 }
817
818 void update_field() {}
819 void set_type_handler(Window_spec *window_spec);
820 const Type_handler *type_handler() const
821 {return Type_handler_hybrid_field_type::type_handler();}
822
823 void fix_length_and_dec()
824 {
825 decimals = 10; // TODO-cvicentiu find out how many decimals the standard
826 // requires.
827 }
828
829 Item *get_copy(THD *thd)
830 { return get_item_copy<Item_sum_percentile_disc>(thd, this); }
831 void setup_window_func(THD *thd, Window_spec *window_spec);
832 void setup_hybrid(THD *thd, Item *item);
833 bool fix_fields(THD *thd, Item **ref);
834
835private:
836 Item_cache *value;
837 bool val_calculated;
838 bool first_call;
839 double prev_value;
840 Item *order_item;
841};
842
843class Item_sum_percentile_cont : public Item_sum_cume_dist,
844 public Type_handler_hybrid_field_type
845{
846public:
847 Item_sum_percentile_cont(THD *thd, Item* arg) : Item_sum_cume_dist(thd, arg),
848 Type_handler_hybrid_field_type(&type_handler_double),
849 floor_value(NULL), ceil_value(NULL), first_call(TRUE),prev_value(0),
850 ceil_val_calculated(FALSE), floor_val_calculated(FALSE), order_item(NULL){}
851
852 double val_real()
853 {
854 if (get_row_count() == 0 || get_arg(0)->is_null())
855 {
856 null_value= true;
857 return 0;
858 }
859 null_value= false;
860 double val= 1 + prev_value * (get_row_count()-1);
861
862 /*
863 Applying the formula to get the value
864 If (CRN = FRN = RN) then the result is (value of expression from row at RN)
865 Otherwise the result is
866 (CRN - RN) * (value of expression for row at FRN) +
867 (RN - FRN) * (value of expression for row at CRN)
868 */
869
870 if(ceil(val) == floor(val))
871 return floor_value->val_real();
872
873 double ret_val= ((val - floor(val)) * ceil_value->val_real()) +
874 ((ceil(val) - val) * floor_value->val_real());
875
876 return ret_val;
877 }
878
879 bool add()
880 {
881 Item *arg= get_arg(0);
882 if (arg->is_null())
883 return false;
884
885 if (first_call)
886 {
887 first_call= false;
888 prev_value= arg->val_real();
889 if (prev_value > 1 || prev_value < 0)
890 {
891 my_error(ER_ARGUMENT_OUT_OF_RANGE, MYF(0), func_name());
892 return true;
893 }
894 }
895
896 double arg_val= arg->val_real();
897 if (prev_value != arg_val)
898 {
899 my_error(ER_ARGUMENT_NOT_CONSTANT, MYF(0), func_name());
900 return true;
901 }
902
903 if (!floor_val_calculated)
904 {
905 floor_value->store(order_item);
906 floor_value->cache_value();
907 if (floor_value->null_value)
908 return false;
909 }
910 if (floor_val_calculated && !ceil_val_calculated)
911 {
912 ceil_value->store(order_item);
913 ceil_value->cache_value();
914 if (ceil_value->null_value)
915 return false;
916 }
917
918 Item_sum_cume_dist::add();
919 double val= 1 + prev_value * (get_row_count()-1);
920
921 if (!floor_val_calculated && get_row_number() == floor(val))
922 floor_val_calculated= true;
923
924 if (!ceil_val_calculated && get_row_number() == ceil(val))
925 ceil_val_calculated= true;
926 return false;
927 }
928
929 enum Sumfunctype sum_func() const
930 {
931 return PERCENTILE_CONT_FUNC;
932 }
933
934 void clear()
935 {
936 first_call= true;
937 floor_value->clear();
938 ceil_value->clear();
939 floor_val_calculated= false;
940 ceil_val_calculated= false;
941 Item_sum_cume_dist::clear();
942 }
943
944 const char*func_name() const
945 {
946 return "percentile_cont";
947 }
948 void update_field() {}
949 void set_type_handler(Window_spec *window_spec);
950 const Type_handler *type_handler() const
951 {return Type_handler_hybrid_field_type::type_handler();}
952
953 void fix_length_and_dec()
954 {
955 decimals = 10; // TODO-cvicentiu find out how many decimals the standard
956 // requires.
957 }
958
959 Item *get_copy(THD *thd)
960 { return get_item_copy<Item_sum_percentile_cont>(thd, this); }
961 void setup_window_func(THD *thd, Window_spec *window_spec);
962 void setup_hybrid(THD *thd, Item *item);
963 bool fix_fields(THD *thd, Item **ref);
964
965private:
966 Item_cache *floor_value;
967 Item_cache *ceil_value;
968 bool first_call;
969 double prev_value;
970 bool ceil_val_calculated;
971 bool floor_val_calculated;
972 Item *order_item;
973};
974
975
976
977
978class Item_window_func : public Item_func_or_sum
979{
980 /* Window function parameters as we've got them from the parser */
981public:
982 LEX_CSTRING *window_name;
983public:
984 Window_spec *window_spec;
985
986public:
987 Item_window_func(THD *thd, Item_sum *win_func, LEX_CSTRING *win_name)
988 : Item_func_or_sum(thd, (Item *) win_func),
989 window_name(win_name), window_spec(NULL),
990 force_return_blank(true),
991 read_value_from_result_field(false) {}
992
993 Item_window_func(THD *thd, Item_sum *win_func, Window_spec *win_spec)
994 : Item_func_or_sum(thd, (Item *) win_func),
995 window_name(NULL), window_spec(win_spec),
996 force_return_blank(true),
997 read_value_from_result_field(false) {}
998
999 Item_sum *window_func() const { return (Item_sum *) args[0]; }
1000
1001 void update_used_tables();
1002
1003 /*
1004 This is used by filesort to mark the columns it needs to read (because they
1005 participate in the sort criteria and/or row retrieval. Window functions can
1006 only be used in sort criteria).
1007
1008 Sorting by window function value is only done after the window functions
1009 have been computed. In that case, window function will need to read its
1010 temp.table field. In order to allow that, mark that field in the read_set.
1011 */
1012 bool register_field_in_read_map(void *arg)
1013 {
1014 TABLE *table= (TABLE*) arg;
1015 if (result_field && (result_field->table == table || !table))
1016 {
1017 bitmap_set_bit(result_field->table->read_set, result_field->field_index);
1018 }
1019 return 0;
1020 }
1021
1022 bool is_frame_prohibited() const
1023 {
1024 switch (window_func()->sum_func()) {
1025 case Item_sum::ROW_NUMBER_FUNC:
1026 case Item_sum::RANK_FUNC:
1027 case Item_sum::DENSE_RANK_FUNC:
1028 case Item_sum::PERCENT_RANK_FUNC:
1029 case Item_sum::CUME_DIST_FUNC:
1030 case Item_sum::NTILE_FUNC:
1031 case Item_sum::PERCENTILE_CONT_FUNC:
1032 case Item_sum::PERCENTILE_DISC_FUNC:
1033 return true;
1034 default:
1035 return false;
1036 }
1037 }
1038
1039 bool requires_special_cursors() const
1040 {
1041 switch (window_func()->sum_func()) {
1042 case Item_sum::FIRST_VALUE_FUNC:
1043 case Item_sum::LAST_VALUE_FUNC:
1044 case Item_sum::NTH_VALUE_FUNC:
1045 case Item_sum::LAG_FUNC:
1046 case Item_sum::LEAD_FUNC:
1047 return true;
1048 default:
1049 return false;
1050 }
1051 }
1052
1053 bool requires_partition_size() const
1054 {
1055 switch (window_func()->sum_func()) {
1056 case Item_sum::PERCENT_RANK_FUNC:
1057 case Item_sum::CUME_DIST_FUNC:
1058 case Item_sum::NTILE_FUNC:
1059 case Item_sum::PERCENTILE_CONT_FUNC:
1060 case Item_sum::PERCENTILE_DISC_FUNC:
1061 return true;
1062 default:
1063 return false;
1064 }
1065 }
1066
1067 bool requires_peer_size() const
1068 {
1069 switch (window_func()->sum_func()) {
1070 case Item_sum::CUME_DIST_FUNC:
1071 return true;
1072 default:
1073 return false;
1074 }
1075 }
1076
1077 bool is_order_list_mandatory() const
1078 {
1079 switch (window_func()->sum_func()) {
1080 case Item_sum::RANK_FUNC:
1081 case Item_sum::DENSE_RANK_FUNC:
1082 case Item_sum::PERCENT_RANK_FUNC:
1083 case Item_sum::CUME_DIST_FUNC:
1084 case Item_sum::PERCENTILE_CONT_FUNC:
1085 case Item_sum::PERCENTILE_DISC_FUNC:
1086 return true;
1087 default:
1088 return false;
1089 }
1090 }
1091
1092 bool only_single_element_order_list() const
1093 {
1094 switch (window_func()->sum_func()){
1095 case Item_sum::PERCENTILE_CONT_FUNC:
1096 case Item_sum::PERCENTILE_DISC_FUNC:
1097 return true;
1098 default:
1099 return false;
1100 }
1101 }
1102
1103 void setting_handler_for_percentile_functions(Item_result rtype) const
1104 {
1105 switch (window_func()->sum_func()){
1106 case Item_sum::PERCENTILE_DISC_FUNC:
1107 ((Item_sum_percentile_disc* ) window_func())->set_handler_by_cmp_type(rtype);
1108 break;
1109 default:
1110 return;
1111 }
1112 }
1113
1114 bool check_result_type_of_order_item();
1115
1116
1117
1118 /*
1119 Computation functions.
1120 TODO: consoder merging these with class Group_bound_tracker.
1121 */
1122 void setup_partition_border_check(THD *thd);
1123
1124 const Type_handler *type_handler() const
1125 {
1126 return ((Item_sum *) args[0])->type_handler();
1127 }
1128 enum Item::Type type() const { return Item::WINDOW_FUNC_ITEM; }
1129
1130private:
1131 /*
1132 Window functions are very special functions, so val_() methods have
1133 special meaning for them:
1134
1135 - Phase#1, "Initial" we run the join and put its result into temporary
1136 table. For window functions, we write the default value (NULL?) as
1137 a placeholder.
1138
1139 - Phase#2: "Computation": executor does the scan in {PARTITION, ORDER BY}
1140 order of this window function. It calls appropriate methods to inform
1141 the window function about rows entering/leaving the window.
1142 It calls window_func()->val_int() so that current window function value
1143 can be saved and stored in the temp.table.
1144
1145 - Phase#3: "Retrieval" the temporary table is read and passed to query
1146 output. However, Item_window_func still remains in the select list,
1147 so item_windowfunc->val_int() will be called.
1148 During Phase#3, read_value_from_result_field= true.
1149 */
1150 bool force_return_blank;
1151 bool read_value_from_result_field;
1152
1153public:
1154 void set_phase_to_initial()
1155 {
1156 force_return_blank= true;
1157 read_value_from_result_field= false;
1158 }
1159 void set_phase_to_computation()
1160 {
1161 force_return_blank= false;
1162 read_value_from_result_field= false;
1163 }
1164 void set_phase_to_retrieval()
1165 {
1166 force_return_blank= false;
1167 read_value_from_result_field= true;
1168 }
1169
1170 bool is_null()
1171 {
1172 if (force_return_blank)
1173 return true;
1174
1175 if (read_value_from_result_field)
1176 return result_field->is_null();
1177
1178 return window_func()->is_null();
1179 }
1180
1181 double val_real()
1182 {
1183 double res;
1184 if (force_return_blank)
1185 {
1186 res= 0.0;
1187 null_value= true;
1188 }
1189 else if (read_value_from_result_field)
1190 {
1191 res= result_field->val_real();
1192 null_value= result_field->is_null();
1193 }
1194 else
1195 {
1196 res= window_func()->val_real();
1197 null_value= window_func()->null_value;
1198 }
1199 return res;
1200 }
1201
1202 longlong val_int()
1203 {
1204 longlong res;
1205 if (force_return_blank)
1206 {
1207 res= 0;
1208 null_value= true;
1209 }
1210 else if (read_value_from_result_field)
1211 {
1212 res= result_field->val_int();
1213 null_value= result_field->is_null();
1214 }
1215 else
1216 {
1217 res= window_func()->val_int();
1218 null_value= window_func()->null_value;
1219 }
1220 return res;
1221 }
1222
1223 String* val_str(String* str)
1224 {
1225 String *res;
1226 if (force_return_blank)
1227 {
1228 null_value= true;
1229 res= NULL;
1230 }
1231 else if (read_value_from_result_field)
1232 {
1233 if ((null_value= result_field->is_null()))
1234 res= NULL;
1235 else
1236 res= result_field->val_str(str);
1237 }
1238 else
1239 {
1240 res= window_func()->val_str(str);
1241 null_value= window_func()->null_value;
1242 }
1243 return res;
1244 }
1245
1246 my_decimal* val_decimal(my_decimal* dec)
1247 {
1248 my_decimal *res;
1249 if (force_return_blank)
1250 {
1251 null_value= true;
1252 res= NULL;
1253 }
1254 else if (read_value_from_result_field)
1255 {
1256 if ((null_value= result_field->is_null()))
1257 res= NULL;
1258 else
1259 res= result_field->val_decimal(dec);
1260 }
1261 else
1262 {
1263 res= window_func()->val_decimal(dec);
1264 null_value= window_func()->null_value;
1265 }
1266 return res;
1267 }
1268
1269 bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
1270 {
1271 bool res;
1272 if (force_return_blank)
1273 {
1274 null_value= true;
1275 res= true;
1276 }
1277 else if (read_value_from_result_field)
1278 {
1279 if ((null_value= result_field->is_null()))
1280 res= true;
1281 else
1282 res= result_field->get_date(ltime, fuzzydate);
1283 }
1284 else
1285 {
1286 res= window_func()->get_date(ltime, fuzzydate);
1287 null_value= window_func()->null_value;
1288 }
1289 return res;
1290 }
1291
1292 void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
1293 List<Item> &fields, uint flags);
1294
1295 void fix_length_and_dec()
1296 {
1297 decimals = window_func()->decimals;
1298 }
1299
1300 const char* func_name() const { return "WF"; }
1301
1302 bool fix_fields(THD *thd, Item **ref);
1303
1304 bool resolve_window_name(THD *thd);
1305
1306 void print(String *str, enum_query_type query_type);
1307
1308 Item *get_copy(THD *thd) { return 0; }
1309
1310};
1311
1312#endif /* ITEM_WINDOWFUNC_INCLUDED */
1313