diff options
author | Sergei Golubchik <serg@mariadb.org> | 2017-09-23 20:22:30 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2017-09-23 20:22:30 +0200 |
commit | 1320ad5b9253256afe98e948d25ed0a423a1e6da (patch) | |
tree | 97369f9aa107f08568e1647c3c6cbfeaabf3feea /sql | |
parent | 88adfd0cea34b93b50d6cc1128df45bae2124bc2 (diff) | |
parent | ca3c8d9b58fdc267b7c4df1ce3afde5ec6599344 (diff) | |
download | mariadb-git-1320ad5b9253256afe98e948d25ed0a423a1e6da.tar.gz |
Merge branch '10.2' into bb-10.2-ext
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 97 | ||||
-rw-r--r-- | sql/field.h | 8 | ||||
-rw-r--r-- | sql/field_conv.cc | 17 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 19 | ||||
-rw-r--r-- | sql/item_timefunc.h | 1 | ||||
-rw-r--r-- | sql/sql_class.h | 23 | ||||
-rw-r--r-- | sql/table.cc | 39 |
7 files changed, 140 insertions, 64 deletions
diff --git a/sql/field.cc b/sql/field.cc index fbb2ad79ba9..acf0af095a1 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1713,6 +1713,33 @@ int Field::store(const char *to, uint length, CHARSET_INFO *cs, } +static int timestamp_to_TIME(THD *thd, MYSQL_TIME *ltime, my_time_t ts, + ulong sec_part, ulonglong fuzzydate) +{ + thd->time_zone_used= 1; + if (ts == 0 && sec_part == 0) + { + if (fuzzydate & TIME_NO_ZERO_DATE) + return 1; + set_zero_time(ltime, MYSQL_TIMESTAMP_DATETIME); + } + else + { + thd->variables.time_zone->gmt_sec_to_TIME(ltime, ts); + ltime->second_part= sec_part; + } + return 0; +} + + +int Field::store_timestamp(my_time_t ts, ulong sec_part) +{ + MYSQL_TIME ltime; + THD *thd= get_thd(); + timestamp_to_TIME(thd, <ime, ts, sec_part, 0); + return store_time_dec(<ime, decimals()); +} + /** Pack the field into a format suitable for storage and transfer. @@ -4810,6 +4837,13 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg, } +int Field_timestamp::save_in_field(Field *to) +{ + ulong sec_part; + my_time_t ts= get_timestamp(&sec_part); + return to->store_timestamp(ts, sec_part); +} + my_time_t Field_timestamp::get_timestamp(const uchar *pos, ulong *sec_part) const { @@ -4936,6 +4970,22 @@ int Field_timestamp::store(longlong nr, bool unsigned_val) } +int Field_timestamp::store_timestamp(my_time_t ts, ulong sec_part) +{ + store_TIME(ts, sec_part); + if (ts == 0 && sec_part == 0 && + get_thd()->variables.sql_mode & TIME_NO_ZERO_DATE) + { + ErrConvString s( + STRING_WITH_LEN("0000-00-00 00:00:00.000000") - (decimals() ? 6 - decimals() : 7), + system_charset_info); + set_datetime_warning(WARN_DATA_TRUNCATED, &s, MYSQL_TIMESTAMP_DATETIME, 1); + return 1; + } + return 0; +} + + double Field_timestamp::val_real(void) { return (double) Field_timestamp::val_int(); @@ -5039,22 +5089,9 @@ Field_timestamp::validate_value_in_record(THD *thd, const uchar *record) const bool Field_timestamp::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) { - THD *thd= get_thd(); - thd->time_zone_used= 1; ulong sec_part; - my_time_t temp= get_timestamp(&sec_part); - if (temp == 0 && sec_part == 0) - { /* Zero time is "000000" */ - if (fuzzydate & TIME_NO_ZERO_DATE) - return 1; - set_zero_time(ltime, MYSQL_TIMESTAMP_DATETIME); - } - else - { - thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp); - ltime->second_part= sec_part; - } - return 0; + my_time_t ts= get_timestamp(&sec_part); + return timestamp_to_TIME(get_thd(), ltime, ts, sec_part, fuzzydate); } @@ -5104,36 +5141,6 @@ int Field_timestamp::set_time() return 0; } -/** - Mark the field as having an explicit default value. - - @param value if available, the value that the field is being set to - @returns whether the explicit default bit was set - - @note - Fields that have an explicit default value should not be updated - automatically via the DEFAULT or ON UPDATE functions. The functions - that deal with data change functionality (INSERT/UPDATE/LOAD), - determine if there is an explicit value for each field before performing - the data change, and call this method to mark the field. - - For timestamp columns, the only case where a column is not marked - as been given a value are: - - It's explicitly assigned with DEFAULT - - We assign NULL to a timestamp field that is defined as NOT NULL. - This is how MySQL has worked since it's start. -*/ - -bool Field_timestamp::set_explicit_default(Item *value) -{ - if (((value->type() == Item::DEFAULT_VALUE_ITEM && - !((Item_default_value*)value)->arg) || - (!maybe_null() && value->null_value))) - return false; - set_has_explicit_value(); - return true; -} - #ifdef NOT_USED static void store_native(ulonglong num, uchar *to, uint bytes) { diff --git a/sql/field.h b/sql/field.h index f3f9c9a30ac..f36e9a668c4 100644 --- a/sql/field.h +++ b/sql/field.h @@ -657,6 +657,7 @@ protected: static void do_field_real(Copy_field *copy); static void do_field_string(Copy_field *copy); static void do_field_temporal(Copy_field *copy); + static void do_field_timestamp(Copy_field *copy); static void do_field_decimal(Copy_field *copy); public: static void *operator new(size_t size, MEM_ROOT *mem_root) throw () @@ -814,6 +815,7 @@ public: virtual int store(longlong nr, bool unsigned_val)=0; virtual int store_decimal(const my_decimal *d)=0; virtual int store_time_dec(MYSQL_TIME *ltime, uint dec); + virtual int store_timestamp(my_time_t timestamp, ulong sec_part); int store_time(MYSQL_TIME *ltime) { return store_time_dec(ltime, TIME_SECOND_PART_DIGITS); } int store(const char *to, uint length, CHARSET_INFO *cs, @@ -980,7 +982,7 @@ public: { return bitmap_is_set(&table->has_value_set, field_index); } - virtual bool set_explicit_default(Item *value); + bool set_explicit_default(Item *value); /** Evaluates the @c UPDATE default function, if one exists, and stores the @@ -2389,11 +2391,14 @@ public: TABLE_SHARE *share); const Type_handler *type_handler() const { return &type_handler_timestamp; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } + Copy_func *get_copy_func(const Field *from) const; int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); int store(longlong nr, bool unsigned_val); int store_time_dec(MYSQL_TIME *ltime, uint dec); int store_decimal(const my_decimal *); + int store_timestamp(my_time_t timestamp, ulong sec_part); + int save_in_field(Field *to); double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -2404,7 +2409,6 @@ public: void sql_type(String &str) const; bool zero_pack() const { return 0; } int set_time(); - bool set_explicit_default(Item *value); int evaluate_update_default_function() { int res= 0; diff --git a/sql/field_conv.cc b/sql/field_conv.cc index a744af76626..932188d56a8 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -417,6 +417,13 @@ void Field::do_field_decimal(Copy_field *copy) } +void Field::do_field_timestamp(Copy_field *copy) +{ + // XXX why couldn't we do it everywhere? + copy->from_field->save_in_field(copy->to_field); +} + + void Field::do_field_temporal(Copy_field *copy) { MYSQL_TIME ltime; @@ -706,6 +713,16 @@ void Copy_field::set(Field *to,Field *from,bool save) } +Field::Copy_func *Field_timestamp::get_copy_func(const Field *from) const +{ + Field::Copy_func *copy= Field_temporal::get_copy_func(from); + if (copy == do_field_temporal && from->type() == MYSQL_TYPE_TIMESTAMP) + return do_field_timestamp; + else + return copy; +} + + Field::Copy_func *Field_temporal::get_copy_func(const Field *from) const { /* If types are not 100 % identical then convert trough get_date() */ diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index b0270c6f055..86bde00cced 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1706,6 +1706,25 @@ void Item_func_now::print(String *str, enum_query_type query_type) str->append(')'); } + +int Item_func_now_local::save_in_field(Field *field, bool no_conversions) +{ + if (field->type() == MYSQL_TYPE_TIMESTAMP) + { + THD *thd= field->get_thd(); + my_time_t ts= thd->query_start(); + uint dec= MY_MIN(decimals, field->decimals()); + ulong sec_part= dec ? thd->query_start_sec_part() : 0; + sec_part-= my_time_fraction_remainder(sec_part, dec); + field->set_notnull(); + ((Field_timestamp*)field)->store_TIME(ts, sec_part); + return 0; + } + else + return Item_temporal_func::save_in_field(field, no_conversions); +} + + /** Converts current time in my_time_t to MYSQL_TIME represenatation for local time zone. Defines time zone (local) used for whole NOW function. diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a752c160557..7d2fe46b644 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -729,6 +729,7 @@ class Item_func_now_local :public Item_func_now public: Item_func_now_local(THD *thd, uint dec): Item_func_now(thd, dec) {} const char *func_name() const { return "current_timestamp"; } + int save_in_field(Field *field, bool no_conversions); virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time); virtual enum Functype functype() const { return NOW_FUNC; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) diff --git a/sql/sql_class.h b/sql/sql_class.h index 452193de0aa..1c4e657cf5a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1636,6 +1636,29 @@ public: /** + Implements the trivial error handler which counts errors as they happen. +*/ + +class Counting_error_handler : public Internal_error_handler +{ +public: + int errors; + bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + Sql_condition::enum_warning_level *level, + const char* msg, + Sql_condition ** cond_hdl) + { + if (*level == Sql_condition::WARN_LEVEL_ERROR) + errors++; + return false; + } + Counting_error_handler() : errors(0) {} +}; + + +/** This class is an internal error handler implementation for DROP TABLE statements. The thing is that there may be warnings during execution of these statements, which should not be exposed to the user. diff --git a/sql/table.cc b/sql/table.cc index a9ab23d672b..7c6aa205edd 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5077,23 +5077,28 @@ void TABLE_LIST::cleanup_items() int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure) { - /* VIEW's CHECK OPTION CLAUSE */ - if (check_option && check_option->val_int() == 0) - { - TABLE_LIST *main_view= top_table(); - const char *name_db= (main_view->view ? main_view->view_db.str : - main_view->db); - const char *name_table= (main_view->view ? main_view->view_name.str : - main_view->table_name); - my_error(ER_VIEW_CHECK_FAILED, MYF(ignore_failure ? ME_JUST_WARNING : 0), - name_db, name_table); - return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR; - } - int result= table->verify_constraints(ignore_failure); - /* We check thd->error() because it can be set by conversion problem. */ - if (thd->is_error()) - return(VIEW_CHECK_ERROR); - return result; + if (check_option) + { + /* VIEW's CHECK OPTION CLAUSE */ + Counting_error_handler ceh; + thd->push_internal_handler(&ceh); + bool res= check_option->val_int() == 0; + thd->pop_internal_handler(); + if (ceh.errors) + return(VIEW_CHECK_ERROR); + if (res) + { + TABLE_LIST *main_view= top_table(); + const char *name_db= (main_view->view ? main_view->view_db.str : + main_view->db); + const char *name_table= (main_view->view ? main_view->view_name.str : + main_view->table_name); + my_error(ER_VIEW_CHECK_FAILED, MYF(ignore_failure ? ME_JUST_WARNING : 0), + name_db, name_table); + return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR; + } + } + return table->verify_constraints(ignore_failure); } |