~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/item/sum.cc

  • Committer: Stewart Smith
  • Date: 2008-11-21 16:06:07 UTC
  • mto: This revision was merged to the branch mainline in revision 593.
  • Revision ID: stewart@flamingspork.com-20081121160607-n6gdlt013spuo54r
remove mysql_frm_type
and fix engines to return correct value from delete_table when table doesn't exist.
(it should be ENOENT).

Also fix up some tests that manipulated frm files by hand. These tests are no longer valid and will need to be rewritten in the not too distant future.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
  @brief
21
21
  Sum functions (COUNT, MIN...)
22
22
*/
23
 
#include "config.h"
24
 
#include <cstdio>
25
 
#include <math.h>
 
23
#include <drizzled/server_includes.h>
26
24
#include <drizzled/sql_select.h>
27
25
#include <drizzled/error.h>
28
26
#include <drizzled/hybrid_type_traits.h>
31
29
#include <drizzled/sql_base.h>
32
30
 
33
31
#include <drizzled/item/sum.h>
34
 
#include <drizzled/field/decimal.h>
 
32
#include <drizzled/field/fdecimal.h>
35
33
#include <drizzled/field/double.h>
36
34
#include <drizzled/field/int64_t.h>
37
35
#include <drizzled/field/date.h>
 
36
#include <drizzled/field/timetype.h>
38
37
#include <drizzled/field/datetime.h>
39
38
 
40
 
#include "drizzled/internal/m_string.h"
41
 
 
42
 
#include <algorithm>
43
 
 
44
 
using namespace std;
45
 
 
46
 
namespace drizzled
47
 
