item_sum.cc 42 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000-2003 MySQL AB
unknown's avatar
unknown committed
2

unknown's avatar
unknown 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.
unknown's avatar
unknown committed
7

unknown's avatar
unknown 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.
unknown's avatar
unknown committed
12

unknown's avatar
unknown 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"
unknown's avatar
unknown committed
25

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

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

44
// Constructor used in processing select with temporary tebles
45 46
Item_sum::Item_sum(THD *thd, Item_sum *item):
  Item_result_field(thd, item), quick_group(item->quick_group)
47
{
48
  arg_count= item->arg_count;
49 50 51 52 53
  if (arg_count <= 2)
    args=tmp_args;
  else
    if (!(args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
      return;
unknown's avatar
unknown committed
54
  for (uint i= 0; i < arg_count; i++)
55
    args[i]= item->args[i];
56 57
}

58
void Item_sum::mark_as_sum_func()
59
{
60
  current_thd->lex->current_select->with_sum_func= 1;
unknown's avatar
unknown committed
61
  with_sum_func= 1;
62
}
unknown's avatar
unknown committed
63

64

unknown's avatar
unknown committed
65 66 67 68
void Item_sum::make_field(Send_field *tmp_field)
{
  if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
  {
69 70 71 72
    ((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;
73 74
    if (maybe_null)
      tmp_field->flags&= ~NOT_NULL_FLAG;
unknown's avatar
unknown committed
75
  }
76 77
  else
    init_make_field(tmp_field, field_type());
unknown's avatar
unknown committed
78 79
}

80

unknown's avatar
unknown committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
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);
}

102
Item *Item_sum::get_tmp_table_item(THD *thd)
103
{
104
  Item_sum* sum_item= (Item_sum *) copy_or_same(thd);
105 106
  if (sum_item && sum_item->result_field)	   // If not a const sum func
  {
107
    Field *result_field_tmp= sum_item->result_field;
108 109 110 111 112 113
    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)
114
	  ((Item_field*) arg)->field= result_field_tmp++;
115
	else
116
	  sum_item->args[i]= new Item_field(result_field_tmp++);
117 118 119 120 121
      }
    }
  }
  return sum_item;
}
unknown's avatar
unknown committed
122

123 124 125 126 127 128 129 130 131 132 133 134 135 136
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);
}

unknown's avatar
unknown committed
137 138 139 140 141 142
String *
Item_sum_num::val_str(String *str)
{
  double nr=val();
  if (null_value)
    return 0;
unknown's avatar
unknown committed
143
  str->set(nr,decimals, &my_charset_bin);
unknown's avatar
unknown committed
144 145 146 147 148 149 150
  return str;
}


String *
Item_sum_int::val_str(String *str)
{
151
  longlong nr= val_int();
unknown's avatar
unknown committed
152 153
  if (null_value)
    return 0;
154
  if (unsigned_flag)
unknown's avatar
unknown committed
155
    str->set((ulonglong) nr, &my_charset_bin);
156
  else
unknown's avatar
unknown committed
157
    str->set(nr, &my_charset_bin);
unknown's avatar
unknown committed
158 159 160 161 162
  return str;
}


bool
unknown's avatar
unknown committed
163
Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
unknown's avatar
unknown committed
164 165 166 167 168 169 170 171 172 173 174
{
  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++)
  {
unknown's avatar
unknown committed
175
    if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
unknown's avatar
unknown committed
176 177 178 179 180 181 182 183 184 185
      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
186
  fixed= 1;
unknown's avatar
unknown committed
187 188 189 190 191
  return 0;
}


bool
unknown's avatar
unknown committed
192
Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
unknown's avatar
unknown committed
193 194 195 196 197 198 199 200
{
  Item *item=args[0];
  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
201 202
  if (!item->fixed &&
      item->fix_fields(thd, tables, args) || item->check_cols(1))
unknown's avatar
unknown committed
203 204 205
    return 1;
  hybrid_type=item->result_type();
  if (hybrid_type == INT_RESULT)
206 207
  {
    cmp_charset= &my_charset_bin;
208
    max_length=20;
209
  }
unknown's avatar
unknown committed
210
  else if (hybrid_type == REAL_RESULT)
211 212
  {
    cmp_charset= &my_charset_bin;
unknown's avatar
unknown committed
213
    max_length=float_length(decimals);
214
  }else
215
  {
216
    cmp_charset= item->collation.collation;
unknown's avatar
unknown committed
217
    max_length=item->max_length;
218
  }
unknown's avatar
unknown committed
219
  decimals=item->decimals;
220 221
  /* MIN/MAX can return NULL for empty set indepedent of the used column */
  maybe_null= 1;
222
  unsigned_flag=item->unsigned_flag;
223
  collation.set(item->collation);
unknown's avatar
unknown committed
224 225 226 227
  result_field=0;
  null_value=1;
  fix_length_and_dec();
  thd->allow_sum_func=1;			// Allow group functions
228 229 230 231
  if (item->type() == Item::FIELD_ITEM)
    hybrid_field_type= ((Item_field*) item)->field->type();
  else
    hybrid_field_type= Item::field_type();
232
  fixed= 1;
unknown's avatar
unknown committed
233 234 235 236 237 238 239 240
  return 0;
}


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

241
Item *Item_sum_sum::copy_or_same(THD* thd)
unknown's avatar
unknown committed
242
{
243
  return new (&thd->mem_root) Item_sum_sum(thd, this);
unknown's avatar
unknown committed
244 245
}

246

247
void Item_sum_sum::clear()
248 249 250 251 252
{
  null_value=1; sum=0.0;
}


unknown's avatar
unknown committed
253 254 255
bool Item_sum_sum::add()
{
  sum+=args[0]->val();
unknown's avatar
unknown committed
256 257
  if (!args[0]->null_value)
    null_value= 0;
unknown's avatar
unknown committed
258 259 260
  return 0;
}

261

unknown's avatar
unknown committed
262 263 264 265 266 267
double Item_sum_sum::val()
{
  return sum;
}


268
Item *Item_sum_count::copy_or_same(THD* thd)
unknown's avatar
unknown committed
269
{
270
  return new (&thd->mem_root) Item_sum_count(thd, this);
unknown's avatar
unknown committed
271 272
}

273

274
void Item_sum_count::clear()
275
{
276
  count= 0;
277 278 279
}


unknown's avatar
unknown committed
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
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()
{
  return (longlong) count;
}

/*
299
  Avgerage
unknown's avatar
unknown committed
300 301
*/

302
Item *Item_sum_avg::copy_or_same(THD* thd)
unknown's avatar
unknown committed
303
{
304
  return new (&thd->mem_root) Item_sum_avg(thd, this);
unknown's avatar
unknown committed
305 306
}

307

308
void Item_sum_avg::clear()
309 310 311 312 313
{
  sum=0.0; count=0;
}


unknown's avatar
unknown committed
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
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()
{
  if (!count)
  {
    null_value=1;
    return 0.0;
  }
  null_value=0;
  return sum/ulonglong2double(count);
}


/*
338
  Standard deviation
unknown's avatar
unknown committed
339 340
*/

