~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/create_field.cc

pandora-build v0.100 - Fixes several bugs found by cb1kenobi. Add several thoughts from folks at LCA.

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-2009 Sun Microsystems
 
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; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
 
 
20
/**
 
21
 * @file Implementation of CreateField class
 
22
 */
 
23
 
 
24
#include "config.h"
 
25
#include <errno.h>
 
26
#include <float.h>
 
27
#include "drizzled/sql_select.h"
 
28
#include "drizzled/error.h"
 
29
#include "drizzled/field.h"
 
30
#include "drizzled/create_field.h"
 
31
#include "drizzled/field/str.h"
 
32
#include "drizzled/field/num.h"
 
33
#include "drizzled/field/blob.h"
 
34
#include "drizzled/field/enum.h"
 
35
#include "drizzled/field/null.h"
 
36
#include "drizzled/field/date.h"
 
37
#include "drizzled/field/decimal.h"
 
38
#include "drizzled/field/real.h"
 
39
#include "drizzled/field/double.h"
 
40
#include "drizzled/field/long.h"
 
41
#include "drizzled/field/int64_t.h"
 
42
#include "drizzled/field/num.h"
 
43
#include "drizzled/field/timestamp.h"
 
44
#include "drizzled/field/datetime.h"
 
45
#include "drizzled/field/varstring.h"
 
46
#include "drizzled/temporal.h"
 
47
 
 
48
#include <algorithm>
 
49
 
 
50
using namespace drizzled;
 
51
using namespace std;
 
52
 
 
53
 
 
54
/** Create a field suitable for create of table. */
 
55
CreateField::CreateField(Field *old_field, Field *orig_field)
 
56
{
 
57
  field= old_field;
 
58
  field_name= change= old_field->field_name;
 
59
  length= old_field->field_length;
 
60
  flags= old_field->flags;
 
61
  unireg_check= old_field->unireg_check;
 
62
  pack_length= old_field->pack_length();
 
63
  key_length= old_field->key_length();
 
64
  sql_type= old_field->real_type();
 
65
  charset= old_field->charset(); // May be NULL ptr
 
66
  comment= old_field->comment;
 
67
  decimals= old_field->decimals();
 
68
 
 
69
  /* Fix if the original table had 4 byte pointer blobs */
 
70
  if (flags & BLOB_FLAG)
 
71
    pack_length= (pack_length - old_field->table->s->blob_ptr_size + portable_sizeof_char_ptr);
 
72
 
 
73
  switch (sql_type) 
 
74
  {
 
75
    case DRIZZLE_TYPE_BLOB:
 
76
      sql_type= DRIZZLE_TYPE_BLOB;
 
77
      length/= charset->mbmaxlen;
 
78
      key_length/= charset->mbmaxlen;
 
79
      break;
 
80
    case DRIZZLE_TYPE_ENUM:
 
81
    case DRIZZLE_TYPE_VARCHAR:
 
82
      /* This is corrected in create_length_to_internal_length */
 
83
      length= (length+charset->mbmaxlen-1) / charset->mbmaxlen;
 
84
      break;
 
85
    default:
 
86
      break;
 
87
  }
 
88
 
 
89
  if (flags & (ENUM_FLAG | SET_FLAG))
 
90
    interval= ((Field_enum*) old_field)->typelib;
 
91
  else
 
92
    interval= 0;
 
93
  def= 0;
 
94
  char_length= length;
 
95
 
 
96
  if (!(flags & (NO_DEFAULT_VALUE_FLAG )) &&
 
97
      old_field->ptr && orig_field &&
 
98
      (sql_type != DRIZZLE_TYPE_TIMESTAMP ||                /* set def only if */
 
99
       old_field->table->timestamp_field != old_field ||  /* timestamp field */
 
100
       unireg_check == Field::TIMESTAMP_UN_FIELD))        /* has default val */
 
101
  {
 
102
    ptrdiff_t diff;
 
103
 
 
104
    /* Get the value from default_values */
 
105
    diff= (ptrdiff_t) (orig_field->table->s->default_values - orig_field->table->record[0]);
 
106
    orig_field->move_field_offset(diff);        // Points now at default_values
 
107
    if (! orig_field->is_real_null())
 
108
    {
 
109
      char buff[MAX_FIELD_WIDTH], *pos;
 
110
      String tmp(buff, sizeof(buff), charset), *res;
 
111
      res= orig_field->val_str(&tmp);
 
112
      pos= (char*) memory::sql_strmake(res->ptr(), res->length());
 
113
      def= new Item_string(pos, res->length(), charset);
 
114
    }
 
115
    orig_field->move_field_offset(-diff);       // Back to record[0]
 
116
  }
 
117
}
 
