~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/enum.cc

  • Committer: Brian Aker
  • Date: 2009-07-11 08:51:36 UTC
  • mfrom: (1089.3.11 merge)
  • Revision ID: brian@gaz-20090711085136-qj01nwm3qynghwtc
Merge Monty

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