unknown's avatar
unknown committed
341
double Item_sum_std::val()
unknown's avatar
unknown committed
342
{
unknown's avatar
unknown committed
343 344
  double tmp= Item_sum_variance::val();
  return tmp <= 0.0 ? 0.0 : sqrt(tmp);
unknown's avatar
unknown committed
345 346
}

347 348
Item *Item_sum_std::copy_or_same(THD* thd)
{
349
  return new (&thd->mem_root) Item_sum_std(thd, this);
350 351 352
}


unknown's avatar
unknown committed
353
/*
354
  Variance
unknown's avatar
unknown committed
355 356
*/

357 358
Item *Item_sum_variance::copy_or_same(THD* thd)
{
359
  return new (&thd->mem_root) Item_sum_variance(thd, this);
360 361 362
}


363
void Item_sum_variance::clear()
unknown's avatar
unknown committed
364 365 366 367 368 369
{
  sum=sum_sqr=0.0; 
  count=0; 
}

bool Item_sum_variance::add()
unknown's avatar
unknown committed
370 371 372 373 374 375 376 377 378 379 380
{
  double nr=args[0]->val();
  if (!args[0]->null_value)
  {
    sum+=nr;
    sum_sqr+=nr*nr;
    count++;
  }
  return 0;
}

unknown's avatar
unknown committed
381
double Item_sum_variance::val()
unknown's avatar
unknown committed
382 383 384 385 386 387 388 389 390 391
{
  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;
unknown's avatar
unknown committed
392
  return tmp2 <= 0.0 ? 0.0 : tmp2;
unknown's avatar
unknown committed
393 394
}

unknown's avatar
unknown committed
395
void Item_sum_variance::reset_field()
unknown's avatar
unknown committed
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
{
  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);
  }
}

unknown's avatar
unknown committed
412
void Item_sum_variance::update_field()
unknown's avatar
unknown committed
413 414 415 416 417
{
  double nr,old_nr,old_sqr;
  longlong field_count;
  char *res=result_field->ptr;

unknown's avatar
unknown committed
418 419 420
  float8get(old_nr, res);
  float8get(old_sqr, res+sizeof(double));
  field_count=sint8korr(res+sizeof(double)*2);
unknown's avatar
unknown committed
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437

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

double Item_sum_hybrid::val()
{
438
  int err;
unknown's avatar
unknown committed
439 440
  if (null_value)
    return 0.0;
441 442
  switch (hybrid_type) {
  case STRING_RESULT:
unknown's avatar
unknown committed
443
    String *res;  res=val_str(&str_value);
444
    return (res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(),
445
			     (char**) 0, &err) : 0.0);
446 447 448 449 450 451
  case INT_RESULT:
    if (unsigned_flag)
      return ulonglong2double(sum_int);
    return (double) sum_int;
  case REAL_RESULT:
    return sum;
452
  case ROW_RESULT:
unknown's avatar
unknown committed
453
  default:
unknown's avatar
unknown committed
454 455 456
    // This case should never be choosen
    DBUG_ASSERT(0);
    return 0;
unknown's avatar
unknown committed
457
  }
458 459 460 461 462 463 464 465 466 467
  return 0;					// Keep compiler happy
}

longlong Item_sum_hybrid::val_int()
{
  if (null_value)
    return 0;
  if (hybrid_type == INT_RESULT)
    return sum_int;
  return (longlong) Item_sum_hybrid::val();
unknown's avatar
unknown committed
468 469 470 471 472 473 474 475
}


String *
Item_sum_hybrid::val_str(String *str)
{
  if (null_value)
    return 0;
476 477
  switch (hybrid_type) {
  case STRING_RESULT:
unknown's avatar
unknown committed
478
    return &value;
479
  case REAL_RESULT:
unknown's avatar
unknown committed
480
    str->set(sum,decimals, &my_charset_bin);
481 482 483
    break;
  case INT_RESULT:
    if (unsigned_flag)
unknown's avatar
unknown committed
484
      str->set((ulonglong) sum_int, &my_charset_bin);
485
    else
unknown's avatar
unknown committed
486
      str->set((longlong) sum_int, &my_charset_bin);
487
    break;
488
  case ROW_RESULT:
unknown's avatar
unknown committed
489
  default:
unknown's avatar
unknown committed
490 491 492
    // This case should never be choosen
    DBUG_ASSERT(0);
    break;
493 494
  }
  return str;					// Keep compiler happy
unknown's avatar
unknown committed
495 496
}

497 498 499

Item *Item_sum_min::copy_or_same(THD* thd)
{
500
  return new (&thd->mem_root) Item_sum_min(thd, this);
501 502 503
}


unknown's avatar
unknown committed
504 505
bool Item_sum_min::add()
{
506 507
  switch (hybrid_type) {
  case STRING_RESULT:
unknown's avatar
unknown committed
508 509 510
  {
    String *result=args[0]->val_str(&tmp_value);
    if (!args[0]->null_value &&
511
	(null_value || sortcmp(&value,result,cmp_charset) > 0))
unknown's avatar
unknown committed
512 513 514 515 516
    {
      value.copy(*result);
      null_value=0;
    }
  }
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
  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:
unknown's avatar
unknown committed
532 533
  {
    double nr=args[0]->val();
534
    if (!args[0]->null_value && (null_value || nr < sum))
unknown's avatar
unknown committed
535 536 537 538 539
    {
      sum=nr;
      null_value=0;
    }
  }
540
  break;
541
  case ROW_RESULT:
unknown's avatar
unknown committed
542
  default:
unknown's avatar
unknown committed
543 544 545
    // This case should never be choosen
    DBUG_ASSERT(0);
    break;
546 547 548 549 550
  }
  return 0;
}


551 552
Item *Item_sum_max::copy_or_same(THD* thd)
{
553
  return new (&thd->mem_root) Item_sum_max(thd, this);
554 555 556
}


557 558 559 560
bool Item_sum_max::add()
{
  switch (hybrid_type) {
  case STRING_RESULT:
unknown's avatar
unknown committed
561 562 563
  {
    String *result=args[0]->val_str(&tmp_value);
    if (!args[0]->null_value &&
564
	(null_value || sortcmp(&value,result,cmp_charset) < 0))
unknown's avatar
unknown committed
565 566 567 568 569
    {
      value.copy(*result);
      null_value=0;
    }
  }
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
  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;
594
  case ROW_RESULT:
unknown's avatar
unknown committed
595
  default:
unknown's avatar
unknown committed
596 597 598
    // This case should never be choosen
    DBUG_ASSERT(0);
    break;
599
  }
unknown's avatar
unknown committed
600 601 602 603 604 605 606 607 608 609 610
  return 0;
}


/* bit_or and bit_and */

longlong Item_sum_bit::val_int()
{
  return (longlong) bits;
}

611

612
void Item_sum_bit::clear()
613
{
614
  bits= reset_bits;
615 616 617
}

Item *Item_sum_or::copy_or_same(THD* thd)
unknown's avatar
unknown committed
618
{
619
  return new (&thd->mem_root) Item_sum_or(thd, this);
unknown's avatar
unknown committed
620 621
}

622

unknown's avatar
unknown committed
623 624 625 626 627 628 629 630
bool Item_sum_or::add()
{
  ulonglong value= (ulonglong) args[0]->val_int();
  if (!args[0]->null_value)
    bits|=value;
  return 0;
}