118
 
 
119
/**
 
120
  Convert CreateField::length from number of characters to number of bytes.
 
121
*/
 
122
void CreateField::create_length_to_internal_length(void)
 
123
{
 
124
  switch (sql_type) 
 
125
  {
 
126
    case DRIZZLE_TYPE_BLOB:
 
127
    case DRIZZLE_TYPE_VARCHAR:
 
128
      length*= charset->mbmaxlen;
 
129
      key_length= length;
 
130
      pack_length= calc_pack_length(sql_type, length);
 
131
      break;
 
132
    case DRIZZLE_TYPE_ENUM:
 
133
      /* Pack_length already calculated in ::init() */
 
134
      length*= charset->mbmaxlen;
 
135
      key_length= pack_length;
 
136
      break;
 
137
    case DRIZZLE_TYPE_DECIMAL:
 
138
      key_length= pack_length=
 
139
        my_decimal_get_binary_size(my_decimal_length_to_precision(length,
 
140
                  decimals,
 
141
                  flags &
 
142
                  UNSIGNED_FLAG),
 
143
          decimals);
 
144
      break;
 
145
    default:
 
146
      key_length= pack_length= calc_pack_length(sql_type, length);
 
147
      break;
 
148
  }
 
149
}
 
150
 
 
151
/**
 
152
  Init for a tmp table field. To be extended if need be.
 
153
*/
 
154
void CreateField::init_for_tmp_table(enum_field_types sql_type_arg,
 
155
                                     uint32_t length_arg,
 
156
                                     uint32_t decimals_arg,
 
157
                                     bool maybe_null)
 
158
{
 
159
  field_name= "";
 
160
  sql_type= sql_type_arg;
 
161
  char_length= length= length_arg;;
 
162
  unireg_check= Field::NONE;
 
163
  interval= 0;
 
164
  charset= &my_charset_bin;
 
165
  decimals= decimals_arg & FIELDFLAG_MAX_DEC;
 
166
  pack_flag= 0;
 
167
 
 
168
  if (! maybe_null)
 
169
    flags= NOT_NULL_FLAG;
 
170
  else
 
171
    flags= 0;
 
172
}
 
173
 
 
174
bool CreateField::init(Session *,
 
175
                        char *fld_name,
 
176
                        enum_field_types fld_type,
 
177
                        char *fld_length,
 
178
                        char *fld_decimals,
 
179
                        uint32_t fld_type_modifier,
 
180
                        Item *fld_default_value,
 
181
                        Item *fld_on_update_value,
 
182
                        LEX_STRING *fld_comment,
 
183
                        char *fld_change,
 
184
                        List<String> *fld_interval_list,
 
185
                        const CHARSET_INFO * const fld_charset,
 
186
                        uint32_t,
 
187
                        enum column_format_type column_format_in)
 
188
                        
 
189
{
 
190
  uint32_t sign_len= 0;
 
191
  uint32_t allowed_type_modifier= 0;
 
192
  uint32_t max_field_charlength= MAX_FIELD_CHARLENGTH;
 
193
 
 
194
  field= 0;
 
195
  field_name= fld_name;
 
196
  def= fld_default_value;
 
197
  flags= fld_type_modifier;
 
198
  flags|= (((uint32_t)column_format_in & COLUMN_FORMAT_MASK) << COLUMN_FORMAT_FLAGS);
 
199
  unireg_check= (fld_type_modifier & AUTO_INCREMENT_FLAG ?
 
200
                 Field::NEXT_NUMBER : Field::NONE);
 
201
  decimals= fld_decimals ? (uint32_t)atoi(fld_decimals) : 0;
 
202
  if (decimals >= NOT_FIXED_DEC)
 
203
  {
 
204
    my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, fld_name,
 
205
             NOT_FIXED_DEC-1);
 
206
    return(true);
 
207
  }
 
