Drizzled Public API Documentation

format.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 #include "format.h"
22 
23 #include <limits>
24 
25 #include <drizzled/charset.h>
26 #include <drizzled/type/decimal.h>
27 #include <drizzled/table.h>
28 
29 using namespace std;
30 
31 namespace drizzled
32 {
33 
40 const int FORMAT_MAX_DECIMALS= 30;
41 
42 void Item_func_format::fix_length_and_dec()
43 {
44  collation.set(default_charset());
45  uint32_t char_length= args[0]->max_length/args[0]->collation.collation->mbmaxlen;
46  max_length= ((char_length + (char_length-args[0]->decimals)/3) *
47  collation.collation->mbmaxlen);
48 }
49 
50 
57 String *Item_func_format::val_str(String *str)
58 {
59  uint32_t length;
60  uint32_t str_length;
61  /* Number of decimal digits */
62  int dec;
63  /* Number of characters used to represent the decimals, including '.' */
64  uint32_t dec_length;
65  int diff;
66  assert(fixed == 1);
67 
68  dec= (int) args[1]->val_int();
69  if (args[1]->null_value)
70  {
71  null_value=1;
72  return NULL;
73  }
74 
75  dec= set_zone(dec, 0, FORMAT_MAX_DECIMALS);
76  dec_length= dec ? dec+1 : 0;
77  null_value=0;
78 
79  if (args[0]->result_type() == DECIMAL_RESULT ||
80  args[0]->result_type() == INT_RESULT)
81  {
82  type::Decimal dec_val, rnd_dec, *res;
83  res= args[0]->val_decimal(&dec_val);
84  if ((null_value=args[0]->null_value))
85  return 0;
86  class_decimal_round(E_DEC_FATAL_ERROR, res, dec, false, &rnd_dec);
87  class_decimal2string(&rnd_dec, 0, str);
88  str_length= str->length();
89  if (rnd_dec.sign())
90  str_length--;
91  }
92  else
93  {
94  double nr= args[0]->val_real();
95  if ((null_value=args[0]->null_value))
96  return 0;
97  nr= my_double_round(nr, (int64_t) dec, false, false);
98  /* Here default_charset() is right as this is not an automatic conversion */
99  str->set_real(nr, dec, default_charset());
100  if (nr == numeric_limits<double>::quiet_NaN())
101  return str;
102  str_length=str->length();
103  if (nr < 0)
104  str_length--; // Don't count sign
105  }
106  /* We need this test to handle 'nan' values */
107  if (str_length >= dec_length+4)
108  {
109  char *tmp,*pos;
110  length= str->length()+(diff=((int)(str_length- dec_length-1))/3);
111  str= copy_if_not_alloced(&tmp_str,str,length);
112  str->length(length);
113  tmp= (char*) str->ptr()+length - dec_length-1;
114  for (pos= (char*) str->ptr()+length-1; pos != tmp; pos--)
115  pos[0]= pos[-diff];
116  while (diff)
117  {
118  *pos= *(pos - diff);
119  pos--;
120  *pos= *(pos - diff);
121  pos--;
122  *pos= *(pos - diff);
123  pos--;
124  pos[0]=',';
125  pos--;
126  diff--;
127  }
128  }
129  return str;
130 }
131 
132 
133 void Item_func_format::print(String *str)
134 {
135  str->append(STRING_WITH_LEN("format("));
136  args[0]->print(str);
137  str->append(',');
138  args[1]->print(str);
139  str->append(')');
140 }
141 
142 } /* namespace drizzled */