diff options
author | unknown <monty@mysql.com> | 2005-04-01 15:04:50 +0300 |
---|---|---|
committer | unknown <monty@mysql.com> | 2005-04-01 15:04:50 +0300 |
commit | db7561ecf8b703e285320f2e0fcec7daf72ca9d6 (patch) | |
tree | 7920c948db7d0f2174fb24ba26cd648144fa4850 /sql | |
parent | 750180d2998cc7d04e4a0fb4ccec8b5214c3f145 (diff) | |
download | mariadb-git-db7561ecf8b703e285320f2e0fcec7daf72ca9d6.tar.gz |
Invalid DEFAULT values for CREATE TABLE now generates errors. (Bug #5902)
CAST() now produces warnings when casting a wrong INTEGER or CHAR values. This also applies to implicite string to number casts. (Bug #5912)
ALTER TABLE now fails in STRICT mode if it generates warnings.
Inserting a zero date in a DATE, DATETIME or TIMESTAMP column during TRADITIONAL mode now produces an error. (Bug #5933)
mysql-test/r/bigint.result:
New warning added
mysql-test/r/cast.result:
Added testing of wrong CAST's of strings to numbers and numbers to strings
mysql-test/r/create.result:
Added test for wrong default values (#5902)
mysql-test/r/func_if.result:
Changed tests to produce less warnings
mysql-test/r/func_misc.result:
New warning
mysql-test/r/func_str.result:
Added missing drop table
Changed test to produce less warnings
New warnings
mysql-test/r/ndb_index_unique.result:
Removed wrong default usage
mysql-test/r/ps_1general.result:
Changed tests to produce less warnings
mysql-test/r/row.result:
New warnings
mysql-test/r/rpl_session_var.result:
Changed tests to produce less warnings
mysql-test/r/strict.result:
New tests for CAST() and zero date handling
mysql-test/r/subselect.result:
Changed tests to produce less warnings
mysql-test/r/type_ranges.result:
Changed tests to produce less warnings
mysql-test/t/cast.test:
Added testing of wrong CAST's of strings to numbers and numbers to strings
mysql-test/t/create.test:
Added test for wrong default values (#5902)
mysql-test/t/func_if.test:
Changed tests to produce less warnings
mysql-test/t/func_str.test:
Added missing drop table
Changed test to produce less warnings
New warnings
mysql-test/t/ndb_index_unique.test:
Removed wrong default usage
mysql-test/t/ps_1general.test:
Changed tests to produce less warnings
mysql-test/t/rpl_session_var.test:
Changed tests to produce less warnings
mysql-test/t/strict.test:
New tests for CAST() and zero date handling
mysql-test/t/subselect.test:
Changed tests to produce less warnings
mysql-test/t/type_ranges.test:
Changed tests to produce less warnings
sql/Makefile.am:
Added new include file
sql/field.cc:
Added warnings for zero dates for DATE, DATETIME and TIMESTAMP
Moved Field_blob::max_length() to a more appropriate position
Changed type for 'level' in set_warning() to avoid casts
sql/field.h:
Changed type for 'level' in set_warning() to avoid casts
sql/field_conv.cc:
Copy date and datetime fields through string in 'traditional' mode to detect zero dates
sql/item.cc:
Removed compiler warnings
Give warnings for wrong CAST of strings -> number
sql/item.h:
Moved Item_string::val_real() and ::val_int() to item.cc
sql/item_row.cc:
Better detection of null values (which doesn't produce warnings)
sql/item_sum.cc:
Better detection of null values (which doesn't produce warnings)
sql/item_timefunc.cc:
Give warnings for wrong CAST of number -> string
sql/my_decimal.cc:
Fixed typo in comment
sql/mysql_priv.h:
Removed prototype for static function
Moved defines for error handling to sql_error.h (to be able to use these in field.h)
sql/mysqld.cc:
Simplify code
sql/sql_class.h:
Moved to sql_error.h
sql/sql_load.cc:
Removed wrong cast
sql/sql_parse.cc:
Fixed wrong printf()
sql/sql_table.cc:
Made mysql_prepare_table() static
Changed references to pointers to make code more readable
ALTER TABLE now aborts if one gets warnings in STRICT mode
sql/time.cc:
Fixed possible wrong call
sql/unireg.cc:
Removed one call to current_thd
Give errors if one uses a wrong DEFAULT value
Diffstat (limited to 'sql')
-rw-r--r-- | sql/Makefile.am | 2 | ||||
-rw-r--r-- | sql/field.cc | 150 | ||||
-rw-r--r-- | sql/field.h | 8 | ||||
-rw-r--r-- | sql/field_conv.cc | 16 | ||||
-rw-r--r-- | sql/item.cc | 60 | ||||
-rw-r--r-- | sql/item.h | 17 | ||||
-rw-r--r-- | sql/item_row.cc | 4 | ||||
-rw-r--r-- | sql/item_sum.cc | 3 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 36 | ||||
-rw-r--r-- | sql/my_decimal.cc | 2 | ||||
-rw-r--r-- | sql/mysql_priv.h | 15 | ||||
-rw-r--r-- | sql/mysqld.cc | 4 | ||||
-rw-r--r-- | sql/sql_class.h | 21 | ||||
-rw-r--r-- | sql/sql_error.h | 42 | ||||
-rw-r--r-- | sql/sql_load.cc | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 7 | ||||
-rw-r--r-- | sql/sql_table.cc | 62 | ||||
-rw-r--r-- | sql/time.cc | 6 | ||||
-rw-r--r-- | sql/unireg.cc | 22 |
19 files changed, 310 insertions, 169 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am index e0ff324b33c..b506d2a767b 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -49,7 +49,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ mysql_priv.h item_geofunc.h sql_bitmap.h \ procedure.h sql_class.h sql_lex.h sql_list.h \ sql_manager.h sql_map.h sql_string.h unireg.h \ - field.h handler.h mysqld_suffix.h \ + sql_error.h field.h handler.h mysqld_suffix.h \ ha_myisammrg.h\ ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \ ha_ndbcluster.h opt_range.h protocol.h \ diff --git a/sql/field.cc b/sql/field.cc index 7850daac8c7..36a703a1b7a 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3735,6 +3735,13 @@ int Field_timestamp::store(longlong nr) set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATETIME, 1); + if (!error && timestamp == 0 && + (table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE)) + { + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_DATA_TRUNCATED, + nr, MYSQL_TIMESTAMP_DATETIME, 1); + } #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) @@ -4360,6 +4367,12 @@ int Field_date::store(double nr) } else tmp=(long) rint(nr); + + /* + We don't need to check for zero dates here as this date type is only + used in .frm tables from very old MySQL versions + */ + #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) { @@ -4388,6 +4401,7 @@ int Field_date::store(longlong nr) } else tmp=(long) nr; + #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) { @@ -4500,6 +4514,7 @@ void Field_date::sql_type(String &res) const res.set_ascii("date", 4); } + /**************************************************************************** ** The new date type ** This is identical to the old date type, but stored on 3 bytes instead of 4 @@ -4532,17 +4547,17 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) return error; } + int Field_newdate::store(double nr) { if (nr < 0.0 || nr > 99991231235959.0) { - (void) Field_newdate::store((longlong) -1); + int3store(ptr,(int32) 0); set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE); return 1; } - else - return Field_newdate::store((longlong) rint(nr)); + return Field_newdate::store((longlong) rint(nr)); } @@ -4562,6 +4577,8 @@ int Field_newdate::store(longlong nr) } else { + uint month, day; + tmp=(int32) nr; if (tmp) { @@ -4569,24 +4586,33 @@ int Field_newdate::store(longlong nr) tmp+= (uint32) 20000000L; else if (tmp < 999999L) tmp+= (uint32) 19000000L; + + month= (uint) ((tmp/100) % 100); + day= (uint) (tmp%100); + if (month > 12 || day > 31) + { + tmp=0L; // Don't allow date to change + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DATA_OUT_OF_RANGE, nr, + MYSQL_TIMESTAMP_DATE, 1); + error= 1; + } + else + tmp= day + month*32 + (tmp/10000)*16*32; } - uint month= (uint) ((tmp/100) % 100); - uint day= (uint) (tmp%100); - if (month > 12 || day > 31) + else if (table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE) { - tmp=0L; // Don't allow date to change set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_DATA_OUT_OF_RANGE, nr, - MYSQL_TIMESTAMP_DATE, 1); + ER_WARN_DATA_OUT_OF_RANGE, + 0, MYSQL_TIMESTAMP_DATE); error= 1; } - else - tmp= day + month*32 + (tmp/10000)*16*32; } - int3store(ptr,(int32) tmp); + int3store(ptr, tmp); return error; } + int Field_newdate::store_time(TIME *ltime,timestamp_type type) { long tmp; @@ -4603,6 +4629,7 @@ int Field_newdate::store_time(TIME *ltime,timestamp_type type) return error; } + bool Field_newdate::send_binary(Protocol *protocol) { TIME tm; @@ -4610,11 +4637,13 @@ bool Field_newdate::send_binary(Protocol *protocol) return protocol->store_date(&tm); } + double Field_newdate::val_real(void) { return (double) Field_newdate::val_int(); } + longlong Field_newdate::val_int(void) { ulong j= uint3korr(ptr); @@ -4622,6 +4651,7 @@ longlong Field_newdate::val_int(void) return (longlong) j; } + String *Field_newdate::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { @@ -4649,6 +4679,7 @@ String *Field_newdate::val_str(String *val_buffer, return val_buffer; } + bool Field_newdate::get_date(TIME *ltime,uint fuzzydate) { uint32 tmp=(uint32) uint3korr(ptr); @@ -4661,11 +4692,13 @@ bool Field_newdate::get_date(TIME *ltime,uint fuzzydate) 1 : 0); } + bool Field_newdate::get_time(TIME *ltime) { return Field_newdate::get_date(ltime,0); } + int Field_newdate::cmp(const char *a_ptr, const char *b_ptr) { uint32 a,b; @@ -4674,6 +4707,7 @@ int Field_newdate::cmp(const char *a_ptr, const char *b_ptr) return (a < b) ? -1 : (a > b) ? 1 : 0; } + void Field_newdate::sort_string(char *to,uint length __attribute__((unused))) { to[0] = ptr[2]; @@ -4681,6 +4715,7 @@ void Field_newdate::sort_string(char *to,uint length __attribute__((unused))) to[2] = ptr[0]; } + void Field_newdate::sql_type(String &res) const { res.set_ascii("date", 4); @@ -4737,10 +4772,10 @@ int Field_datetime::store(double nr) set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_DATETIME); - nr=0.0; + nr= 0.0; error= 1; } - error |= Field_datetime::store((longlong) rint(nr)); + error|= Field_datetime::store((longlong) rint(nr)); return error; } @@ -4757,6 +4792,13 @@ int Field_datetime::store(longlong nr) set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, initial_nr, MYSQL_TIMESTAMP_DATETIME, 1); + else if (nr == 0 && table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE) + { + set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DATA_OUT_OF_RANGE, + initial_nr, MYSQL_TIMESTAMP_DATE); + error= 1; + } #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) @@ -7542,7 +7584,37 @@ create_field::create_field(Field *old_field,Field *orig_field) } -/* Warning handling */ +/* + maximum possible display length for blob + + SYNOPSIS + Field_blob::max_length() + + RETURN + length +*/ +uint32 Field_blob::max_length() +{ + switch (packlength) + { + case 1: + return 255; + case 2: + return 65535; + case 3: + return 16777215; + case 4: + return (uint32) 4294967295U; + default: + DBUG_ASSERT(0); // we should never go here + return 0; + } +} + + +/***************************************************************************** + Warning handling +*****************************************************************************/ /* Produce warning or note about data saved into field @@ -7558,18 +7630,20 @@ create_field::create_field(Field *old_field,Field *orig_field) if count_cuted_fields == FIELD_CHECK_IGNORE for current thread. RETURN VALUE - true - if count_cuted_fields == FIELD_CHECK_IGNORE - false - otherwise + 1 if count_cuted_fields == FIELD_CHECK_IGNORE + 0 otherwise */ + bool -Field::set_warning(uint level, uint code, int cuted_increment) +Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code, + int cuted_increment) { THD *thd= table->in_use; if (thd->count_cuted_fields) { thd->cuted_fields+= cuted_increment; - push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level) level, - code, ER(code), field_name, thd->row_count); + push_warning_printf(thd, level, code, ER(code), field_name, + thd->row_count); return 0; } return 1; @@ -7593,8 +7667,9 @@ Field::set_warning(uint level, uint code, int cuted_increment) fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current thread. */ + void -Field::set_datetime_warning(const uint level, const uint code, +Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, const char *str, uint str_length, timestamp_type ts_type, int cuted_increment) { @@ -7621,8 +7696,9 @@ Field::set_datetime_warning(const uint level, const uint code, fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current thread. */ + void -Field::set_datetime_warning(const uint level, const uint code, +Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, longlong nr, timestamp_type ts_type, int cuted_increment) { @@ -7652,8 +7728,9 @@ Field::set_datetime_warning(const uint level, const uint code, fields counter if count_cuted_fields == FIELD_CHECK_IGNORE for current thread. */ + void -Field::set_datetime_warning(const uint level, const uint code, +Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, double nr, timestamp_type ts_type) { if (table->in_use->really_abort_on_warning() || @@ -7666,30 +7743,3 @@ Field::set_datetime_warning(const uint level, const uint code, field_name); } } - -/* - maximum possible display length for blob - - SYNOPSIS - Field_blob::max_length() - - RETURN - length -*/ -uint32 Field_blob::max_length() -{ - switch (packlength) - { - case 1: - return 255; - case 2: - return 65535; - case 3: - return 16777215; - case 4: - return (uint32) 4294967295U; - default: - DBUG_ASSERT(0); // we should never go here - return 0; - } -} diff --git a/sql/field.h b/sql/field.h index 16fa4a58d0c..399992bee64 100644 --- a/sql/field.h +++ b/sql/field.h @@ -279,17 +279,17 @@ public: virtual CHARSET_INFO *sort_charset(void) const { return charset(); } virtual bool has_charset(void) const { return FALSE; } virtual void set_charset(CHARSET_INFO *charset) { } - bool set_warning(unsigned int level, unsigned int code, + bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code, int cuted_increment); bool check_int(const char *str, int length, const char *int_end, CHARSET_INFO *cs); - void set_datetime_warning(const uint level, const uint code, + void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code, const char *str, uint str_len, timestamp_type ts_type, int cuted_increment); - void set_datetime_warning(const uint level, const uint code, + void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code, longlong nr, timestamp_type ts_type, int cuted_increment); - void set_datetime_warning(const uint level, const uint code, + void set_datetime_warning(MYSQL_ERROR::enum_warning_level, const uint code, double nr, timestamp_type ts_type); inline bool check_overflow(int op_result) { diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 57161a7063e..bbdd6619bf3 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -508,8 +508,16 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) // Check if identical fields if (from->result_type() == STRING_RESULT) { + /* + If we are copying date or datetime's we have to check the dates + if we don't allow 'all' dates. +p */ if (to->real_type() != from->real_type() || - !compatible_db_low_byte_first) + !compatible_db_low_byte_first || + ((to->table->in_use->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) && + to->type() == FIELD_TYPE_DATE || + to->type() == FIELD_TYPE_DATETIME)) { if (from->real_type() == FIELD_TYPE_ENUM || from->real_type() == FIELD_TYPE_SET) @@ -590,7 +598,11 @@ void field_conv(Field *to,Field *from) (to->field_length == from->field_length && (((Field_num*)to)->dec == ((Field_num*)from)->dec))) && from->charset() == to->charset() && - to->table->s->db_low_byte_first == from->table->s->db_low_byte_first) + to->table->s->db_low_byte_first == from->table->s->db_low_byte_first && + (!(to->table->in_use->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) || + to->type() != FIELD_TYPE_DATE && + to->type() != FIELD_TYPE_DATETIME)) { // Identical fields memcpy(to->ptr,from->ptr,to->pack_length()); return; diff --git a/sql/item.cc b/sql/item.cc index 457aa774352..2d8fb98c670 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -46,7 +46,7 @@ void Hybrid_type_traits::fix_length_and_dec(Item *item, Item *arg) const const Hybrid_type_traits *Hybrid_type_traits::instance() { - const static Hybrid_type_traits real_traits; + static const Hybrid_type_traits real_traits; return &real_traits; } @@ -70,7 +70,7 @@ Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const const Hybrid_type_traits_decimal *Hybrid_type_traits_decimal::instance() { - const static Hybrid_type_traits_decimal decimal_traits; + static const Hybrid_type_traits_decimal decimal_traits; return &decimal_traits; } @@ -146,7 +146,7 @@ Hybrid_type_traits_decimal::val_str(Hybrid_type *val, String *to, const Hybrid_type_traits_integer *Hybrid_type_traits_integer::instance() { - const static Hybrid_type_traits_integer integer_traits; + static const Hybrid_type_traits_integer integer_traits; return &integer_traits; } @@ -1455,6 +1455,60 @@ void Item_string::print(String *str) } +inline bool check_if_only_end_space(CHARSET_INFO *cs, char *str, char *end) +{ + return str+ cs->cset->scan(cs, str, end, MY_SEQ_SPACES) == end; +} + + +double Item_string::val_real() +{ + DBUG_ASSERT(fixed == 1); + int error; + char *end, *org_end; + double tmp; + CHARSET_INFO *cs= str_value.charset(); + + org_end= (char*) str_value.ptr() + str_value.length(); + tmp= my_strntod(cs, (char*) str_value.ptr(), str_value.length(), &end, + &error); + if (error || (end != org_end && !check_if_only_end_space(cs, end, org_end))) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), "DOUBLE", + str_value.ptr()); + } + return tmp; +} + + +longlong Item_string::val_int() +{ + DBUG_ASSERT(fixed == 1); + int err; + longlong tmp; + char *end= (char*) str_value.ptr()+ str_value.length(); + char *org_end= end; + CHARSET_INFO *cs= str_value.charset(); + + tmp= (*(cs->cset->my_strtoll10))(cs, str_value.ptr(), &end, &err); + /* + TODO: Give error if we wanted a signed integer and we got an unsigned + one + */ + if (err > 0 || + (end != org_end && !check_if_only_end_space(cs, end, org_end))) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER", + str_value.ptr()); + } + return tmp; +} + + my_decimal *Item_string::val_decimal(my_decimal *decimal_value) { /* following assert is redundant, because fixed=1 assigned in constructor */ diff --git a/sql/item.h b/sql/item.h index 55c9af356a8..83b10a0940a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1097,21 +1097,8 @@ public: fixed= 1; } enum Type type() const { return STRING_ITEM; } - double val_real() - { - DBUG_ASSERT(fixed == 1); - int err_not_used; - char *end_not_used; - return my_strntod(str_value.charset(), (char*) str_value.ptr(), - str_value.length(), &end_not_used, &err_not_used); - } - longlong val_int() - { - DBUG_ASSERT(fixed == 1); - int err; - return my_strntoll(str_value.charset(), str_value.ptr(), - str_value.length(), 10, (char**) 0, &err); - } + double val_real(); + longlong val_int(); String *val_str(String*) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_row.cc b/sql/item_row.cc index 00d849e55de..0c8baa332ca 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -73,8 +73,8 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) with_null|= item->null_inside(); else { - item->val_int(); - with_null|= item->null_value; + if (item->is_null()) + with_null|= 1; } } maybe_null|= item->maybe_null; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 3dbc3833f9e..66b64128dab 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2966,8 +2966,7 @@ bool Item_func_group_concat::setup(THD *thd) DBUG_RETURN(TRUE); if (item->const_item()) { - (void) item->val_int(); - if (item->null_value) + if (item->is_null()) { always_null= 1; DBUG_RETURN(FALSE); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index c603d41fa2e..1ea20e9d7cc 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2181,39 +2181,47 @@ String *Item_char_typecast::val_str(String *str) res->set_charset(cast_cs); /* - Cut the tail if cast with length - and the result is longer than cast length, e.g. - CAST('string' AS CHAR(1)) + Cut the tail if cast with length + and the result is longer than cast length, e.g. + CAST('string' AS CHAR(1)) */ if (cast_length >= 0 && (res->length() > (length= (uint32) res->charpos(cast_length)))) { // Safe even if const arg + char char_type[40]; + my_snprintf(char_type, sizeof(char_type), "CHAR(%lu)", length); + if (!res->alloced_length()) { // Don't change const str str_value= *res; // Not malloced string res= &str_value; } + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), char_type, + res->c_ptr()); res->length((uint) length); } null_value= 0; return res; } + void Item_char_typecast::fix_length_and_dec() { uint32 char_length; - /* - We always force character set conversion if cast_cs - is a multi-byte character set. It garantees that the - result of CAST is a well-formed string. - For single-byte character sets we allow just to copy - from the argument. A single-byte character sets string - is always well-formed. + /* + We always force character set conversion if cast_cs is a + multi-byte character set. It garantees that the result of CAST is + a well-formed string. For single-byte character sets we allow + just to copy from the argument. A single-byte character sets + string is always well-formed. */ - charset_conversion= (cast_cs->mbmaxlen > 1) || - !my_charset_same(args[0]->collation.collation, cast_cs) && - args[0]->collation.collation != &my_charset_bin && - cast_cs != &my_charset_bin; + charset_conversion= ((cast_cs->mbmaxlen > 1) || + !my_charset_same(args[0]->collation.collation, + cast_cs) && + args[0]->collation.collation != &my_charset_bin && + cast_cs != &my_charset_bin); collation.set(cast_cs, DERIVATION_IMPLICIT); char_length= (cast_length >= 0) ? cast_length : args[0]->max_length/args[0]->collation.collation->mbmaxlen; diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 19b6abd7243..b4bbef4a637 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -175,7 +175,7 @@ int str2my_decimal(uint mask, const char *from, uint length, err= string2decimal((char *)from, (decimal_t*) decimal_value, &end); if (end != from_end && !err) { - /* Give warining if there is something other than end space */ + /* Give warning if there is something other than end space */ for ( ; end < from_end; end++) { if (!my_isspace(&my_charset_latin1, *end)) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7e4c6675e45..a594846933c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -442,7 +442,6 @@ extern ulong server_id, concurrency; typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, uint key_length, ulonglong *engine_data); - #include "sql_string.h" #include "sql_list.h" #include "sql_map.h" @@ -450,6 +449,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, #include "handler.h" #include "parse_file.h" #include "table.h" +#include "sql_error.h" #include "field.h" /* Field definitions */ #include "protocol.h" #include "sql_udf.h" @@ -651,11 +651,6 @@ int prepare_create_field(create_field *sql_field, uint *blob_columns, int *timestamps, int *timestamps_with_niladic, uint table_flags); -int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, - List<create_field> &fields, - List<Key> &keys, uint &db_options, - handler *file, KEY *&key_info_buffer, - uint &key_count, int select_field_count); bool mysql_create_table(THD *thd,const char *db, const char *table_name, HA_CREATE_INFO *create_info, List<create_field> &fields, List<Key> &keys, @@ -830,14 +825,6 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length); void reset_stmt_for_execute(THD *thd, LEX *lex); void init_stmt_after_parse(THD*, LEX*); -/* sql_error.cc */ -MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code, - const char *msg); -void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level, - uint code, const char *format, ...); -void mysql_reset_errors(THD *thd, bool force); -bool mysqld_show_warnings(THD *thd, ulong levels_to_show); - /* sql_handler.cc */ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen); bool mysql_ha_close(THD *thd, TABLE_LIST *tables); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 95de170b99d..e1303585114 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1036,8 +1036,8 @@ void clean_up(bool print_message) (void) my_delete(pidfile_name,MYF(0)); // This may not always exist #endif finish_client_errs(); - const char **errmsgs= my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST); - x_free((gptr) errmsgs); /* Free messages */ + my_free((gptr) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST), + MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); DBUG_PRINT("quit", ("Error messages freed")); /* Tell main we are ready */ (void) pthread_mutex_lock(&LOCK_thread_count); diff --git a/sql/sql_class.h b/sql/sql_class.h index 6d6ac810fbf..bd9154f7b01 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -482,27 +482,6 @@ public: }; -class MYSQL_ERROR: public Sql_alloc -{ -public: - enum enum_warning_level - { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; - - uint code; - enum_warning_level level; - char *msg; - - MYSQL_ERROR(THD *thd, uint code_arg, enum_warning_level level_arg, - const char *msg_arg) - :code(code_arg), level(level_arg) - { - if (msg_arg) - set_msg(thd, msg_arg); - } - void set_msg(THD *thd, const char *msg_arg); -}; - - class delayed_insert; class select_result; diff --git a/sql/sql_error.h b/sql/sql_error.h new file mode 100644 index 00000000000..223b50be744 --- /dev/null +++ b/sql/sql_error.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +class MYSQL_ERROR: public Sql_alloc +{ +public: + enum enum_warning_level + { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; + + uint code; + enum_warning_level level; + char *msg; + + MYSQL_ERROR(THD *thd, uint code_arg, enum_warning_level level_arg, + const char *msg_arg) + :code(code_arg), level(level_arg) + { + if (msg_arg) + set_msg(thd, msg_arg); + } + void set_msg(THD *thd, const char *msg_arg); +}; + +MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, + uint code, const char *msg); +void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level, + uint code, const char *format, ...); +void mysql_reset_errors(THD *thd, bool force); +bool mysqld_show_warnings(THD *thd, ulong levels_to_show); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index a0fed715405..c827bbace3e 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -671,7 +671,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, if (field->type() == FIELD_TYPE_TIMESTAMP) ((Field_timestamp*) field)->set_time(); else if (field != table->next_number_field) - field->set_warning((uint) MYSQL_ERROR::WARN_LEVEL_WARN, + field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_NULL_TO_NOTNULL, 1); } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ccd3277d785..e051788ad39 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1910,10 +1910,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #endif ulong uptime = (ulong) (thd->start_time - start_time); sprintf((char*) buff, - "Uptime: %ld Threads: %d Questions: %lu Slow queries: %ld Opens: %ld Flush tables: %ld Open tables: %u Queries per second avg: %.3f", + "Uptime: %ld Threads: %d Questions: %lu Slow queries: %lu Opens: %ld Flush tables: %ld Open tables: %u Queries per second avg: %.3f", uptime, - (int) thread_count,thd->query_id,thd->status_var.long_query_count, - thd->status_var.opened_tables,refresh_version, cached_tables(), + (int) thread_count, (ulong) thd->query_id, + (ulong) thd->status_var.long_query_count, + thd->status_var.opened_tables, refresh_version, cached_tables(), uptime ? (float)thd->query_id/(float)uptime : 0); #ifdef SAFEMALLOC if (sf_malloc_cur_memory) // Using SAFEMALLOC diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b125eeaf03a..7f5c3a52017 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -620,11 +620,12 @@ int prepare_create_field(create_field *sql_field, -1 error */ -int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, - List<create_field> &fields, - List<Key> &keys, bool tmp_table, uint &db_options, - handler *file, KEY *&key_info_buffer, - uint *key_count, int select_field_count) +static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, + List<create_field> *fields, + List<Key> *keys, bool tmp_table, + uint *db_options, + handler *file, KEY **key_info_buffer, + uint *key_count, int select_field_count) { const char *key_name; create_field *sql_field,*dup_field; @@ -636,11 +637,11 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, int timestamps= 0, timestamps_with_niladic= 0; int field_no,dup_no; int select_field_pos,auto_increment=0; - List_iterator<create_field> it(fields),it2(fields); + List_iterator<create_field> it(*fields),it2(*fields); uint total_uneven_bit_length= 0; DBUG_ENTER("mysql_prepare_table"); - select_field_pos=fields.elements - select_field_count; + select_field_pos= fields->elements - select_field_count; null_fields=blob_columns=0; create_info->varchar= 0; @@ -845,11 +846,11 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, if ((sql_field->flags & BLOB_FLAG) || sql_field->sql_type == MYSQL_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED) - db_options|= HA_OPTION_PACK_RECORD; + (*db_options)|= HA_OPTION_PACK_RECORD; it2.rewind(); } /* If fixed row records, we need one bit to check for deleted rows */ - if (!(db_options & HA_OPTION_PACK_RECORD)) + if (!((*db_options) & HA_OPTION_PACK_RECORD)) null_fields++; pos= (null_fields + total_uneven_bit_length + 7) / 8; @@ -897,7 +898,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, /* Create keys */ - List_iterator<Key> key_iterator(keys), key_iterator2(keys); + List_iterator<Key> key_iterator(*keys), key_iterator2(*keys); uint key_parts=0, fk_key_count=0; bool primary_key=0,unique_key=0; Key *key, *key2; @@ -984,9 +985,9 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(-1); } - key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)* *key_count); + (*key_info_buffer) = key_info= (KEY*) sql_calloc(sizeof(KEY)* *key_count); key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts); - if (!key_info_buffer || ! key_part_info) + if (!*key_info_buffer || ! key_part_info) DBUG_RETURN(-1); // Out of memory key_iterator.rewind(); @@ -1260,7 +1261,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, } key_part_info->length=(uint16) length; /* Use packed keys for long strings on the first column */ - if (!(db_options & HA_OPTION_NO_PACK_KEYS) && + if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) && (length >= KEY_DEFAULT_PACK_LENGTH && (sql_field->sql_type == MYSQL_TYPE_STRING || sql_field->sql_type == MYSQL_TYPE_VARCHAR || @@ -1291,8 +1292,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, } else if (!(key_name = key->name)) key_name=make_unique_key_name(sql_field->field_name, - key_info_buffer,key_info); - if (check_if_keyname_exists(key_name,key_info_buffer,key_info)) + *key_info_buffer, key_info); + if (check_if_keyname_exists(key_name, *key_info_buffer, key_info)) { my_error(ER_DUP_KEYNAME, MYF(0), key_name); DBUG_RETURN(-1); @@ -1327,7 +1328,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(-1); } /* Sort keys in optimized order */ - qsort((gptr) key_info_buffer, *key_count, sizeof(KEY), + qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY), (qsort_cmp) sort_keys); DBUG_RETURN(0); @@ -1393,7 +1394,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, ha_get_storage_engine(new_db_type), table_name); } - db_options=create_info->table_options; + db_options= create_info->table_options; if (create_info->row_type == ROW_TYPE_DYNAMIC) db_options|=HA_OPTION_PACK_RECORD; alias= table_case_name(create_info, table_name); @@ -1432,9 +1433,9 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, create_info->default_table_charset= db_info.default_table_charset; } - if (mysql_prepare_table(thd, create_info, fields, - keys, internal_tmp_table, db_options, file, - key_info_buffer, &key_count, + if (mysql_prepare_table(thd, create_info, &fields, + &keys, internal_tmp_table, &db_options, file, + &key_info_buffer, &key_count, select_field_count)) DBUG_RETURN(TRUE); @@ -2706,9 +2707,9 @@ int mysql_create_indexes(THD *thd, TABLE_LIST *table_list, List<Key> &keys) create_info.db_type=DB_TYPE_DEFAULT; create_info.default_table_charset= thd->variables.collation_database; db_options= 0; - if (mysql_prepare_table(thd, &create_info, fields, - keys, /*tmp_table*/ 0, db_options, table->file, - key_info_buffer, key_count, + if (mysql_prepare_table(thd, &create_info, &fields, + &keys, /*tmp_table*/ 0, &db_options, table->file, + &key_info_buffer, key_count, /*select_field_count*/ 0)) DBUG_RETURN(-1); @@ -2839,9 +2840,9 @@ int mysql_drop_indexes(THD *thd, TABLE_LIST *table_list, { db_options= 0; if (table->file->drop_index(table, key_numbers, key_count)|| - mysql_prepare_table(thd, &create_info, fields, - keys, /*tmp_table*/ 0, db_options, table->file, - key_info_buffer, key_count, + mysql_prepare_table(thd, &create_info, &fields, + &keys, /*tmp_table*/ 0, &db_options, table->file, + &key_info_buffer, key_count, /*select_field_count*/ 0)|| (snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home, table_list->db, (lower_case_table_names == 2)? @@ -3666,6 +3667,13 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (to->file->external_lock(thd, F_WRLCK)) DBUG_RETURN(-1); + + /* We can abort alter table for any table type */ + thd->no_trans_update= 0; + thd->abort_on_warning= !ignore && test(thd->variables.sql_mode & + (MODE_STRICT_TRANS_TABLES | + MODE_STRICT_ALL_TABLES)); + from->file->info(HA_STATUS_VARIABLE); to->file->start_bulk_insert(from->file->records); @@ -3745,6 +3753,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, else to->next_number_field->reset(); } + for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++) { copy_ptr->do_copy(copy_ptr); @@ -3789,6 +3798,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, err: thd->variables.sql_mode= save_sql_mode; + thd->abort_on_warning= 0; free_io_cache(from); *copied= found_count; *deleted=delete_count; diff --git a/sql/time.cc b/sql/time.cc index f1d21915c23..52a2ae13892 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -712,9 +712,9 @@ void make_truncated_value_warning(THD *thd, const char *str_val, else cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), ER(ER_TRUNCATED_WRONG_VALUE), - type_str, str.ptr()); - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE, warn_buff); + type_str, str.c_ptr()); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, warn_buff); } diff --git a/sql/unireg.cc b/sql/unireg.cc index 3e85767dc86..57e2c1029f1 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -40,7 +40,7 @@ static bool pack_header(uchar *forminfo,enum db_type table_type, static uint get_interval_id(uint *int_count,List<create_field> &create_fields, create_field *last_field); static bool pack_fields(File file, List<create_field> &create_fields); -static bool make_empty_rec(int file, enum db_type table_type, +static bool make_empty_rec(THD *thd, int file, enum db_type table_type, uint table_options, List<create_field> &create_fields, uint reclength,uint null_fields); @@ -134,7 +134,7 @@ bool mysql_create_frm(THD *thd, my_string file_name, VOID(my_seek(file, (ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length, MY_SEEK_SET,MYF(0))); - if (make_empty_rec(file,create_info->db_type,create_info->table_options, + if (make_empty_rec(thd,file,create_info->db_type,create_info->table_options, create_fields,reclength,null_fields)) goto err; @@ -640,7 +640,7 @@ static bool pack_fields(File file,List<create_field> &create_fields) /* save an empty record on start of formfile */ -static bool make_empty_rec(File file,enum db_type table_type, +static bool make_empty_rec(THD *thd, File file,enum db_type table_type, uint table_options, List<create_field> &create_fields, uint reclength, uint null_fields) @@ -652,6 +652,7 @@ static bool make_empty_rec(File file,enum db_type table_type, TABLE table; create_field *field; handler *handler; + enum_check_fields old_count_cuted_fields= thd->count_cuted_fields; DBUG_ENTER("make_empty_rec"); /* We need a table to generate columns for default values */ @@ -666,7 +667,7 @@ static bool make_empty_rec(File file,enum db_type table_type, DBUG_RETURN(1); } - table.in_use= current_thd; + table.in_use= thd; table.s->db_low_byte_first= handler->low_byte_first(); table.s->blob_ptr_size= portable_sizeof_char_ptr; @@ -681,6 +682,7 @@ static bool make_empty_rec(File file,enum db_type table_type, null_pos=buff; List_iterator<create_field> it(create_fields); + thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values while ((field=it++)) { Field *regfield=make_field((char*) buff+field->offset,field->length, @@ -709,7 +711,14 @@ static bool make_empty_rec(File file,enum db_type table_type, if (field->def && (regfield->real_type() != FIELD_TYPE_YEAR || field->def->val_int() != 0)) - (void) field->def->save_in_field(regfield, 1); + { + if (field->def->save_in_field(regfield, 1)) + { + my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name); + error= 1; + goto err; + } + } else if (regfield->real_type() == FIELD_TYPE_ENUM && (field->flags & NOT_NULL_FLAG)) { @@ -728,7 +737,10 @@ static bool make_empty_rec(File file,enum db_type table_type, /* Fill not used startpos */ bfill((byte*) buff+null_length,firstpos-null_length,255); error=(int) my_write(file,(byte*) buff,(uint) reclength,MYF_RW); + +err: my_free((gptr) buff,MYF(MY_FAE)); delete handler; + thd->count_cuted_fields= old_count_cuted_fields; DBUG_RETURN(error); } /* make_empty_rec */ |