631 632
Item *Item_sum_xor::copy_or_same(THD* thd)
{
633
  return new (&thd->mem_root) Item_sum_xor(thd, this);
634 635 636 637 638 639 640 641 642 643 644
}


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

645 646
Item *Item_sum_and::copy_or_same(THD* thd)
{
647
  return new (&thd->mem_root) Item_sum_and(thd, this);
648 649 650
}


unknown's avatar
unknown committed
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
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];
687
    String tmp(buff,sizeof(buff),result_field->charset()),*res;
unknown's avatar
unknown committed
688 689 690 691 692 693 694 695 696 697

    res=args[0]->val_str(&tmp);
    if (args[0]->null_value)
    {
      result_field->set_null();
      result_field->reset();
    }
    else
    {
      result_field->set_notnull();
698
      result_field->store(res->ptr(),res->length(),tmp.charset());
unknown's avatar
unknown committed
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
    }
  }
  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);
unknown's avatar
unknown committed
740 741 742 743
  if (args[0]->null_value)
    result_field->set_null();
  else
    result_field->set_notnull();
unknown's avatar
unknown committed
744 745 746 747 748 749 750 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
}


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()
unknown's avatar
unknown committed
781
{
782 783
  reset();
  int8store(result_field->ptr, bits);
unknown's avatar
unknown committed
784 785 786
}

void Item_sum_bit::update_field()
unknown's avatar
unknown committed
787 788
{
  char *res=result_field->ptr;
unknown's avatar
unknown committed
789 790 791
  bits= uint8korr(res);
  add();
  int8store(res, bits);
unknown's avatar
unknown committed
792 793 794 795 796 797
}

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

unknown's avatar
unknown committed
798
void Item_sum_sum::update_field()
unknown's avatar
unknown committed
799 800 801 802
{
  double old_nr,nr;
  char *res=result_field->ptr;

unknown's avatar
unknown committed
803
  float8get(old_nr,res);
unknown's avatar
unknown committed
804 805
  nr=args[0]->val();
  if (!args[0]->null_value)
unknown's avatar
unknown committed
806
  {
unknown's avatar
unknown committed
807
    old_nr+=nr;
unknown's avatar
unknown committed
808 809
    result_field->set_notnull();
  }
unknown's avatar
unknown committed
810 811 812 813
  float8store(res,old_nr);
}


unknown's avatar
unknown committed
814
void Item_sum_count::update_field()
unknown's avatar
unknown committed
815 816 817 818
{
  longlong nr;
  char *res=result_field->ptr;

unknown's avatar
unknown committed
819
  nr=sint8korr(res);
unknown's avatar
unknown committed
820 821 822 823 824 825 826 827 828 829 830 831
  if (!args[0]->maybe_null)
    nr++;
  else
  {
    (void) args[0]->val_int();
    if (!args[0]->null_value)
      nr++;
  }
  int8store(res,nr);
}


unknown's avatar
unknown committed
832
void Item_sum_avg::update_field()
unknown's avatar
unknown committed
833 834 835 836 837
{
  double nr,old_nr;
  longlong field_count;
  char *res=result_field->ptr;

unknown's avatar
unknown committed
838 839
  float8get(old_nr,res);
  field_count=sint8korr(res+sizeof(double));
unknown's avatar
unknown committed
840 841 842 843 844 845 846 847 848 849 850 851

  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);
}

unknown's avatar
unknown committed
852
void Item_sum_hybrid::update_field()
unknown's avatar
unknown committed
853 854
{
  if (hybrid_type == STRING_RESULT)
unknown's avatar
unknown committed
855
    min_max_update_str_field();
unknown's avatar
unknown committed
856
  else if (hybrid_type == INT_RESULT)
unknown's avatar
unknown committed
857
    min_max_update_int_field();
unknown's avatar
unknown committed
858
  else
unknown's avatar
unknown committed
859
    min_max_update_real_field();
unknown's avatar
unknown committed
860 861 862 863
}


void
unknown's avatar
unknown committed
864
Item_sum_hybrid::min_max_update_str_field()
unknown's avatar
unknown committed
865 866 867
{
  String *res_str=args[0]->val_str(&value);

unknown's avatar
unknown committed
868
  if (!args[0]->null_value)
unknown's avatar
unknown committed
869 870 871 872 873
  {
    res_str->strip_sp();
    result_field->val_str(&tmp_value,&tmp_value);

    if (result_field->is_null() ||
874
	(cmp_sign * sortcmp(res_str,&tmp_value,cmp_charset)) < 0)
875
      result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
unknown's avatar
unknown committed
876 877 878 879 880 881
    result_field->set_notnull();
  }
}


void
unknown's avatar
unknown committed
882
Item_sum_hybrid::min_max_update_real_field()
unknown's avatar
unknown committed
883 884 885 886 887 888 889
{
  double nr,old_nr;

  old_nr=result_field->val_real();
  nr=args[0]->val();
  if (!args[0]->null_value)
  {
unknown's avatar
unknown committed
890
    if (result_field->is_null(0) ||
unknown's avatar
unknown committed
891 892 893 894
	(cmp_sign > 0 ? old_nr > nr : old_nr < nr))
      old_nr=nr;
    result_field->set_notnull();
  }
unknown's avatar
unknown committed
895
  else if (result_field->is_null(0))
unknown's avatar
unknown committed
896 897 898 899 900 901
    result_field->set_null();
  result_field->store(old_nr);
}


void
unknown's avatar
unknown committed
902
Item_sum_hybrid::min_max_update_int_field()
unknown's avatar
unknown committed
903 904 905 906 907 908 909
{
  longlong nr,old_nr;

  old_nr=result_field->val_int();
  nr=args[0]->val_int();
  if (!args[0]->null_value)
  {
unknown's avatar
unknown committed
910
    if (result_field->is_null(0))
unknown's avatar
unknown committed
911
      old_nr=nr;
912 913 914 915 916 917
    else
    {
      bool res=(unsigned_flag ?
		(ulonglong) old_nr > (ulonglong) nr :
		old_nr > nr);
      /* (cmp_sign > 0 && res) || (!(cmp_sign > 0) && !res) */
unknown's avatar
unknown committed
918
      if ((cmp_sign > 0) ^ (!res))
919 920
	old_nr=nr;
    }
unknown's avatar
unknown committed
921 922
    result_field->set_notnull();
  }
unknown's avatar
unknown committed
923
  else if (result_field->is_null(0))
unknown's avatar
unknown committed
924 925 926 927 928 929 930 931 932 933 934 935 936 937
    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;
}

unknown's avatar
unknown committed
938

unknown's avatar
unknown committed
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
double Item_avg_field::val()
{
  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)
{
  double nr=Item_avg_field::val();
  if (null_value)
    return 0;
unknown's avatar
unknown committed
961
  str->set(nr,decimals, &my_charset_bin);
unknown's avatar
unknown committed
962 963 964 965
  return str;
}

Item_std_field::Item_std_field(Item_sum_std *item)
unknown's avatar
unknown committed
966 967 968 969 970 971 972 973 974 975 976
  : Item_variance_field(item)
{
}

double Item_std_field::val()
{
  double tmp= Item_variance_field::val();
  return tmp <= 0.0 ? 0.0 : sqrt(tmp);
}

