~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/create_field.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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/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 */