~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/functions/func.cc

  • Committer: Monty Taylor
  • Date: 2008-08-04 19:37:18 UTC
  • mto: (261.2.2 codestyle)
  • mto: This revision was merged to the branch mainline in revision 262.
  • Revision ID: monty@inaugust.com-20080804193718-f0rz13uli4429ozb
Changed gettext_noop() to N_()

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