Item_variance_field::Item_variance_field(Item_sum_variance *item)
unknown's avatar
unknown committed
977 978 979 980 981 982 983 984
{
  name=item->name;
  decimals=item->decimals;
  max_length=item->max_length;
  field=item->result_field;
  maybe_null=1;
}

unknown's avatar
unknown committed
985
double Item_variance_field::val()
unknown's avatar
unknown committed
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
{
  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;
unknown's avatar
unknown committed
1001
  return tmp2 <= 0.0 ? 0.0 : tmp2;
unknown's avatar
unknown committed
1002 1003
}

unknown's avatar
unknown committed
1004
String *Item_variance_field::val_str(String *str)
unknown's avatar
unknown committed
1005 1006 1007 1008
{
  double nr=val();
  if (null_value)
    return 0;
unknown's avatar
unknown committed
1009
  str->set(nr,decimals, &my_charset_bin);
unknown's avatar
unknown committed
1010 1011 1012 1013 1014 1015 1016 1017 1018
  return str;
}

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

#include "sql_select.h"

1019
int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
1020
{
1021
  return memcmp(key1, key2, *(uint*) arg);
1022 1023
}

1024
int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
1025
{
1026 1027 1028
  Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
  CHARSET_INFO *cs=item->key_charset;
  uint len=item->key_length;
unknown's avatar
Fix:  
unknown committed
1029 1030 1031
  return cs->coll->strnncollsp(cs, 
			       (const uchar*) key1, len, 
			       (const uchar*) key2, len);
1032 1033
}

unknown's avatar
unknown committed
1034 1035 1036 1037 1038 1039 1040
/*
  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
*/

1041 1042 1043
int composite_key_cmp(void* arg, byte* key1, byte* key2)
{
  Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
unknown's avatar
unknown committed
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
  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;
  }
1057 1058 1059
  return 0;
}

unknown's avatar
unknown committed
1060 1061 1062 1063
/*
  helper function for walking the tree when we dump it to MyISAM -
  tree_walk will call it for each leaf
*/
1064

1065 1066 1067
int dump_leaf(byte* key, uint32 count __attribute__((unused)),
		     Item_sum_count_distinct* item)
{
unknown's avatar
unknown committed
1068
  byte* buf = item->table->record[0];
1069
  int error;
unknown's avatar
unknown committed
1070 1071
  /*
    The first item->rec_offset bytes are taken care of with
unknown's avatar
unknown committed
1072
    restore_record(table,default_values) in setup()
unknown's avatar
unknown committed
1073
  */
1074
  memcpy(buf + item->rec_offset, key, item->tree->size_of_element);
1075 1076
  if ((error = item->table->file->write_row(buf)))
  {
unknown's avatar
unknown committed
1077 1078 1079
    if (error != HA_ERR_FOUND_DUPP_KEY &&
	error != HA_ERR_FOUND_DUPP_UNIQUE)
      return 1;
1080 1081 1082
  }
  return 0;
}
1083

unknown's avatar
unknown committed
1084

unknown's avatar
unknown committed
1085
void Item_sum_count_distinct::cleanup()
unknown's avatar
unknown committed
1086
{
unknown's avatar
unknown committed
1087
  Item_sum_int::cleanup();
unknown's avatar
unknown committed
1088 1089 1090 1091
  /*
    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 )
  */
1092 1093 1094 1095 1096 1097 1098
  if (!original)
  {
    if (table)
      free_tmp_table(current_thd, table);
    delete tmp_table_param;
    if (use_tree)
      delete_tree(tree);
unknown's avatar
unknown committed
1099
    table= 0;
1100
    use_tree= 0;
1101
  }
unknown's avatar
unknown committed
1102 1103
}

unknown's avatar
unknown committed
1104 1105
bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables,
					 Item **ref)
unknown's avatar
unknown committed
1106
{
1107
  if (Item_sum_num::fix_fields(thd, tables, ref))
unknown's avatar
unknown committed
1108 1109 1110 1111
    return 1;
  return 0;
}

1112 1113 1114 1115 1116 1117
/* 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;
unknown's avatar
unknown committed
1118
  use_tree= 0; // to prevent delete_tree call on uninitialized tree
1119 1120 1121 1122
  tree= &tree_base;
}


unknown's avatar
unknown committed
1123 1124 1125
bool Item_sum_count_distinct::setup(THD *thd)
{
  List<Item> list;
1126
  SELECT_LEX *select_lex= thd->lex->current_select;
1127 1128 1129
  if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
    return 1;
    
1130 1131 1132
  if (!(tmp_table_param= new TMP_TABLE_PARAM))
    return 1;

unknown's avatar
unknown committed
1133 1134
  /* Create a table with an unique key over all parameters */
  for (uint i=0; i < arg_count ; i++)
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
  {
    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;
unknown's avatar
unknown committed
1148
  count_field_types(tmp_table_param,list,0);
unknown's avatar
unknown committed
1149 1150 1151 1152 1153
  if (table)
  {
    free_tmp_table(thd, table);
    tmp_table_param->cleanup();
  }
1154
  if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
unknown's avatar
unknown committed
1155
				0,
1156
				select_lex->options | thd->options,
1157
				HA_POS_ERROR, (char*)"")))
unknown's avatar
unknown committed
1158 1159
    return 1;
  table->file->extra(HA_EXTRA_NO_ROWS);		// Don't update rows
1160
  table->no_rows=1;
1161

unknown's avatar
unknown committed
1162

unknown's avatar
unknown committed
1163 1164 1165 1166 1167
  // no blobs, otherwise it would be MyISAM
  if (table->db_type == DB_TYPE_HEAP)
  {
    qsort_cmp2 compare_key;
    void* cmp_arg;
unknown's avatar
unknown committed
1168

unknown's avatar
unknown committed
1169
    // to make things easier for dump_leaf if we ever have to dump to MyISAM
unknown's avatar
unknown committed
1170
    restore_record(table,default_values);
unknown's avatar
unknown committed
1171

unknown's avatar
unknown committed
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
    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:
1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
	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;
	}
unknown's avatar
unknown committed
1199 1200 1201 1202 1203 1204 1205
	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;
1206
	cmp_arg = (void*) &key_length;
unknown's avatar
unknown committed
1207 1208
	break;
      }
1209 1210 1211
      key_charset = field->charset();
      key_length  = field->pack_length();
      rec_offset  = 1;
1212
    }
unknown's avatar
unknown committed
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
    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;

1223
      for (key_length = 0, lengths=field_lengths; field < field_end; ++field)
unknown's avatar
unknown committed
1224 1225
      {
	uint32 length= (*field)->pack_length();
1226
	key_length += length;
unknown's avatar
unknown committed
1227 1228 1229 1230
	*lengths++ = length;
	if (!(*field)->binary())
	  all_binary = 0;			// Can't break loop here
      }
1231
      rec_offset = table->reclength - key_length;
unknown's avatar
unknown committed
1232 1233 1234
      if (all_binary)
      {
	compare_key = (qsort_cmp2)simple_raw_key_cmp;
1235
	cmp_arg = (void*) &key_length;
unknown's avatar
unknown committed
1236 1237 1238 1239
      }
      else
      {
	compare_key = (qsort_cmp2) composite_key_cmp ;
1240
	cmp_arg = (void*) this;
unknown's avatar
unknown committed
1241 1242 1243
      }
    }

