item_sum.cc 45.8 KB
Newer Older
1
/* Copyright (C) 2000-2003 MySQL AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18 19 20 21 22 23 24
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/* Sum functions (COUNT, MIN...) */

#ifdef __GNUC__
#pragma implementation				// gcc: Class implementation
#endif

#include "mysql_priv.h"
25

bk@work.mysql.com's avatar
bk@work.mysql.com committed
26
Item_sum::Item_sum(List<Item> &list)
27
  :args_copy(0), arg_count(list.elements)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
28 29 30 31
{
  if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
  {
    uint i=0;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
32
    List_iterator_fast<Item> li(list);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
33 34 35 36 37 38 39
    Item *item;

    while ((item=li++))
    {
      args[i++]= item;
    }
  }
40
  mark_as_sum_func();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
41 42 43
  list.empty();					// Fields are used
}

44 45 46 47 48

/*
  Constructor used in processing select with temporary tebles
*/

49
Item_sum::Item_sum(THD *thd, Item_sum *item):
50 51
  Item_result_field(thd, item), arg_count(item->arg_count),
  quick_group(item->quick_group)
52 53 54 55
{
  if (arg_count <= 2)
    args=tmp_args;
  else
56
    if (!(args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
57
      return;
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
  memcpy(args, item->args, sizeof(Item*)*arg_count);
  if (item->args_copy != 0)
    save_args(thd);
  else
    args_copy= 0;
}


/*
  Save copy of arguments if we are prepare prepared statement
  (arguments can be rewritten in get_tmp_table_item())

  SYNOPSIS
    Item_sum::save_args_for_prepared_statements()
    thd		- thread handler

  RETURN
    0 - OK
    1 - Error
*/
bool Item_sum::save_args_for_prepared_statements(THD *thd)
{
  if (thd->current_statement)
    return save_args(thd->current_statement);
  return 0;
83 84
}

85 86 87 88 89 90 91 92 93 94

bool Item_sum::save_args(Statement* stmt)
{
  if (!(args_copy= (Item**) stmt->alloc(sizeof(Item*)*arg_count)))
    return 1;
  memcpy(args_copy, args, sizeof(Item*)*arg_count);
  return 0;
}


95
void Item_sum::mark_as_sum_func()
96
{
97
  current_thd->lex->current_select->with_sum_func= 1;
98
  with_sum_func= 1;
99
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
100

101

102 103 104 105 106 107 108 109 110 111 112
void Item_sum::cleanup()
{
  DBUG_ENTER("Item_sum::cleanup");
  Item_result_field::cleanup();
  if (args_copy != 0)
    memcpy(args, args_copy, sizeof(Item*)*arg_count);
  result_field=0;
  DBUG_VOID_RETURN;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
113 114 115 116
void Item_sum::make_field(Send_field *tmp_field)
{
  if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
  {
117 118 119 120
    ((Item_field*) args[0])->field->make_field(tmp_field);
    tmp_field->db_name=(char*)"";
    tmp_field->org_table_name=tmp_field->table_name=(char*)"";
    tmp_field->org_col_name=tmp_field->col_name=name;
121 122
    if (maybe_null)
      tmp_field->flags&= ~NOT_NULL_FLAG;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
123
  }
124 125
  else
    init_make_field(tmp_field, field_type());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
126 127
}

128

bk@work.mysql.com's avatar
bk@work.mysql.com committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
void Item_sum::print(String *str)
{
  str->append(func_name());
  str->append('(');
  for (uint i=0 ; i < arg_count ; i++)
  {
    if (i)
      str->append(',');
    args[i]->print(str);
  }
  str->append(')');
}

void Item_sum::fix_num_length_and_dec()
{
  decimals=0;
  for (uint i=0 ; i < arg_count ; i++)
    set_if_bigger(decimals,args[i]->decimals);
  max_length=float_length(decimals);
}

150
Item *Item_sum::get_tmp_table_item(THD *thd)
151
{
152
  Item_sum* sum_item= (Item_sum *) copy_or_same(thd);
153 154
  if (sum_item && sum_item->result_field)	   // If not a const sum func
  {
155
    Field *result_field_tmp= sum_item->result_field;
156 157 158 159 160 161
    for (uint i=0 ; i < sum_item->arg_count ; i++)
    {
      Item *arg= sum_item->args[i];
      if (!arg->const_item())
      {
	if (arg->type() == Item::FIELD_ITEM)
162
	  ((Item_field*) arg)->field= result_field_tmp++;
163
	else
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
164
	  sum_item->args[i]= new Item_field(result_field_tmp++);
165 166 167 168 169
      }
    }
  }
  return sum_item;
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
170

171 172 173 174 175 176 177 178 179 180 181 182 183 184
bool Item_sum::walk (Item_processor processor, byte *argument)
{
  if (arg_count)
  {
    Item **arg,**arg_end;
    for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
    {
      if ((*arg)->walk(processor, argument))
	return 1;
    }
  }
  return (this->*processor)(argument);
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
185 186 187
String *
Item_sum_num::val_str(String *str)
{
188
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
189 190 191
  double nr=val();
  if (null_value)
    return 0;
monty@mysql.com's avatar
monty@mysql.com committed
192
  str->set(nr,decimals, &my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
193 194 195 196 197 198 199
  return str;
}


String *
Item_sum_int::val_str(String *str)
{
200
  DBUG_ASSERT(fixed == 1);
201
  longlong nr= val_int();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
202 203
  if (null_value)
    return 0;
204
  if (unsigned_flag)
monty@mysql.com's avatar
monty@mysql.com committed
205
    str->set((ulonglong) nr, &my_charset_bin);
206
  else
monty@mysql.com's avatar
monty@mysql.com committed
207
    str->set(nr, &my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
208 209 210 211 212
  return str;
}


bool
213
Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
214
{
215
  DBUG_ASSERT(fixed == 0);
216 217 218 219

  if (save_args_for_prepared_statements(thd))
    return 1;
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
220 221 222 223 224 225 226 227 228 229
  if (!thd->allow_sum_func)
  {
    my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
    return 1;
  }
  thd->allow_sum_func=0;			// No included group funcs
  decimals=0;
  maybe_null=0;
  for (uint i=0 ; i < arg_count ; i++)
  {
230
    if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
231 232 233 234 235 236 237 238 239 240
      return 1;
    if (decimals < args[i]->decimals)
      decimals=args[i]->decimals;
    maybe_null |= args[i]->maybe_null;
  }
  result_field=0;
  max_length=float_length(decimals);
  null_value=1;
  fix_length_and_dec();
  thd->allow_sum_func=1;			// Allow group functions
241
  fixed= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
242 243 244 245 246
  return 0;
}


bool
247
Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
248
{
249
  DBUG_ASSERT(fixed == 0);
250 251 252 253

  if (save_args_for_prepared_statements(thd))
    return 1;

254
  Item *item= args[0];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
255 256 257 258 259 260
  if (!thd->allow_sum_func)
  {
    my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
    return 1;
  }
  thd->allow_sum_func=0;			// No included group funcs
261 262

  // 'item' can be changed during fix_fields
263
  if (!item->fixed &&
264 265
      item->fix_fields(thd, tables, args) ||
      (item= args[0])->check_cols(1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
266
    return 1;
267 268

  hybrid_type= item->result_type();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
269
  if (hybrid_type == INT_RESULT)
270 271
  {
    cmp_charset= &my_charset_bin;
272
    max_length=20;
273
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
274
  else if (hybrid_type == REAL_RESULT)
275 276
  {
    cmp_charset= &my_charset_bin;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
277
    max_length=float_length(decimals);
278
  }else
279
  {
280
    cmp_charset= item->collation.collation;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
281
    max_length=item->max_length;
282
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
283
  decimals=item->decimals;
284 285
  /* MIN/MAX can return NULL for empty set indepedent of the used column */
  maybe_null= 1;
286
  unsigned_flag=item->unsigned_flag;
287
  collation.set(item->collation);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
288 289 290 291
  result_field=0;
  null_value=1;
  fix_length_and_dec();
  thd->allow_sum_func=1;			// Allow group functions
292 293 294 295
  if (item->type() == Item::FIELD_ITEM)
    hybrid_field_type= ((Item_field*) item)->field->type();
  else
    hybrid_field_type= Item::field_type();
296
  fixed= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
297 298 299 300 301 302 303 304
  return 0;
}


/***********************************************************************
** reset and add of sum_func
***********************************************************************/

305
Item *Item_sum_sum::copy_or_same(THD* thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
306
{
307
  return new (&thd->mem_root) Item_sum_sum(thd, this);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
308 309
}

310

311
void Item_sum_sum::clear()
312 313 314 315 316
{
  null_value=1; sum=0.0;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
317 318 319
bool Item_sum_sum::add()
{
  sum+=args[0]->val();
320 321
  if (!args[0]->null_value)
    null_value= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
322 323 324
  return 0;
}

325

bk@work.mysql.com's avatar
bk@work.mysql.com committed
326 327
double Item_sum_sum::val()
{
328
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
329 330 331 332
  return sum;
}


333
Item *Item_sum_count::copy_or_same(THD* thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
334
{
335
  return new (&thd->mem_root) Item_sum_count(thd, this);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
336 337
}

338

339
void Item_sum_count::clear()
340
{
341
  count= 0;
342 343 344
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
bool Item_sum_count::add()
{
  if (!args[0]->maybe_null)
    count++;
  else
  {
    (void) args[0]->val_int();
    if (!args[0]->null_value)
      count++;
  }
  return 0;
}

longlong Item_sum_count::val_int()
{
360
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
361 362 363
  return (longlong) count;
}

364 365 366 367 368 369 370 371 372 373

void Item_sum_count::cleanup()
{
  DBUG_ENTER("Item_sum_count::cleanup");
  Item_sum_int::cleanup();
  used_table_cache= ~(table_map) 0;
  DBUG_VOID_RETURN;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
374
/*
375
  Avgerage
bk@work.mysql.com's avatar
bk@work.mysql.com committed
376 377
*/

378
Item *Item_sum_avg::copy_or_same(THD* thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
379
{
380
  return new (&thd->mem_root) Item_sum_avg(thd, this);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
381 382
}

383

384
void Item_sum_avg::clear()
385 386 387 388 389
{
  sum=0.0; count=0;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
390 391 392 393 394 395 396 397 398 399 400 401 402
bool Item_sum_avg::add()
{
  double nr=args[0]->val();
  if (!args[0]->null_value)
  {
    sum+=nr;
    count++;
  }
  return 0;
}

double Item_sum_avg::val()
{
403
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
404 405 406 407 408 409 410 411 412 413 414
  if (!count)
  {
    null_value=1;
    return 0.0;
  }
  null_value=0;
  return sum/ulonglong2double(count);
}


/*
415
  Standard deviation
bk@work.mysql.com's avatar
bk@work.mysql.com committed
416 417
*/

418
double Item_sum_std::val()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
419
{
420
  DBUG_ASSERT(fixed == 1);
421 422
  double tmp= Item_sum_variance::val();
  return tmp <= 0.0 ? 0.0 : sqrt(tmp);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
423 424
}

425 426
Item *Item_sum_std::copy_or_same(THD* thd)
{
427
  return new (&thd->mem_root) Item_sum_std(thd, this);
428 429 430
}


431
/*
432
  Variance
433 434
*/

435 436
Item *Item_sum_variance::copy_or_same(THD* thd)
{
437
  return new (&thd->mem_root) Item_sum_variance(thd, this);
438 439 440
}


441
void Item_sum_variance::clear()
442 443 444 445 446 447
{
  sum=sum_sqr=0.0; 
  count=0; 
}

bool Item_sum_variance::add()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
448 449 450 451 452 453 454 455 456 457 458
{
  double nr=args[0]->val();
  if (!args[0]->null_value)
  {
    sum+=nr;
    sum_sqr+=nr*nr;
    count++;
  }
  return 0;
}

459
double Item_sum_variance::val()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
460
{
461
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
462 463 464 465 466 467 468 469 470
  if (!count)
  {
    null_value=1;
    return 0.0;
  }
  null_value=0;
  /* Avoid problems when the precision isn't good enough */
  double tmp=ulonglong2double(count);
  double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
471
  return tmp2 <= 0.0 ? 0.0 : tmp2;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
472 473
}

474
void Item_sum_variance::reset_field()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
{
  double nr=args[0]->val();
  char *res=result_field->ptr;

  if (args[0]->null_value)
    bzero(res,sizeof(double)*2+sizeof(longlong));
  else
  {
    float8store(res,nr);
    nr*=nr;
    float8store(res+sizeof(double),nr);
    longlong tmp=1;
    int8store(res+sizeof(double)*2,tmp);
  }
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
491
void Item_sum_variance::update_field()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
492 493 494 495 496
{
  double nr,old_nr,old_sqr;
  longlong field_count;
  char *res=result_field->ptr;

497 498 499
  float8get(old_nr, res);
  float8get(old_sqr, res+sizeof(double));
  field_count=sint8korr(res+sizeof(double)*2);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514

  nr=args[0]->val();
  if (!args[0]->null_value)
  {
    old_nr+=nr;
    old_sqr+=nr*nr;
    field_count++;
  }
  float8store(res,old_nr);
  float8store(res+sizeof(double),old_sqr);
  int8store(res+sizeof(double)*2,field_count);
}

/* min & max */

515 516 517 518 519 520 521 522
void Item_sum_hybrid::clear()
{
  sum= 0.0;
  sum_int= 0;
  value.length(0);
  null_value= 1;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
523 524
double Item_sum_hybrid::val()
{
525
  DBUG_ASSERT(fixed == 1);
526
  int err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
527 528
  if (null_value)
    return 0.0;
529 530
  switch (hybrid_type) {
  case STRING_RESULT:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
531
    String *res;  res=val_str(&str_value);
532
    return (res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(),
533
			     (char**) 0, &err) : 0.0);
534 535 536 537 538 539
  case INT_RESULT:
    if (unsigned_flag)
      return ulonglong2double(sum_int);
    return (double) sum_int;
  case REAL_RESULT:
    return sum;
540
  case ROW_RESULT:
541
  default:
542 543 544
    // This case should never be choosen
    DBUG_ASSERT(0);
    return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
545
  }
546 547 548 549 550
  return 0;					// Keep compiler happy
}

longlong Item_sum_hybrid::val_int()
{
551
  DBUG_ASSERT(fixed == 1);
552 553 554 555 556
  if (null_value)
    return 0;
  if (hybrid_type == INT_RESULT)
    return sum_int;
  return (longlong) Item_sum_hybrid::val();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
557 558 559 560 561 562
}


String *
Item_sum_hybrid::val_str(String *str)
{
563
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
564 565
  if (null_value)
    return 0;
566 567
  switch (hybrid_type) {
  case STRING_RESULT:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
568
    return &value;
569
  case REAL_RESULT:
monty@mysql.com's avatar
monty@mysql.com committed
570
    str->set(sum,decimals, &my_charset_bin);
571 572 573
    break;
  case INT_RESULT:
    if (unsigned_flag)
monty@mysql.com's avatar
monty@mysql.com committed
574
      str->set((ulonglong) sum_int, &my_charset_bin);
575
    else
monty@mysql.com's avatar
monty@mysql.com committed
576
      str->set((longlong) sum_int, &my_charset_bin);
577
    break;
578
  case ROW_RESULT:
579
  default:
580 581 582
    // This case should never be choosen
    DBUG_ASSERT(0);
    break;
583 584
  }
  return str;					// Keep compiler happy
bk@work.mysql.com's avatar
bk@work.mysql.com committed
585 586
}

587

588 589 590 591 592 593 594 595 596
void Item_sum_hybrid::cleanup()
{
  DBUG_ENTER("Item_sum_hybrid::cleanup");
  Item_sum::cleanup();
  used_table_cache= ~(table_map) 0;
  DBUG_VOID_RETURN;
}


597 598
Item *Item_sum_min::copy_or_same(THD* thd)
{
599
  return new (&thd->mem_root) Item_sum_min(thd, this);
600 601 602
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
603 604
bool Item_sum_min::add()
{
605 606
  switch (hybrid_type) {
  case STRING_RESULT:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
607 608 609
  {
    String *result=args[0]->val_str(&tmp_value);
    if (!args[0]->null_value &&
610
	(null_value || sortcmp(&value,result,cmp_charset) > 0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
611 612 613 614 615
    {
      value.copy(*result);
      null_value=0;
    }
  }
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
  break;
  case INT_RESULT:
  {
    longlong nr=args[0]->val_int();
    if (!args[0]->null_value && (null_value ||
				 (unsigned_flag && 
				  (ulonglong) nr < (ulonglong) sum_int) ||
				 (!unsigned_flag && nr < sum_int)))
    {
      sum_int=nr;
      null_value=0;
    }
  }
  break;
  case REAL_RESULT:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
631 632
  {
    double nr=args[0]->val();
633
    if (!args[0]->null_value && (null_value || nr < sum))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
634 635 636 637 638
    {
      sum=nr;
      null_value=0;
    }
  }
639
  break;
640
  case ROW_RESULT:
641
  default:
642 643 644
    // This case should never be choosen
    DBUG_ASSERT(0);
    break;
645 646 647 648 649
  }
  return 0;
}


650 651
Item *Item_sum_max::copy_or_same(THD* thd)
{
652
  return new (&thd->mem_root) Item_sum_max(thd, this);
653 654 655
}


656 657 658 659
bool Item_sum_max::add()
{
  switch (hybrid_type) {
  case STRING_RESULT:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
660 661 662
  {
    String *result=args[0]->val_str(&tmp_value);
    if (!args[0]->null_value &&
663
	(null_value || sortcmp(&value,result,cmp_charset) < 0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
664 665 666 667 668
    {
      value.copy(*result);
      null_value=0;
    }
  }
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
  break;
  case INT_RESULT:
  {
    longlong nr=args[0]->val_int();
    if (!args[0]->null_value && (null_value ||
				 (unsigned_flag && 
				  (ulonglong) nr > (ulonglong) sum_int) ||
				 (!unsigned_flag && nr > sum_int)))
    {
      sum_int=nr;
      null_value=0;
    }
  }
  break;
  case REAL_RESULT:
  {
    double nr=args[0]->val();
    if (!args[0]->null_value && (null_value || nr > sum))
    {
      sum=nr;
      null_value=0;
    }
  }
  break;
693
  case ROW_RESULT:
694
  default:
695 696 697
    // This case should never be choosen
    DBUG_ASSERT(0);
    break;
698
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
699 700 701 702 703 704 705 706
  return 0;
}


/* bit_or and bit_and */

longlong Item_sum_bit::val_int()
{
707
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
708 709 710
  return (longlong) bits;
}

711

712
void Item_sum_bit::clear()
713
{
714
  bits= reset_bits;
715 716 717
}

Item *Item_sum_or::copy_or_same(THD* thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
718
{
719
  return new (&thd->mem_root) Item_sum_or(thd, this);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
720 721
}

722

bk@work.mysql.com's avatar
bk@work.mysql.com committed
723 724 725 726 727 728 729 730
bool Item_sum_or::add()
{
  ulonglong value= (ulonglong) args[0]->val_int();
  if (!args[0]->null_value)
    bits|=value;
  return 0;
}

731 732
Item *Item_sum_xor::copy_or_same(THD* thd)
{
733
  return new (&thd->mem_root) Item_sum_xor(thd, this);
734 735 736 737 738 739 740 741 742 743 744
}


bool Item_sum_xor::add()
{
  ulonglong value= (ulonglong) args[0]->val_int();
  if (!args[0]->null_value)
    bits^=value;
  return 0;
}

745 746
Item *Item_sum_and::copy_or_same(THD* thd)
{
747
  return new (&thd->mem_root) Item_sum_and(thd, this);
748 749 750
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
bool Item_sum_and::add()
{
  ulonglong value= (ulonglong) args[0]->val_int();
  if (!args[0]->null_value)
    bits&=value;
  return 0;
}

/************************************************************************
** reset result of a Item_sum with is saved in a tmp_table
*************************************************************************/

void Item_sum_num::reset_field()
{
  double nr=args[0]->val();
  char *res=result_field->ptr;

  if (maybe_null)
  {
    if (args[0]->null_value)
    {
      nr=0.0;
      result_field->set_null();
    }
    else
      result_field->set_notnull();
  }
  float8store(res,nr);
}


void Item_sum_hybrid::reset_field()
{
  if (hybrid_type == STRING_RESULT)
  {
    char buff[MAX_FIELD_WIDTH];
787
    String tmp(buff,sizeof(buff),result_field->charset()),*res;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
788 789 790 791 792 793 794 795 796 797

    res=args[0]->val_str(&tmp);
    if (args[0]->null_value)
    {
      result_field->set_null();
      result_field->reset();
    }
    else
    {
      result_field->set_notnull();
798
      result_field->store(res->ptr(),res->length(),tmp.charset());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
    }
  }
  else if (hybrid_type == INT_RESULT)
  {
    longlong nr=args[0]->val_int();

    if (maybe_null)
    {
      if (args[0]->null_value)
      {
	nr=0;
	result_field->set_null();
      }
      else
	result_field->set_notnull();
    }
    result_field->store(nr);
  }
  else						// REAL_RESULT
  {
    double nr=args[0]->val();

    if (maybe_null)
    {
      if (args[0]->null_value)
      {
	nr=0.0;
	result_field->set_null();
      }
      else
	result_field->set_notnull();
    }
    result_field->store(nr);
  }
}


void Item_sum_sum::reset_field()
{
  double nr=args[0]->val();			// Nulls also return 0
  float8store(result_field->ptr,nr);
840 841 842 843
  if (args[0]->null_value)
    result_field->set_null();
  else
    result_field->set_notnull();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
}


void Item_sum_count::reset_field()
{
  char *res=result_field->ptr;
  longlong nr=0;

  if (!args[0]->maybe_null)
    nr=1;
  else
  {
    (void) args[0]->val_int();
    if (!args[0]->null_value)
      nr=1;
  }
  int8store(res,nr);
}


void Item_sum_avg::reset_field()
{
  double nr=args[0]->val();
  char *res=result_field->ptr;

  if (args[0]->null_value)
    bzero(res,sizeof(double)+sizeof(longlong));
  else
  {
    float8store(res,nr);
    res+=sizeof(double);
    longlong tmp=1;
    int8store(res,tmp);
  }
}

void Item_sum_bit::reset_field()
konstantin@mysql.com's avatar
konstantin@mysql.com committed
881
{
882 883
  reset();
  int8store(result_field->ptr, bits);
konstantin@mysql.com's avatar
konstantin@mysql.com committed
884 885 886
}

void Item_sum_bit::update_field()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
887 888
{
  char *res=result_field->ptr;
konstantin@mysql.com's avatar
konstantin@mysql.com committed
889 890 891
  bits= uint8korr(res);
  add();
  int8store(res, bits);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
892 893 894 895 896 897
}

/*
** calc next value and merge it with field_value
*/

898
void Item_sum_sum::update_field()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
899 900 901 902
{
  double old_nr,nr;
  char *res=result_field->ptr;

903
  float8get(old_nr,res);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
904 905
  nr=args[0]->val();
  if (!args[0]->null_value)
906
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
907
    old_nr+=nr;
908 909
    result_field->set_notnull();
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
910 911 912 913
  float8store(res,old_nr);
}


914
void Item_sum_count::update_field()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
915 916 917 918
{
  longlong nr;
  char *res=result_field->ptr;

919
  nr=sint8korr(res);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
920 921 922 923 924 925 926 927 928 929 930 931
  if (!args[0]->maybe_null)
    nr++;
  else
  {
    (void) args[0]->val_int();
    if (!args[0]->null_value)
      nr++;
  }
  int8store(res,nr);
}


932
void Item_sum_avg::update_field()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
933 934 935 936 937
{
  double nr,old_nr;
  longlong field_count;
  char *res=result_field->ptr;

938 939
  float8get(old_nr,res);
  field_count=sint8korr(res+sizeof(double));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
940 941 942 943 944 945 946 947 948 949 950 951

  nr=args[0]->val();
  if (!args[0]->null_value)
  {
    old_nr+=nr;
    field_count++;
  }
  float8store(res,old_nr);
  res+=sizeof(double);
  int8store(res,field_count);
}

952
void Item_sum_hybrid::update_field()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
953 954
{
  if (hybrid_type == STRING_RESULT)
955
    min_max_update_str_field();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
956
  else if (hybrid_type == INT_RESULT)
957
    min_max_update_int_field();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
958
  else
959
    min_max_update_real_field();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
960 961 962 963
}


void
964
Item_sum_hybrid::min_max_update_str_field()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
965 966 967
{
  String *res_str=args[0]->val_str(&value);

968
  if (!args[0]->null_value)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
969 970
  {
    res_str->strip_sp();
971
    result_field->val_str(&tmp_value);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
972 973

    if (result_field->is_null() ||
974
	(cmp_sign * sortcmp(res_str,&tmp_value,cmp_charset)) < 0)
975
      result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
976 977 978 979 980 981
    result_field->set_notnull();
  }
}


void
982
Item_sum_hybrid::min_max_update_real_field()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
983 984 985 986 987 988 989
{
  double nr,old_nr;

  old_nr=result_field->val_real();
  nr=args[0]->val();
  if (!args[0]->null_value)
  {
990
    if (result_field->is_null(0) ||
bk@work.mysql.com's avatar
bk@work.mysql.com committed
991 992 993 994
	(cmp_sign > 0 ? old_nr > nr : old_nr < nr))
      old_nr=nr;
    result_field->set_notnull();
  }
995
  else if (result_field->is_null(0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
996 997 998 999 1000 1001
    result_field->set_null();
  result_field->store(old_nr);
}


void
1002
Item_sum_hybrid::min_max_update_int_field()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1003 1004 1005 1006 1007 1008 1009
{
  longlong nr,old_nr;

  old_nr=result_field->val_int();
  nr=args[0]->val_int();
  if (!args[0]->null_value)
  {
1010
    if (result_field->is_null(0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1011
      old_nr=nr;
1012 1013 1014 1015 1016 1017
    else
    {
      bool res=(unsigned_flag ?
		(ulonglong) old_nr > (ulonglong) nr :
		old_nr > nr);
      /* (cmp_sign > 0 && res) || (!(cmp_sign > 0) && !res) */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1018
      if ((cmp_sign > 0) ^ (!res))
1019 1020
	old_nr=nr;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1021 1022
    result_field->set_notnull();
  }
1023
  else if (result_field->is_null(0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
    result_field->set_null();
  result_field->store(old_nr);
}


Item_avg_field::Item_avg_field(Item_sum_avg *item)
{
  name=item->name;
  decimals=item->decimals;
  max_length=item->max_length;
  field=item->result_field;
  maybe_null=1;
}

konstantin@mysql.com's avatar
konstantin@mysql.com committed
1038

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1039 1040
double Item_avg_field::val()
{
1041
  // fix_fields() never calls for this Item
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
  double nr;
  longlong count;
  float8get(nr,field->ptr);
  char *res=(field->ptr+sizeof(double));
  count=sint8korr(res);

  if (!count)
  {
    null_value=1;
    return 0.0;
  }
  null_value=0;
  return nr/(double) count;
}

String *Item_avg_field::val_str(String *str)
{
1059
  // fix_fields() never calls for this Item
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1060 1061 1062
  double nr=Item_avg_field::val();
  if (null_value)
    return 0;
monty@mysql.com's avatar
monty@mysql.com committed
1063
  str->set(nr,decimals, &my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1064 1065 1066 1067
  return str;
}

Item_std_field::Item_std_field(Item_sum_std *item)
1068 1069 1070 1071 1072 1073
  : Item_variance_field(item)
{
}

double Item_std_field::val()
{
1074
  // fix_fields() never calls for this Item
1075 1076 1077 1078 1079
  double tmp= Item_variance_field::val();
  return tmp <= 0.0 ? 0.0 : sqrt(tmp);
}

Item_variance_field::Item_variance_field(Item_sum_variance *item)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1080 1081 1082 1083 1084 1085 1086 1087
{
  name=item->name;
  decimals=item->decimals;
  max_length=item->max_length;
  field=item->result_field;
  maybe_null=1;
}

1088
double Item_variance_field::val()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1089
{
1090
  // fix_fields() never calls for this Item
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
  double sum,sum_sqr;
  longlong count;
  float8get(sum,field->ptr);
  float8get(sum_sqr,(field->ptr+sizeof(double)));
  count=sint8korr(field->ptr+sizeof(double)*2);

  if (!count)
  {
    null_value=1;
    return 0.0;
  }
  null_value=0;
  double tmp= (double) count;
  double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
1105
  return tmp2 <= 0.0 ? 0.0 : tmp2;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1106 1107
}

1108
String *Item_variance_field::val_str(String *str)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1109
{
1110
  // fix_fields() never calls for this Item
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1111 1112 1113
  double nr=val();
  if (null_value)
    return 0;
monty@mysql.com's avatar
monty@mysql.com committed
1114
  str->set(nr,decimals, &my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1115 1116 1117 1118 1119 1120 1121 1122 1123
  return str;
}

/****************************************************************************
** COUNT(DISTINCT ...)
****************************************************************************/

#include "sql_select.h"

1124
int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
1125
{
1126
  return memcmp(key1, key2, *(uint*) arg);
1127 1128
}

1129
int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
1130
{
1131 1132 1133
  Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
  CHARSET_INFO *cs=item->key_charset;
  uint len=item->key_length;
bar@bar.mysql.r18.ru's avatar
Fix:  
bar@bar.mysql.r18.ru committed
1134 1135 1136
  return cs->coll->strnncollsp(cs, 
			       (const uchar*) key1, len, 
			       (const uchar*) key2, len);
1137 1138
}

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1139 1140 1141 1142 1143 1144 1145
/*
  Did not make this one static - at least gcc gets confused when
  I try to declare a static function as a friend. If you can figure
  out the syntax to make a static function a friend, make this one
  static
*/

1146 1147 1148
int composite_key_cmp(void* arg, byte* key1, byte* key2)
{
  Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
  Field **field    = item->table->field;
  Field **field_end= field + item->table->fields;
  uint32 *lengths=item->field_lengths;
  for (; field < field_end; ++field)
  {
    Field* f = *field;
    int len = *lengths++;
    int res = f->key_cmp(key1, key2);
    if (res)
      return res;
    key1 += len;
    key2 += len;
  }
1162 1163 1164
  return 0;
}

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1165 1166 1167 1168
/*
  helper function for walking the tree when we dump it to MyISAM -
  tree_walk will call it for each leaf
*/
1169

1170 1171 1172
int dump_leaf(byte* key, uint32 count __attribute__((unused)),
		     Item_sum_count_distinct* item)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1173
  byte* buf = item->table->record[0];
1174
  int error;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1175 1176
  /*
    The first item->rec_offset bytes are taken care of with
1177
    restore_record(table,default_values) in setup()
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1178
  */
1179
  memcpy(buf + item->rec_offset, key, item->tree->size_of_element);
1180 1181
  if ((error = item->table->file->write_row(buf)))
  {
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1182 1183 1184
    if (error != HA_ERR_FOUND_DUPP_KEY &&
	error != HA_ERR_FOUND_DUPP_UNIQUE)
      return 1;
1185 1186 1187
  }
  return 0;
}
1188

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1189

hf@deer.(none)'s avatar
hf@deer.(none) committed
1190
void Item_sum_count_distinct::cleanup()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1191
{
1192
  DBUG_ENTER("Item_sum_count_distinct::cleanup");
hf@deer.(none)'s avatar
hf@deer.(none) committed
1193
  Item_sum_int::cleanup();
1194 1195 1196 1197
  /*
    Free table and tree if they belong to this item (if item have not pointer
    to original item from which was made copy => it own its objects )
  */
1198 1199 1200
  if (!original)
  {
    if (table)
1201
    {
1202
      free_tmp_table(current_thd, table);
1203 1204
      table= 0;
    }
1205
    delete tmp_table_param;
1206
    tmp_table_param= 0;
1207
    if (use_tree)
1208
    {
1209
      delete_tree(tree);
1210 1211
      use_tree= 0;
    }
1212
  }
1213
  DBUG_VOID_RETURN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1214 1215
}

1216

1217 1218 1219 1220 1221 1222
/* This is used by rollup to create a separate usable copy of the function */

void Item_sum_count_distinct::make_unique()
{
  table=0;
  original= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1223
  use_tree= 0; // to prevent delete_tree call on uninitialized tree
1224 1225 1226 1227
  tree= &tree_base;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
1228 1229 1230
bool Item_sum_count_distinct::setup(THD *thd)
{
  List<Item> list;
1231
  SELECT_LEX *select_lex= thd->lex->current_select;
1232 1233 1234
  if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
    return 1;
    
1235 1236 1237
  if (!(tmp_table_param= new TMP_TABLE_PARAM))
    return 1;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1238 1239
  /* Create a table with an unique key over all parameters */
  for (uint i=0; i < arg_count ; i++)
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
  {
    Item *item=args[i];
    if (list.push_back(item))
      return 1;					// End of memory
    if (item->const_item())
    {
      (void) item->val_int();
      if (item->null_value)
	always_null=1;
    }
  }
  if (always_null)
    return 0;
1253
  count_field_types(tmp_table_param,list,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1254 1255 1256 1257 1258
  if (table)
  {
    free_tmp_table(thd, table);
    tmp_table_param->cleanup();
  }
1259
  if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1260
				0,
1261
				select_lex->options | thd->options,
1262
				HA_POS_ERROR, (char*)"")))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1263 1264
    return 1;
  table->file->extra(HA_EXTRA_NO_ROWS);		// Don't update rows
1265
  table->no_rows=1;
1266

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1267

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1268 1269 1270 1271 1272
  // no blobs, otherwise it would be MyISAM
  if (table->db_type == DB_TYPE_HEAP)
  {
    qsort_cmp2 compare_key;
    void* cmp_arg;
1273

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1274
    // to make things easier for dump_leaf if we ever have to dump to MyISAM
1275
    restore_record(table,default_values);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1276

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
    if (table->fields == 1)
    {
      /*
	If we have only one field, which is the most common use of
	count(distinct), it is much faster to use a simpler key
	compare method that can take advantage of not having to worry
	about other fields
      */
      Field* field = table->field[0];
      switch(field->type())
      {
      case FIELD_TYPE_STRING:
      case FIELD_TYPE_VAR_STRING:
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
	if (field->binary())
	{
	  compare_key = (qsort_cmp2)simple_raw_key_cmp;
	  cmp_arg = (void*) &key_length;
	}
	else
	{
	  /*
	    If we have a string, we must take care of charsets and case
	    sensitivity
	  */
	  compare_key = (qsort_cmp2)simple_str_key_cmp;
	  cmp_arg = (void*) this;
	}
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1304 1305 1306 1307 1308 1309 1310
	break;
      default:
	/*
	  Since at this point we cannot have blobs anything else can
	  be compared with memcmp
	*/
	compare_key = (qsort_cmp2)simple_raw_key_cmp;
1311
	cmp_arg = (void*) &key_length;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1312 1313
	break;
      }
1314 1315 1316
      key_charset = field->charset();
      key_length  = field->pack_length();
      rec_offset  = 1;
1317
    }
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
    else // too bad, cannot cheat - there is more than one field
    {
      bool all_binary = 1;
      Field** field, **field_end;
      field_end = (field = table->field) + table->fields;
      uint32 *lengths;
      if (!(field_lengths= 
	    (uint32*) thd->alloc(sizeof(uint32) * table->fields)))
	return 1;

1328
      for (key_length = 0, lengths=field_lengths; field < field_end; ++field)
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1329 1330
      {
	uint32 length= (*field)->pack_length();
1331
	key_length += length;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1332 1333 1334 1335
	*lengths++ = length;
	if (!(*field)->binary())
	  all_binary = 0;			// Can't break loop here
      }
1336
      rec_offset = table->reclength - key_length;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1337 1338 1339
      if (all_binary)
      {
	compare_key = (qsort_cmp2)simple_raw_key_cmp;
1340
	cmp_arg = (void*) &key_length;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1341 1342 1343 1344
      }
      else
      {
	compare_key = (qsort_cmp2) composite_key_cmp ;
1345
	cmp_arg = (void*) this;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1346 1347 1348
      }
    }

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1349 1350
    if (use_tree)
      delete_tree(tree);
1351 1352
    init_tree(tree, min(thd->variables.max_heap_table_size,
			thd->variables.sortbuff_size/16), 0,
1353
	      key_length, compare_key, 0, NULL, cmp_arg);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1354 1355 1356
    use_tree = 1;

    /*
1357
      The only time key_length could be 0 is if someone does
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1358 1359 1360 1361
      count(distinct) on a char(0) field - stupid thing to do,
      but this has to be handled - otherwise someone can crash
      the server with a DoS attack
    */
1362 1363
    max_elements_in_tree = ((key_length) ? 
			    thd->variables.max_heap_table_size/key_length : 1);
1364 1365 1366 1367 1368 1369

  }
  if (original)
  {
    original->table= table;
    original->use_tree= use_tree;
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1370
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1371 1372 1373
  return 0;
}

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1374

1375 1376
int Item_sum_count_distinct::tree_to_myisam()
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1377
  if (create_myisam_from_heap(current_thd, table, tmp_table_param,
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1378
			      HA_ERR_RECORD_FILE_FULL, 1) ||
1379
      tree_walk(tree, (tree_walk_action)&dump_leaf, (void*)this,
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1380
		left_root_right))
1381
    return 1;
1382
  delete_tree(tree);
1383 1384 1385
  use_tree = 0;
  return 0;
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1386

1387 1388 1389

Item *Item_sum_count_distinct::copy_or_same(THD* thd) 
{
1390
  return new (&thd->mem_root) Item_sum_count_distinct(thd, this);
1391 1392 1393
}


1394
void Item_sum_count_distinct::clear()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1395
{
monty@work.mysql.com's avatar
merge  
monty@work.mysql.com committed
1396
  if (use_tree)
1397
    reset_tree(tree);
monty@work.mysql.com's avatar
merge  
monty@work.mysql.com committed
1398
  else if (table)
1399 1400 1401 1402 1403
  {
    table->file->extra(HA_EXTRA_NO_CACHE);
    table->file->delete_all_rows();
    table->file->extra(HA_EXTRA_WRITE_CACHE);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1404 1405 1406 1407 1408
}

bool Item_sum_count_distinct::add()
{
  int error;
1409 1410
  if (always_null)
    return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1411
  copy_fields(tmp_table_param);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1412
  copy_funcs(tmp_table_param->items_to_copy);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1413

1414 1415 1416 1417
  for (Field **field=table->field ; *field ; field++)
    if ((*field)->is_real_null(0))
      return 0;					// Don't count NULL

monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1418 1419 1420 1421 1422 1423
  if (use_tree)
  {
    /*
      If the tree got too big, convert to MyISAM, otherwise insert into the
      tree.
    */
1424
    if (tree->elements_in_tree > max_elements_in_tree)
1425
    {
1426
      if (tree_to_myisam())
1427 1428
	return 1;
    }
1429 1430
    else if (!tree_insert(tree, table->record[0] + rec_offset, 0,
			  tree->custom_arg))
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1431 1432
      return 1;
  }
1433
  else if ((error=table->file->write_row(table->record[0])))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1434 1435 1436 1437
  {
    if (error != HA_ERR_FOUND_DUPP_KEY &&
	error != HA_ERR_FOUND_DUPP_UNIQUE)
    {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1438 1439
      if (create_myisam_from_heap(current_thd, table, tmp_table_param, error,
				  1))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1440 1441 1442 1443 1444 1445
	return 1;				// Not a table_is_full error
    }
  }
  return 0;
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1446

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1447 1448
longlong Item_sum_count_distinct::val_int()
{
1449
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1450 1451
  if (!table)					// Empty query
    return LL(0);
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
1452
  if (use_tree)
1453
    return tree->elements_in_tree;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1454 1455 1456 1457
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
  return table->file->records;
}

1458 1459 1460

void Item_sum_count_distinct::print(String *str)
{
1461
  str->append("count(distinct ", 15);
1462 1463 1464 1465
  args[0]->print(str);
  str->append(')');
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1466 1467 1468 1469 1470 1471 1472 1473 1474
/****************************************************************************
** Functions to handle dynamic loadable aggregates
** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su>
** Adapted for UDAs by: Andreas F. Bobak <bobak@relog.ch>.
** Rewritten by: Monty.
****************************************************************************/

#ifdef HAVE_DLOPEN

1475
void Item_udf_sum::clear()
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1476
{
1477
  DBUG_ENTER("Item_udf_sum::clear");
1478
  udf.clear();
1479
  DBUG_VOID_RETURN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1480 1481 1482 1483
}

bool Item_udf_sum::add()
{
1484
  DBUG_ENTER("Item_udf_sum::add");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1485 1486 1487 1488
  udf.add(&null_value);
  DBUG_RETURN(0);
}

1489 1490
Item *Item_sum_udf_float::copy_or_same(THD* thd)
{
1491
  return new (&thd->mem_root) Item_sum_udf_float(thd, this);
1492 1493
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1494 1495
double Item_sum_udf_float::val()
{
1496
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1497 1498 1499 1500 1501 1502 1503 1504
  DBUG_ENTER("Item_sum_udf_float::val");
  DBUG_PRINT("info",("result_type: %d  arg_count: %d",
		     args[0]->result_type(), arg_count));
  DBUG_RETURN(udf.val(&null_value));
}

String *Item_sum_udf_float::val_str(String *str)
{
1505
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1506 1507 1508
  double nr=val();
  if (null_value)
    return 0;					/* purecov: inspected */
monty@mysql.com's avatar
monty@mysql.com committed
1509
  str->set(nr,decimals, &my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1510 1511 1512 1513
  return str;
}


1514 1515
Item *Item_sum_udf_int::copy_or_same(THD* thd)
{
1516
  return new (&thd->mem_root) Item_sum_udf_int(thd, this);
1517 1518 1519
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
1520 1521
longlong Item_sum_udf_int::val_int()
{
1522
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1523 1524 1525 1526 1527 1528
  DBUG_ENTER("Item_sum_udf_int::val_int");
  DBUG_PRINT("info",("result_type: %d  arg_count: %d",
		     args[0]->result_type(), arg_count));
  DBUG_RETURN(udf.val_int(&null_value));
}

1529

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1530 1531
String *Item_sum_udf_int::val_str(String *str)
{
1532
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1533 1534 1535
  longlong nr=val_int();
  if (null_value)
    return 0;
monty@mysql.com's avatar
monty@mysql.com committed
1536
  str->set(nr, &my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550
  return str;
}

/* Default max_length is max argument length */

void Item_sum_udf_str::fix_length_and_dec()
{
  DBUG_ENTER("Item_sum_udf_str::fix_length_and_dec");
  max_length=0;
  for (uint i = 0; i < arg_count; i++)
    set_if_bigger(max_length,args[i]->max_length);
  DBUG_VOID_RETURN;
}

1551 1552 1553

Item *Item_sum_udf_str::copy_or_same(THD* thd)
{
1554
  return new (&thd->mem_root) Item_sum_udf_str(thd, this);
1555 1556 1557
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
1558 1559
String *Item_sum_udf_str::val_str(String *str)
{
1560
  DBUG_ASSERT(fixed == 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1561 1562 1563 1564 1565 1566 1567
  DBUG_ENTER("Item_sum_udf_str::str");
  String *res=udf.val_str(str,&str_value);
  null_value = !res;
  DBUG_RETURN(res);
}

#endif /* HAVE_DLOPEN */
1568 1569 1570 1571


/*****************************************************************************
 GROUP_CONCAT function
1572 1573 1574 1575 1576

 SQL SYNTAX:
  GROUP_CONCAT([DISTINCT] expr,... [ORDER BY col [ASC|DESC],...] 
    [SEPARATOR str_const])

1577
 concat of values from "group by" operation
1578 1579 1580 1581 1582

 BUGS
   DISTINCT and ORDER BY only works if ORDER BY uses all fields and only fields
   in expression list
   Blobs doesn't work with DISTINCT or ORDER BY
1583 1584 1585
*****************************************************************************/

/*
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1586 1587
  function of sort for syntax:
  GROUP_CONCAT(DISTINCT expr,...)
1588 1589
*/

wax@kishkin.ru's avatar
wax@kishkin.ru committed
1590 1591
int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
				       byte* key2)
1592
{
monty@mysql.com's avatar
monty@mysql.com committed
1593
  Item_func_group_concat* grp_item= (Item_func_group_concat*)arg;
1594
  Item **field_item, **end;
monty@mysql.com's avatar
monty@mysql.com committed
1595
  char *record= (char*) grp_item->table->record[0];
wax@kishkin.ru's avatar
wax@kishkin.ru committed
1596

monty@mysql.com's avatar
monty@mysql.com committed
1597
  for (field_item= grp_item->args, end= field_item + grp_item->arg_count_field;
1598 1599
       field_item < end;
       field_item++)
1600
  {
monty@mysql.com's avatar
monty@mysql.com committed
1601 1602 1603 1604 1605 1606
    /*
      We have to use get_tmp_table_field() instead of
      real_item()->get_tmp_table_field() because we want the field in
      the temporary table, not the original field
    */
    Field *field= (*field_item)->get_tmp_table_field();
1607 1608
    if (field)
    {
1609
      int res;
monty@mysql.com's avatar
monty@mysql.com committed
1610 1611
      uint offset= (uint) (field->ptr - record);
      if ((res= field->key_cmp(key1 + offset, key2 + offset)))
1612
	return res;
1613
    }
1614
  }
1615 1616 1617
  return 0;
}

1618

1619
/*
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1620 1621
  function of sort for syntax:
  GROUP_CONCAT(expr,... ORDER BY col,... )
1622 1623
*/

wax@kishkin.ru's avatar
wax@kishkin.ru committed
1624
int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
1625
{
monty@mysql.com's avatar
monty@mysql.com committed
1626
  Item_func_group_concat* grp_item= (Item_func_group_concat*) arg;
1627
  ORDER **order_item, **end;
monty@mysql.com's avatar
monty@mysql.com committed
1628
  char *record= (char*) grp_item->table->record[0];
wax@kishkin.ru's avatar
wax@kishkin.ru committed
1629

monty@mysql.com's avatar
monty@mysql.com committed
1630
  for (order_item= grp_item->order, end=order_item+ grp_item->arg_count_order;
1631 1632
       order_item < end;
       order_item++)
1633
  {
1634
    Item *item= *(*order_item)->item;
monty@mysql.com's avatar
monty@mysql.com committed
1635 1636 1637 1638 1639 1640
    /*
      We have to use get_tmp_table_field() instead of
      real_item()->get_tmp_table_field() because we want the field in
      the temporary table, not the original field
    */
    Field *field= item->get_tmp_table_field();
1641 1642
    if (field)
    {
monty@mysql.com's avatar
monty@mysql.com committed
1643 1644 1645
      int res;
      uint offset= (uint) (field->ptr - record);
      if ((res= field->key_cmp(key1 + offset, key2 + offset)))
1646
        return (*order_item)->asc ? res : -res;
1647
    }
1648
  }
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1649
  /*
monty@mysql.com's avatar
monty@mysql.com committed
1650 1651 1652 1653
    We can't return 0 because in that case the tree class would remove this
    item as double value. This would cause problems for case-changes and
    if the the returned values are not the same we do the sort on.
  */
1654 1655 1656
  return 1;
}

1657

1658
/*
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1659 1660
  function of sort for syntax:
  GROUP_CONCAT(DISTINCT expr,... ORDER BY col,... )
1661 1662 1663 1664 1665

  BUG:
    This doesn't work in the case when the order by contains data that
    is not part of the field list because tree-insert will not notice
    the duplicated values when inserting things sorted by ORDER BY
1666
*/
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1667

wax@kishkin.ru's avatar
wax@kishkin.ru committed
1668 1669
int group_concat_key_cmp_with_distinct_and_order(void* arg,byte* key1,
						 byte* key2)
1670 1671 1672 1673 1674 1675
{
  if (!group_concat_key_cmp_with_distinct(arg,key1,key2))
    return 0;
  return(group_concat_key_cmp_with_order(arg,key1,key2));
}

1676

1677
/*
1678
  Append data from current leaf to item->result
1679
*/
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1680

wax@kishkin.ru's avatar
wax@kishkin.ru committed
1681
int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
1682
                  Item_func_group_concat *item)
1683 1684
{
  char buff[MAX_FIELD_WIDTH];
1685
  String tmp((char *)&buff,sizeof(buff),default_charset_info), tmp2;
monty@mysql.com's avatar
monty@mysql.com committed
1686 1687
  char *record= (char*) item->table->record[0];

ram@gw.mysql.r18.ru's avatar
a fix  
ram@gw.mysql.r18.ru committed
1688 1689 1690
  if (item->result.length())
    item->result.append(*item->separator);

1691 1692
  tmp.length(0);
  
1693
  for (uint i= 0; i < item->arg_count_field; i++)
1694
  {
1695
    Item *show_item= item->args[i];
1696 1697
    if (!show_item->const_item())
    {
monty@mysql.com's avatar
monty@mysql.com committed
1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709
      /*
	We have to use get_tmp_table_field() instead of
	real_item()->get_tmp_table_field() because we want the field in
	the temporary table, not the original field
      */
      Field *field= show_item->get_tmp_table_field();
      String *res;
      char *save_ptr= field->ptr;
      uint offset= (uint) (save_ptr - record);
      DBUG_ASSERT(offset < item->table->reclength);
      field->ptr= (char *) key + offset;
      res= field->val_str(&tmp,&tmp2);
1710
      item->result.append(*res);
monty@mysql.com's avatar
monty@mysql.com committed
1711
      field->ptr= save_ptr;
1712 1713 1714
    }
    else 
    {
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1715
      String *res= show_item->val_str(&tmp);
1716
      if (res)
1717
        item->result.append(*res);
1718 1719
    }
  }
1720 1721 1722

  /* stop if length of result more than group_concat_max_len */  
  if (item->result.length() > item->group_concat_max_len)
1723
  {
1724 1725 1726
    item->count_cut_values++;
    item->result.length(item->group_concat_max_len);
    item->warning_for_row= TRUE;
1727 1728 1729 1730 1731
    return 1;
  }
  return 0;
}

1732

1733
/*
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1734 1735 1736 1737 1738
  Constructor of Item_func_group_concat
  is_distinct - distinct
  is_select - list of expression for show values
  is_order - list of sort columns 
  is_separator - string value of separator
1739
*/
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1740

1741
Item_func_group_concat::Item_func_group_concat(bool is_distinct,
1742 1743 1744
					       List<Item> *is_select,
					       SQL_LIST *is_order,
					       String *is_separator)
wax@kishkin.ru's avatar
wax@kishkin.ru committed
1745
  :Item_sum(), tmp_table_param(0), max_elements_in_tree(0), warning(0),
monty@mysql.com's avatar
monty@mysql.com committed
1746
   warning_available(0), key_length(0),
wax@kishkin.ru's avatar
wax@kishkin.ru committed
1747 1748
   tree_mode(0), distinct(is_distinct), warning_for_row(0),
   separator(is_separator), tree(&tree_base), table(0),
1749
   order(0), tables_list(0),
ram@gw.mysql.r18.ru's avatar
a fix  
ram@gw.mysql.r18.ru committed
1750
   arg_count_order(0), arg_count_field(0),
1751
   count_cut_values(0)
1752
{
1753 1754 1755
  Item *item_select;
  Item **arg_ptr;

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1756 1757
  original= 0;
  quick_group= 0;
1758
  mark_as_sum_func();
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1759
  order= 0;
1760
  group_concat_max_len= current_thd->variables.group_concat_max_len;
1761
    
1762
  arg_count_field= is_select->elements;
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1763
  arg_count_order= is_order ? is_order->elements : 0;
1764
  arg_count= arg_count_field + arg_count_order;
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1765 1766 1767
  
  /*
    We need to allocate:
1768 1769
    args - arg_count_field+arg_count_order
           (for possible order items in temporare tables)
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1770 1771
    order - arg_count_order
  */
monty@mysql.com's avatar
monty@mysql.com committed
1772
  if (!(args= (Item**) sql_alloc(sizeof(Item*) * arg_count +
1773
				 sizeof(ORDER*)*arg_count_order)))
wax@kishkin.ru's avatar
wax@kishkin.ru committed
1774
    return;
1775

1776 1777
  order= (ORDER**)(args + arg_count);

1778
  /* fill args items of show and sort */
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1779
  List_iterator_fast<Item> li(*is_select);
1780

1781 1782
  for (arg_ptr=args ; (item_select= li++) ; arg_ptr++)
    *arg_ptr= item_select;
1783 1784

  if (arg_count_order) 
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1785
  {
1786
    ORDER **order_ptr= order;
1787
    for (ORDER *order_item= (ORDER*) is_order->first;
1788 1789
	 order_item != NULL;
	 order_item= order_item->next)
1790
    {
1791 1792 1793
      (*order_ptr++)= order_item;
      *arg_ptr= *order_item->item;
      order_item->item= arg_ptr++;
1794 1795 1796
    }
  }
}
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
  

Item_func_group_concat::Item_func_group_concat(THD *thd,
					       Item_func_group_concat *item)
  :Item_sum(thd, item),item_thd(thd),
  tmp_table_param(item->tmp_table_param),
  max_elements_in_tree(item->max_elements_in_tree),
  warning(item->warning),
  warning_available(item->warning_available),
  key_length(item->key_length), 
  tree_mode(item->tree_mode),
  distinct(item->distinct),
  warning_for_row(item->warning_for_row),
  separator(item->separator),
  tree(item->tree),
  table(item->table),
  order(item->order),
  tables_list(item->tables_list),
  group_concat_max_len(item->group_concat_max_len),
  arg_count_order(item->arg_count_order),
  arg_count_field(item->arg_count_field),
  field_list_offset(item->field_list_offset),
  count_cut_values(item->count_cut_values),
  original(item)
{
  quick_group= item->quick_group;
}

1825

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1826

hf@deer.(none)'s avatar
hf@deer.(none) committed
1827 1828
void Item_func_group_concat::cleanup()
{
1829
  DBUG_ENTER("Item_func_group_concat::cleanup");
1830
  Item_sum::cleanup();
1831 1832 1833 1834 1835

  /* fix order list */
  for (uint i= 0; i < arg_count_order ; i++)
    order[i]->item= &order[i]->item_ptr;

hf@deer.(none)'s avatar
hf@deer.(none) committed
1836 1837 1838 1839 1840 1841 1842 1843
  /*
    Free table and tree if they belong to this item (if item have not pointer
    to original item from which was made copy => it own its objects )
  */
  if (!original)
  {
    THD *thd= current_thd;
    if (table)
1844
    {
hf@deer.(none)'s avatar
hf@deer.(none) committed
1845
      free_tmp_table(thd, table);
1846 1847
      table= 0;
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
1848
    delete tmp_table_param;
1849
    tmp_table_param= 0;
hf@deer.(none)'s avatar
hf@deer.(none) committed
1850
    if (tree_mode)
1851 1852
    {
      tree_mode= 0;
hf@deer.(none)'s avatar
hf@deer.(none) committed
1853
      delete_tree(tree); 
1854
    }
hf@deer.(none)'s avatar
hf@deer.(none) committed
1855
  }
1856
  DBUG_VOID_RETURN;
hf@deer.(none)'s avatar
hf@deer.(none) committed
1857 1858
}

1859

1860 1861
Item_func_group_concat::~Item_func_group_concat()
{
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1862 1863 1864 1865
  /*
    Free table and tree if they belong to this item (if item have not pointer
    to original item from which was made copy => it own its objects )
  */
1866 1867 1868 1869 1870 1871
  if (!original)
  {
    if (warning_available)
    {
      char warn_buff[MYSQL_ERRMSG_SIZE];
      sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
1872
      warning->set_msg(current_thd, warn_buff);
1873 1874 1875 1876 1877
    }
  }
}


1878 1879
Item *Item_func_group_concat::copy_or_same(THD* thd)
{
1880
  return new (&thd->mem_root) Item_func_group_concat(thd, this);
1881 1882 1883
}


1884
void Item_func_group_concat::clear()
1885 1886 1887
{
  result.length(0);
  result.copy();
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1888
  null_value= TRUE;
monty@mysql.com's avatar
monty@mysql.com committed
1889
  warning_for_row= FALSE;
1890 1891 1892 1893 1894 1895 1896 1897 1898 1899
  if (table)
  {
    table->file->extra(HA_EXTRA_NO_CACHE);
    table->file->delete_all_rows();
    table->file->extra(HA_EXTRA_WRITE_CACHE);
  }
  if (tree_mode)
    reset_tree(tree);
}

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1900

1901 1902
bool Item_func_group_concat::add()
{
wax@kishkin.ru's avatar
BUG  
wax@kishkin.ru committed
1903 1904
  if (always_null)
    return 0;
1905 1906 1907
  copy_fields(tmp_table_param);
  copy_funcs(tmp_table_param->items_to_copy);

1908
  for (uint i= 0; i < arg_count_field; i++)
1909
  {
wax@kishkin.ru's avatar
wax@kishkin.ru committed
1910
    Item *show_item= args[i];
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1911
    if (!show_item->const_item())
1912
    {
monty@mysql.com's avatar
monty@mysql.com committed
1913 1914 1915 1916
      /*
	Here we use real_item as we want the original field data that should
	be written to table->record[0]
      */
wax@kishkin.ru's avatar
BUG  
wax@kishkin.ru committed
1917
      Field *f= show_item->real_item()->get_tmp_table_field();
monty@mysql.com's avatar
monty@mysql.com committed
1918 1919
      if (f->is_null())
	return 0;				// Skip row if it contains null
1920 1921
    }
  }
monty@mysql.com's avatar
monty@mysql.com committed
1922

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1923 1924 1925
  null_value= FALSE;
  if (tree_mode)
  {
monty@mysql.com's avatar
monty@mysql.com committed
1926
    if (!tree_insert(tree, table->record[0], 0, tree->custom_arg))
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1927 1928
      return 1;
  }
1929 1930 1931
  else
  {
    if (result.length() <= group_concat_max_len && !warning_for_row)
monty@mysql.com's avatar
monty@mysql.com committed
1932
      dump_leaf_key(table->record[0], 1, this);
1933 1934 1935 1936
  }
  return 0;
}

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1937

1938 1939 1940 1941 1942 1943
void Item_func_group_concat::reset_field()
{
  if (tree_mode)
    reset_tree(tree);
}

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1944

1945 1946 1947
bool
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
1948
  DBUG_ASSERT(fixed == 0);
1949 1950 1951 1952

  if (save_args_for_prepared_statements(thd))
    return 1;

1953
  uint i;			/* for loop variable */ 
1954

1955 1956 1957 1958 1959 1960
  if (!thd->allow_sum_func)
  {
    my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
    return 1;
  }
  
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1961 1962
  thd->allow_sum_func= 0;
  maybe_null= 0;
1963
  item_thd= thd;
1964

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1965
  /*
1966
    Fix fields for select list and ORDER clause
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1967
  */
1968 1969

  for (i= 0 ; i < arg_count ; i++)
1970
  {
1971
    if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
1972
      return 1;
1973 1974
    if (i < arg_count_field && args[i]->maybe_null)
      maybe_null= 0;
1975
  }
1976

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1977 1978
  result_field= 0;
  null_value= 1;
1979
  max_length= group_concat_max_len;
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1980
  thd->allow_sum_func= 1;			
1981 1982
  if (!(tmp_table_param= new TMP_TABLE_PARAM))
    return 1;
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1983
  tables_list= tables;
1984 1985 1986 1987
  fixed= 1;
  return 0;
}

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
1988

1989 1990 1991
bool Item_func_group_concat::setup(THD *thd)
{
  List<Item> list;
1992
  SELECT_LEX *select_lex= thd->lex->current_select;
monty@mysql.com's avatar
monty@mysql.com committed
1993 1994
  uint const_fields;
  byte *record;
1995 1996
  qsort_cmp2 compare_key;
  DBUG_ENTER("Item_func_group_concat::setup");
1997 1998

  if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
1999
    DBUG_RETURN(1);
2000

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2001
  /*
konstantin@oak.local's avatar
konstantin@oak.local committed
2002
    push all not constant fields to list and create temp table
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2003
  */ 
2004
  const_fields= 0;
wax@kishkin.ru's avatar
BUG  
wax@kishkin.ru committed
2005
  always_null= 0;
2006
  for (uint i= 0; i < arg_count_field; i++)
2007
  {
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2008
    Item *item= args[i];
2009
    if (list.push_back(item))
2010
      DBUG_RETURN(1);
2011 2012
    if (item->const_item())
    {
2013
      const_fields++;
2014 2015
      (void) item->val_int();
      if (item->null_value)
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2016
	always_null= 1;
2017 2018
    }
  }
wax@kishkin.ru's avatar
BUG  
wax@kishkin.ru committed
2019
  if (always_null)
2020
    DBUG_RETURN(0);
2021 2022 2023 2024 2025 2026 2027 2028 2029 2030
        
  List<Item> all_fields(list);
  if (arg_count_order) 
  {
    bool hidden_group_fields;
    setup_group(thd, args, tables_list, list, all_fields, *order,
                &hidden_group_fields);
  }
  
  count_field_types(tmp_table_param,all_fields,0);
2031 2032
  if (table)
  {
2033 2034 2035 2036
    /*
      We come here when we are getting the result from a temporary table,
      not the original tables used in the query
    */
2037 2038 2039
    free_tmp_table(thd, table);
    tmp_table_param->cleanup();
  }
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2040
  /*
2041
    We have to create a temporary table to get descriptions of fields 
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2042
    (types, sizes and so on).
2043 2044 2045

    Note that in the table, we first have the ORDER BY fields, then the
    field list.
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2046 2047
  */
  if (!(table=create_tmp_table(thd, tmp_table_param, all_fields, 0,
2048 2049
			       0, 0, 0,select_lex->options | thd->options,
			       (char *) "")))
2050
    DBUG_RETURN(1);
2051
  table->file->extra(HA_EXTRA_NO_ROWS);
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2052
  table->no_rows= 1;
wax@kishkin.ru's avatar
wax@kishkin.ru committed
2053

monty@mysql.com's avatar
monty@mysql.com committed
2054 2055
  key_length= table->reclength;
  record= table->record[0];
wax@kishkin.ru's avatar
wax@kishkin.ru committed
2056

2057 2058
  /* Offset to first result field in table */
  field_list_offset= table->fields - (list.elements - const_fields);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2059 2060 2061

  if (tree_mode)
    delete_tree(tree);
2062 2063

  /* choose function of sort */  
wax@kishkin.ru's avatar
wax@kishkin.ru committed
2064
  tree_mode= distinct || arg_count_order; 
2065 2066 2067 2068 2069
  if (tree_mode)
  {
    if (arg_count_order)
    {
      if (distinct)
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2070
        compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct_and_order;
2071
      else
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2072
        compare_key= (qsort_cmp2) group_concat_key_cmp_with_order;
2073 2074 2075
    }
    else
    {
2076
       compare_key= NULL;
2077
      if (distinct)
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2078
        compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct;
2079
    }
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2080
    /*
2081 2082
      Create a tree of sort. Tree is used for a sort and a remove double 
      values (according with syntax of the function). If function doesn't
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2083 2084
      contain DISTINCT and ORDER BY clauses, we don't create this tree.
    */
2085
    init_tree(tree, min(thd->variables.max_heap_table_size,
2086
			thd->variables.sortbuff_size/16), 0,
wax@kishkin.ru's avatar
wax@kishkin.ru committed
2087
              key_length, compare_key, 0, NULL, (void*) this);
2088 2089
    max_elements_in_tree= (key_length ? 
			   thd->variables.max_heap_table_size/key_length : 1);
2090 2091
  };

wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2092 2093 2094 2095
  /*
    Copy table and tree_mode if they belong to this item (if item have not 
    pointer to original item from which was made copy => it own its objects)
  */
2096 2097 2098 2099 2100
  if (original)
  {
    original->table= table;
    original->tree_mode= tree_mode;
  }
2101
  DBUG_RETURN(0);
2102 2103
}

2104

2105 2106 2107 2108 2109 2110
/* This is used by rollup to create a separate usable copy of the function */

void Item_func_group_concat::make_unique()
{
  table=0;
  original= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2111
  tree_mode= 0; // to prevent delete_tree call on uninitialized tree
2112 2113 2114 2115
  tree= &tree_base;
}


2116 2117
String* Item_func_group_concat::val_str(String* str)
{
2118
  DBUG_ASSERT(fixed == 1);
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2119 2120
  if (null_value)
    return 0;
2121 2122 2123 2124 2125 2126 2127
  if (tree_mode)
  {
    tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
              left_root_right);
  }
  if (count_cut_values && !warning_available)
  {
wax@kishkin.ru's avatar
SCRUM  
wax@kishkin.ru committed
2128 2129
    warning_available= TRUE;
    warning= push_warning(item_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
2130 2131 2132 2133
                           ER_CUT_VALUE_GROUP_CONCAT, NULL);
  }
  return &result;
}
2134

2135

2136 2137
void Item_func_group_concat::print(String *str)
{
2138
  str->append("group_concat(", 13);
2139
  if (distinct)
2140
    str->append("distinct ", 9);
2141
  for (uint i= 0; i < arg_count_field; i++)
2142 2143 2144 2145 2146 2147 2148
  {
    if (i)
      str->append(',');
    args[i]->print(str);
  }
  if (arg_count_order)
  {
2149
    str->append(" order by ", 10);
2150 2151 2152 2153 2154 2155 2156
    for (uint i= 0 ; i < arg_count_order ; i++)
    {
      if (i)
	str->append(',');
      (*order[i]->item)->print(str);
    }
  }
2157
  str->append(" seperator \'", 12);
2158
  str->append(*separator);
2159
  str->append("\')", 2);
2160
}