Drizzled Public API Documentation

create_field.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008-2009 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00024 #include <config.h>
00025 #include <errno.h>
00026 #include <float.h>
00027 #include <drizzled/sql_select.h>
00028 #include <drizzled/error.h>
00029 #include <drizzled/field.h>
00030 #include <drizzled/create_field.h>
00031 #include <drizzled/field/str.h>
00032 #include <drizzled/field/num.h>
00033 #include <drizzled/field/blob.h>
00034 #include <drizzled/field/boolean.h>
00035 #include <drizzled/field/enum.h>
00036 #include <drizzled/field/null.h>
00037 #include <drizzled/field/date.h>
00038 #include <drizzled/field/decimal.h>
00039 #include <drizzled/field/real.h>
00040 #include <drizzled/field/double.h>
00041 #include <drizzled/field/int32.h>
00042 #include <drizzled/field/int64.h>
00043 #include <drizzled/field/num.h>
00044 #include <drizzled/field/epoch.h>
00045 #include <drizzled/field/datetime.h>
00046 #include <drizzled/field/varstring.h>
00047 #include <drizzled/field/uuid.h>
00048 #include <drizzled/field/ipv6.h>
00049 #include <drizzled/temporal.h>
00050 #include <drizzled/item/string.h>
00051 #include <drizzled/table.h>
00052 
00053 #include <drizzled/display.h>
00054 
00055 #include <algorithm>
00056 
00057 using namespace std;
00058 
00059 namespace drizzled
00060 {
00061 
00063 CreateField::CreateField(Field *old_field, Field *orig_field)
00064 {
00065   field= old_field;
00066   field_name= change= old_field->field_name;
00067   length= old_field->field_length;
00068   flags= old_field->flags;
00069   unireg_check= old_field->unireg_check;
00070   pack_length= old_field->pack_length();
00071   key_length= old_field->key_length();
00072   sql_type= old_field->real_type();
00073   charset= old_field->charset(); // May be NULL ptr
00074   comment= old_field->comment;
00075   decimals= old_field->decimals();
00076 
00077   /* Fix if the original table had 4 byte pointer blobs */
00078   if (flags & BLOB_FLAG)
00079   {
00080     pack_length= (pack_length - old_field->getTable()->getShare()->sizeBlobPtr() + portable_sizeof_char_ptr);
00081   }
00082 
00083   switch (sql_type) 
00084   {
00085     case DRIZZLE_TYPE_BLOB:
00086       sql_type= DRIZZLE_TYPE_BLOB;
00087       length/= charset->mbmaxlen;
00088       key_length/= charset->mbmaxlen;
00089       break;
00090     case DRIZZLE_TYPE_ENUM:
00091     case DRIZZLE_TYPE_VARCHAR:
00092       /* This is corrected in create_length_to_internal_length */
00093       length= (length+charset->mbmaxlen-1) / charset->mbmaxlen;
00094       break;
00095     default:
00096       break;
00097   }
00098 
00099   if (flags & ENUM_FLAG)
00100     interval= ((Field_enum*) old_field)->typelib;
00101   else
00102     interval= 0;
00103   def= 0;
00104   char_length= length;
00105 
00106   if (!(flags & (NO_DEFAULT_VALUE_FLAG)) &&
00107       !(flags & AUTO_INCREMENT_FLAG) &&
00108       old_field->ptr && orig_field &&
00109       (not old_field->is_timestamp() ||                /* set def only if */
00110        old_field->getTable()->timestamp_field != old_field ||  /* timestamp field */
00111        unireg_check == Field::TIMESTAMP_UN_FIELD))        /* has default val */
00112   {
00113     /* Get the value from default_values */
00114     ptrdiff_t diff= (ptrdiff_t) (orig_field->getTable()->getDefaultValues() - orig_field->getTable()->getInsertRecord());
00115     orig_field->move_field_offset(diff);  // Points now at default_values
00116     if (! orig_field->is_real_null())
00117     {
00118       char buff[MAX_FIELD_WIDTH];
00119       String tmp(buff, sizeof(buff), charset);
00120       String* res= orig_field->val_str_internal(&tmp);
00121       char* pos= memory::sql_strdup(*res);
00122       def= new Item_string(pos, res->length(), charset);
00123     }
00124     orig_field->move_field_offset(-diff); // Back to getInsertRecord()
00125   }
00126 }
00127 
00131 void CreateField::create_length_to_internal_length(void)
00132 {
00133   switch (sql_type) 
00134   {
00135     case DRIZZLE_TYPE_BLOB:
00136     case DRIZZLE_TYPE_VARCHAR:
00137       length*= charset->mbmaxlen;
00138       key_length= length;
00139       pack_length= calc_pack_length(sql_type, length);
00140       break;
00141     case DRIZZLE_TYPE_ENUM:
00142       /* Pack_length already calculated in ::init() */
00143       length*= charset->mbmaxlen;
00144       key_length= pack_length;
00145       break;
00146     case DRIZZLE_TYPE_DECIMAL:
00147       key_length= pack_length=
00148         class_decimal_get_binary_size(class_decimal_length_to_precision(length,
00149                   decimals,
00150                   flags &
00151                   UNSIGNED_FLAG),
00152           decimals);
00153       break;
00154     default:
00155       key_length= pack_length= calc_pack_length(sql_type, length);
00156       break;
00157   }
00158 }
00159 
00163 void CreateField::init_for_tmp_table(enum_field_types sql_type_arg,
00164                                      uint32_t length_arg,
00165                                      uint32_t decimals_arg,
00166                                      bool maybe_null)
00167 {
00168   field_name= "";
00169   sql_type= sql_type_arg;
00170   char_length= length= length_arg;;
00171   unireg_check= Field::NONE;
00172   interval= 0;
00173   charset= &my_charset_bin;
00174   decimals= decimals_arg & FIELDFLAG_MAX_DEC;
00175 
00176   flags= maybe_null ? 0 : NOT_NULL_FLAG;
00177 }
00178 
00179 bool CreateField::init(Session *,
00180                         const char *fld_name,
00181                         enum_field_types fld_type,
00182                         const char *fld_length,
00183                         const char *fld_decimals,
00184                         uint32_t fld_type_modifier,
00185                         str_ref fld_comment,
00186                         const char *fld_change,
00187                         List<String> *fld_interval_list,
00188                         const charset_info_st* fld_charset,
00189                         uint32_t,
00190                         column_format_type column_format_in)
00191 {
00192   uint32_t sign_len= 0;
00193   uint32_t allowed_type_modifier= 0;
00194   uint32_t max_field_charlength= MAX_FIELD_CHARLENGTH;
00195 
00196   field= 0;
00197   field_name= fld_name;
00198   flags= fld_type_modifier;
00199   flags|= (((uint32_t)column_format_in & COLUMN_FORMAT_MASK) << COLUMN_FORMAT_FLAGS);
00200   unireg_check= (fld_type_modifier & AUTO_INCREMENT_FLAG ?
00201                  Field::NEXT_NUMBER : Field::NONE);
00202   decimals= fld_decimals ? (uint32_t)atoi(fld_decimals) : 0;
00203   if (decimals >= NOT_FIXED_DEC)
00204   {
00205     my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, fld_name,
00206              NOT_FIXED_DEC-1);
00207     return true;
00208   }
00209 
00210   sql_type= fld_type;
00211   length= 0;
00212   change= fld_change;
00213   interval= 0;
00214   pack_length= key_length= 0;
00215   charset= fld_charset;
00216   interval_list.clear();
00217 
00218   comment= fld_comment;
00219 
00220   if (fld_length && !(length= (uint32_t) atoi(fld_length)))
00221     fld_length= 0;
00222   sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1;
00223 
00224   switch (fld_type) 
00225   {
00226     case DRIZZLE_TYPE_LONG:
00227       if (!fld_length)
00228         length= MAX_INT_WIDTH+sign_len;
00229       allowed_type_modifier= AUTO_INCREMENT_FLAG;
00230       break;
00231     case DRIZZLE_TYPE_LONGLONG:
00232       if (!fld_length)
00233         length= MAX_BIGINT_WIDTH;
00234       allowed_type_modifier= AUTO_INCREMENT_FLAG;
00235       break;
00236     case DRIZZLE_TYPE_NULL:
00237       break;
00238     case DRIZZLE_TYPE_DECIMAL:
00239       class_decimal_trim(&length, &decimals);
00240       if (length > DECIMAL_MAX_PRECISION)
00241       {
00242         my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
00243                 DECIMAL_MAX_PRECISION);
00244         return true;
00245       }
00246       if (length < decimals)
00247       {
00248         my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
00249         return true;
00250       }
00251       length= class_decimal_precision_to_length(length, decimals, fld_type_modifier & UNSIGNED_FLAG);
00252       pack_length= class_decimal_get_binary_size(length, decimals);
00253       break;
00254     case DRIZZLE_TYPE_VARCHAR:
00255       /*
00256         Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
00257         if they don't have a default value
00258       */
00259       max_field_charlength= MAX_FIELD_VARCHARLENGTH;
00260       break;
00261     case DRIZZLE_TYPE_BLOB:
00262       flags|= BLOB_FLAG;
00263       break;
00264     case DRIZZLE_TYPE_DOUBLE:
00265       allowed_type_modifier= AUTO_INCREMENT_FLAG;
00266       if (!fld_length && !fld_decimals)
00267       {
00268         length= DBL_DIG+7;
00269         decimals= NOT_FIXED_DEC;
00270       }
00271       if (length < decimals &&
00272           decimals != NOT_FIXED_DEC)
00273       {
00274         my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name);
00275         return true;
00276       }
00277       break;
00278     case DRIZZLE_TYPE_MICROTIME:
00279       /* 
00280         This assert() should be correct due to absence of length
00281         specifiers for timestamp. Previous manipulation also wasn't
00282         ever called (from examining lcov)
00283       */
00284       assert(fld_type);
00285     case DRIZZLE_TYPE_TIMESTAMP:
00286       length= MicroTimestamp::MAX_STRING_LENGTH;
00287       break;
00288     case DRIZZLE_TYPE_DATE:
00289       length= Date::MAX_STRING_LENGTH;
00290       break;
00291     case DRIZZLE_TYPE_UUID:
00292       length= field::Uuid::max_string_length();
00293       break;
00294     case DRIZZLE_TYPE_IPV6:
00295       length= field::IPv6::max_string_length();
00296       break;
00297     case DRIZZLE_TYPE_BOOLEAN:
00298       length= field::Boolean::max_string_length();
00299       break;
00300     case DRIZZLE_TYPE_DATETIME:
00301       length= DateTime::MAX_STRING_LENGTH;
00302       break;
00303     case DRIZZLE_TYPE_TIME:
00304       length= DateTime::MAX_STRING_LENGTH;
00305       break;
00306     case DRIZZLE_TYPE_ENUM:
00307       {
00308         /* Should be safe. */
00309         pack_length= 4;
00310 
00311         List<String>::iterator it(fld_interval_list->begin());
00312         while (String* tmp= it++)
00313           interval_list.push_back(tmp);
00314         length= 1;
00315         break;
00316     }
00317   }
00318   /* Remember the value of length */
00319   char_length= length;
00320 
00321   if (!(flags & BLOB_FLAG) &&
00322       ((length > max_field_charlength &&
00323         fld_type != DRIZZLE_TYPE_ENUM  &&
00324         (fld_type != DRIZZLE_TYPE_VARCHAR)) ||
00325        (!length && fld_type != DRIZZLE_TYPE_VARCHAR)))
00326   {
00327     my_error((fld_type == DRIZZLE_TYPE_VARCHAR) ?  ER_TOO_BIG_FIELDLENGTH : ER_TOO_BIG_DISPLAYWIDTH,
00328               MYF(0),
00329              fld_name, max_field_charlength / (charset? charset->mbmaxlen : 1));
00330     return true;
00331   }
00332   fld_type_modifier&= AUTO_INCREMENT_FLAG;
00333   if ((~allowed_type_modifier) & fld_type_modifier)
00334   {
00335     my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name);
00336     return true;
00337   }
00338 
00339   return false; /* success */
00340 }
00341 
00342 bool CreateField::setDefaultValue(Item *default_value_item,
00343                                   Item *on_update_item)
00344 {
00345   def= default_value_item;
00346 
00347   /*
00348     Set NO_DEFAULT_VALUE_FLAG if this field doesn't have a default value and
00349     it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP.
00350   */
00351   if (! default_value_item
00352       && ! (flags & AUTO_INCREMENT_FLAG)
00353       && (flags & NOT_NULL_FLAG)
00354       && (sql_type != DRIZZLE_TYPE_TIMESTAMP
00355           and sql_type != DRIZZLE_TYPE_MICROTIME))
00356   {
00357     flags|= NO_DEFAULT_VALUE_FLAG;
00358   }
00359   else
00360   {
00361     flags&= ~NO_DEFAULT_VALUE_FLAG;
00362   }
00363 
00364   if (sql_type == DRIZZLE_TYPE_BLOB && default_value_item)
00365   {
00366     /* Allow empty as default value. */
00367     String str;
00368     String* res= default_value_item->val_str(&str);
00369     if (res->length())
00370     {
00371       my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), field_name);
00372       return true;
00373     }
00374   }
00375 
00376   if (sql_type == DRIZZLE_TYPE_TIMESTAMP
00377       || sql_type == DRIZZLE_TYPE_MICROTIME)
00378   {
00379     bool on_update_now= on_update_item
00380       || (unireg_check == Field::TIMESTAMP_DNUN_FIELD
00381           || unireg_check == Field::TIMESTAMP_UN_FIELD);
00382 
00383     if (default_value_item)
00384     {
00385       /* Grammar allows only NOW() value for ON UPDATE clause */
00386       if (default_value_item->type() == Item::FUNC_ITEM &&
00387           ((Item_func*)default_value_item)->functype() == Item_func::NOW_FUNC)
00388       {
00389         unireg_check= (on_update_now ? Field::TIMESTAMP_DNUN_FIELD:
00390                        Field::TIMESTAMP_DN_FIELD);
00391         /*
00392           We don't need default value any longer moreover it is dangerous.
00393           Everything handled by unireg_check further.
00394         */
00395         def= 0;
00396       }
00397       else
00398       {
00399         unireg_check= on_update_now ? Field::TIMESTAMP_UN_FIELD : Field::NONE;
00400       }
00401     }
00402     else
00403     {
00404       /*
00405         If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
00406         or ON UPDATE values then for the sake of compatiblity we should treat
00407         this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
00408         have another TIMESTAMP column with auto-set option before this one)
00409         or DEFAULT 0 (in other cases).
00410         So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
00411         replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
00412         information about all TIMESTAMP fields in table will be availiable.
00413 
00414         If we have TIMESTAMP NULL column without explicit DEFAULT value
00415         we treat it as having DEFAULT NULL attribute.
00416       */
00417       unireg_check= on_update_now ? Field::TIMESTAMP_UN_FIELD :
00418                      (flags & NOT_NULL_FLAG ? Field::TIMESTAMP_OLD_FIELD : Field::NONE);
00419     }
00420   }
00421 
00422   return false;
00423 }
00424 
00425 std::ostream& operator<<(std::ostream& output, const CreateField &field)
00426 {
00427   output << "CreateField:(";
00428   output <<  field.field_name;
00429   output << ", ";
00430   output << display::type(field.type());
00431   output << ", { ";
00432 
00433   if (field.flags & NOT_NULL_FLAG)
00434     output << " NOT_NULL";
00435 
00436   if (field.flags & PRI_KEY_FLAG)
00437     output << ", PRIMARY KEY";
00438 
00439   if (field.flags & UNIQUE_KEY_FLAG)
00440     output << ", UNIQUE KEY";
00441 
00442   if (field.flags & MULTIPLE_KEY_FLAG)
00443     output << ", MULTIPLE KEY";
00444 
00445   if (field.flags & BLOB_FLAG)
00446     output << ", BLOB";
00447 
00448   if (field.flags & UNSIGNED_FLAG)
00449     output << ", UNSIGNED";
00450 
00451   if (field.flags & BINARY_FLAG)
00452     output << ", BINARY";
00453   output << "}, ";
00454   if (field.field)
00455     output << *field.field;
00456   output << ")";
00457 
00458   return output;  // for multiple << operators.
00459 }
00460 
00461 } /* namespace drizzled */