diff options
author | Sergei Golubchik <serg@mariadb.org> | 2014-11-08 17:37:19 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2014-12-04 16:09:34 +0100 |
commit | 227510e039b4ec6bff3096a4b9b39847551dab1a (patch) | |
tree | 2c40cbba45ca53e688d3f5cd388dbcd032c82984 /sql/field.cc | |
parent | d1522af72dad1965b8a8a37415545014ba743f49 (diff) | |
download | mariadb-git-227510e039b4ec6bff3096a4b9b39847551dab1a.tar.gz |
parser cleanup: don't store field properties in LEX, use Create_field directly
length/dec/charset are still in LEX, because they're also used
for CAST and dynamic columns.
also
1. fix "MDEV-7041 COLLATION(CAST('a' AS CHAR BINARY)) returns a wrong result"
2. allow BINARY modifier in stored function RETURN clause
3. allow "COLLATION without CHARSET" in SP/SF (parameters, RETURN, DECLARE)
4. print correct variable name in error messages for stored routine parameters
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 280 |
1 files changed, 114 insertions, 166 deletions
diff --git a/sql/field.cc b/sql/field.cc index 7467aa63a26..a9bd1fe2dc0 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9163,96 +9163,100 @@ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg, } -/** - Initialize field definition for create. - - @param thd Thread handle - @param fld_name Field name - @param fld_type Field type - @param fld_length Field length - @param fld_decimals Decimal (if any) - @param fld_type_modifier Additional type information - @param fld_default_value Field default value (if any) - @param fld_on_update_value The value of ON UPDATE clause - @param fld_comment Field comment - @param fld_change Field change - @param fld_interval_list Interval list (if any) - @param fld_charset Field charset - @param fld_geom_type Field geometry type (if any) - @param fld_vcol_info Virtual column data +static inline bool is_item_func(Item* x) +{ + return x != NULL && x->type() == Item::FUNC_ITEM; +} - @retval - FALSE on success - @retval - TRUE on error -*/ -bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, - char *fld_length, char *fld_decimals, - uint fld_type_modifier, Item *fld_default_value, - Item *fld_on_update_value, LEX_STRING *fld_comment, - char *fld_change, List<String> *fld_interval_list, - CHARSET_INFO *fld_charset, uint fld_geom_type, - Virtual_column_info *fld_vcol_info, - engine_option_value *create_opt, bool check_exists) +bool Create_field::check(THD *thd) { + const uint conditional_type_modifiers= AUTO_INCREMENT_FLAG; uint sign_len, allowed_type_modifier= 0; ulong max_field_charlength= MAX_FIELD_CHARLENGTH; - const bool on_update_is_function= - (fld_on_update_value != NULL && - fld_on_update_value->type() == Item::FUNC_ITEM); + DBUG_ENTER("Create_field::check"); + + if (vcol_info) + { + vcol_info->set_field_type(sql_type); + sql_type= (enum enum_field_types)MYSQL_TYPE_VIRTUAL; + } + + if (length > MAX_FIELD_BLOBLENGTH) + { + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name, MAX_FIELD_BLOBLENGTH); + DBUG_RETURN(1); + } + + if (decimals >= NOT_FIXED_DEC) + { + my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, field_name, + static_cast<ulong>(NOT_FIXED_DEC - 1)); + DBUG_RETURN(TRUE); + } - DBUG_ENTER("Create_field::init()"); + if (def) + { + /* + Default value should be literal => basic constants => + no need fix_fields() - field= 0; - field_name= fld_name; - flags= fld_type_modifier; - option_list= create_opt; + We allow only one function as part of default value - + NOW() as default for TIMESTAMP and DATETIME type. + */ + if (def->type() == Item::FUNC_ITEM && + (static_cast<Item_func*>(def)->functype() != Item_func::NOW_FUNC || + (mysql_type_to_time_type(sql_type) != MYSQL_TIMESTAMP_DATETIME) || + def->decimals < length)) + { + my_error(ER_INVALID_DEFAULT, MYF(0), field_name); + DBUG_RETURN(1); + } + else if (def->type() == Item::NULL_ITEM) + { + def= 0; + if ((flags & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) == NOT_NULL_FLAG) + { + my_error(ER_INVALID_DEFAULT, MYF(0), field_name); + DBUG_RETURN(1); + } + } + else if (flags & AUTO_INCREMENT_FLAG) + { + my_error(ER_INVALID_DEFAULT, MYF(0), field_name); + DBUG_RETURN(1); + } + } - if (fld_default_value != NULL && fld_default_value->type() == Item::FUNC_ITEM) + if (is_item_func(def)) { /* There is a function default for insertions. */ def= NULL; - unireg_check= (on_update_is_function ? + unireg_check= (is_item_func(on_update) ? Field::TIMESTAMP_DNUN_FIELD : // for insertions and for updates. Field::TIMESTAMP_DN_FIELD); // only for insertions. } else { /* No function default for insertions. Either NULL or a constant. */ - def= fld_default_value; - if (on_update_is_function) + if (is_item_func(on_update)) unireg_check= Field::TIMESTAMP_UN_FIELD; // function default for updates else - unireg_check= ((fld_type_modifier & AUTO_INCREMENT_FLAG) != 0 ? + unireg_check= ((flags & AUTO_INCREMENT_FLAG) ? Field::NEXT_NUMBER : // Automatic increment. Field::NONE); } - decimals= fld_decimals ? (uint)atoi(fld_decimals) : 0; - if (decimals >= NOT_FIXED_DEC) + if (on_update && + (mysql_type_to_time_type(sql_type) != MYSQL_TIMESTAMP_DATETIME || + on_update->decimals < length)) { - my_error(ER_TOO_BIG_SCALE, MYF(0), decimals, fld_name, - static_cast<ulong>(NOT_FIXED_DEC - 1)); - DBUG_RETURN(TRUE); + my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name); + DBUG_RETURN(1); } - sql_type= fld_type; - length= 0; - change= fld_change; - interval= 0; - pack_length= key_length= 0; - charset= fld_charset; - geom_type= (Field::geometry_type) fld_geom_type; - interval_list.empty(); - - comment= *fld_comment; - vcol_info= fld_vcol_info; - create_if_not_exists= check_exists; - stored_in_db= TRUE; - /* Initialize data for a computed field */ - if ((uchar)fld_type == (uchar)MYSQL_TYPE_VIRTUAL) + if (sql_type == MYSQL_TYPE_VIRTUAL) { DBUG_ASSERT(vcol_info && vcol_info->expr_item); stored_in_db= vcol_info->is_stored(); @@ -9272,56 +9276,42 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, Field::vcol_info. It is is always NULL for a column that is not computed. */ - sql_type= fld_type= vcol_info->get_real_type(); + sql_type= vcol_info->get_real_type(); } /* Set NO_DEFAULT_VALUE_FLAG if this field doesn't have a default value and it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP. */ - if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) && - (fld_type_modifier & NOT_NULL_FLAG) && !is_timestamp_type(fld_type)) + if (!def && unireg_check == Field::NONE && + (flags & NOT_NULL_FLAG) && !is_timestamp_type(sql_type)) flags|= NO_DEFAULT_VALUE_FLAG; - if (fld_length != NULL) - { - errno= 0; - length= strtoul(fld_length, NULL, 10); - if ((errno != 0) || (length > MAX_FIELD_BLOBLENGTH)) - { - my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name, MAX_FIELD_BLOBLENGTH); - DBUG_RETURN(TRUE); - } - - if (length == 0) - fld_length= NULL; /* purecov: inspected */ - } + sign_len= flags & UNSIGNED_FLAG ? 0 : 1; - sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1; - - switch (fld_type) { + switch (sql_type) { case MYSQL_TYPE_TINY: - if (!fld_length) + if (!length) length= MAX_TINYINT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; case MYSQL_TYPE_SHORT: - if (!fld_length) + if (!length) length= MAX_SMALLINT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; case MYSQL_TYPE_INT24: - if (!fld_length) + if (!length) length= MAX_MEDIUMINT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; case MYSQL_TYPE_LONG: - if (!fld_length) + if (!length) length= MAX_INT_WIDTH+sign_len; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; case MYSQL_TYPE_LONGLONG: - if (!fld_length) + if (!length) length= MAX_BIGINT_WIDTH; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; @@ -9331,18 +9321,17 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, my_decimal_trim(&length, &decimals); if (length > DECIMAL_MAX_PRECISION) { - my_error(ER_TOO_BIG_PRECISION, MYF(0), static_cast<int>(length), - fld_name, static_cast<ulong>(DECIMAL_MAX_PRECISION)); + my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name, + DECIMAL_MAX_PRECISION); DBUG_RETURN(TRUE); } if (length < decimals) { - my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name); + my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name); DBUG_RETURN(TRUE); } length= - my_decimal_precision_to_length(length, decimals, - fld_type_modifier & UNSIGNED_FLAG); + my_decimal_precision_to_length(length, decimals, flags & UNSIGNED_FLAG); pack_length= my_decimal_get_binary_size(length, decimals); break; @@ -9360,11 +9349,11 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_GEOMETRY: - if (fld_default_value) + if (def) { /* Allow empty as default value. */ String str,*res; - res= fld_default_value->val_str(&str); + res= def->val_str(&str); /* A default other than '' is always an error, and any non-NULL specified default is an error in strict mode. @@ -9372,7 +9361,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, if (res->length() || thd->is_strict_mode()) { my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), - fld_name); /* purecov: inspected */ + field_name); /* purecov: inspected */ DBUG_RETURN(TRUE); } else @@ -9383,39 +9372,21 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_BLOB_CANT_HAVE_DEFAULT, ER(ER_BLOB_CANT_HAVE_DEFAULT), - fld_name); + field_name); } def= 0; } flags|= BLOB_FLAG; break; case MYSQL_TYPE_YEAR: - if (!fld_length || length != 2) + if (!length || length != 2) length= 4; /* Default length */ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; break; case MYSQL_TYPE_FLOAT: /* change FLOAT(precision) to FLOAT or DOUBLE */ allowed_type_modifier= AUTO_INCREMENT_FLAG; - if (fld_length && !fld_decimals) - { - uint tmp_length= length; - if (tmp_length > PRECISION_FOR_DOUBLE) - { - my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name); - DBUG_RETURN(TRUE); - } - else if (tmp_length > PRECISION_FOR_FLOAT) - { - sql_type= MYSQL_TYPE_DOUBLE; - length= MAX_DOUBLE_STR_LENGTH; - } - else - length= MAX_FLOAT_STR_LENGTH; - decimals= NOT_FIXED_DEC; - break; - } - if (!fld_length && !fld_decimals) + if (!length && !decimals) { length= MAX_FLOAT_STR_LENGTH; decimals= NOT_FIXED_DEC; @@ -9423,13 +9394,13 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, if (length < decimals && decimals != NOT_FIXED_DEC) { - my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name); + my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name); DBUG_RETURN(TRUE); } break; case MYSQL_TYPE_DOUBLE: allowed_type_modifier= AUTO_INCREMENT_FLAG; - if (!fld_length && !fld_decimals) + if (!length && !decimals) { length= DBL_DIG+7; decimals= NOT_FIXED_DEC; @@ -9437,7 +9408,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, if (length < decimals && decimals != NOT_FIXED_DEC) { - my_error(ER_M_BIGGER_THAN_D, MYF(0), fld_name); + my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name); DBUG_RETURN(TRUE); } break; @@ -9445,7 +9416,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, case MYSQL_TYPE_TIMESTAMP2: if (length > MAX_DATETIME_PRECISION) { - my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name, + my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name, MAX_DATETIME_PRECISION); DBUG_RETURN(TRUE); } @@ -9463,7 +9434,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, case MYSQL_TYPE_TIME2: if (length > MAX_DATETIME_PRECISION) { - my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name, + my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name, MAX_DATETIME_PRECISION); DBUG_RETURN(TRUE); } @@ -9473,50 +9444,29 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, case MYSQL_TYPE_DATETIME2: if (length > MAX_DATETIME_PRECISION) { - my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name, + my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name, MAX_DATETIME_PRECISION); DBUG_RETURN(TRUE); } length+= MAX_DATETIME_WIDTH + (length ? 1 : 0); break; case MYSQL_TYPE_SET: - { - pack_length= get_set_pack_length(fld_interval_list->elements); - - List_iterator<String> it(*fld_interval_list); - String *tmp; - while ((tmp= it++)) - interval_list.push_back(tmp); - /* - Set fake length to 1 to pass the below conditions. - Real length will be set in mysql_prepare_table() - when we know the character set of the column - */ - length= 1; - break; - } + pack_length= get_set_pack_length(interval_list.elements); + break; case MYSQL_TYPE_ENUM: - { - /* Should be safe. */ - pack_length= get_enum_pack_length(fld_interval_list->elements); - - List_iterator<String> it(*fld_interval_list); - String *tmp; - while ((tmp= it++)) - interval_list.push_back(tmp); - length= 1; /* See comment for MYSQL_TYPE_SET above. */ - break; - } + /* Should be safe. */ + pack_length= get_enum_pack_length(interval_list.elements); + break; case MYSQL_TYPE_VAR_STRING: DBUG_ASSERT(0); /* Impossible. */ break; case MYSQL_TYPE_BIT: { - if (!fld_length) + if (!length) length= 1; if (length > MAX_BIT_FIELD_LENGTH) { - my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name, + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name, static_cast<ulong>(MAX_BIT_FIELD_LENGTH)); DBUG_RETURN(TRUE); } @@ -9525,37 +9475,35 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, } case MYSQL_TYPE_DECIMAL: DBUG_ASSERT(0); /* Was obsolete */ - } + } /* Remember the value of length */ char_length= length; if (!(flags & BLOB_FLAG) && - ((length > max_field_charlength && fld_type != MYSQL_TYPE_SET && - fld_type != MYSQL_TYPE_ENUM && - (fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) || - ((length == 0) && - fld_type != MYSQL_TYPE_STRING && - fld_type != MYSQL_TYPE_VARCHAR && fld_type != MYSQL_TYPE_GEOMETRY))) - { - my_error((fld_type == MYSQL_TYPE_VAR_STRING || - fld_type == MYSQL_TYPE_VARCHAR || - fld_type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH : + ((length > max_field_charlength && + (sql_type != MYSQL_TYPE_VARCHAR || def)) || + (length == 0 && + sql_type != MYSQL_TYPE_ENUM && sql_type != MYSQL_TYPE_SET && + sql_type != MYSQL_TYPE_STRING && sql_type != MYSQL_TYPE_VARCHAR && + sql_type != MYSQL_TYPE_GEOMETRY))) + { + my_error((sql_type == MYSQL_TYPE_VAR_STRING || + sql_type == MYSQL_TYPE_VARCHAR || + sql_type == MYSQL_TYPE_STRING) ? ER_TOO_BIG_FIELDLENGTH : ER_TOO_BIG_DISPLAYWIDTH, MYF(0), - fld_name, max_field_charlength); /* purecov: inspected */ + field_name, max_field_charlength); /* purecov: inspected */ DBUG_RETURN(TRUE); } - fld_type_modifier&= AUTO_INCREMENT_FLAG; - if ((~allowed_type_modifier) & fld_type_modifier) + if ((~allowed_type_modifier) & flags & conditional_type_modifiers) { - my_error(ER_WRONG_FIELD_SPEC, MYF(0), fld_name); + my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name); DBUG_RETURN(TRUE); } DBUG_RETURN(FALSE); /* success */ } - enum_field_types get_blob_type_from_length(ulong length) { enum_field_types type; |