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