~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/enum.cc

Merged Nathan from lp:~nlws/drizzle/fix-string-c-ptr-overrun

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 */
20
20
 
21
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>
 
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>
27
30
 
28
31
/****************************************************************************
29
32
** enum type.
33
36
 
34
37
enum ha_base_keytype Field_enum::key_type() const
35
38
{
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;
 
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;
42
46
  }
43
47
}
44
48
 
79
83
  }
80
84
}
81
85
 
82
 
 
83
86
/**
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)
 
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)
90
92
{
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);
95
 
 
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
 
  }
 
93
  uint32_t tmp;
104
94
 
105
95
  /* Remove end space */
106
96
  length= field_charset->cset->lengthsp(field_charset, from, length);
107
 
  uint32_t tmp=find_type2(typelib, from, length, field_charset);
108
 
  if (!tmp)
 
97
  tmp= find_type2(typelib, from, length, field_charset);
 
98
  if (! tmp)
109
99
  {
110
 
    if (length < 6) // Can't be more than 99999 enums
 
100
    if (length < 6) /* Can't be more than 99999 enums */
111
101
    {
112
102
      /* This is for reading numbers with LOAD DATA INFILE */
113
 
      char *end;
114
 
      tmp=(uint) my_strntoul(cs,from,length,10,&end,&err);
115
 
      if (err || end != from+length || tmp > typelib->count)
 
103
      /* Convert the string to an integer using stringstream */
 
104
      std::stringstream ss;
 
105
      ss << from;
 
106
      ss >> tmp;
 
107
 
 
108
      if (tmp == 0 || tmp > typelib->count)
116
109
      {
117
 
        tmp=0;
118
 
        set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
 
110
        my_error(ER_INVALID_ENUM_VALUE, MYF(ME_FATALERROR), from);
 
111
        return 1;
119
112
      }
120
 
      if (!table->in_use->count_cuted_fields)
121
 
        err= 0;
122
113
    }
123
114
    else
124
 
      set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
 
115
    {
 
116
      my_error(ER_INVALID_ENUM_VALUE, MYF(ME_FATALERROR), from);
 
117
      return 1;
 
118
    }
125
119
  }
126
120
  store_type((uint64_t) tmp);
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 unsigned_val __attribute__((unused)))
139
 
{
140
 
  int error= 0;
141
 
  if ((uint64_t) nr > typelib->count || nr == 0)
 
121
  return 0;
 
122
}
 
123
 
 
124
int Field_enum::store(double from)
 
125
{
 
126
  return Field_enum::store((int64_t) from, false);
 
127
}
 
128
 
 
129
/**
 
130
 * @note MySQL allows 0 values, saying that 0 is "the index of the
 
131
 * blank string error", whatever that means.  Uhm, Drizzle doesn't
 
132
 * allow this.  To store an ENUM column value using an integer, you
 
133
 * must specify the 1-based index of the enum column definition's 
 
134
 * key.
 
135
 */
 
136
int Field_enum::store(int64_t from, bool)
 
137
{
 
138
  if (from <= 0 || (uint64_t) from > typelib->count)
142
139
  {
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
 
    }
 
140
    /* Convert the integer to a string using stringstream */
 
141
    std::stringstream ss;
 
142
    std::string tmp;
 
143
    ss << from; ss >> tmp;
 
144
 
 
145
    my_error(ER_INVALID_ENUM_VALUE, MYF(ME_FATALERROR), tmp.c_str());
 
146
    return 1;
149
147
  }
150
 
  store_type((uint64_t) (uint) nr);
151
 
  return error;
 
148
  store_type((uint64_t) (uint32_t) from);
 
149
  return 0;
152
150
}
153
151
 
154
 
 
155
152
double Field_enum::val_real(void)
156
153
{
157
154
  return (double) Field_enum::val_int();
158
155
}
159
156
 
160
 
 
161
157
int64_t Field_enum::val_int(void)
162
158
{
163
159
  switch (packlength) {
202
198
  return 0;                                     // impossible
203
199
}
204
200
 
205
 
 
206
201
/**
207
202
   Save the field metadata for enum fields.
208
203
 
209
 
   Saves the real type in the first byte and the pack length in the 
 
204
   Saves the real type in the first byte and the pack length in the
210
205
   second byte of the field metadata array at index of *metadata_ptr and
211
206
   *(metadata_ptr + 1).
212
207
 
221
216
  return 2;
222
217
}
223
218
 
224
 
 
225
 
String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
226
 
                            String *val_ptr)
 
219
String *Field_enum::val_str(String *, String *val_ptr)
227
220
{
228
 
  uint32_t tmp=(uint) Field_enum::val_int();
 
221
  uint32_t tmp=(uint32_t) Field_enum::val_int();
229
222
  if (!tmp || tmp > typelib->count)
230
223
    val_ptr->set("", 0, field_charset);
231
224
  else
246
239
  return (a < b) ? -1 : (a > b) ? 1 : 0;
247
240
}
248
241
 
249
 
void Field_enum::sort_string(unsigned char *to,uint32_t length __attribute__((unused)))
 
242
void Field_enum::sort_string(unsigned char *to,uint32_t )
250
243
{
251
244
  uint64_t value=Field_enum::val_int();
252
245
  to+=packlength-1;
257
250
  }
258
251
}
259
252
 
260
 
 
261
253
void Field_enum::sql_type(String &res) const
262
254
{
263
255
  char buffer[255];
275
267
      res.append(',');
276
268
    /* convert to res.charset() == utf8, then quote */
277
269
    enum_item.copy(*pos, *len, charset(), res.charset(), &dummy_errors);
278
 
    append_unescaped(&res, enum_item.ptr(), enum_item.length());
 
270
    append_unescaped(&res, enum_item.c_ptr(), enum_item.length());
279
271
    flag= 1;
280
272
  }
281
273
  res.append(')');
282
274
}
283
275
 
284
 
 
285
276
Field *Field_enum::new_field(MEM_ROOT *root, Table *new_table,
286
277
                             bool keep_type)
287
278
{