unknown's avatar
unknown committed
1244 1245
    if (use_tree)
      delete_tree(tree);
1246 1247
    init_tree(tree, min(thd->variables.max_heap_table_size,
			thd->variables.sortbuff_size/16), 0,
1248
	      key_length, compare_key, 0, NULL, cmp_arg);
unknown's avatar
unknown committed
1249 1250 1251
    use_tree = 1;

    /*
1252
      The only time key_length could be 0 is if someone does
unknown's avatar
unknown committed
1253 1254 1255 1256
      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
    */
1257 1258
    max_elements_in_tree = ((key_length) ? 
			    thd->variables.max_heap_table_size/key_length : 1);
1259 1260 1261 1262 1263 1264

  }
  if (original)
  {
    original->table= table;
    original->use_tree= use_tree;
unknown's avatar
unknown committed
1265
  }
unknown's avatar
unknown committed
1266 1267 1268
  return 0;
}

unknown's avatar
unknown committed
1269

1270 1271
int Item_sum_count_distinct::tree_to_myisam()
{
unknown's avatar
unknown committed
1272
  if (create_myisam_from_heap(current_thd, table, tmp_table_param,
unknown's avatar
unknown committed
1273
			      HA_ERR_RECORD_FILE_FULL, 1) ||
1274
      tree_walk(tree, (tree_walk_action)&dump_leaf, (void*)this,
unknown's avatar
unknown committed
1275
		left_root_right))
1276
    return 1;
1277
  delete_tree(tree);
1278 1279 1280
  use_tree = 0;
  return 0;
}
unknown's avatar
unknown committed
1281

1282 1283 1284

Item *Item_sum_count_distinct::copy_or_same(THD* thd) 
{
1285
  return new (&thd->mem_root) Item_sum_count_distinct(thd, this);
1286 1287 1288
}


1289
void Item_sum_count_distinct::clear()
unknown's avatar
unknown committed
1290
{
unknown's avatar
merge  
unknown committed
1291
  if (use_tree)
1292
    reset_tree(tree);
unknown's avatar
merge  
unknown committed
1293
  else if (table)
1294 1295 1296 1297 1298
  {
    table->file->extra(HA_EXTRA_NO_CACHE);
    table->file->delete_all_rows();
    table->file->extra(HA_EXTRA_WRITE_CACHE);
  }
unknown's avatar
unknown committed
1299 1300 1301 1302 1303
}

bool Item_sum_count_distinct::add()
{
  int error;
1304 1305
  if (always_null)
    return 0;
unknown's avatar
unknown committed
1306
  copy_fields(tmp_table_param);
unknown's avatar
unknown committed
1307
  copy_funcs(tmp_table_param->items_to_copy);
unknown's avatar
unknown committed
1308

1309 1310 1311 1312
  for (Field **field=table->field ; *field ; field++)
    if ((*field)->is_real_null(0))
      return 0;					// Don't count NULL

unknown's avatar
unknown committed
1313 1314 1315 1316 1317 1318
  if (use_tree)
  {
    /*
      If the tree got too big, convert to MyISAM, otherwise insert into the
      tree.
    */
1319
    if (tree->elements_in_tree > max_elements_in_tree)
1320
    {
1321
      if (tree_to_myisam())
1322 1323
	return 1;
    }
1324 1325
    else if (!tree_insert(tree, table->record[0] + rec_offset, 0,
			  tree->custom_arg))
unknown's avatar
unknown committed
1326 1327
      return 1;
  }
1328
  else if ((error=table->file->write_row(table->record[0])))
unknown's avatar
unknown committed
1329 1330 1331 1332
  {
    if (error != HA_ERR_FOUND_DUPP_KEY &&
	error != HA_ERR_FOUND_DUPP_UNIQUE)
    {
unknown's avatar
unknown committed
1333 1334
      if (create_myisam_from_heap(current_thd, table, tmp_table_param, error,
				  1))
unknown's avatar
unknown committed
1335 1336 1337 1338 1339 1340
	return 1;				// Not a table_is_full error
    }
  }
  return 0;
}

unknown's avatar
unknown committed
1341

unknown's avatar
unknown committed
1342 1343 1344 1345
longlong Item_sum_count_distinct::val_int()
{
  if (!table)					// Empty query
    return LL(0);
unknown's avatar
unknown committed
1346
  if (use_tree)
1347
    return tree->elements_in_tree;
unknown's avatar
unknown committed
1348 1349 1350 1351
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
  return table->file->records;
}

1352 1353 1354

void Item_sum_count_distinct::print(String *str)
{
1355
  str->append("count(distinct ", 15);
1356 1357 1358 1359
  args[0]->print(str);
  str->append(')');
}

unknown's avatar
unknown committed
1360 1361 1362 1363 1364 1365 1366 1367 1368
/****************************************************************************
** 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

1369
void Item_udf_sum::clear()
unknown's avatar
unknown committed
1370
{
1371
  DBUG_ENTER("Item_udf_sum::clear");
1372
  udf.clear();
1373
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
1374 1375 1376 1377
}

bool Item_udf_sum::add()
{
1378
  DBUG_ENTER("Item_udf_sum::add");
unknown's avatar
unknown committed
1379 1380 1381 1382
  udf.add(&null_value);
  DBUG_RETURN(0);
}

1383 1384
Item *Item_sum_udf_float::copy_or_same(THD* thd)
{
1385
  return new (&thd->mem_root) Item_sum_udf_float(thd, this);
1386 1387
}

unknown's avatar
unknown committed
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400
double Item_sum_udf_float::val()
{
  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)
{
  double nr=val();
  if (null_value)
    return 0;					/* purecov: inspected */
unknown's avatar
unknown committed
1401
  str->set(nr,decimals, &my_charset_bin);
unknown's avatar
unknown committed
1402 1403 1404 1405
  return str;
}


1406 1407
Item *Item_sum_udf_int::copy_or_same(THD* thd)
{
1408
  return new (&thd->mem_root) Item_sum_udf_int(thd, this);
1409 1410 1411
}


unknown's avatar
unknown committed
1412 1413 1414 1415 1416 1417 1418 1419
longlong Item_sum_udf_int::val_int()
{
  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));
}

1420

unknown's avatar
unknown committed
1421 1422 1423 1424 1425
String *Item_sum_udf_int::val_str(String *str)
{
  longlong nr=val_int();
  if (null_value)
    return 0;
unknown's avatar
unknown committed
1426
  str->set(nr, &my_charset_bin);
unknown's avatar
unknown committed
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
  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;
}

1441 1442 1443

Item *Item_sum_udf_str::copy_or_same(THD* thd)
{
1444
  return new (&thd->mem_root) Item_sum_udf_str(thd, this);
1445 1446 1447
}


unknown's avatar
unknown committed
1448 1449 1450 1451 1452 1453 1454 1455 1456
String *Item_sum_udf_str::val_str(String *str)
{
  DBUG_ENTER("Item_sum_udf_str::str");
  String *res=udf.val_str(str,&str_value);
  null_value = !res;
  DBUG_RETURN(res);
}

#endif /* HAVE_DLOPEN */
1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467