{
 
39
#include CMATH_H
 
40
 
 
41
#if defined(CMATH_NAMESPACE)
 
42
using namespace CMATH_NAMESPACE;
 
43
#endif
48
44
 
49
45
extern my_decimal decimal_zero;
50
 
extern plugin::StorageEngine *heap_engine;
51
46
 
52
47
/**
53
48
  Prepare an aggregate function item for checking context conditions.
70
65
  @retval
71
66
    FALSE  otherwise
72
67
*/
73
 
 
 
68
 
74
69
bool Item_sum::init_sum_func_check(Session *session)
75
70
{
76
71
  if (!session->lex->allow_sum_func)
105
100
    If the context conditions are not met the method reports an error.
106
101
    If the set function is aggregated in some outer subquery the method
107
102
    adds it to the chain of items for such set functions that is attached
108
 
    to the the Select_Lex structure for this subquery.
 
103
    to the the st_select_lex structure for this subquery.
109
104
 
110
105
    A number of designated members of the object are used to check the
111
106
    conditions. They are specified in the comment before the Item_sum
122
117
         HAVING t1.a IN (SELECT t2.c FROM t2 WHERE AVG(t1.b) > 20) AND
123
118
                t1.a > (SELECT MIN(t2.d) FROM t2);
124
119
    @endcode
125
 
    allow_sum_func will contain:
126
 
    - for SUM(t1.b) - 1 at the first position
 
120
    allow_sum_func will contain: 
 
121
    - for SUM(t1.b) - 1 at the first position 
127
122
    - for AVG(t1.b) - 1 at the first position, 0 at the second position
128
123
    - for MIN(t2.d) - 1 at the first position, 1 at the second position.
129
124
 
141
136
  @retval
142
137
    FALSE  otherwise
143
138
*/
144
 
 
 
139
 
145
140
bool Item_sum::check_sum_func(Session *session, Item **ref)
146
141
{
147
142
  bool invalid= false;
148
143
  nesting_map allow_sum_func= session->lex->allow_sum_func;
149
 
  /*
 
144
  /*  
150
145
    The value of max_arg_level is updated if an argument of the set function
151
146
    contains a column reference resolved  against a subquery whose level is
152
147
    greater than the current value of max_arg_level.
153
148
    max_arg_level cannot be greater than nest level.
154
 
    nest level is always >= 0
155
 
  */
 
149
    nest level is always >= 0  
 
150
  */ 
156
151
  if (nest_level == max_arg_level)
157
152
  {
158
153
    /*
159
 
      The function must be aggregated in the current subquery,
160
 
      If it is there under a construct where it is not allowed
161
 
      we report an error.
162
 
    */
 
154
      The function must be aggregated in the current subquery, 
 
155
      If it is there under a construct where it is not allowed 
 
156
      we report an error. 
 
157
    */ 
163
158
    invalid= !(allow_sum_func & (1 << max_arg_level));
164
159
  }
165
160
  else if (max_arg_level >= 0 || !(allow_sum_func & (1 << nest_level)))
183
178
  /*
184
179
    By this moment we either found a subquery where the set function is
185
180
    to be aggregated  and assigned a value that is  >= 0 to aggr_level,
186
 
    or set the value of 'invalid' to TRUE to report later an error.
 
181
    or set the value of 'invalid' to TRUE to report later an error. 
187
182
  */
188
 
  /*
 
183
  /* 
189
184
    Additionally we have to check whether possible nested set functions
190
185
    are acceptable here: they are not, if the level of aggregation of
191
186
    some of them is less than aggr_level.
192
187
  */
193
 
  if (!invalid)
 
188
  if (!invalid) 
194
189
    invalid= aggr_level <= max_sum_func_level;
195
 
  if (invalid)
 
190
  if (invalid)  
196
191
  {
197
192
    my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
198
193
               MYF(0));
204
199
    /*
205
200
      If the set function is nested adjust the value of
206
201
      max_sum_func_level for the nesting set function.
207
 
      We take into account only enclosed set functions that are to be
208
 
      aggregated on the same level or above of the nest level of
 
202
      We take into account only enclosed set functions that are to be 
 
203
      aggregated on the same level or above of the nest level of 
209
204
      the enclosing set function.
210
205
      But we must always pass up the max_sum_func_level because it is
211
206
      the maximum nested level of all directly and indirectly enclosed
256
251
    List_iterator<Item_field> of(outer_fields);
257
252
    while ((field= of++))
258
253
    {
259
 
      Select_Lex *sel= field->cached_table->select_lex;
 
254
      SELECT_LEX *sel= field->cached_table->select_lex;
260
255
      if (sel->nest_level < aggr_level)
261
256
      {
262
257
        if (in_sum_func)
268
263
          in_sum_func->outer_fields.push_back(field);
269
264
        }
270
265
        else
271
 
        {
272
 
          sel->full_group_by_flag.set(NON_AGG_FIELD_USED);
273
 
        }
 
266
          sel->full_group_by_flag|= NON_AGG_FIELD_USED;
274
267
      }
275
268
      if (sel->nest_level > aggr_level &&
276
 
          (sel->full_group_by_flag.test(SUM_FUNC_USED)) &&
277
 
          ! sel->group_list.elements)
 
269
          (sel->full_group_by_flag & SUM_FUNC_USED) &&
 
270
          !sel->group_list.elements)
278
271
      {
279
272
        my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,
280
273
                   ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0));
282
275
      }
283
276
    }
284
277
  }
285
 
  aggr_sel->full_group_by_flag.set(SUM_FUNC_USED);
 
278
  aggr_sel->full_group_by_flag|= SUM_FUNC_USED;
286
279
  update_used_tables();
287
280
  session->lex->in_sum_func= in_sum_func;
288
281
  return false;
295
288
    aggregated. If it finds such a subquery then aggr_level is set to
296
289
    the nest level of this subquery and the item for the set function
297
290
    is added to the list of set functions used in nested subqueries
298
 
    inner_sum_func_list defined for each subquery. When the item is placed
 
291
    inner_sum_func_list defined for each subquery. When the item is placed 
299
292
    there the field 'ref_by' is set to ref.
300
293
 
301
294
  @note
311
304
    FALSE  if the executes without failures (currently always)
312
305
  @retval
313
306
    TRUE   otherwise
314
 
*/
 
307
*/  
315
308
 
316
309
bool Item_sum::register_sum_func(Session *session, Item **ref)
317
310
{
318
 
  Select_Lex *sl;
 
311
  SELECT_LEX *sl;
319
312
  nesting_map allow_sum_func= session->lex->allow_sum_func;
320
313
  for (sl= session->lex->current_select->master_unit()->outer_select() ;
321
314
       sl && sl->nest_level > max_arg_level;
330
323
  }
331
324
  if (sl && (allow_sum_func & (1 << sl->nest_level)))
332
325
  {
333
 
    /*
 
326
    /* 
334
327
      We reached the subquery of level max_arg_level and checked
335
 
      that the function can be aggregated here.
 
328
      that the function can be aggregated here. 
336
329
      The set function will be aggregated in this subquery.
337
 
    */
 
330
    */   
338
331
    aggr_level= sl->nest_level;
339
332
    aggr_sel= sl;
340
333
 
353
346
    aggr_sel->inner_sum_func_list= this;
354
347
    aggr_sel->with_sum_func= 1;
355
348
 
356
 
    /*
 
349
    /* 
357
350
      Mark Item_subselect(s) as containing aggregate function all the way up
358
351
      to aggregate function's calculation context.
359
352
      Note that we must not mark the Item of calculation context itself
360
 
      because with_sum_func on the calculation context Select_Lex is
 
353
      because with_sum_func on the calculation context st_select_lex is
361
354
      already set above.
362
355
 
363
 
      with_sum_func being set for an Item means that this Item refers
 
356
      with_sum_func being set for an Item means that this Item refers 
364
357
      (somewhere in it, e.g. one of its arguments if it's a function) directly
365
358
      or through intermediate items to an aggregate function that is calculated
366
359
      in a context "outside" of the Item (e.g. in the current or outer select).
367
360
 
368
 
      with_sum_func being set for an Select_Lex means that this Select_Lex
 
361
      with_sum_func being set for an st_select_lex means that this st_select_lex
369
362
      has aggregate functions directly referenced (i.e. not through a sub-select).
370
363
    */
371
 
    for (sl= session->lex->current_select;
 
364
    for (sl= session->lex->current_select; 
372
365
         sl && sl != aggr_sel && sl->master_unit()->item;
373
366
         sl= sl->master_unit()->outer_select() )
374
367
      sl->master_unit()->item->with_sum_func= 1;
378
371
}
379
372
 
380
373
 
381
 
Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements),
 
374
Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements), 
382
375
  forced_const(false)
383
376
{
384
 
  if ((args=(Item**) memory::sql_alloc(sizeof(Item*)*arg_count)))
 
377
  if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
385
378
  {
386
379
    uint32_t i=0;
387
380
    List_iterator_fast<Item> li(list);
406
399
  aggr_sel(item->aggr_sel),
407
400
  nest_level(item->nest_level), aggr_level(item->aggr_level),
408
401
  quick_group(item->quick_group), used_tables_cache(item->used_tables_cache),
409
 
  forced_const(item->forced_const)
 
402
  forced_const(item->forced_const) 
410
403
{
411
404
  if (arg_count <= 2)
412
405
    args=tmp_args;
419
412
 
420
413
void Item_sum::mark_as_sum_func()
421
414
{
422
 
  Select_Lex *cur_select= current_session->lex->current_select;
 
415
  SELECT_LEX *cur_select= current_session->lex->current_select;
423
416
  cur_select->n_sum_items++;
424
417
  cur_select->with_sum_func= 1;
425
418
  with_sum_func= 1;
426
419
}
427
420
 
428
421
 
429
 
void Item_sum::make_field(SendField *tmp_field)
 
422
void Item_sum::make_field(Send_field *tmp_field)
430
423
{
431
424
  if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
432
425
  {
504
497
}
505
498
 
506
499
 
507
 
Field *Item_sum::create_tmp_field(bool ,
 
500
Field *Item_sum::create_tmp_field(bool group __attribute__((unused)),
508
501
                                  Table *table,
509
502
                                  uint32_t convert_blob_length)
510
503
{
522
515
        !convert_blob_length)
523
516
      return make_string_field(table);
524
517
    field= new Field_varstring(convert_blob_length, maybe_null,
525
 
                               name, table->getMutableShare(), collation.collation);
 
518
                               name, table->s, collation.collation);
526
519
    break;
527
520
  case DECIMAL_RESULT:
528
 
    field= new Field_decimal(max_length, maybe_null, name,
 
521
    field= new Field_new_decimal(max_length, maybe_null, name,
529
522
                                 decimals, unsigned_flag);
530
523
    break;
531
524
  case ROW_RESULT:
714
707
  if (args[0]->type() == Item::FIELD_ITEM)
715
708
  {
716
709
    field= ((Item_field*) args[0])->field;
717
 
 
 
710
    
718
711
    if ((field= create_tmp_field_from_field(current_session, field, name, table,
719
712
                                            NULL, convert_blob_length)))
720
713
      field->flags&= ~NOT_NULL_FLAG;
729
722
  case DRIZZLE_TYPE_DATE:
730
723
    field= new Field_date(maybe_null, name, collation.collation);
731
724
    break;
 
725
  case DRIZZLE_TYPE_TIME:
 
726
    field= new Field_time(maybe_null, name, collation.collation);
 
727
    break;
732
728
  case DRIZZLE_TYPE_TIMESTAMP:
733
729
  case DRIZZLE_TYPE_DATETIME:
734
730
    field= new Field_datetime(maybe_null, name, collation.collation);
750
746
  @todo
751
747
  check if the following assignments are really needed
752
748
*/
753
 
Item_sum_sum::Item_sum_sum(Session *session, Item_sum_sum *item)
 
749
Item_sum_sum::Item_sum_sum(Session *session, Item_sum_sum *item) 
754
750
  :Item_sum_num(session, item), hybrid_type(item->hybrid_type),
755
751
   curr_dec_buff(item->curr_dec_buff)
756
752
{
877
873
 
878
874
/***************************************************************************/
879
875
 
 
876
#ifdef __cplusplus
 
877
extern "C" {
 
878
#endif
 
879
 
880
880
/* Declarations for auxilary C-callbacks */
881
881
 
882
882
static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
886
886
 
887
887
 
888
888
static int item_sum_distinct_walk(void *element,
889
 
                                  uint32_t ,
 
889
                                  element_count num_of_dups __attribute__((unused)),
890
890
                                  void *item)
891
891
{
892
892
  return ((Item_sum_distinct*) (item))->unique_walk_function(element);
893
893
}
894
894
 
 
895
#ifdef __cplusplus
 
896
}
 
897
#endif
 
898
 
895
899
/* Item_sum_distinct */
896
900
 
897
901
Item_sum_distinct::Item_sum_distinct(Item *item_arg)
953
957
{
954
958
  assert(args[0]->fixed);
955
959
 
956
 
  null_value= maybe_null= true;
957
960
  table_field_type= args[0]->field_type();
958
961
 
959
962
  /* Adjust tmp table type according to the chosen aggregation type */
981
984
  case DECIMAL_RESULT:
982
985
    val.traits= Hybrid_type_traits_decimal::instance();
983
986
    if (table_field_type != DRIZZLE_TYPE_LONGLONG)
984
 
      table_field_type= DRIZZLE_TYPE_DECIMAL;
 
987
      table_field_type= DRIZZLE_TYPE_NEWDECIMAL;
985
988
    break;
986
989
  case ROW_RESULT:
987
990
  default:
1003
1006
*/
1004
1007
bool Item_sum_distinct::setup(Session *session)
1005
1008
{
1006
 
  List<CreateField> field_list;
1007
 
  CreateField field_def;                              /* field definition */
 
1009
  List<Create_field> field_list;
 
1010
  Create_field field_def;                              /* field definition */
1008
1011
  /* It's legal to call setup() more than once when in a subquery */
1009
1012
  if (tree)
1010
1013
    return(false);
1023
1026
  assert(args[0]->fixed);
1024
1027
 
1025
1028
  field_def.init_for_tmp_table(table_field_type, args[0]->max_length,
1026
 
                               args[0]->decimals, args[0]->maybe_null);
 
1029
                               args[0]->decimals, args[0]->maybe_null,
 
1030
                               args[0]->unsigned_flag);
1027
1031
 
1028
 
  if (! (table= session->create_virtual_tmp_table(field_list)))
 
1032
  if (! (table= create_virtual_tmp_table(session, field_list)))
1029
1033
    return(true);
1030
1034
 
1031
1035
  /* XXX: check that the case of CHAR(0) works OK */
1032
 
  tree_key_length= table->getShare()->getRecordLength() - table->getShare()->null_bytes;
 
1036
  tree_key_length= table->s->reclength - table->s->null_bytes;
1033
1037
 
1034
1038
  /*
1035
1039
    Unique handles all unique elements in a tree until they can't fit
1037
1041
    simple_raw_key_cmp because the table contains numbers only; decimals
1038
1042
    are converted to binary representation as well.
1039
1043
  */
1040
 
  tree= new Unique(simple_raw_key_cmp, &tree_key_length,
1041
 
                   tree_key_length,
1042
 
                   (size_t)session->variables.max_heap_table_size);
 
1044
  tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length,
 
1045
                   session->variables.max_heap_table_size);
1043
1046
 
1044
1047
  is_evaluated= false;
1045
1048
  return(tree == 0);
1048
1051
 
1049
1052
bool Item_sum_distinct::add()
1050
1053
{
1051
 
  args[0]->save_in_field(table->getField(0), false);
 
1054
  args[0]->save_in_field(table->field[0], false);
1052
1055
  is_evaluated= false;
1053
 
  if (!table->getField(0)->is_null())
 
1056
  if (!table->field[0]->is_null())
1054
1057
  {
1055
1058
    assert(tree);
1056
1059
    null_value= 0;
1058
1061
      '0' values are also stored in the tree. This doesn't matter
1059
1062
      for SUM(DISTINCT), but is important for AVG(DISTINCT)
1060
1063
    */
1061
 
    return tree->unique_add(table->getField(0)->ptr);
 
1064
    return tree->unique_add(table->field[0]->ptr);
1062
1065
  }
1063
1066
  return 0;
1064
1067
}
1066
1069
 
1067
1070
bool Item_sum_distinct::unique_walk_function(void *element)
1068
1071
{
1069
 
  memcpy(table->getField(0)->ptr, element, tree_key_length);
 
1072
  memcpy(table->field[0]->ptr, element, tree_key_length);
1070
1073
  ++count;
1071
 
  val.traits->add(&val, table->getField(0));
 
1074
  val.traits->add(&val, table->field[0]);
1072
1075
  return 0;
1073
1076
}
1074
1077
 
1110
1113
     */
1111
1114
    if (tree)
1112
1115
    {
1113
 
      table->getField(0)->set_notnull();
 
1116
      table->field[0]->set_notnull();
1114
1117
      tree->walk(item_sum_distinct_walk, (void*) this);
1115
1118
    }
1116
1119
    is_evaluated= true;
1162
1165
    AVG() will divide val by count. We need to reserve digits
1163
1166
    after decimal point as the result can be fractional.
1164
1167
  */
1165
 
  decimals= min(decimals + prec_increment, (unsigned int)NOT_FIXED_DEC);
 
1168
  decimals= cmin(decimals + prec_increment, (unsigned int)NOT_FIXED_DEC);
1166
1169
}
1167
1170
 
1168
1171
 
1224
1227
  if (hybrid_type == DECIMAL_RESULT)
1225
1228
  {
1226
1229
    int precision= args[0]->decimal_precision() + prec_increment;
1227
 
    decimals= min(args[0]->decimals + prec_increment, (unsigned int) DECIMAL_MAX_SCALE);
 
1230
    decimals= cmin(args[0]->decimals + prec_increment, (unsigned int) DECIMAL_MAX_SCALE);
1228
1231
    max_length= my_decimal_precision_to_length(precision, decimals,
1229
1232
                                               unsigned_flag);
1230
 
    f_precision= min(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION);
 
1233
    f_precision= cmin(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION);
1231
1234
    f_scale=  args[0]->decimals;
1232
1235
    dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale);
1233
1236
  }
1234
1237
  else {
1235
 
    decimals= min(args[0]->decimals + prec_increment, (unsigned int) NOT_FIXED_DEC);
 
1238
    decimals= cmin(args[0]->decimals + prec_increment, (unsigned int) NOT_FIXED_DEC);
1236
1239
    max_length= args[0]->max_length + prec_increment;
1237
1240
  }
1238
1241
}
1245
1248
 
1246
1249
 
1247
1250
Field *Item_sum_avg::create_tmp_field(bool group, Table *table,
1248
 
                                      uint32_t )
 
1251
                                      uint32_t convert_blob_len __attribute__((unused)))
1249
1252
{
1250
1253
  Field *field;
1251
1254
  if (group)
1257
1260
    */
1258
1261
    field= new Field_varstring(((hybrid_type == DECIMAL_RESULT) ?
1259
1262
                                dec_bin_size : sizeof(double)) + sizeof(int64_t),
1260
 
                               0, name, table->getMutableShare(), &my_charset_bin);
 
1263
                               0, name, table->s, &my_charset_bin);
1261
1264
  }
1262
1265
  else if (hybrid_type == DECIMAL_RESULT)
1263
 
    field= new Field_decimal(max_length, maybe_null, name,
1264
 
                             decimals, unsigned_flag);
 
1266
    field= new Field_new_decimal(max_length, maybe_null, name,
 
1267
                                 decimals, unsigned_flag);
1265
1268
  else
1266
1269
    field= new Field_double(max_length, maybe_null, name, decimals, true);
1267
1270
  if (field)
1376
1379
{
1377
1380
  *count += 1;
1378
1381
 
1379
 
  if (*count == 1)
 
1382
  if (*count == 1) 
1380
1383
  {
1381
1384
    *m= nr;
1382
1385
    *s= 0;
1420
1423
 
1421
1424
  /*
1422
1425
    According to the SQL2003 standard (Part 2, Foundations; sec 10.9,
1423
 
    aggregate function; paragraph 7h of Syntax Rules), "the declared
 
1426
    aggregate function; paragraph 7h of Syntax Rules), "the declared 
1424
1427
    type of the result is an implementation-defined aproximate numeric
1425
1428
    type.
1426
1429
  */
1429
1432
  switch (args[0]->result_type()) {
1430
1433
  case REAL_RESULT:
1431
1434
  case STRING_RESULT:
1432
 
    decimals= min(args[0]->decimals + 4, (int)NOT_FIXED_DEC);
 
1435
    decimals= cmin(args[0]->decimals + 4, NOT_FIXED_DEC);
1433
1436
    break;
1434
1437
  case INT_RESULT:
1435
1438
  case DECIMAL_RESULT:
1436
1439
  {
1437
1440
    int precision= args[0]->decimal_precision()*2 + prec_increment;
1438
 
    decimals= min(args[0]->decimals + prec_increment, (unsigned int) DECIMAL_MAX_SCALE);
 
1441
    decimals= cmin(args[0]->decimals + prec_increment, (unsigned int) DECIMAL_MAX_SCALE);
1439
1442
    max_length= my_decimal_precision_to_length(precision, decimals,
1440
1443
                                               unsigned_flag);
1441
1444
 
1461
1464
  pass around.
1462
1465
*/
1463
1466
Field *Item_sum_variance::create_tmp_field(bool group, Table *table,
1464
 
                                           uint32_t )
 
1467
                                           uint32_t convert_blob_len __attribute__((unused)))
1465
1468
{
1466
1469
  Field *field;
1467
1470
  if (group)
1471
1474
      The easiest way is to do this is to store both value in a string
1472
1475
      and unpack on access.
1473
1476
    */
1474
 
    field= new Field_varstring(sizeof(double)*2 + sizeof(int64_t), 0, name, table->getMutableShare(), &my_charset_bin);
 
1477
    field= new Field_varstring(sizeof(double)*2 + sizeof(int64_t), 0, name, table->s, &my_charset_bin);
1475
1478
  }
1476
1479
  else
1477
1480
    field= new Field_double(max_length, maybe_null, name, decimals, true);
1485
1488
 
1486
1489
void Item_sum_variance::clear()
1487
1490
{
1488
 
  count= 0;
 
1491
  count= 0; 
1489
1492
}
1490
1493
 
1491
1494
bool Item_sum_variance::add()
1492
1495
{
1493
 
  /*
 
1496
  /* 
1494
1497
    Why use a temporary variable?  We don't know if it is null until we
1495
1498
    evaluate it, which has the side-effect of setting null_value .
1496
1499
  */
1497
1500
  double nr= args[0]->val_real();
1498
 
 
 
1501
  
1499
1502
  if (!args[0]->null_value)
1500
1503
    variance_fp_recurrence_next(&recurrence_m, &recurrence_s, &count, nr);
1501
1504
  return 0;
1760
1763
  {
1761
1764
    int64_t nr=args[0]->val_int();
1762
1765
    if (!args[0]->null_value && (null_value ||
1763
 
                                 (unsigned_flag &&
 
1766
                                 (unsigned_flag && 
1764
1767
                                  (uint64_t) nr < (uint64_t) sum_int) ||
1765
1768
                                 (!unsigned_flag && nr < sum_int)))
1766
1769
    {
1824
1827
  {
1825
1828
    int64_t nr=args[0]->val_int();
1826
1829
    if (!args[0]->null_value && (null_value ||
1827
 
                                 (unsigned_flag &&
 
1830
                                 (unsigned_flag && 
1828
1831
                                  (uint64_t) nr > (uint64_t) sum_int) ||
1829
1832
                                 (!unsigned_flag && nr > sum_int)))
1830
1833
    {
2494
2497
int composite_key_cmp(void* arg, unsigned char* key1, unsigned char* key2)
2495
2498
{
2496
2499
  Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
2497
 
  Field **field    = item->table->getFields();
2498
 
  Field **field_end= field + item->table->getShare()->sizeFields();
 
2500
  Field **field    = item->table->field;
 
2501
  Field **field_end= field + item->table->s->fields;
2499
2502
  uint32_t *lengths=item->field_lengths;
2500
2503
  for (; field < field_end; ++field)
2501
2504
  {
2510
2513
  return 0;
2511
2514
}
2512
2515
 
2513
 
static int count_distinct_walk(void *,
2514
 
                               uint32_t ,
 
2516
#ifdef __cplusplus
 
2517
extern "C" {
 
2518
#endif
 
2519
 
 
2520
static int count_distinct_walk(void *elem __attribute__((unused)),
 
2521
                               element_count count __attribute__((unused)),
2515
2522
                               void *arg)
2516
2523
{
2517
2524
  (*((uint64_t*)arg))++;
2518
2525
  return 0;
2519
2526
}
2520
2527
 
 
2528
#ifdef __cplusplus
 
2529
}
 
2530
#endif
 
2531
 
 
2532
 
 
2533
 
2521
2534
void Item_sum_count_distinct::cleanup()
2522
2535
{
2523
2536
  Item_sum_int::cleanup();
2535
2548
    is_evaluated= false;
2536
2549
    if (table)
2537
2550
    {
 
2551
      table->free_tmp_table(table->in_use);
2538
2552
      table= 0;
2539
2553
    }
2540
2554
    delete tmp_table_param;
2571
2585
bool Item_sum_count_distinct::setup(Session *session)
2572
2586
{
2573
2587
  List<Item> list;
2574
 
  Select_Lex *select_lex= session->lex->current_select;
 
2588
  SELECT_LEX *select_lex= session->lex->current_select;
2575
2589
 
2576
2590
  /*
2577
2591
    Setup can be called twice for ROLLUP items. This is a bug.
2581
2595
  if (tree || table || tmp_table_param)
2582
2596
    return false;
2583
2597
 
2584
 
  if (!(tmp_table_param= new Tmp_Table_Param))
 
2598
  if (!(tmp_table_param= new TMP_TABLE_PARAM))
2585
2599
    return true;
2586
2600
 
2587
2601
  /* Create a table with an unique key over all parameters */
2603
2617
                                0,
2604
2618
                                (select_lex->options | session->options),
2605
2619
                                HA_POS_ERROR, (char*)"")))
2606
 
  {
2607
2620
    return true;
2608
 
  }
2609
 
  table->cursor->extra(HA_EXTRA_NO_ROWS);               // Don't update rows
 
2621
  table->file->extra(HA_EXTRA_NO_ROWS);         // Don't update rows
2610
2622
  table->no_rows=1;
2611
2623
 
2612
 
  if (table->getShare()->db_type() == heap_engine)
 
2624
  if (table->s->db_type() == heap_hton)
2613
2625
  {
2614
2626
    /*
2615
2627
      No blobs, otherwise it would have been MyISAM: set up a compare
2617
2629
    */
2618
2630
    qsort_cmp2 compare_key;
2619
2631
    void* cmp_arg;
2620
 
    Field **field= table->getFields();
2621
 
    Field **field_end= field + table->getShare()->sizeFields();
 
2632
    Field **field= table->field;
 
2633
    Field **field_end= field + table->s->fields;
2622
2634
    bool all_binary= true;
2623
2635
 
2624
2636
    for (tree_key_length= 0; field < field_end; ++field)
2639
2651
    }
2640
2652
    else
2641
2653
    {
2642
 
      if (table->getShare()->sizeFields() == 1)
 
2654
      if (table->s->fields == 1)
2643
2655
      {
2644
2656
        /*
2645
2657
          If we have only one field, which is the most common use of
2648
2660
          about other fields.
2649
2661
        */
2650
2662
        compare_key= (qsort_cmp2) simple_str_key_cmp;
2651
 
        cmp_arg= (void*) table->getField(0);
 
2663
        cmp_arg= (void*) table->field[0];
2652
2664
        /* tree_key_length has been set already */
2653
2665
      }
2654
2666
      else
2656
2668
        uint32_t *length;
2657
2669
        compare_key= (qsort_cmp2) composite_key_cmp;
2658
2670
        cmp_arg= (void*) this;
2659
 
        field_lengths= (uint32_t*) session->alloc(table->getShare()->sizeFields() * sizeof(uint32_t));
2660
 
        for (tree_key_length= 0, length= field_lengths, field= table->getFields();
 
2671
        field_lengths= (uint32_t*) session->alloc(table->s->fields * sizeof(uint32_t));
 
2672
        for (tree_key_length= 0, length= field_lengths, field= table->field;
2661
2673
             field < field_end; ++field, ++length)
2662
2674
        {
2663
2675
          *length= (*field)->pack_length();
2667
2679
    }
2668
2680
    assert(tree == 0);
2669
2681
    tree= new Unique(compare_key, cmp_arg, tree_key_length,
2670
 
                     (size_t)session->variables.max_heap_table_size);
 
2682
                     session->variables.max_heap_table_size);
2671
2683
    /*
2672
2684
      The only time tree_key_length could be 0 is if someone does
2673
2685
      count(distinct) on a char(0) field - stupid thing to do,
2682
2694
}
2683
2695
 
2684
2696
 
2685
 
Item *Item_sum_count_distinct::copy_or_same(Session* session)
 
2697
Item *Item_sum_count_distinct::copy_or_same(Session* session) 
2686
2698
{
2687
2699
  return new (session->mem_root) Item_sum_count_distinct(session, this);
2688
2700
}
2698
2710
  }
2699
2711
  else if (table)
2700
2712
  {
2701
 
    table->cursor->extra(HA_EXTRA_NO_CACHE);
2702
 
    table->cursor->ha_delete_all_rows();
2703
 
    table->cursor->extra(HA_EXTRA_WRITE_CACHE);
 
2713
    table->file->extra(HA_EXTRA_NO_CACHE);
 
2714
    table->file->ha_delete_all_rows();
 
2715
    table->file->extra(HA_EXTRA_WRITE_CACHE);
2704
2716
  }
2705
2717
}
2706
2718
 
2712
2724
  copy_fields(tmp_table_param);
2713
2725
  copy_funcs(tmp_table_param->items_to_copy);
2714
2726
 
2715
 
  for (Field **field= table->getFields() ; *field ; field++)
2716
 
  {
 
2727
  for (Field **field=table->field ; *field ; field++)
2717
2728
    if ((*field)->is_real_null(0))
2718
 
    {
2719
2729
      return 0;                                 // Don't count NULL
2720
 
    }
2721
 
  }
2722
2730
 
2723
2731
  is_evaluated= false;
2724
2732
  if (tree)
2729
2737
      bloat the tree without providing any valuable info. Besides,
2730
2738
      key_length used to initialize the tree didn't include space for them.
2731
2739
    */
2732
 
    return tree->unique_add(table->record[0] + table->getShare()->null_bytes);
 
2740
    return tree->unique_add(table->record[0] + table->s->null_bytes);
2733
2741
  }
2734
 
  if ((error= table->cursor->insertRecord(table->record[0])) &&
2735
 
      table->cursor->is_fatal_error(error, HA_CHECK_DUP))
 
2742
  if ((error= table->file->ha_write_row(table->record[0])) &&
 
2743
      table->file->is_fatal_error(error, HA_CHECK_DUP))
2736
2744
    return true;
2737
2745
  return false;
2738
2746
}
2757
2765
    return (int64_t) count;
2758
2766
  }
2759
2767
 
2760
 
  error= table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
2768
  error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
2761
2769
 
2762
2770
  if(error)
2763
2771
  {
2764
 
    table->print_error(error, MYF(0));
 
2772
    table->file->print_error(error, MYF(0));
2765
2773
  }
2766
2774
 
2767
 
  return table->cursor->stats.records;
 
2775
  return table->file->stats.records;
2768
2776
}
2769
2777
 
2770
2778
/*****************************************************************************
2781
2789
*****************************************************************************/
2782
2790
 
2783
2791
 
2784
 
/**
 
2792
/** 
2785
2793
  Compares the values for fields in expr list of GROUP_CONCAT.
2786
2794
  @note
2787
 
 
 
2795
       
2788
2796
     GROUP_CONCAT([DISTINCT] expr [,expr ...]
2789
2797
              [order_st BY {unsigned_integer | col_name | expr}
2790
2798
                  [ASC | DESC] [,col_name ...]]
2791
2799
              [SEPARATOR str_val])
2792
 
 
 
2800
 
2793
2801
  @return
2794
 
  @retval -1 : key1 < key2
 
2802
  @retval -1 : key1 < key2 
2795
2803
  @retval  0 : key1 = key2
2796
 
  @retval  1 : key1 > key2
 
2804
  @retval  1 : key1 > key2 
2797
2805
*/
2798
2806
 
2799
 
int group_concat_key_cmp_with_distinct(void* arg, const void* key1,
 
2807
int group_concat_key_cmp_with_distinct(void* arg, const void* key1, 
2800
2808
                                       const void* key2)
2801
2809
{
2802
2810
  Item_func_group_concat *item_func= (Item_func_group_concat*)arg;
2805
2813
  for (uint32_t i= 0; i < item_func->arg_count_field; i++)
2806
2814
  {
2807
2815
    Item *item= item_func->args[i];
2808
 
    /*
 
2816
    /* 
2809
2817
      If field_item is a const item then either get_tp_table_field returns 0
2810
 
      or it is an item over a const table.
 
2818
      or it is an item over a const table. 
2811
2819
    */
2812
2820
    if (item->const_item())
2813
2821
      continue;
2818
2826
    */
2819
2827
    Field *field= item->get_tmp_table_field();
2820
2828
    int res;
2821
 
    uint32_t offset= field->offset(field->getTable()->record[0])-table->getShare()->null_bytes;
 
2829
    uint32_t offset= field->offset(field->table->record[0])-table->s->null_bytes;
2822
2830
    if((res= field->cmp((unsigned char*)key1 + offset, (unsigned char*)key2 + offset)))
2823
2831
      return res;
2824
2832
  }
2827
2835
 
2828
2836
 
2829
2837
/**
2830
 
  function of sort for syntax: GROUP_CONCAT(expr,... ORDER BY col,... )
 
2838
  function of sort for syntax: GROUP_CONCAT(expr,... order_st BY col,... )
2831
2839
*/
2832
2840
 
2833
 
int group_concat_key_cmp_with_order(void* arg, const void* key1,
 
2841
int group_concat_key_cmp_with_order(void* arg, const void* key1, 
2834
2842
                                    const void* key2)
2835
2843
{
2836
2844
  Item_func_group_concat* grp_item= (Item_func_group_concat*) arg;
2848
2856
      the temporary table, not the original field
2849
2857
    */
2850
2858
    Field *field= item->get_tmp_table_field();
2851
 
    /*
 
2859
    /* 
2852
2860
      If item is a const item then either get_tp_table_field returns 0
2853
 
      or it is an item over a const table.
 
2861
      or it is an item over a const table. 
2854
2862
    */
2855
2863
    if (field && !item->const_item())
2856
2864
    {
2857
2865
      int res;
2858
 
      uint32_t offset= (field->offset(field->getTable()->record[0]) -
2859
 
                    table->getShare()->null_bytes);
 
2866
      uint32_t offset= (field->offset(field->table->record[0]) -
 
2867
                    table->s->null_bytes);
2860
2868
      if ((res= field->cmp((unsigned char*)key1 + offset, (unsigned char*)key2 + offset)))
2861
2869
        return (*order_item)->asc ? res : -res;
2862
2870
    }
2874
2882
  Append data from current leaf to item->result.
2875
2883
*/
2876
2884
 
2877
 
int dump_leaf_key(unsigned char* key, uint32_t ,
 
2885
int dump_leaf_key(unsigned char* key, element_count count __attribute__((unused)),
2878
2886
                  Item_func_group_concat *item)
2879
2887
{
2880
2888
  Table *table= item->table;
2881
 
  String tmp((char *)table->getUpdateRecord(), table->getShare()->getRecordLength(),
 
2889
  String tmp((char *)table->record[1], table->s->reclength,
2882
2890
             default_charset_info);
2883
2891
  String tmp2;
2884
2892
  String *result= &item->result;
2905
2913
        because it contains both order and arg list fields.
2906
2914
      */
2907
2915
      Field *field= (*arg)->get_tmp_table_field();
2908
 
      uint32_t offset= (field->offset(field->getTable()->record[0]) -
2909
 
                    table->getShare()->null_bytes);
2910
 
      assert(offset < table->getShare()->getRecordLength());
 
2916
      uint32_t offset= (field->offset(field->table->record[0]) -
 
2917
                    table->s->null_bytes);
 
2918
      assert(offset < table->s->reclength);
2911
2919
      res= field->val_str(&tmp, key + offset);
2912
2920
    }
2913
2921
    else
2956
2964
                       bool distinct_arg, List<Item> *select_list,
2957
2965
                       SQL_LIST *order_list, String *separator_arg)
2958
2966
  :tmp_table_param(0), warning(0),
2959
 
   separator(separator_arg), tree(NULL), unique_filter(NULL), table(0),
 
2967
   separator(separator_arg), tree(0), unique_filter(NULL), table(0),
2960
2968
   order(0), context(context_arg),
2961
2969
   arg_count_order(order_list ? order_list->elements : 0),
2962
2970
   arg_count_field(select_list->elements),
2977
2985
           (for possible order items in temporare tables)
2978
2986
    order - arg_count_order
2979
2987
  */
2980
 
  if (!(args= (Item**) memory::sql_alloc(sizeof(Item*) * arg_count +
 
2988
  if (!(args= (Item**) sql_alloc(sizeof(Item*) * arg_count +
2981
2989
                                 sizeof(order_st*)*arg_count_order)))
2982
2990
    return;
2983
2991
 
3038
3046
  if (warning)
3039
3047
  {
3040
3048
    char warn_buff[DRIZZLE_ERRMSG_SIZE];
3041
 
    snprintf(warn_buff, sizeof(warn_buff), ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
 
3049
    sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
3042
3050
    warning->set_msg(current_session, warn_buff);
3043
3051
    warning= 0;
3044
3052
  }
3054
3062
    if (table)
3055
3063
    {
3056
3064
      Session *session= table->in_use;
 
3065
      table->free_tmp_table(session);
3057
3066
      table= 0;
3058
3067
      if (tree)
3059
3068
      {
3068
3077
      if (warning)
3069
3078
      {
3070
3079
        char warn_buff[DRIZZLE_ERRMSG_SIZE];
3071
 
        snprintf(warn_buff, sizeof(warn_buff), ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
 
3080
        sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
3072
3081
        warning->set_msg(session, warn_buff);
3073
3082
        warning= 0;
3074
3083
      }
3121
3130
  null_value= false;
3122
3131
  bool row_eligible= true;
3123
3132
 
3124
 
  if (distinct)
 
3133
  if (distinct) 
3125
3134
  {
3126
3135
    /* Filter out duplicate rows. */
3127
3136
    uint32_t count= unique_filter->elements_in_tree();
3128
 
    unique_filter->unique_add(table->record[0] + table->getShare()->null_bytes);
 
3137
    unique_filter->unique_add(table->record[0] + table->s->null_bytes);
3129
3138
    if (count == unique_filter->elements_in_tree())
3130
3139
      row_eligible= false;
3131
3140
  }
3132
3141
 
3133
3142
  TREE_ELEMENT *el= 0;                          // Only for safety
3134
3143
  if (row_eligible && tree)
3135
 
    el= tree_insert(tree, table->record[0] + table->getShare()->null_bytes, 0,
 
3144
    el= tree_insert(tree, table->record[0] + table->s->null_bytes, 0,
3136
3145
                    tree->custom_arg);
3137
3146
  /*
3138
3147
    If the row is not a duplicate (el->count == 1)
3141
3150
  */
3142
3151
  if (row_eligible && !warning_for_row &&
3143
3152
      (!tree || (el->count == 1 && distinct && !arg_count_order)))
3144
 
    dump_leaf_key(table->record[0] + table->getShare()->null_bytes, 1, this);
 
3153
    dump_leaf_key(table->record[0] + table->s->null_bytes, 1, this);
3145
3154
 
3146
3155
  return 0;
3147
3156
}
3180
3189
  result.set_charset(collation.collation);
3181
3190
  result_field= 0;
3182
3191
  null_value= 1;
3183
 
  max_length= (size_t)session->variables.group_concat_max_len;
 
3192
  max_length= session->variables.group_concat_max_len;
 
3193
 
 
3194
  uint32_t offset;
 
3195
  if (separator->needs_conversion(separator->length(), separator->charset(),
 
3196
                                  collation.collation, &offset))
 
3197
  {
 
3198
    uint32_t buflen= collation.collation->mbmaxlen * separator->length();
 
3199
    uint32_t errors, conv_length;
 
3200
    char *buf;
 
3201
    String *new_separator;
 
3202
 
 
3203
    if (!(buf= (char*) session->alloc(buflen)) ||
 
3204
        !(new_separator= new(session->mem_root)
 
3205
                           String(buf, buflen, collation.collation)))
 
3206
      return true;
 
3207
    
 
3208
    conv_length= copy_and_convert(buf, buflen, collation.collation,
 
3209
                                  separator->ptr(), separator->length(),
 
3210
                                  separator->charset(), &errors);
 
3211
    new_separator->length(conv_length);
 
3212
    separator= new_separator;
 
3213
  }
3184
3214
 
3185
3215
  if (check_sum_func(session, ref))
3186
3216
    return true;
3193
3223
bool Item_func_group_concat::setup(Session *session)
3194
3224
{
3195
3225
  List<Item> list;
3196
 
  Select_Lex *select_lex= session->lex->current_select;
 
3226
  SELECT_LEX *select_lex= session->lex->current_select;
3197
3227
 
3198
3228
  /*
3199
3229
    Currently setup() can be called twice. Please add
3202
3232
  if (table || tree)
3203
3233
    return(false);
3204
3234
 
3205
 
  if (!(tmp_table_param= new Tmp_Table_Param))
 
3235
  if (!(tmp_table_param= new TMP_TABLE_PARAM))
3206
3236
    return(true);
3207
3237
 
3208
3238
  /* We'll convert all blobs to varchar fields in the temporary table */
3243
3273
  {
3244
3274
    /*
3245
3275
      Currently we have to force conversion of BLOB values to VARCHAR's
3246
 
      if we are to store them in TREE objects used for ORDER BY and
 
3276
      if we are to store them in TREE objects used for order_st BY and
3247
3277
      DISTINCT. This leads to truncation if the BLOB's size exceeds
3248
3278
      Field_varstring::MAX_SIZE.
3249
3279
    */
3250
 
    set_if_smaller(tmp_table_param->convert_blob_length,
 
3280
    set_if_smaller(tmp_table_param->convert_blob_length, 
3251
3281
                   Field_varstring::MAX_SIZE);
3252
3282
  }
3253
3283
 
3255
3285
    We have to create a temporary table to get descriptions of fields
3256
3286
    (types, sizes and so on).
3257
3287
 
3258
 
    Note that in the table, we first have the ORDER BY fields, then the
 
3288
    Note that in the table, we first have the order_st BY fields, then the
3259
3289
    field list.
3260
3290
  */
3261
3291
  if (!(table= create_tmp_table(session, tmp_table_param, all_fields,
3262
3292
                                (order_st*) 0, 0, true,
3263
3293
                                (select_lex->options | session->options),
3264
3294
                                HA_POS_ERROR, (char*) "")))
3265
 
  {
3266
3295
    return(true);
3267
 
  }
3268
 
 
3269
 
  table->cursor->extra(HA_EXTRA_NO_ROWS);
 
3296
  table->file->extra(HA_EXTRA_NO_ROWS);
3270
3297
  table->no_rows= 1;
3271
3298
 
3272
3299
  /*
3274
3301
     Don't reserve space for NULLs: if any of gconcat arguments is NULL,
3275
3302
     the row is not added to the result.
3276
3303
  */
3277
 
  uint32_t tree_key_length= table->getShare()->getRecordLength() - table->getShare()->null_bytes;
 
3304
  uint32_t tree_key_length= table->s->reclength - table->s->null_bytes;
3278
3305
 
3279
3306
  if (arg_count_order)
3280
3307
  {
3281
3308
    tree= &tree_base;
3282
3309
    /*
3283
3310
      Create a tree for sorting. The tree is used to sort (according to the
3284
 
      syntax of this function). If there is no ORDER BY clause, we don't
 
3311
      syntax of this function). If there is no order_st BY clause, we don't
3285
3312
      create this tree.
3286
3313
    */
3287
 
    init_tree(tree, (uint32_t) min(session->variables.max_heap_table_size,
3288
 
                                   (uint64_t)(session->variables.sortbuff_size/16)), 
3289
 
              0,
3290
 
              tree_key_length,
3291
 
              group_concat_key_cmp_with_order , false, NULL, (void*) this);
 
3314
    init_tree(tree, (uint) cmin(session->variables.max_heap_table_size,
 
3315
                               session->variables.sortbuff_size/16), 0,
 
3316
              tree_key_length, 
 
3317
              group_concat_key_cmp_with_order , 0, NULL, (void*) this);
3292
3318
  }
3293
3319
 
3294
3320
  if (distinct)
3295
3321
    unique_filter= new Unique(group_concat_key_cmp_with_distinct,
3296
3322
                              (void*)this,
3297
3323
                              tree_key_length,
3298
 
                              (size_t)session->variables.max_heap_table_size);
3299
 
 
 
3324
                              session->variables.max_heap_table_size);
 
3325
  
3300
3326
  return(false);
3301
3327
}
3302
3328
 
3312
3338
  tree= 0;
3313
3339
}
3314
3340
 
3315
 
double Item_func_group_concat::val_real()
3316
 
{
3317
 
  String *res;  res=val_str(&str_value);
3318
 
  return res ? internal::my_atof(res->c_ptr()) : 0.0;
3319
 
}
3320
 
 
3321
 
int64_t Item_func_group_concat::val_int()
3322
 
{
3323
 
  String *res;
3324
 
  char *end_ptr;
3325
 
  int error;
3326
 
  if (!(res= val_str(&str_value)))
3327
 
    return (int64_t) 0;
3328
 
  end_ptr= (char*) res->ptr()+ res->length();
3329
 
  return internal::my_strtoll10(res->ptr(), &end_ptr, &error);
3330
 
}
3331
 
 
3332
 
String* Item_func_group_concat::val_str(String* )
 
3341
 
 
3342
String* Item_func_group_concat::val_str(String* str __attribute__((unused)))
3333
3343
{
3334
3344
  assert(fixed == 1);
3335
3345
  if (null_value)
3387
3397
Item_func_group_concat::~Item_func_group_concat()
3388
3398
{
3389
3399
  if (!original && unique_filter)
3390
 
    delete unique_filter;
 
3400
    delete unique_filter;    
3391
3401
}
3392
 
 
3393
 
} /* namespace drizzled */