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 | |
22 | class Window_spec; |
23 | |
24 | |
25 | int test_if_group_changed(List<Cached_item> &list); |
26 | |
27 | |
28 | /* A wrapper around test_if_group_changed */ |
29 | class Group_bound_tracker |
30 | { |
31 | public: |
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 | |
90 | private: |
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 | |
113 | class Item_sum_row_number: public Item_sum_int |
114 | { |
115 | longlong count; |
116 | |
117 | public: |
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 | |
171 | class Item_sum_rank: public Item_sum_int |
172 | { |
173 | protected: |
174 | longlong row_number; // just ROW_NUMBER() |
175 | longlong cur_rank; // current value |
176 | |
177 | Group_bound_tracker *peer_tracker; |
178 | public: |
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 | |
248 | class 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 | |
298 | class 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 | */ |
341 | class 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 | */ |
368 | class 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 | |
388 | class 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 | |
408 | class 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 | |
428 | class 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 | */ |
452 | class 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 | */ |
480 | class 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 | |
571 | class 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 | |
635 | class 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 = 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 | |
706 | class Item_sum_percentile_disc : public Item_sum_cume_dist, |
707 | public Type_handler_hybrid_field_type |
708 | { |
709 | public: |
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 | |
835 | private: |
836 | Item_cache *value; |
837 | bool val_calculated; |
838 | bool first_call; |
839 | double prev_value; |
840 | Item *order_item; |
841 | }; |
842 | |
843 | class Item_sum_percentile_cont : public Item_sum_cume_dist, |
844 | public Type_handler_hybrid_field_type |
845 | { |
846 | public: |
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 | |
965 | private: |
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 | |
978 | class Item_window_func : public Item_func_or_sum |
979 | { |
980 | /* Window function parameters as we've got them from the parser */ |
981 | public: |
982 | LEX_CSTRING *window_name; |
983 | public: |
984 | Window_spec *window_spec; |
985 | |
986 | public: |
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 | |
1130 | private: |
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 | |
1153 | public: |
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 | |