/*****************************************************************************
 GROUP_CONCAT function
 Syntax:
 GROUP_CONCAT([DISTINCT] expr,... [ORDER BY col [ASC|DESC],...] 
   [SEPARATOR str_const])
 concat of values from "group by" operation
*****************************************************************************/

/*
unknown's avatar
SCRUM  
unknown committed
1468 1469
  function of sort for syntax:
  GROUP_CONCAT(DISTINCT expr,...)
1470 1471
*/

unknown's avatar
unknown committed
1472 1473
int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
				       byte* key2)
1474
{
unknown's avatar
SCRUM  
unknown committed
1475
  Item_func_group_concat* item= (Item_func_group_concat*)arg;
unknown's avatar
unknown committed
1476

unknown's avatar
unknown committed
1477
  for (uint i= 0; i < item->arg_count_field; i++)
1478
  {
unknown's avatar
unknown committed
1479
    Item *field_item= item->args[i];
unknown's avatar
BUG  
unknown committed
1480
    Field *field= field_item->real_item()->get_tmp_table_field();
1481 1482
    if (field)
    {
unknown's avatar
unknown committed
1483
      uint offset= field->abs_offset;
1484

unknown's avatar
SCRUM  
unknown committed
1485 1486
      int res= field->key_cmp(key1 + offset, key2 + offset);
      /*
1487
        if key1 and key2 is not equal than field->key_cmp return offset. This
unknown's avatar
unknown committed
1488
        function must return value 1 for this case.
unknown's avatar
SCRUM  
unknown committed
1489
      */
1490 1491 1492
      if (res)
        return 1;
    }
unknown's avatar
unknown committed
1493
  } 
1494 1495 1496
  return 0;
}

1497

1498
/*
unknown's avatar
SCRUM  
unknown committed
1499 1500
  function of sort for syntax:
  GROUP_CONCAT(expr,... ORDER BY col,... )
1501 1502
*/

unknown's avatar
unknown committed
1503
int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
1504
{
unknown's avatar
SCRUM  
unknown committed
1505
  Item_func_group_concat* item= (Item_func_group_concat*)arg;
unknown's avatar
unknown committed
1506

unknown's avatar
unknown committed
1507
  for (uint i=0; i < item->arg_count_order; i++)
1508
  {
unknown's avatar
SCRUM  
unknown committed
1509 1510
    ORDER *order_item= item->order[i];
    Item *item= *order_item->item;
unknown's avatar
BUG  
unknown committed
1511
    Field *field= item->real_item()->get_tmp_table_field();
1512 1513
    if (field)
    {
unknown's avatar
unknown committed
1514
      uint offset= field->abs_offset;
1515

unknown's avatar
SCRUM  
unknown committed
1516 1517
      bool dir= order_item->asc;
      int res= field->key_cmp(key1 + offset, key2 + offset);
1518 1519 1520
      if (res)
        return dir ? res : -res;
    }
unknown's avatar
unknown committed
1521
  } 
unknown's avatar
SCRUM  
unknown committed
1522
  /*
1523
    We can't return 0 because tree class remove this item as double value. 
unknown's avatar
SCRUM  
unknown committed
1524
  */   
1525 1526 1527
  return 1;
}

1528

1529
/*
unknown's avatar
SCRUM  
unknown committed
1530 1531
  function of sort for syntax:
  GROUP_CONCAT(DISTINCT expr,... ORDER BY col,... )
1532
*/
unknown's avatar
SCRUM  
unknown committed
1533

unknown's avatar
unknown committed
1534 1535
int group_concat_key_cmp_with_distinct_and_order(void* arg,byte* key1,
						 byte* key2)
1536 1537 1538 1539 1540 1541
{
  if (!group_concat_key_cmp_with_distinct(arg,key1,key2))
    return 0;
  return(group_concat_key_cmp_with_order(arg,key1,key2));
}

1542

1543
/*
unknown's avatar
SCRUM  
unknown committed
1544 1545
  create result
  item is pointer to Item_func_group_concat
1546
*/
unknown's avatar
SCRUM  
unknown committed
1547

unknown's avatar
unknown committed
1548
int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
unknown's avatar
SCRUM  
unknown committed
1549
                  Item_func_group_concat *group_concat_item)
1550 1551 1552 1553
{
  char buff[MAX_FIELD_WIDTH];
  String tmp((char *)&buff,sizeof(buff),default_charset_info);
  String tmp2((char *)&buff,sizeof(buff),default_charset_info);
unknown's avatar
unknown committed
1554
  
1555 1556
  tmp.length(0);
  
unknown's avatar
unknown committed
1557
  for (uint i= 0; i < group_concat_item->arg_show_fields; i++)
1558
  {
unknown's avatar
unknown committed
1559
    Item *show_item= group_concat_item->args[i];
1560 1561
    if (!show_item->const_item())
    {
unknown's avatar
BUG  
unknown committed
1562
      Field *f= show_item->real_item()->get_tmp_table_field();
unknown's avatar
SCRUM  
unknown committed
1563
      char *sv= f->ptr;
unknown's avatar
unknown committed
1564
      f->ptr= (char *)key + f->abs_offset;
unknown's avatar
SCRUM  
unknown committed
1565 1566 1567
      String *res= f->val_str(&tmp,&tmp2);
      group_concat_item->result.append(*res);
      f->ptr= sv;
1568 1569 1570
    }
    else 
    {
unknown's avatar
SCRUM  
unknown committed
1571
      String *res= show_item->val_str(&tmp);
1572
      if (res)
unknown's avatar
SCRUM  
unknown committed
1573
        group_concat_item->result.append(*res);
1574 1575
    }
  }
unknown's avatar
SCRUM  
unknown committed
1576
  if (group_concat_item->tree_mode) // Last item of tree
1577
  {
unknown's avatar
SCRUM  
unknown committed
1578 1579 1580 1581
    group_concat_item->show_elements++;
    if (group_concat_item->show_elements < 
        group_concat_item->tree->elements_in_tree)
      group_concat_item->result.append(*group_concat_item->separator);
1582 1583 1584
  }
  else
  {
unknown's avatar
SCRUM  
unknown committed
1585
    group_concat_item->result.append(*group_concat_item->separator); 
1586
  }
unknown's avatar
SCRUM  
unknown committed
1587 1588 1589 1590 1591 1592 1593 1594 1595
  /*
    if length of result more than group_concat_max_len - stop !
  */  
  if (group_concat_item->result.length() > 
      group_concat_item->group_concat_max_len)
  {
    group_concat_item->count_cut_values++;
    group_concat_item->result.length(group_concat_item->group_concat_max_len);
    group_concat_item->warning_for_row= TRUE;
1596 1597 1598 1599 1600
    return 1;
  }
  return 0;
}

1601

1602
/*
unknown's avatar
SCRUM  
unknown committed
1603 1604 1605 1606 1607
  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
1608
*/
unknown's avatar
SCRUM  
unknown committed
1609

unknown's avatar
unknown committed
1610
Item_func_group_concat::Item_func_group_concat(bool is_distinct,
1611 1612 1613
					       List<Item> *is_select,
					       SQL_LIST *is_order,
					       String *is_separator)
