Drizzled Public API Documentation

type_holder.cc
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, Inc.
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 <config.h>
21 
22 #include <float.h>
23 
24 #include <algorithm>
25 
26 #include <drizzled/error.h>
27 #include <drizzled/function/func.h>
28 #include <drizzled/item/sum.h>
29 #include <drizzled/item/type_holder.h>
30 #include <drizzled/field/enum.h>
31 
32 using namespace std;
33 
34 namespace drizzled {
35 
36 Item_type_holder::Item_type_holder(Session *session, Item *item)
37  :Item(session, item), enum_set_typelib(0), fld_type(get_real_type(item))
38 {
39  assert(item->fixed);
40  maybe_null= item->maybe_null;
41  collation.set(item->collation);
42  get_full_info(item);
43  /* fix variable decimals which always is NOT_FIXED_DEC */
44  if (Field::result_merge_type(fld_type) == INT_RESULT)
45  decimals= 0;
46  prev_decimal_int_part= item->decimal_int_part();
47 }
48 
49 
50 Item_result Item_type_holder::result_type() const
51 {
52  return Field::result_merge_type(fld_type);
53 }
54 
55 
56 enum_field_types Item_type_holder::get_real_type(Item *item)
57 {
58  switch(item->type())
59  {
60  case FIELD_ITEM:
61  {
62  /*
63  Item_fields::field_type ask Field_type() but sometimes field return
64  a different type, like for enum/set, so we need to ask real type.
65  */
66  Field *field= ((Item_field *) item)->field;
67  enum_field_types type= field->real_type();
68  if (field->is_created_from_null_item)
69  return DRIZZLE_TYPE_NULL;
70  return type;
71  }
72  case SUM_FUNC_ITEM:
73  {
74  /*
75  Argument of aggregate function sometimes should be asked about field
76  type
77  */
78  Item_sum *item_sum= (Item_sum *) item;
79  if (item_sum->keep_field_type())
80  return get_real_type(item_sum->args[0]);
81  break;
82  }
83  case FUNC_ITEM:
84  if (((Item_func *) item)->functype() == Item_func::GUSERVAR_FUNC)
85  {
86  /*
87  There are work around of problem with changing variable type on the
88  fly and variable always report "string" as field type to get
89  acceptable information for client in send_field, so we make field
90  type from expression type.
91  */
92  switch (item->result_type()) {
93  case STRING_RESULT:
94  return DRIZZLE_TYPE_VARCHAR;
95  case INT_RESULT:
96  return DRIZZLE_TYPE_LONGLONG;
97  case REAL_RESULT:
98  return DRIZZLE_TYPE_DOUBLE;
99  case DECIMAL_RESULT:
100  return DRIZZLE_TYPE_DECIMAL;
101  case ROW_RESULT:
102  assert(0);
103  return DRIZZLE_TYPE_VARCHAR;
104  }
105  }
106  break;
107  default:
108  break;
109  }
110  return item->field_type();
111 }
112 
113 
115 {
116  uint32_t max_length_orig= max_length;
117  uint32_t decimals_orig= decimals;
118  fld_type= Field::field_type_merge(fld_type, get_real_type(item));
119  {
120  int item_decimals= item->decimals;
121  /* fix variable decimals which always is NOT_FIXED_DEC */
122  if (Field::result_merge_type(fld_type) == INT_RESULT)
123  item_decimals= 0;
124  decimals= max((int)decimals, item_decimals);
125  }
126  if (Field::result_merge_type(fld_type) == DECIMAL_RESULT)
127  {
128  decimals= min((int)max(decimals, item->decimals), DECIMAL_MAX_SCALE);
129  int precision= min(max(prev_decimal_int_part, item->decimal_int_part())
130  + decimals, DECIMAL_MAX_PRECISION);
131  unsigned_flag&= item->unsigned_flag;
132  max_length= class_decimal_precision_to_length(precision, decimals,
133  unsigned_flag);
134  }
135 
136  switch (Field::result_merge_type(fld_type))
137  {
138  case STRING_RESULT:
139  {
140  const char *old_cs, *old_derivation;
141  uint32_t old_max_chars= max_length / collation.collation->mbmaxlen;
142  old_cs= collation.collation->name;
143  old_derivation= collation.derivation_name();
144  if (collation.aggregate(item->collation, MY_COLL_ALLOW_CONV))
145  {
146  my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
147  old_cs, old_derivation,
148  item->collation.collation->name,
149  item->collation.derivation_name(),
150  "UNION");
151  return true;
152  }
153  /*
154  To figure out max_length, we have to take into account possible
155  expansion of the size of the values because of character set
156  conversions.
157  */
158  if (collation.collation != &my_charset_bin)
159  {
160  max_length= max(old_max_chars * collation.collation->mbmaxlen,
161  display_length(item) /
162  item->collation.collation->mbmaxlen *
163  collation.collation->mbmaxlen);
164  }
165  else
166  set_if_bigger(max_length, display_length(item));
167  break;
168  }
169  case REAL_RESULT:
170  {
171  if (decimals != NOT_FIXED_DEC)
172  {
173  int delta1= max_length_orig - decimals_orig;
174  int delta2= item->max_length - item->decimals;
175  max_length= max(delta1, delta2) + decimals;
176  if (fld_type == DRIZZLE_TYPE_DOUBLE && max_length > DBL_DIG + 2)
177  {
178  max_length= DBL_DIG + 7;
179  decimals= NOT_FIXED_DEC;
180  }
181  }
182  else
183  max_length= DBL_DIG+7;
184  break;
185  }
186 
187  case INT_RESULT:
188  case DECIMAL_RESULT:
189  case ROW_RESULT:
190  max_length= max(max_length, display_length(item));
191  };
192  maybe_null|= item->maybe_null;
193  get_full_info(item);
194 
195  /* Remember decimal integer part to be used in DECIMAL_RESULT handleng */
196  prev_decimal_int_part= decimal_int_part();
197 
198  return false;
199 }
200 
201 
203 {
204  if (item->type() == Item::FIELD_ITEM)
205  return ((Item_field *)item)->max_disp_length();
206 
207  switch (item->field_type())
208  {
209  case DRIZZLE_TYPE_TIME:
210  case DRIZZLE_TYPE_BOOLEAN:
211  case DRIZZLE_TYPE_UUID:
212  case DRIZZLE_TYPE_IPV6:
213  case DRIZZLE_TYPE_MICROTIME:
214  case DRIZZLE_TYPE_TIMESTAMP:
215  case DRIZZLE_TYPE_DATETIME:
216  case DRIZZLE_TYPE_DATE:
217  case DRIZZLE_TYPE_VARCHAR:
218  case DRIZZLE_TYPE_DECIMAL:
219  case DRIZZLE_TYPE_ENUM:
220  case DRIZZLE_TYPE_BLOB:
221  return item->max_length;
222  case DRIZZLE_TYPE_LONG:
223  return MY_INT32_NUM_DECIMAL_DIGITS;
224  case DRIZZLE_TYPE_DOUBLE:
225  return 53;
226  case DRIZZLE_TYPE_NULL:
227  return 0;
228  case DRIZZLE_TYPE_LONGLONG:
229  return 20;
230  }
231  assert(0);
232  abort();
233 }
234 
235 
237 {
238  /*
239  The field functions defines a field to be not null if null_ptr is not 0
240  */
241  unsigned char *null_ptr= maybe_null ? (unsigned char*) "" : 0;
242  Field *field;
243 
244  switch (fld_type) {
245  case DRIZZLE_TYPE_ENUM:
246  assert(enum_set_typelib);
247  field= new Field_enum((unsigned char *) 0,
248  max_length,
249  null_ptr,
250  0,
251  name,
252  enum_set_typelib,
253  collation.collation);
254  if (field)
255  field->init(table);
256  return field;
257  case DRIZZLE_TYPE_NULL:
258  return make_string_field(table);
259  default:
260  break;
261  }
262  return tmp_table_field_from_field_type(table, 0);
263 }
264 
265 
267 {
268  if (fld_type == DRIZZLE_TYPE_ENUM)
269  {
270  if (item->type() == Item::SUM_FUNC_ITEM &&
271  (((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC ||
272  ((Item_sum*)item)->sum_func() == Item_sum::MIN_FUNC))
273  item = ((Item_sum*)item)->args[0];
274  /*
275  We can have enum/set type after merging only if we have one enum|set
276  field (or MIN|MAX(enum|set field)) and number of NULL fields
277  */
278  assert((enum_set_typelib &&
279  get_real_type(item) == DRIZZLE_TYPE_NULL) ||
280  (!enum_set_typelib &&
281  item->type() == Item::FIELD_ITEM &&
282  (get_real_type(item) == DRIZZLE_TYPE_ENUM) &&
283  ((Field_enum*)((Item_field *) item)->field)->typelib));
284  if (!enum_set_typelib)
285  {
286  enum_set_typelib= ((Field_enum*)((Item_field *) item)->field)->typelib;
287  }
288  }
289 }
290 
291 
293 {
294  assert(0); // should never be called
295  return 0.0;
296 }
297 
298 
300 {
301  assert(0); // should never be called
302  return 0;
303 }
304 
306 {
307  assert(0); // should never be called
308  return 0;
309 }
310 
312 {
313  assert(0); // should never be called
314  return 0;
315 }
316 
317 void Item_result_field::cleanup()
318 {
319  Item::cleanup();
320  result_field= 0;
321  return;
322 }
323 
324 } /* namespace drizzled */