~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/enum.cc

  • Committer: Brian Aker
  • Date: 2010-01-22 00:53:13 UTC
  • Revision ID: brian@gaz-20100122005313-jmizcbcdi1lt4tcx
Revert db patch.

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