unknown's avatar
unknown committed
1614 1615 1616 1617
  :Item_sum(), tmp_table_param(0), max_elements_in_tree(0), warning(0),
   warning_available(0), key_length(0), rec_offset(0),
   tree_mode(0), distinct(is_distinct), warning_for_row(0),
   separator(is_separator), tree(&tree_base), table(0),
1618
   order(0), tables_list(0),
unknown's avatar
unknown committed
1619 1620 1621
   show_elements(0), arg_count_order(0), arg_count_field(0),
   arg_show_fields(0), count_cut_values(0)
   
1622
{
unknown's avatar
SCRUM  
unknown committed
1623 1624
  original= 0;
  quick_group= 0;
1625
  mark_as_sum_func();
unknown's avatar
SCRUM  
unknown committed
1626
  order= 0;
unknown's avatar
unknown committed
1627
  group_concat_max_len= current_thd->variables.group_concat_max_len;
1628

1629
    
unknown's avatar
SCRUM  
unknown committed
1630 1631 1632 1633 1634 1635 1636 1637 1638 1639
  arg_show_fields= arg_count_field= is_select->elements;
  arg_count_order= is_order ? is_order->elements : 0;
  arg_count= arg_count_field;
  
  /*
    We need to allocate:
    args - arg_count+arg_count_order (for possible order items in temporare 
           tables)
    order - arg_count_order
  */
unknown's avatar
unknown committed
1640
  args= (Item**) sql_alloc(sizeof(Item*)*(arg_count+arg_count_order)+
unknown's avatar
unknown committed
1641
			   sizeof(ORDER*)*arg_count_order);
unknown's avatar
SCRUM  
unknown committed
1642
  if (!args)
unknown's avatar
unknown committed
1643
    return;
unknown's avatar
unknown committed
1644 1645

  /* fill args items of show and sort */
unknown's avatar
SCRUM  
unknown committed
1646 1647 1648
  int i= 0;
  List_iterator_fast<Item> li(*is_select);
  Item *item_select;
1649

unknown's avatar
unknown committed
1650
  for ( ; (item_select= li++) ; i++)
unknown's avatar
unknown committed
1651
    args[i]= item_select;
unknown's avatar
unknown committed
1652 1653

  if (arg_count_order) 
unknown's avatar
SCRUM  
unknown committed
1654
  {
unknown's avatar
unknown committed
1655
    i= 0;
unknown's avatar
unknown committed
1656
    order= (ORDER**)(args + arg_count + arg_count_order);
unknown's avatar
unknown committed
1657
    for (ORDER *order_item= (ORDER*) is_order->first;
unknown's avatar
SCRUM  
unknown committed
1658 1659
                order_item != NULL;
                order_item= order_item->next)
1660
    {
unknown's avatar
unknown committed
1661
      order[i++]= order_item;
1662 1663 1664 1665
    }
  }
}

unknown's avatar
SCRUM  
unknown committed
1666

unknown's avatar
unknown committed
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
void Item_func_group_concat::cleanup()
{
  /*
    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)
      free_tmp_table(thd, table);
    delete tmp_table_param;
    if (tree_mode)
      delete_tree(tree); 
  }
}

1684 1685
Item_func_group_concat::~Item_func_group_concat()
{
unknown's avatar
SCRUM  
unknown committed
1686 1687 1688 1689
  /*
    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 )
  */
1690 1691
  if (!original)
  {
1692
    THD *thd= current_thd;
1693 1694 1695 1696
    if (warning_available)
    {
      char warn_buff[MYSQL_ERRMSG_SIZE];
      sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
1697
      warning->set_msg(thd, warn_buff);
1698 1699 1700 1701 1702
    }
  }
}


1703 1704
Item *Item_func_group_concat::copy_or_same(THD* thd)
{
1705
  return new (&thd->mem_root) Item_func_group_concat(thd, this);
1706 1707 1708
}


1709
void Item_func_group_concat::clear()
1710 1711 1712
{
  result.length(0);
  result.copy();
unknown's avatar
SCRUM  
unknown committed
1713 1714
  null_value= TRUE;
  warning_for_row= false;
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
  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);
}

unknown's avatar
SCRUM  
unknown committed
1725

1726 1727
bool Item_func_group_concat::add()
{
unknown's avatar
BUG  
unknown committed
1728 1729
  if (always_null)
    return 0;
1730 1731 1732
  copy_fields(tmp_table_param);
  copy_funcs(tmp_table_param->items_to_copy);

unknown's avatar
SCRUM  
unknown committed
1733
  bool record_is_null= TRUE;
unknown's avatar
unknown committed
1734
  for (uint i= 0; i < arg_show_fields; i++)
1735
  {
unknown's avatar
unknown committed
1736
    Item *show_item= args[i];
unknown's avatar
SCRUM  
unknown committed
1737
    if (!show_item->const_item())
1738
    {
unknown's avatar
BUG  
unknown committed
1739
      Field *f= show_item->real_item()->get_tmp_table_field();
unknown's avatar
SCRUM  
unknown committed
1740
      if (!f->is_null())
unknown's avatar
unknown committed
1741
      {
unknown's avatar
SCRUM  
unknown committed
1742
        record_is_null= FALSE;      
unknown's avatar
unknown committed
1743 1744
	break;
      }
1745 1746
    }
  }
unknown's avatar
SCRUM  
unknown committed
1747 1748 1749 1750 1751
  if (record_is_null)
    return 0;
  null_value= FALSE;
  if (tree_mode)
  {
unknown's avatar
unknown committed
1752
    if (!tree_insert(tree, table->record[0] + rec_offset, 0, tree->custom_arg))
unknown's avatar
SCRUM  
unknown committed
1753 1754
      return 1;
  }
1755 1756 1757
  else
  {
    if (result.length() <= group_concat_max_len && !warning_for_row)
unknown's avatar
unknown committed
1758
      dump_leaf_key(table->record[0] + rec_offset, 1,
1759 1760 1761 1762 1763
                    (Item_func_group_concat*)this);
  }
  return 0;
}

unknown's avatar
SCRUM  
unknown committed
1764

1765 1766 1767 1768 1769 1770
void Item_func_group_concat::reset_field()
{
  if (tree_mode)
    reset_tree(tree);
}

unknown's avatar
SCRUM  
unknown committed
1771

1772 1773 1774
bool
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
unknown's avatar
unknown committed
1775
  uint i;			/* for loop variable */ 
1776

1777 1778 1779 1780 1781 1782
  if (!thd->allow_sum_func)
  {
    my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
    return 1;
  }
  
unknown's avatar
SCRUM  
unknown committed
1783 1784
  thd->allow_sum_func= 0;
  maybe_null= 0;
unknown's avatar
unknown committed
1785
  item_thd= thd;
unknown's avatar
unknown committed
1786
  for (i= 0 ; i < arg_count ; i++)
1787
  {
unknown's avatar
unknown committed
1788
    if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
1789
      return 1;
unknown's avatar
unknown committed
1790
    maybe_null |= args[i]->maybe_null;
1791
  }
unknown's avatar
SCRUM  
unknown committed
1792 1793 1794 1795
  /*
    Fix fields for order clause in function:
    GROUP_CONCAT(expr,... ORDER BY col,... )
  */
1796
  for (i= 0 ; i < arg_count_order ; i++)