208
 
 
209
  sql_type= fld_type;
 
210
  length= 0;
 
211
  change= fld_change;
 
212
  interval= 0;
 
213
  pack_length= key_length= 0;
 
214
  charset= fld_charset;
 
215
  interval_list.empty();
 
216
 
 
217
  comment= *fld_comment;
 
218
 
 
219
  /*
 
220
    Set NO_DEFAULT_VALUE_FLAG if this field doesn't have a default value and
 
221
    it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP.
 
222
  */
 
223
  if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) &&
 
224
      (fld_type_modifier & NOT_NULL_FLAG) && fld_type != DRIZZLE_TYPE_TIMESTAMP)
 
225
    flags|= NO_DEFAULT_VALUE_FLAG;
 
226
 
 
227
  if (fld_length && !(length= (uint32_t) atoi(fld_length)))
 
228
    fld_length= 0;
 
229
  sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1;
 
230
 
 
231
  switch (fld_type) 
 
232
  {
 
233
    case DRIZZLE_TYPE_LONG:
 
234
      if (!fld_length)
 
235
        length= MAX_INT_WIDTH+sign_len;
 
236
      allowed_type_modifier= AUTO_INCREMENT_FLAG;
 
237
      break;
 
238
    case DRIZZLE_TYPE_LONGLONG:
 
239
      if (!fld_length)
 
240
        length= MAX_BIGINT_WIDTH;
 
241
      allowed_type_modifier= AUTO_INCREMENT_FLAG;
 
242
      break;
 
243
    case DRIZZLE_TYPE_NULL:
 
244
      break;
 
245
    case DRIZZLE_TYPE_DECIMAL:
 
246
      my_decimal_trim(&length, &decimals);
 
247
      if (length > DECIMAL_MAX_PRECISION)
 
248
      {
 
249
        my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
 
250
                DECIMAL_MAX_PRECISION);
 
251
        return(true);
 
252
      }
 
253
      if (length < decimals)
 
254
      {
 
255
        my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
 
256
        return(true);
 
257
      }
 
258
      length= my_decimal_precision_to_length(length, decimals, fld_type_modifier & UNSIGNED_FLAG);
 
259
      pack_length= my_decimal_get_binary_size(length, decimals);
 
260
      break;
 
261
    case DRIZZLE_TYPE_VARCHAR:
 
262
      /*
 
263
        Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
 
264
        if they don't have a default value
 
265
      */
 
266
      max_field_charlength= MAX_FIELD_VARCHARLENGTH;
 
267
      break;
 
268
    case DRIZZLE_TYPE_BLOB:
 
269
      if (fld_default_value)
 
270
      {
 
271
        /* Allow empty as default value. */
 
272
        String str,*res;
 
273
        res= fld_default_value->val_str(&str);
 
274
        if (res->length())
 
275
        {
 
276
          my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), fld_name);
 
277
          return(true);
 
278
        }
 
279
 
 
280
      }
 
281
      flags|= BLOB_FLAG;
 
282
      break;
 
283
    case DRIZZLE_TYPE_DOUBLE:
 
284
      allowed_type_modifier= AUTO_INCREMENT_FLAG;
 
285
      if (!fld_length && !fld_decimals)
 
286
      {
 
287
        length= DBL_DIG+7;
 
288
        decimals= NOT_FIXED_DEC;
 
289
      }
 
290
      if (length < decimals &&
 
291
          decimals != NOT_FIXED_DEC)
 
292
      {
 
293
        my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
 
294
        return(true);
 
295
      }
 
296
      break;
 
297
    case DRIZZLE_TYPE_TIMESTAMP:
 
