| 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 |  |