~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/create_field.cc

  • Committer: Brian Aker
  • Date: 2010-12-18 18:24:57 UTC
  • mfrom: (1999.6.3 trunk)
  • Revision ID: brian@tangent.org-20101218182457-yi1wd0so2hml1k1w
Merge in Lee's copyright header fix

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