~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/enum.cc

  • Committer: Jay Pipes
  • Date: 2009-02-28 17:49:22 UTC
  • mto: (910.2.6 mordred-noatomics)
  • mto: This revision was merged to the branch mainline in revision 908.
  • Revision ID: jpipes@serialcoder-20090228174922-jczgt4d0662fqmnf
Merging in old r902 temporal changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
19
 */
20
20
 
21
 
#include "config.h"
22
 
#include <boost/lexical_cast.hpp>
23
 
#include "drizzled/field/enum.h"
24
 
#include "drizzled/error.h"
25
 
#include "drizzled/table.h"
26
 
#include "drizzled/session.h"
27
 
#include "drizzled/strfunc.h"
28
 
 
29
 
#include <sstream>
30
 
#include <string>
31
 
 
32
 
namespace drizzled
33
 
{
 
21
 
 
22
#include <drizzled/server_includes.h>
 
23
#include <drizzled/field/enum.h>
 
24
#include <drizzled/error.h>
 
25
#include <drizzled/table.h>
 
26
#include <drizzled/session.h>
34
27
 
35
28
/****************************************************************************
36
29
** enum type.
38
31
** If one uses this string in a number context one gets the type number.
39
32
****************************************************************************/
40
33
 
 
34
enum ha_base_keytype Field_enum::key_type() const
 
35
{
 
36
  switch (packlength) {
 
37
  default: return HA_KEYTYPE_BINARY;
 
38
  case 2: assert(1);
 
39
  case 3: assert(1);
 
40
  case 4: return HA_KEYTYPE_ULONG_INT;
 
41
  case 8: return HA_KEYTYPE_ULONGLONG;
 
42
  }
 
43
}
 
44
 
41
45
void Field_enum::store_type(uint64_t value)
42
46
{
43
 
  value--; /* we store as starting from 0, although SQL starts from 1 */
44
 
 
45
 
#ifdef WORDS_BIGENDIAN
46
 
  if (getTable()->getShare()->db_low_byte_first)
47
 
  {
48
 
    int4store(ptr, (unsigned short) value);
49
 
  }
50
 
  else
51
 
#endif
52
 
    longstore(ptr, (unsigned short) value);
 
47
  switch (packlength) {
 
48
  case 1: ptr[0]= (unsigned char) value;  break;
 
49
  case 2:
 
50
#ifdef WORDS_BIGENDIAN
 
51
  if (table->s->db_low_byte_first)
 
52
  {
 
53
    int2store(ptr,(unsigned short) value);
 
54
  }
 
55
  else
 
56
#endif
 
57
    shortstore(ptr,(unsigned short) value);
 
58
  break;
 
59
  case 3: int3store(ptr,(long) value); break;
 
60
  case 4:
 
61
#ifdef WORDS_BIGENDIAN
 
62
  if (table->s->db_low_byte_first)
 
63
  {
 
64
    int4store(ptr,value);
 
65
  }
 
66
  else
 
67
#endif
 
68
    longstore(ptr,(long) value);
 
69
  break;
 
70
  case 8:
 
71
#ifdef WORDS_BIGENDIAN
 
72
  if (table->s->db_low_byte_first)
 
73
  {
 
74
    int8store(ptr,value);
 
75
  }
 
76
  else
 
77
#endif
 
78
    int64_tstore(ptr,value); break;
 
79
  }
53
80
}
54
81
 
 
82
 
55
83
/**
56
 
 * Given a supplied string, looks up the string in the internal typelib
57
 
 * and stores the found key.  Upon not finding an entry in the typelib,
58
 
 * we always throw an error.
59
 
 */
60
 
int Field_enum::store(const char *from, uint32_t length, const CHARSET_INFO * const)
 
84
  @note
 
85
    Storing a empty string in a enum field gives a warning
 
86
    (if there isn't a empty value in the enum)
 
87
*/
 
88
 
 
89
int Field_enum::store(const char *from, uint32_t length, const CHARSET_INFO * const cs)
61
90
{
62
 
  uint32_t tmp;
 
91
  int err= 0;
 
92
  uint32_t not_used;
 
93
  char buff[STRING_BUFFER_USUAL_SIZE];
 
94
  String tmpstr(buff,sizeof(buff), &my_charset_bin);
63
95
 
64
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
 
96
  /* Convert character set if necessary */
 
97
  if (String::needs_conversion(length, cs, field_charset, &not_used))
 
98
  {
 
99
    uint32_t dummy_errors;
 
100
    tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
 
101
    from= tmpstr.ptr();
 
102
    length=  tmpstr.length();
 
103
  }
65
104
 
66
105
  /* Remove end space */
67
106
  length= field_charset->cset->lengthsp(field_charset, from, length);
68
 
  tmp= find_type2(typelib, from, length, field_charset);
69
 
  if (! tmp)
 
107
  uint32_t tmp=find_type2(typelib, from, length, field_charset);
 
108
  if (!tmp)
70
109
  {
71
 
    if (length < 6) /* Can't be more than 99999 enums */
 
110
    if (length < 6) // Can't be more than 99999 enums
72
111
    {
73
112
      /* This is for reading numbers with LOAD DATA INFILE */
74
 
      /* Convert the string to an integer using stringstream */
75
 
      std::stringstream ss;
76
 
      ss << from;
77
 
      ss >> tmp;
78
 
 
79
 
      if (tmp == 0 || tmp > typelib->count)
 
113
      char *end;
 
114
      tmp=(uint32_t) my_strntoul(cs,from,length,10,&end,&err);
 
115
      if (err || end != from+length || tmp > typelib->count)
80
116
      {
81
 
        my_error(ER_INVALID_ENUM_VALUE, MYF(ME_FATALERROR), from);
82
 
        return 1;
 
117
        tmp=0;
 
118
        set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
83
119
      }
 
120
      if (!table->in_use->count_cuted_fields)
 
121
        err= 0;
84
122
    }
85
123
    else
86
 
    {
87
 
      my_error(ER_INVALID_ENUM_VALUE, MYF(ME_FATALERROR), from);
88
 
      return 1;
89
 
    }
 
124
      set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
90
125
  }
91
126
  store_type((uint64_t) tmp);
92
 
  return 0;
93
 
}
94
 
 
95
 
int Field_enum::store(double from)
96
 
{
97
 
  return Field_enum::store((int64_t) from, false);
98
 
}
99
 
 
100
 
/**
101
 
 * @note MySQL allows 0 values, saying that 0 is "the index of the
102
 
 * blank string error", whatever that means.  Uhm, Drizzle doesn't
103
 
 * allow this.  To store an ENUM column value using an integer, you
104
 
 * must specify the 1-based index of the enum column definition's
105
 
 * key.
106
 
 */
107
 
int Field_enum::store(int64_t from, bool)
108
 
{
109
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
110
 
 
111
 
  if (from <= 0 || (uint64_t) from > typelib->count)
 
127
  return err;
 
128
}
 
129
 
 
130
 
 
131
int Field_enum::store(double nr)
 
132
{
 
133
  return Field_enum::store((int64_t) nr, false);
 
134
}
 
135
 
 
136
 
 
137
int Field_enum::store(int64_t nr,
 
138
                      bool )
 
139
{
 
140
  int error= 0;
 
141
  if ((uint64_t) nr > typelib->count || nr == 0)
112
142
  {
113
 
    /* Convert the integer to a string using boost::lexical_cast */
114
 
    std::string tmp(boost::lexical_cast<std::string>(from));
115
 
 
116
 
    my_error(ER_INVALID_ENUM_VALUE, MYF(ME_FATALERROR), tmp.c_str());
117
 
    return 1;
 
143
    set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
 
144
    if (nr != 0 || table->in_use->count_cuted_fields)
 
145
    {
 
146
      nr= 0;
 
147
      error= 1;
 
148
    }
118
149
  }
119
 
  store_type((uint64_t) (uint32_t) from);
120
 
  return 0;
 
150
  store_type((uint64_t) (uint32_t) nr);
 
151
  return error;
121
152
}
122
153
 
 
154
 
123
155
double Field_enum::val_real(void)
124
156
{
125
157
  return (double) Field_enum::val_int();
126
158
}
127
159
 
 
160
 
128
161
int64_t Field_enum::val_int(void)
129
162
{
130
 
  ASSERT_COLUMN_MARKED_FOR_READ;
131
 
 
132
 
  uint16_t tmp;
133
 
#ifdef WORDS_BIGENDIAN
134
 
  if (getTable()->getShare()->db_low_byte_first)
135
 
    tmp= sint4korr(ptr);
136
 
  else
137
 
#endif
138
 
    longget(tmp,ptr);
139
 
  return ((int64_t) tmp) + 1; /* SQL is from 1, we store from 0 */
140
 
}
141
 
 
142
 
String *Field_enum::val_str(String *, String *val_ptr)
 
163
  switch (packlength) {
 
164
  case 1:
 
165
    return (int64_t) ptr[0];
 
166
  case 2:
 
167
  {
 
168
    uint16_t tmp;
 
169
#ifdef WORDS_BIGENDIAN
 
170
    if (table->s->db_low_byte_first)
 
171
      tmp=sint2korr(ptr);
 
172
    else
 
173
#endif
 
174
      shortget(tmp,ptr);
 
175
    return (int64_t) tmp;
 
176
  }
 
177
  case 3:
 
178
    return (int64_t) uint3korr(ptr);
 
179
  case 4:
 
180
  {
 
181
    uint32_t tmp;
 
182
#ifdef WORDS_BIGENDIAN
 
183
    if (table->s->db_low_byte_first)
 
184
      tmp=uint4korr(ptr);
 
185
    else
 
186
#endif
 
187
      longget(tmp,ptr);
 
188
    return (int64_t) tmp;
 
189
  }
 
190
  case 8:
 
191
  {
 
192
    int64_t tmp;
 
193
#ifdef WORDS_BIGENDIAN
 
194
    if (table->s->db_low_byte_first)
 
195
      tmp=sint8korr(ptr);
 
196
    else
 
197
#endif
 
198
      int64_tget(tmp,ptr);
 
199
    return tmp;
 
200
  }
 
201
  }
 
202
  return 0;                                     // impossible
 
203
}
 
204
 
 
205
 
 
206
/**
 
207
   Save the field metadata for enum fields.
 
208
 
 
209
   Saves the real type in the first byte and the pack length in the
 
210
   second byte of the field metadata array at index of *metadata_ptr and
 
211
   *(metadata_ptr + 1).
 
212
 
 
213
   @param   metadata_ptr   First byte of field metadata
 
214
 
 
215
   @returns number of bytes written to metadata_ptr
 
216
*/
 
217
int Field_enum::do_save_field_metadata(unsigned char *metadata_ptr)
 
218
{
 
219
  *metadata_ptr= real_type();
 
220
  *(metadata_ptr + 1)= pack_length();
 
221
  return 2;
 
222
}
 
223
 
 
224
 
 
225
String *Field_enum::val_str(String *,
 
226
                            String *val_ptr)
143
227
{
144
228
  uint32_t tmp=(uint32_t) Field_enum::val_int();
145
 
 
146
 
  ASSERT_COLUMN_MARKED_FOR_READ;
147
 
 
148
 
  if (not tmp || tmp > typelib->count)
149
 
  {
 
229
  if (!tmp || tmp > typelib->count)
150
230
    val_ptr->set("", 0, field_charset);
151
 
  }
152
231
  else
153
 
  {
154
 
    val_ptr->set((const char*) typelib->type_names[tmp-1], typelib->type_lengths[tmp-1], field_charset);
155
 
  }
156
 
 
 
232
    val_ptr->set((const char*) typelib->type_names[tmp-1],
 
233
                 typelib->type_lengths[tmp-1],
 
234
                 field_charset);
157
235
  return val_ptr;
158
236
}
159
237
 
161
239
{
162
240
  unsigned char *old= ptr;
163
241
  ptr= (unsigned char*) a_ptr;
164
 
  uint64_t a= Field_enum::val_int();
 
242
  uint64_t a=Field_enum::val_int();
165
243
  ptr= (unsigned char*) b_ptr;
166
 
  uint64_t b= Field_enum::val_int();
 
244
  uint64_t b=Field_enum::val_int();
167
245
  ptr= old;
168
246
  return (a < b) ? -1 : (a > b) ? 1 : 0;
169
247
}
170
248
 
171
249
void Field_enum::sort_string(unsigned char *to,uint32_t )
172
250
{
173
 
  uint64_t value=Field_enum::val_int()-1; /* SQL is 1 based, stored as 0 based*/
174
 
  to+=pack_length() -1;
175
 
  for (uint32_t i=0 ; i < pack_length() ; i++)
 
251
  uint64_t value=Field_enum::val_int();
 
252
  to+=packlength-1;
 
253
  for (uint32_t i=0 ; i < packlength ; i++)
176
254
  {
177
255
    *to-- = (unsigned char) (value & 255);
178
256
    value>>=8;
179
257
  }
180
258
}
181
259
 
 
260
 
182
261
void Field_enum::sql_type(String &res) const
183
262
{
184
263
  char buffer[255];
191
270
  uint32_t *len= typelib->type_lengths;
192
271
  for (const char **pos= typelib->type_names; *pos; pos++, len++)
193
272
  {
194
 
    size_t dummy_errors;
 
273
    uint32_t dummy_errors;
195
274
    if (flag)
196
275
      res.append(',');
197
276
    /* convert to res.charset() == utf8, then quote */
202
281
  res.append(')');
203
282
}
204
283
 
205
 
Field *Field_enum::new_field(memory::Root *root, Table *new_table,
 
284
 
 
285
Field *Field_enum::new_field(MEM_ROOT *root, Table *new_table,
206
286
                             bool keep_type)
207
287
{
208
288
  Field_enum *res= (Field_enum*) Field::new_field(root, new_table, keep_type);
209
289
  if (res)
210
 
  {
211
 
    res->typelib= typelib->copy_typelib(root);
212
 
  }
 
290
    res->typelib= copy_typelib(root, typelib);
213
291
  return res;
214
292
}
215
 
 
216
 
} /* namespace drizzled */