298
      if (!fld_length)
 
299
      {
 
300
        length= drizzled::DateTime::MAX_STRING_LENGTH;
 
301
      }
 
302
 
 
303
      /* This assert() should be correct due to absence of length
 
304
         specifiers for timestamp. Previous manipulation also wasn't
 
305
         ever called (from examining lcov)
 
306
      */
 
307
      assert(length == (uint32_t)drizzled::DateTime::MAX_STRING_LENGTH);
 
308
 
 
309
      flags|= UNSIGNED_FLAG;
 
310
      if (fld_default_value)
 
311
      {
 
312
        /* Grammar allows only NOW() value for ON UPDATE clause */
 
313
        if (fld_default_value->type() == Item::FUNC_ITEM &&
 
314
            ((Item_func*)fld_default_value)->functype() == Item_func::NOW_FUNC)
 
315
        {
 
316
          unireg_check= (fld_on_update_value ? Field::TIMESTAMP_DNUN_FIELD:
 
317
                                              Field::TIMESTAMP_DN_FIELD);
 
318
          /*
 
319
            We don't need default value any longer moreover it is dangerous.
 
320
            Everything handled by unireg_check further.
 
321
          */
 
322
          def= 0;
 
323
        }
 
324
        else
 
325
          unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD:
 
326
                                              Field::NONE);
 
327
      }
 
328
      else
 
329
      {
 
330
        /*
 
331
          If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
 
332
          or ON UPDATE values then for the sake of compatiblity we should treat
 
333
          this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
 
334
          have another TIMESTAMP column with auto-set option before this one)
 
335
          or DEFAULT 0 (in other cases).
 
336
          So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
 
337
          replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
 
338
          information about all TIMESTAMP fields in table will be availiable.
 
339
 
 
340
          If we have TIMESTAMP NULL column without explicit DEFAULT value
 
341
          we treat it as having DEFAULT NULL attribute.
 
342
        */
 
343
        unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD :
 
344
                      (flags & NOT_NULL_FLAG ? Field::TIMESTAMP_OLD_FIELD :
 
345
                                                Field::NONE));
 
346
      }
 
347
      break;
 
348
    case DRIZZLE_TYPE_DATE:
 
349
      length= drizzled::Date::MAX_STRING_LENGTH;
 
350
      break;
 
351
    case DRIZZLE_TYPE_DATETIME:
 
352
      length= drizzled::DateTime::MAX_STRING_LENGTH;
 
353
      break;
 
354
    case DRIZZLE_TYPE_ENUM:
 
355
      {
 
356
        /* Should be safe. */
 
357
        pack_length= get_enum_pack_length(fld_interval_list->elements);
 
358
 
 
359
        List_iterator<String> it(*fld_interval_list);
 
360
        String *tmp;
 
361
        while ((tmp= it++))
 
362
          interval_list.push_back(tmp);
 
363
        length= 1;
 
364
        break;
 
365
    }
 
366
  }
 
367
  /* Remember the value of length */
 
368
  char_length= length;
 
369
 
 
370
  if (!(flags & BLOB_FLAG) &&
 
371
      ((length > max_field_charlength &&
 
372
        fld_type != DRIZZLE_TYPE_ENUM &&
 
373
        (fld_type != DRIZZLE_TYPE_VARCHAR || fld_default_value)) ||
 
374
       (!length && fld_type != DRIZZLE_TYPE_VARCHAR)))
 
375
  {
 
376
    my_error((fld_type == DRIZZLE_TYPE_VARCHAR) ?  ER_TOO_BIG_FIELDLENGTH : ER_TOO_BIG_DISPLAYWIDTH,
 
377
              MYF(0),
 
378
              fld_name, max_field_charlength);
 
379
    return true;
 
380
  }
 
381
  fld_type_modifier&= AUTO_INCREMENT_FLAG;
 
382
  if ((~allowed_type_modifier) & fld_type_modifier)
 
383
  {
 
384
    my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
 
385
    return true;
 
386
  }
 
387
 
 
388
  return false; /* success */
 
389
}