~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/functions/func.cc

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

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