~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/functions/func.cc

  • Committer: Brian Aker
  • Date: 2008-09-04 19:31:00 UTC
  • Revision ID: brian@tangent.org-20080904193100-l849hgghfy4urj43
Changing default character set from this point on.

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
 
}