1797
  {
unknown's avatar
unknown committed
1798
    // order_item->item can be changed by fix_fields() call
unknown's avatar
SCRUM  
unknown committed
1799
    ORDER *order_item= order[i];
1800 1801
    if ((*order_item->item)->fix_fields(thd, tables, order_item->item) ||
	(*order_item->item)->check_cols(1))
1802 1803
      return 1;
  }
unknown's avatar
SCRUM  
unknown committed
1804 1805
  result_field= 0;
  null_value= 1;
1806
  max_length= group_concat_max_len;
unknown's avatar
SCRUM  
unknown committed
1807
  thd->allow_sum_func= 1;			
1808 1809
  if (!(tmp_table_param= new TMP_TABLE_PARAM))
    return 1;
unknown's avatar
SCRUM  
unknown committed
1810
  tables_list= tables;
1811 1812 1813 1814
  fixed= 1;
  return 0;
}

unknown's avatar
SCRUM  
unknown committed
1815

1816 1817
bool Item_func_group_concat::setup(THD *thd)
{
1818
  DBUG_ENTER("Item_func_group_concat::setup");
1819
  List<Item> list;
1820
  SELECT_LEX *select_lex= thd->lex->current_select;
1821 1822

  if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
1823
    DBUG_RETURN(1);
unknown's avatar
SCRUM  
unknown committed
1824
  /*
unknown's avatar
unknown committed
1825
    push all not constant fields to list and create temp table
unknown's avatar
SCRUM  
unknown committed
1826
  */ 
unknown's avatar
BUG  
unknown committed
1827
  always_null= 0;
unknown's avatar
SCRUM  
unknown committed
1828
  for (uint i= 0; i < arg_count; i++)
1829
  {
unknown's avatar
SCRUM  
unknown committed
1830
    Item *item= args[i];
1831
    if (list.push_back(item))
1832
      DBUG_RETURN(1);
1833 1834 1835 1836
    if (item->const_item())
    {
      (void) item->val_int();
      if (item->null_value)
unknown's avatar
SCRUM  
unknown committed
1837
	always_null= 1;
1838 1839
    }
  }
unknown's avatar
BUG  
unknown committed
1840
  if (always_null)
1841
    DBUG_RETURN(0);
1842 1843 1844 1845 1846 1847 1848 1849 1850 1851
        
  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);
1852 1853 1854 1855 1856
  if (table)
  {
    free_tmp_table(thd, table);
    tmp_table_param->cleanup();
  }
unknown's avatar
SCRUM  
unknown committed
1857 1858 1859 1860 1861
  /*
    We have to create a temporary table for that we get descriptions of fields 
    (types, sizes and so on).
  */
  if (!(table=create_tmp_table(thd, tmp_table_param, all_fields, 0,
1862 1863
			       0, 0, 0,select_lex->options | thd->options,
			       (char *) "")))
1864
    DBUG_RETURN(1);
1865
  table->file->extra(HA_EXTRA_NO_ROWS);
unknown's avatar
SCRUM  
unknown committed
1866
  table->no_rows= 1;
unknown's avatar
unknown committed
1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880


  Field** field, **field_end;
  field_end = (field = table->field) + table->fields;
  uint offset = 0;
  for (key_length = 0; field < field_end; ++field)
  {
    uint32 length= (*field)->pack_length();
    (*field)->abs_offset= offset;
    offset+= length;
    key_length += length;
  } 
  rec_offset = table->reclength - key_length;

unknown's avatar
unknown committed
1881 1882 1883

  if (tree_mode)
    delete_tree(tree);
unknown's avatar
SCRUM  
unknown committed
1884 1885 1886
  /*
    choise function of sort
  */  
unknown's avatar
unknown committed
1887 1888
  tree_mode= distinct || arg_count_order; 
  qsort_cmp2 compare_key;
1889 1890 1891 1892 1893
  if (tree_mode)
  {
    if (arg_count_order)
    {
      if (distinct)
unknown's avatar
SCRUM  
unknown committed
1894
        compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct_and_order;
1895
      else
unknown's avatar
SCRUM  
unknown committed
1896
        compare_key= (qsort_cmp2) group_concat_key_cmp_with_order;
1897 1898 1899 1900
    }
    else
    {
      if (distinct)
unknown's avatar
SCRUM  
unknown committed
1901
        compare_key= (qsort_cmp2) group_concat_key_cmp_with_distinct;
1902
      else 
unknown's avatar
SCRUM  
unknown committed
1903
       compare_key= NULL; 
1904
    }
unknown's avatar
SCRUM  
unknown committed
1905 1906 1907 1908 1909
    /*
      Create a tree of sort. Tree is used for a sort and a remove dubl 
      values (according with syntax of the function). If function does't
      contain DISTINCT and ORDER BY clauses, we don't create this tree.
    */
1910 1911
    init_tree(tree, min(thd->variables.max_heap_table_size,
              thd->variables.sortbuff_size/16), 0,
unknown's avatar
unknown committed
1912 1913 1914
              key_length, compare_key, 0, NULL, (void*) this);
    max_elements_in_tree= ((key_length) ? 
           thd->variables.max_heap_table_size/key_length : 1);
1915 1916
  };

unknown's avatar
SCRUM  
unknown committed
1917 1918 1919 1920
  /*
    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)
  */
1921 1922 1923 1924 1925
  if (original)
  {
    original->table= table;
    original->tree_mode= tree_mode;
  }
1926
  DBUG_RETURN(0);
1927 1928
}

1929 1930 1931 1932 1933 1934
/* 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;
unknown's avatar
unknown committed
1935
  tree_mode= 0; // to prevent delete_tree call on uninitialized tree
1936 1937 1938 1939
  tree= &tree_base;
}


1940 1941
String* Item_func_group_concat::val_str(String* str)
{
unknown's avatar
SCRUM  
unknown committed
1942 1943
  if (null_value)
    return 0;
1944 1945
  if (tree_mode)
  {
unknown's avatar
SCRUM  
unknown committed
1946
    show_elements= 0;
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956
    tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
              left_root_right);
  }
  else
  {
    if (!warning_for_row)
      result.length(result.length()-separator->length());
  }
  if (count_cut_values && !warning_available)
  {
unknown's avatar
SCRUM  
unknown committed
1957 1958
    warning_available= TRUE;
    warning= push_warning(item_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
1959 1960 1961 1962
                           ER_CUT_VALUE_GROUP_CONCAT, NULL);
  }
  return &result;
}
1963

unknown's avatar
unknown committed
1964

1965 1966
void Item_func_group_concat::print(String *str)
{
1967
  str->append("group_concat(", 13);
1968
  if (distinct)
1969
    str->append("distinct ", 9);
1970 1971 1972 1973 1974 1975 1976 1977
  for (uint i= 0; i < arg_count; i++)
  {
    if (i)
      str->append(',');
    args[i]->print(str);
  }
  if (arg_count_order)
  {
1978
    str->append(" order by ", 10);
1979 1980 1981 1982 1983 1984 1985
    for (uint i= 0 ; i < arg_count_order ; i++)
    {
      if (i)
	str->append(',');
      (*order[i]->item)->print(str);
    }
  }
1986
  str->append(" seperator \'", 12);
1987
  str->append(*separator);
1988
  str->append("\')", 2);
1989
}