~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/functions/func.cc

  • Committer: Brian Aker
  • Date: 2008-11-04 15:39:09 UTC
  • mfrom: (575.1.2 devel)
  • Revision ID: brian@tangent.org-20081104153909-c72hn65udxs1ccal
Merge of Monty's work

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