~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/enum.cc

  • Committer: Brian Aker
  • Date: 2008-11-04 15:39:09 UTC
  • mfrom: (575.1.2 devel)
  • Revision ID: brian@tangent.org-20081104153909-c72hn65udxs1ccal
Merge of Monty's work

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
 
 
26
/****************************************************************************
 
27
** enum type.
 
28
** This is a string which only can have a selection of different values.
 
29
** If one uses this string in a number context one gets the type number.
 
30
****************************************************************************/
 
31
 
 
32
enum ha_base_keytype Field_enum::key_type() const
 
33
{
 
34
  switch (packlength) {
 
35
  default: return HA_KEYTYPE_BINARY;
 
36
  case 2: assert(1);
 
37
  case 3: assert(1);
 
38
  case 4: return HA_KEYTYPE_ULONG_INT;
 
39
  case 8: return HA_KEYTYPE_ULONGLONG;
 
40
  }
 
41
}
 
42
 
 
43
void Field_enum::store_type(uint64_t value)
 
44
{
 
45
  switch (packlength) {
 
46
  case 1: ptr[0]= (unsigned char) value;  break;
 
47
  case 2:
 
48
#ifdef WORDS_BIGENDIAN
 
49
  if (table->s->db_low_byte_first)
 
50
  {
 
51
    int2store(ptr,(unsigned short) value);
 
52
  }
 
53
  else
 
54
#endif
 
55
    shortstore(ptr,(unsigned short) value);
 
56
  break;
 
57
  case 3: int3store(ptr,(long) value); break;
 
58
  case 4:
 
59
#ifdef WORDS_BIGENDIAN
 
60
  if (table->s->db_low_byte_first)
 
61
  {
 
62
    int4store(ptr,value);
 
63
  }
 
64
  else
 
65
#endif
 
66
    longstore(ptr,(long) value);
 
67
  break;
 
68
  case 8:
 
69
#ifdef WORDS_BIGENDIAN
 
70
  if (table->s->db_low_byte_first)
 
71
  {
 
72
    int8store(ptr,value);
 
73
  }
 
74
  else
 
75
#endif
 
76
    int64_tstore(ptr,value); break;
 
77
  }
 
78
}
 
79
 
 
80
 
 
81
/**
 
82
  @note
 
83
    Storing a empty string in a enum field gives a warning
 
84
    (if there isn't a empty value in the enum)
 
85
*/
 
86
 
 
87
int Field_enum::store(const char *from, uint32_t length, const CHARSET_INFO * const cs)
 
88
{
 
89
  int err= 0;
 
90
  uint32_t not_used;
 
91
  char buff[STRING_BUFFER_USUAL_SIZE];
 
92
  String tmpstr(buff,sizeof(buff), &my_charset_bin);
 
93
 
 
94
  /* Convert character set if necessary */
 
95
  if (String::needs_conversion(length, cs, field_charset, &not_used))
 
96
  { 
 
97
    uint32_t dummy_errors;
 
98
    tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
 
99
    from= tmpstr.ptr();
 
100
    length=  tmpstr.length();
 
101
  }
 
102
 
 
103
  /* Remove end space */
 
104
  length= field_charset->cset->lengthsp(field_charset, from, length);
 
105
  uint32_t tmp=find_type2(typelib, from, length, field_charset);
 
106
  if (!tmp)
 
107
  {
 
108
    if (length < 6) // Can't be more than 99999 enums
 
109
    {
 
110
      /* This is for reading numbers with LOAD DATA INFILE */
 
111
      char *end;
 
112
      tmp=(uint) my_strntoul(cs,from,length,10,&end,&err);
 
113
      if (err || end != from+length || tmp > typelib->count)
 
114
      {
 
115
        tmp=0;
 
116
        set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
 
117
      }
 
118
      if (!table->in_use->count_cuted_fields)
 
119
        err= 0;
 
120
    }
 
121
    else
 
122
      set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
 
123
  }
 
124
  store_type((uint64_t) tmp);
 
125
  return err;
 
126
}
 
127
 
 
128
 
 
129
int Field_enum::store(double nr)
 
130
{
 
131
  return Field_enum::store((int64_t) nr, false);
 
132
}
 
133
 
 
134
 
 
135
int Field_enum::store(int64_t nr,
 
136
                      bool unsigned_val __attribute__((unused)))
 
137
{
 
138
  int error= 0;
 
139
  if ((uint64_t) nr > typelib->count || nr == 0)
 
140
  {
 
141
    set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
 
142
    if (nr != 0 || table->in_use->count_cuted_fields)
 
143
    {
 
144
      nr= 0;
 
145
      error= 1;
 
146
    }
 
147
  }
 
148
  store_type((uint64_t) (uint) nr);
 
149
  return error;
 
150
}
 
151
 
 
152
 
 
153
double Field_enum::val_real(void)
 
154
{
 
155
  return (double) Field_enum::val_int();
 
156
}
 
