~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/functions/func.cc

  • Committer: Monty Taylor
  • Date: 2008-10-08 00:14:19 UTC
  • mto: This revision was merged to the branch mainline in revision 491.
  • Revision ID: monty@inaugust.com-20081008001419-tg3g62sm9e3yz9q4
Split out Item_int_func and Item_func from Item_func. (don't think too hard about the second one)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 Sun Microsystems
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
 
 
20
#include <drizzled/server_includes.h>
 
21
 
 
22
#include CSTDINT_H
 
23
#include <cassert>
 
24
 
 
25
#include <drizzled/version.h>
 
26
 
 
27
#include <drizzled/sql_string.h>
 
28
#include <drizzled/sql_list.h>
 
29
 
 
30
#include <drizzled/functions/int.h>
 
31
 
 
32
 
 
33
void Item_func::set_arguments(List<Item> &list)
 
34
{
 
35
  allowed_arg_cols= 1;
 
36
  arg_count=list.elements;
 
37
  args= tmp_arg;                                // If 2 arguments
 
38
  if (arg_count <= 2 || (args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
 
39
  {
 
40
    List_iterator_fast<Item> li(list);
 
41
    Item *item;
 
42
    Item **save_args= args;
 
43
 
 
44
    while ((item=li++))
 
45
    {
 
46
      *(save_args++)= item;
 
47
      with_sum_func|=item->with_sum_func;
 
48
    }
 
49
  }
 
50
  list.empty();          // Fields are used
 
51
}
 
52
 
 
53
Item_func::Item_func(List<Item> &list)
 
54
  :allowed_arg_cols(1)
 
55
{
 
56
  set_arguments(list);
 
57
}
 
58
 
 
59
Item_func::Item_func(THD *thd, Item_func *item)
 
60
  :Item_result_field(thd, item),
 
61
   allowed_arg_cols(item->allowed_arg_cols),
 
62
   arg_count(item->arg_count),
 
63
   used_tables_cache(item->used_tables_cache),
 
64
   not_null_tables_cache(item->not_null_tables_cache),
 
65
   const_item_cache(item->const_item_cache)
 
66
{
 
67
  if (arg_count)
 
68
  {
 
69
    if (arg_count <=2)
 
70
      args= tmp_arg;
 
71
    else
 
72
    {
 
73
      if (!(args=(Item**) thd->alloc(sizeof(Item*)*arg_count)))
 
74
        return;
 
75
    }
 
76
    memcpy(args, item->args, sizeof(Item*)*arg_count);
 
77
  }
 
78
}
 
79
 
 
80
 
 
81
/*
 
82
  Resolve references to table column for a function and its argument
 
83
 
 
84
  SYNOPSIS:
 
85
  fix_fields()
 
86
  thd    Thread object
 
87
  ref    Pointer to where this object is used.  This reference
 
88
  is used if we want to replace this object with another
 
89
  one (for example in the summary functions).
 
90
 
 
91
  DESCRIPTION
 
92
  Call fix_fields() for all arguments to the function.  The main intention
 
93
  is to allow all Item_field() objects to setup pointers to the table fields.
 
94
 
 
95
  Sets as a side effect the following class variables:
 
96
  maybe_null  Set if any argument may return NULL
 
97
  with_sum_func  Set if any of the arguments contains a sum function
 
98
  used_tables_cache Set to union of the tables used by arguments
 
99
 
 
100
  str_value.charset If this is a string function, set this to the
 
101
  character set for the first argument.
 
102
  If any argument is binary, this is set to binary
 
103
 
 
104
  If for any item any of the defaults are wrong, then this can
 
105
  be fixed in the fix_length_and_dec() function that is called
 
106
  after this one or by writing a specialized fix_fields() for the
 
107
  item.
 
108
 
 
109
  RETURN VALUES
 
110
  false  ok
 
111
  true  Got error.  Stored with my_error().
 
112
*/
 
113
 
 
114
bool
 
115
Item_func::fix_fields(THD *thd, Item **ref __attribute__((unused)))
 
116
{
 
117
  assert(fixed == 0);
 
118
  Item **arg,**arg_end;
 
119
  void *save_thd_marker= thd->thd_marker;
 
120
  unsigned char buff[STACK_BUFF_ALLOC];      // Max argument in function
 
121
  thd->thd_marker= 0;
 
122
  used_tables_cache= not_null_tables_cache= 0;
 
123
  const_item_cache=1;
 
124
 
 
125
  if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
 
126
    return true;        // Fatal error if flag is set!
 
127
  if (arg_count)
 
128
  {            // Print purify happy
 
129
    for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
 
130
    {
 
131
      Item *item;
 
132
      /*
 
133
        We can't yet set item to *arg as fix_fields may change *arg
 
134
        We shouldn't call fix_fields() twice, so check 'fixed' field first
 
135
      */
 
136
      if ((!(*arg)->fixed && (*arg)->fix_fields(thd, arg)))
 
137
        return true;        /* purecov: inspected */
 
138
      item= *arg;
 
139
 
 
140
      if (allowed_arg_cols)
 
141
      {
 
142
        if (item->check_cols(allowed_arg_cols))
 
143
          return 1;
 
144
      }
 
145
      else
 
146
      {
 
147
        /*  we have to fetch allowed_arg_cols from first argument */
 
148
        assert(arg == args); // it is first argument
 
149
        allowed_arg_cols= item->cols();
 
150
        assert(allowed_arg_cols); // Can't be 0 any more
 
151
      }
 
152
 
 
153
      if (item->maybe_null)
 
154
        maybe_null=1;
 
155
 
 
156
      with_sum_func= with_sum_func || item->with_sum_func;
 
157
      used_tables_cache|=     item->used_tables();
 
158
      not_null_tables_cache|= item->not_null_tables();
 
159
      const_item_cache&=      item->const_item();
 
160
      with_subselect|=        item->with_subselect;
 
161
    }
 
162
  }
 
163
  fix_length_and_dec();
 
164
  if (thd->is_error()) // An error inside fix_length_and_dec occured
 
165
    return true;
 
166
  fixed= 1;
 
167
  thd->thd_marker= save_thd_marker;
 
168
  return false;
 
169
}
 
170
 
 
171
 
 
172
void Item_func::fix_after_pullout(st_select_lex *new_parent,
 
173
                                  Item **ref __attribute__((unused)))
 
174
{
 
175
  Item **arg,**arg_end;
 
176
 
 
177
  used_tables_cache= not_null_tables_cache= 0;
 
178
  const_item_cache=1;
 
179
 
 
180
  if (arg_count)
 
181
  {
 
182
    for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
 
183
    {
 
184
      (*arg)->fix_after_pullout(new_parent, arg);
 
185
      Item *item= *arg;
 
186
 
 
187
      used_tables_cache|=     item->used_tables();
 
188
      not_null_tables_cache|= item->not_null_tables();
 
189
      const_item_cache&=      item->const_item();
 
190
    }
 
191
  }
 
192
}
 
193
 
 
194
 
 
195
bool Item_func::walk(Item_processor processor, bool walk_subquery,
 
196
                     unsigned char *argument)
 
197
{
 
198
  if (arg_count)
 
199
  {
 
200
    Item **arg,**arg_end;
 
201
    for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
 
202
    {
 
203
      if ((*arg)->walk(processor, walk_subquery, argument))
 
204
        return 1;
 
205
    }
 
206
  }
 
207
  return (this->*processor)(argument);
 
208
}
 
209
 
 
210
void Item_func::traverse_cond(Cond_traverser traverser,
 
211
                              void *argument, traverse_order order)
 
212
{
 
213
  if (arg_count)
 
214
  {
 
215
    Item **arg,**arg_end;
 
216
 
 
217
    switch (order) {
 
218
    case(PREFIX):
 
219
      (*traverser)(this, argument);
 
220
      for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
 
221
      {
 
222
        (*arg)->traverse_cond(traverser, argument, order);
 
223
      }
 
224
      break;
 
225
    case (POSTFIX):
 
226
      for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
 
227
      {
 
228
        (*arg)->traverse_cond(traverser, argument, order);
 
229
      }
 
230
      (*traverser)(this, argument);
 
231
    }
 
232
  }
 
233
  else
 
234
    (*traverser)(this, argument);
 
235
}
 
236
 
 
237
 
 
238
/**
 
239
   Transform an Item_func object with a transformer callback function.
 
240
 
 
241
   The function recursively applies the transform method to each
 
242
   argument of the Item_func node.
 
243
   If the call of the method for an argument item returns a new item
 
244
   the old item is substituted for a new one.
 
245
   After this the transformer is applied to the root node
 
246
   of the Item_func object.
 
247
   @param transformer   the transformer callback function to be applied to
 
248
   the nodes of the tree of the object
 
249
   @param argument      parameter to be passed to the transformer
 
250
 
 
251
   @return
 
252
   Item returned as the result of transformation of the root node
 
253
*/
 
254
 
 
255
Item *Item_func::transform(Item_transformer transformer, unsigned char *argument)
 
256
{
 
257
  if (arg_count)
 
258
  {
 
259
    Item **arg,**arg_end;
 
260
    for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
 
261
    {
 
262
      Item *new_item= (*arg)->transform(transformer, argument);
 
263
      if (!new_item)
 
264
        return 0;
 
265
 
 
266
      /*
 
267
        THD::change_item_tree() should be called only if the tree was
 
268
        really transformed, i.e. when a new item has been created.
 
269
        Otherwise we'll be allocating a lot of unnecessary memory for
 
270
        change records at each execution.
 
271
      */
 
272
      if (*arg != new_item)
 
273
        current_thd->change_item_tree(arg, new_item);
 
274
    }
 
275
  }
 
276
  return (this->*transformer)(argument);
 
277
}
 
278
 
 
279
 
 
280
/**
 
281
   Compile Item_func object with a processor and a transformer
 
282
   callback functions.
 
283
 
 
284
   First the function applies the analyzer to the root node of
 
285
   the Item_func object. Then if the analizer succeeeds (returns true)
 
286
   the function recursively applies the compile method to each argument
 
287
   of the Item_func node.
 
288
   If the call of the method for an argument item returns a new item
 
289
   the old item is substituted for a new one.
 
290
   After this the transformer is applied to the root node
 
291
   of the Item_func object.
 
292
 
 
293
   @param analyzer      the analyzer callback function to be applied to the
 
294
   nodes of the tree of the object
 
295
   @param[in,out] arg_p parameter to be passed to the processor
 
296
   @param transformer   the transformer callback function to be applied to the
 
297
   nodes of the tree of the object
 
298
   @param arg_t         parameter to be passed to the transformer
 
299
 
 
300
   @return
 
301
   Item returned as the result of transformation of the root node
 
302
*/
 
303
 
 
304
Item *Item_func::compile(Item_analyzer analyzer, unsigned char **arg_p,
 
305
                         Item_transformer transformer, unsigned char *arg_t)
 
306
{
 
307
  if (!(this->*analyzer)(arg_p))
 
308
    return 0;
 
309
  if (arg_count)
 
310
  {
 
311
    Item **arg,**arg_end;
 
312
    for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
 
313
    {
 
314
      /*
 
315
        The same parameter value of arg_p must be passed
 
316
        to analyze any argument of the condition formula.
 
317
      */
 
318
      unsigned char *arg_v= *arg_p;
 
319
      Item *new_item= (*arg)->compile(analyzer, &arg_v, transformer, arg_t);
 
320
      if (new_item && *arg != new_item)
 
321
        current_thd->change_item_tree(arg, new_item);
 
322
    }
 
323
  }
 
324
  return (this->*transformer)(arg_t);
 
325
}
 
326
 
 
327
/**
 
328
   See comments in Item_cmp_func::split_sum_func()
 
329
*/
 
330
 
 
331
void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
 
332
                               List<Item> &fields)
 
333
{
 
334
  Item **arg, **arg_end;
 
335
  for (arg= args, arg_end= args+arg_count; arg != arg_end ; arg++)
 
336
    (*arg)->split_sum_func2(thd, ref_pointer_array, fields, arg, true);
 
337
}
 
338
 
 
339
 
 
340
void Item_func::update_used_tables()
 
341
{
 
342
  used_tables_cache=0;
 
343
  const_item_cache=1;
 
344
  for (uint32_t i=0 ; i < arg_count ; i++)
 
345
  {
 
346
    args[i]->update_used_tables();
 
347
    used_tables_cache|=args[i]->used_tables();
 
348
    const_item_cache&=args[i]->const_item();
 
349
  }
 
350
}
 
351
 
 
352
 
 
353
table_map Item_func::used_tables() const
 
354
{
 
355
  return used_tables_cache;
 
356
}
 
357
 
 
358
 
 
359
table_map Item_func::not_null_tables() const
 
360
{
 
361
  return not_null_tables_cache;
 
362
}
 
363
 
 
364
 
 
365
void Item_func::print(String *str, enum_query_type query_type)
 
366
{
 
367
  str->append(func_name());
 
368
  str->append('(');
 
369
  print_args(str, 0, query_type);
 
370
  str->append(')');
 
371
}
 
372
 
 
373
 
 
374
void Item_func::print_args(String *str, uint32_t from, enum_query_type query_type)
 
375
{
 
376
  for (uint32_t i=from ; i < arg_count ; i++)
 
377
  {
 
378
    if (i != from)
 
379
      str->append(',');
 
380
    args[i]->print(str, query_type);
 
381
  }
 
382
}
 
383
 
 
384
 
 
385
void Item_func::print_op(String *str, enum_query_type query_type)
 
386
{
 
387
  str->append('(');
 
388
  for (uint32_t i=0 ; i < arg_count-1 ; i++)
 
389
  {
 
390
    args[i]->print(str, query_type);
 
391
    str->append(' ');
 
392
    str->append(func_name());
 
393
    str->append(' ');
 
394
  }
 
395
  args[arg_count-1]->print(str, query_type);
 
396
  str->append(')');
 
397
}
 
398
 
 
399
 
 
400
bool Item_func::eq(const Item *item, bool binary_cmp) const
 
401
{
 
402
  /* Assume we don't have rtti */
 
403
  if (this == item)
 
404
    return 1;
 
405
  if (item->type() != FUNC_ITEM)
 
406
    return 0;
 
407
  Item_func *item_func=(Item_func*) item;
 
408
  Item_func::Functype func_type;
 
409
  if ((func_type= functype()) != item_func->functype() ||
 
410
      arg_count != item_func->arg_count ||
 
411
      (func_type != Item_func::FUNC_SP &&
 
412
       func_name() != item_func->func_name()) ||
 
413
      (func_type == Item_func::FUNC_SP &&
 
414
       my_strcasecmp(system_charset_info, func_name(), item_func->func_name())))
 
415
    return 0;
 
416
  for (uint32_t i=0; i < arg_count ; i++)
 
417
    if (!args[i]->eq(item_func->args[i], binary_cmp))
 
418
      return 0;
 
419
  return 1;
 
420
}
 
421
 
 
422
 
 
423
bool Item_func::get_arg0_date(DRIZZLE_TIME *ltime, uint32_t fuzzy_date)
 
424
{
 
425
  return (null_value=args[0]->get_date(ltime, fuzzy_date));
 
426
}
 
427
 
 
428
 
 
429
bool Item_func::get_arg0_time(DRIZZLE_TIME *ltime)
 
430
{
 
431
  return (null_value=args[0]->get_time(ltime));
 
432
}
 
433
 
 
434
 
 
435
bool Item_func::is_null()
 
436
{
 
437
  update_null_value();
 
438
  return null_value;
 
439
}
 
440
 
 
441
 
 
442
Field *Item_func::tmp_table_field(Table *table)
 
443
{
 
444
  Field *field;
 
445
 
 
446
  switch (result_type()) {
 
447
  case INT_RESULT:
 
448
    if (max_length > MY_INT32_NUM_DECIMAL_DIGITS)
 
449
      field= new Field_int64_t(max_length, maybe_null, name, unsigned_flag);
 
450
    else
 
451
      field= new Field_long(max_length, maybe_null, name, unsigned_flag);
 
452
    break;
 
453
  case REAL_RESULT:
 
454
    field= new Field_double(max_length, maybe_null, name, decimals);
 
455
    break;
 
456
  case STRING_RESULT:
 
457
    return make_string_field(table);
 
458
    break;
 
459
  case DECIMAL_RESULT:
 
460
    field= new Field_new_decimal(
 
461
                       my_decimal_precision_to_length(decimal_precision(),
 
462
                                                      decimals,
 
463
                                                      unsigned_flag),
 
464
                       maybe_null, name, decimals, unsigned_flag);
 
465
    break;
 
466
  case ROW_RESULT:
 
467
  default:
 
468
    // This case should never be chosen
 
469
    assert(0);
 
470
    field= 0;
 
471
    break;
 
472
  }
 
473
  if (field)
 
474
    field->init(table);
 
475
  return field;
 
476
}
 
477
 
 
478
 
 
479
my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
 
480
{
 
481
  assert(fixed);
 
482
  int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value);
 
483
  return decimal_value;
 
484
}
 
485
 
 
486
 
 
487
bool Item_func::agg_arg_collations(DTCollation &c, Item **items,
 
488
                                   uint32_t nitems, uint32_t flags)
 
489
{
 
490
  return agg_item_collations(c, func_name(), items, nitems, flags, 1);
 
491
}
 
492
 
 
493
 
 
494
bool Item_func::agg_arg_collations_for_comparison(DTCollation &c,
 
495
                                                  Item **items,
 
496
                                                  uint32_t nitems,
 
497
                                                  uint32_t flags)
 
498
{
 
499
  return agg_item_collations_for_comparison(c, func_name(),
 
500
                                            items, nitems, flags);
 
501
}
 
502
 
 
503
 
 
504
bool Item_func::agg_arg_charsets(DTCollation &c, Item **items, uint32_t nitems,
 
505
                                 uint32_t flags, int item_sep)
 
506
{
 
507
  return agg_item_charsets(c, func_name(), items, nitems, flags, item_sep);
 
508
}
 
509
 
 
510
 
 
511
double Item_func::fix_result(double value)
 
512
{
 
513
  if (CMATH_C99_NAMESPACE isfinite(value))
 
514
    return value;
 
515
  null_value=1;
 
516
  return 0.0;
 
517
}