157
 
 
158
 
 
159
int64_t Field_enum::val_int(void)
 
160
{
 
161
  switch (packlength) {
 
162
  case 1:
 
163
    return (int64_t) ptr[0];
 
164
  case 2:
 
165
  {
 
166
    uint16_t tmp;
 
167
#ifdef WORDS_BIGENDIAN
 
168
    if (table->s->db_low_byte_first)
 
169
      tmp=sint2korr(ptr);
 
170
    else
 
171
#endif
 
172
      shortget(tmp,ptr);
 
173
    return (int64_t) tmp;
 
174
  }
 
175
  case 3:
 
176
    return (int64_t) uint3korr(ptr);
 
177
  case 4:
 
178
  {
 
179
    uint32_t tmp;
 
180
#ifdef WORDS_BIGENDIAN
 
181
    if (table->s->db_low_byte_first)
 
182
      tmp=uint4korr(ptr);
 
183
    else
 
184
#endif
 
185
      longget(tmp,ptr);
 
186
    return (int64_t) tmp;
 
187
  }
 
188
  case 8:
 
189
  {
 
190
    int64_t tmp;
 
191
#ifdef WORDS_BIGENDIAN
 
192
    if (table->s->db_low_byte_first)
 
193
      tmp=sint8korr(ptr);
 
194
    else
 
195
#endif
 
196
      int64_tget(tmp,ptr);
 
197
    return tmp;
 
198
  }
 
199
  }
 
200
  return 0;                                     // impossible
 
201
}
 
202
 
 
203
 
 
204
/**
 
205
   Save the field metadata for enum fields.
 
206
 
 
207
   Saves the real type in the first byte and the pack length in the 
 
208
   second byte of the field metadata array at index of *metadata_ptr and
 
209
   *(metadata_ptr + 1).
 
210
 
 
211
   @param   metadata_ptr   First byte of field metadata
 
212
 
 
213
   @returns number of bytes written to metadata_ptr
 
214
*/
 
215
int Field_enum::do_save_field_metadata(unsigned char *metadata_ptr)
 
216
{
 
217
  *metadata_ptr= real_type();
 
218
  *(metadata_ptr + 1)= pack_length();
 
219
  return 2;
 
220
}
 
221
 
 
222
 
 
223
String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
 
224
                            String *val_ptr)
 
225
{
 
226
  uint32_t tmp=(uint) Field_enum::val_int();
 
227
  if (!tmp || tmp > typelib->count)
 
228
    val_ptr->set("", 0, field_charset);
 
229
  else
 
230
    val_ptr->set((const char*) typelib->type_names[tmp-1],
 
231
                 typelib->type_lengths[tmp-1],
 
232
                 field_charset);
 
233
  return val_ptr;
 
234
}
 
235
 
 
236
int Field_enum::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
 
237
{
 
238
  unsigned char *old= ptr;
 
239
  ptr= (unsigned char*) a_ptr;
 
240
  uint64_t a=Field_enum::val_int();
 
241
  ptr= (unsigned char*) b_ptr;
 
242
  uint64_t b=Field_enum::val_int();
 
243
  ptr= old;
 
244
  return (a < b) ? -1 : (a > b) ? 1 : 0;
 
245
}
 
246
 
 
247
void Field_enum::sort_string(unsigned char *to,uint32_t length __attribute__((unused)))
 
248
{
 
249
  uint64_t value=Field_enum::val_int();
 
250
  to+=packlength-1;
 
251
  for (uint32_t i=0 ; i < packlength ; i++)
 
252
  {
 
253
    *to-- = (unsigned char) (value & 255);
 
254
    value>>=8;
 
255
  }
 
256
}
 
257
 
 
258
 
 
259
void Field_enum::sql_type(String &res) const
 
260
{
 
261
  char buffer[255];
 
262
  String enum_item(buffer, sizeof(buffer), res.charset());
 
263
 
 
264
  res.length(0);
 
265
  res.append(STRING_WITH_LEN("enum("));
 
266
 
 
267
  bool flag=0;
 
268
  uint32_t *len= typelib->type_lengths;
 
269
  for (const char **pos= typelib->type_names; *pos; pos++, len++)
 
270
  {
 
271
    uint32_t dummy_errors;
 
272
    if (flag)
 
273
      res.append(',');
 
274
    /* convert to res.charset() == utf8, then quote */
 
275
    enum_item.copy(*pos, *len, charset(), res.charset(), &dummy_errors);
 
276
    append_unescaped(&res, enum_item.ptr(), enum_item.length());
 
277
    flag= 1;
 
278
  }
 
279
  res.append(')');
 
280
}
 
281
 
 
282
 
 
283
Field *Field_enum::new_field(MEM_ROOT *root, Table *new_table,
 
284
                             bool keep_type)
 
285
{
 
286
  Field_enum *res= (Field_enum*) Field::new_field(root, new_table, keep_type);
 
287
  if (res)
 
288
    res->typelib= copy_typelib(root, typelib);
 
289
  return res;
 
290
}