diff options
-rw-r--r-- | libmysqld/CMakeLists.txt | 12 | ||||
-rw-r--r-- | mysql-test/suite/gcol/r/innodb_virtual_index.result | 65 | ||||
-rw-r--r-- | mysql-test/suite/gcol/t/innodb_virtual_index.test | 50 | ||||
-rw-r--r-- | sql/mysqld.cc | 24 | ||||
-rw-r--r-- | sql/sql_class.h | 15 | ||||
-rw-r--r-- | sql/table.cc | 25 | ||||
-rw-r--r-- | sql/table.h | 2 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 7 | ||||
-rw-r--r-- | storage/innobase/include/row0mysql.h | 9 | ||||
-rw-r--r-- | storage/innobase/include/row0upd.h | 5 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 2 | ||||
-rw-r--r-- | storage/innobase/row/row0log.cc | 2 | ||||
-rw-r--r-- | storage/innobase/row/row0sel.cc | 3 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 3 | ||||
-rw-r--r-- | storage/mroonga/mrn_mysql_compat.h | 2 | ||||
-rw-r--r-- | storage/myisam/ha_myisam.cc | 4 |
16 files changed, 204 insertions, 26 deletions
diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 30ddf9ec1c3..b9eff10bc18 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -30,15 +30,23 @@ ${SSL_INTERNAL_INCLUDE_DIRS} ) SET(GEN_SOURCES -${CMAKE_BINARY_DIR}/sql/sql_yacc.hh +${CMAKE_BINARY_DIR}/sql/sql_yacc.hh ${CMAKE_BINARY_DIR}/sql/yy_mariadb.cc ${CMAKE_BINARY_DIR}/sql/yy_oracle.hh ${CMAKE_BINARY_DIR}/sql/yy_oracle.cc -${CMAKE_BINARY_DIR}/sql/lex_hash.h +${CMAKE_BINARY_DIR}/sql/lex_hash.h ) SET_SOURCE_FILES_PROPERTIES(${GEN_SOURCES} PROPERTIES GENERATED TRUE) +IF(CMAKE_C_COMPILER_ID MATCHES "Clang" AND + NOT CMAKE_C_COMPILER_VERSION VERSION_LESS "13.0.0") + ADD_COMPILE_FLAGS( + ${CMAKE_BINARY_DIR}/sql/yy_mariadb.cc + ${CMAKE_BINARY_DIR}/sql/yy_oracle.cc + COMPILE_FLAGS "-Wno-unused-but-set-variable") +ENDIF() + SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc libmysql.c ../sql-common/errmsg.c ../sql-common/client.c diff --git a/mysql-test/suite/gcol/r/innodb_virtual_index.result b/mysql-test/suite/gcol/r/innodb_virtual_index.result index e63d47391c9..b0c29da2f22 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_index.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_index.result @@ -1,3 +1,4 @@ +SET default_storage_engine= innodb; SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; # @@ -248,12 +249,15 @@ ENGINE=InnoDB; INSERT IGNORE INTO t1 (a,b) VALUES(1,20190132); Warnings: Warning 1265 Data truncated for column 'vb' at row 1 +SELECT * FROM t1; +a b vb +1 20190132 0000-00-00 BEGIN; DELETE FROM t1; INSERT INTO t1 (a,b) VALUES(1,20190123); -ERROR 22007: Incorrect date value: '20190132' for column `test`.`t1`.`vb` at row 1 SELECT * FROM t1; a b vb +1 20190123 2019-01-23 ROLLBACK; SELECT * FROM t1; a b vb @@ -310,3 +314,62 @@ ALTER TABLE t1 ADD KEY (b), ALGORITHM=INPLACE; # Cleanup DROP TABLE t1; # End of 10.2 tests +# +# MDEV-29299 SELECT from table with vcol index reports warning +# +CREATE TABLE t(fld1 INT NOT NULL, +fld2 INT AS (100/fld1) VIRTUAL, +KEY(fld1), KEY(fld2)); +CREATE TABLE t_odd(id int); +INSERT INTO t(fld1) VALUES(1), (2); +connect stop_purge,localhost,root; +START TRANSACTION WITH CONSISTENT SNAPSHOT; +INSERT INTO t_odd VALUES(10000); +connection default; +UPDATE IGNORE t SET fld1= 3 WHERE fld1= 2; +UPDATE IGNORE t SET fld1= 4 WHERE fld1= 3; +UPDATE IGNORE t SET fld1= 0 WHERE fld1= 4; +Warnings: +Warning 1365 Division by 0 +SELECT fld2 FROM t FORCE INDEX(fld2); +fld2 +NULL +100 +SELECT fld2 FROM t FORCE INDEX(fld1); +fld2 +100 +NULL +Warnings: +Warning 1365 Division by 0 +disconnect stop_purge; +DROP TABLE t, t_odd; +# +# MDEV-29753 An error is wrongly reported during INSERT with vcol index +# See also Bug #22990029 +# +CREATE TABLE t(pk INT PRIMARY KEY, +fld1 INT NOT NULL, +fld2 INT AS (100/fld1) VIRTUAL, +KEY(fld1), KEY(fld2)); +INSERT IGNORE t(pk, fld1) VALUES(1, 0); +Warnings: +Warning 1365 Division by 0 +SELECT * FROM t; +pk fld1 fld2 +1 0 NULL +Warnings: +Warning 1365 Division by 0 +BEGIN; +DELETE FROM t; +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +INSERT INTO t (pk, fld1) VALUES(1,1); +SELECT * FROM t; +pk fld1 fld2 +1 1 100 +# Cleanup +ROLLBACK; +DROP TABLE t; +# End of 10.3 tests diff --git a/mysql-test/suite/gcol/t/innodb_virtual_index.test b/mysql-test/suite/gcol/t/innodb_virtual_index.test index 46ffadcdd8c..747a2fdb64c 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_index.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_index.test @@ -1,6 +1,8 @@ --source include/have_innodb.inc --source include/have_sequence.inc +SET default_storage_engine= innodb; + # Ensure that the history list length will actually be decremented by purge. SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; @@ -273,9 +275,9 @@ DROP TABLE t1; CREATE TABLE t1(a INT PRIMARY KEY, b INT, vb DATE AS(b) VIRTUAL, KEY(vb)) ENGINE=InnoDB; INSERT IGNORE INTO t1 (a,b) VALUES(1,20190132); +SELECT * FROM t1; BEGIN; DELETE FROM t1; ---error ER_TRUNCATED_WRONG_VALUE INSERT INTO t1 (a,b) VALUES(1,20190123); SELECT * FROM t1; ROLLBACK; @@ -334,3 +336,49 @@ DROP TABLE t1; --echo # End of 10.2 tests +--echo # +--echo # MDEV-29299 SELECT from table with vcol index reports warning +--echo # + +CREATE TABLE t(fld1 INT NOT NULL, + fld2 INT AS (100/fld1) VIRTUAL, + KEY(fld1), KEY(fld2)); +CREATE TABLE t_odd(id int); +INSERT INTO t(fld1) VALUES(1), (2); + +--connect stop_purge,localhost,root +# This prevents purge for records in t +START TRANSACTION WITH CONSISTENT SNAPSHOT; +INSERT INTO t_odd VALUES(10000); + +--connection default +UPDATE IGNORE t SET fld1= 3 WHERE fld1= 2; +UPDATE IGNORE t SET fld1= 4 WHERE fld1= 3; +UPDATE IGNORE t SET fld1= 0 WHERE fld1= 4; +SELECT fld2 FROM t FORCE INDEX(fld2); +SELECT fld2 FROM t FORCE INDEX(fld1); + +--disconnect stop_purge +DROP TABLE t, t_odd; + +--echo # +--echo # MDEV-29753 An error is wrongly reported during INSERT with vcol index +--echo # See also Bug #22990029 +--echo # + +CREATE TABLE t(pk INT PRIMARY KEY, + fld1 INT NOT NULL, + fld2 INT AS (100/fld1) VIRTUAL, + KEY(fld1), KEY(fld2)); +INSERT IGNORE t(pk, fld1) VALUES(1, 0); +SELECT * FROM t; +BEGIN; +DELETE FROM t; +INSERT INTO t (pk, fld1) VALUES(1,1); +SELECT * FROM t; + +--echo # Cleanup +ROLLBACK; +DROP TABLE t; + +--echo # End of 10.3 tests diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4444e02d983..2cc9e878f74 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3708,14 +3708,24 @@ static int init_common_variables() if (ignore_db_dirs_init()) exit(1); -#ifdef _WIN32 - get_win_tzname(system_time_zone, sizeof(system_time_zone)); -#elif defined(HAVE_TZNAME) struct tm tm_tmp; - localtime_r(&server_start_time,&tm_tmp); - const char *tz_name= tzname[tm_tmp.tm_isdst != 0 ? 1 : 0]; - strmake_buf(system_time_zone, tz_name); -#endif /* HAVE_TZNAME */ + localtime_r(&server_start_time, &tm_tmp); + +#ifdef HAVE_TZNAME +#ifdef _WIN32 + /* + If env.variable TZ is set, derive timezone name from it. + Otherwise, use IANA tz name from get_win_tzname. + */ + if (!getenv("TZ")) + get_win_tzname(system_time_zone, sizeof(system_time_zone)); + else +#endif + { + const char *tz_name= tzname[tm_tmp.tm_isdst != 0 ? 1 : 0]; + strmake_buf(system_time_zone, tz_name); + } +#endif /* We set SYSTEM time zone as reasonable default and diff --git a/sql/sql_class.h b/sql/sql_class.h index 51c1bc984da..273b53e4227 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1970,6 +1970,21 @@ private: }; +struct Suppress_warnings_error_handler : public Internal_error_handler +{ + bool handle_condition(THD *thd, + uint sql_errno, + const char *sqlstate, + Sql_condition::enum_warning_level *level, + const char *msg, + Sql_condition **cond_hdl) + { + return *level == Sql_condition::WARN_LEVEL_WARN; + } +}; + + + /** Tables that were locked with LOCK TABLES statement. diff --git a/sql/table.cc b/sql/table.cc index 7c3bc88de2c..299bafcd0db 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8794,12 +8794,28 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) DBUG_RETURN(in_use->is_error()); } -int TABLE::update_virtual_field(Field *vf) +/* + Calculate the virtual field value for a specified field. + @param vf A field to calculate + @param ignore_warnings Ignore the warnings and also make the + calculations permissive. This usually means + that a calculation is internal and is not + expected to fail. +*/ +int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) { DBUG_ENTER("TABLE::update_virtual_field"); Query_arena backup_arena; Counting_error_handler count_errors; + Suppress_warnings_error_handler warning_handler; in_use->push_internal_handler(&count_errors); + bool abort_on_warning; + if (ignore_warnings) + { + abort_on_warning= in_use->abort_on_warning; + in_use->abort_on_warning= false; + in_use->push_internal_handler(&warning_handler); + } /* TODO: this may impose memory leak until table flush. See comment in @@ -8813,6 +8829,13 @@ int TABLE::update_virtual_field(Field *vf) DBUG_RESTORE_WRITE_SET(vf); in_use->restore_active_arena(expr_arena, &backup_arena); in_use->pop_internal_handler(); + if (ignore_warnings) + { + in_use->abort_on_warning= abort_on_warning; + in_use->pop_internal_handler(); + // This is an internal calculation, we expect it to always succeed + DBUG_ASSERT(count_errors.errors == 0); + } DBUG_RETURN(count_errors.errors); } diff --git a/sql/table.h b/sql/table.h index f394f549ff7..70198ed5fdc 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1678,7 +1678,7 @@ public: uint actual_n_key_parts(KEY *keyinfo); ulong actual_key_flags(KEY *keyinfo); - int update_virtual_field(Field *vf); + int update_virtual_field(Field *vf, bool ignore_warnings); int update_virtual_fields(handler *h, enum_vcol_update_mode update_mode); int update_default_fields(bool ignore_errors); void evaluate_update_default_function(); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index e18d0d5968c..fb8b0180c3d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -20500,7 +20500,8 @@ innobase_get_computed_value( TABLE* mysql_table, byte* mysql_rec, const dict_table_t* old_table, - const upd_t* update) + const upd_t* update, + bool ignore_warnings) { byte rec_buf2[REC_VERSION_56_MAX_INDEX_COL_LEN]; byte* buf; @@ -20607,7 +20608,9 @@ innobase_get_computed_value( MY_BITMAP *old_write_set = dbug_tmp_use_all_columns(mysql_table, &mysql_table->write_set); MY_BITMAP *old_read_set = dbug_tmp_use_all_columns(mysql_table, &mysql_table->read_set); - ret = mysql_table->update_virtual_field(mysql_table->field[col->m_col.ind]); + ret = mysql_table->update_virtual_field( + mysql_table->field[col->m_col.ind], + ignore_warnings); dbug_tmp_restore_column_map(&mysql_table->read_set, old_read_set); dbug_tmp_restore_column_map(&mysql_table->write_set, old_write_set); diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 04ac6bb9d70..e3f7ea7d701 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -921,7 +921,9 @@ void innobase_report_computed_value_failed(dtuple_t *row); @param[in] old_table during ALTER TABLE, this is the old table or NULL. @param[in] update update vector for the parent row -@param[in] foreign foreign key information +@param[in] ignore_warnings ignore warnings during calculation. Usually + means that a calculation is internal and + should have no side effects. @return the field filled with computed value */ dfield_t* innobase_get_computed_value( @@ -934,8 +936,9 @@ innobase_get_computed_value( THD* thd, TABLE* mysql_table, byte* mysql_rec, - const dict_table_t* old_table, - const upd_t* update); + const dict_table_t* old_table=NULL, + const upd_t* update=NULL, + bool ignore_warnings=false); /** Get the computed value by supplying the base column values. @param[in,out] table the table whose virtual column diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index 9ee5d77f5e5..d47ec793f89 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -150,6 +150,8 @@ the equal ordering fields. NOTE: we compare the fields as binary strings! @param[in] offsets rec_get_offsets(rec,index), or NULL @param[in] no_sys skip the system columns DB_TRX_ID and DB_ROLL_PTR +@param[in] ignore_warnings ignore warnings during vcol calculation, which + means that this calculation is internal only @param[in] trx transaction (for diagnostics), or NULL @param[in] heap memory heap from which allocated @@ -165,11 +167,12 @@ row_upd_build_difference_binary( const rec_t* rec, const rec_offs* offsets, bool no_sys, + bool ignore_warnings, trx_t* trx, mem_heap_t* heap, TABLE* mysql_table, dberr_t* error) - MY_ATTRIBUTE((nonnull(1,2,3,7,9), warn_unused_result)); + MY_ATTRIBUTE((nonnull(1,2,3,8,10), warn_unused_result)); /** Apply an update vector to an index entry. @param[in,out] entry index entry to be updated; the clustered index record must be covered by a lock or a page latch to prevent diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 18c56031e29..e7fe0afced7 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -305,7 +305,7 @@ row_ins_clust_index_entry_by_modify( } update = row_upd_build_difference_binary( - cursor->index, entry, rec, NULL, true, + cursor->index, entry, rec, NULL, true, true, thr_get_trx(thr), heap, mysql_table, &err); if (err != DB_SUCCESS) { return(err); diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 51b40876f65..ceefe626044 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -2252,7 +2252,7 @@ func_exit_committed: row, NULL, index, heap, ROW_BUILD_NORMAL); upd_t* update = row_upd_build_difference_binary( index, entry, btr_pcur_get_rec(&pcur), cur_offsets, - false, NULL, heap, dup->table, &error); + false, false, NULL, heap, dup->table, &error); if (error != DB_SUCCESS) { goto func_exit; } diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 9c11898f70c..d75199ccb64 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -332,7 +332,8 @@ row_sel_sec_rec_is_for_clust_rec( &heap, NULL, NULL, thr_get_trx(thr)->mysql_thd, thr->prebuilt->m_mysql_table, - record, NULL, NULL); + record, NULL, NULL, + true); if (vfield == NULL) { innobase_report_computed_value_failed(row); diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 3c63e8ab2c8..639a887ed2f 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -675,6 +675,7 @@ row_upd_build_difference_binary( const rec_t* rec, const rec_offs* offsets, bool no_sys, + bool ignore_warnings, trx_t* trx, mem_heap_t* heap, TABLE* mysql_table, @@ -773,7 +774,7 @@ row_upd_build_difference_binary( dfield_t* vfield = innobase_get_computed_value( update->old_vrow, col, index, &vc.heap, heap, NULL, thd, mysql_table, record, - NULL, NULL); + NULL, NULL, ignore_warnings); if (vfield == NULL) { *error = DB_COMPUTE_VALUE_FAILED; return(NULL); diff --git a/storage/mroonga/mrn_mysql_compat.h b/storage/mroonga/mrn_mysql_compat.h index 08d874fabaf..538aaf51cb6 100644 --- a/storage/mroonga/mrn_mysql_compat.h +++ b/storage/mroonga/mrn_mysql_compat.h @@ -412,7 +412,7 @@ #ifdef MRN_MARIADB_P # if (MYSQL_VERSION_ID >= 100203) # define MRN_GENERATED_COLUMNS_UPDATE_VIRTUAL_FIELD(table, field) \ - (table->update_virtual_field(field)) + (table->update_virtual_field(field,false)) # else # define MRN_GENERATED_COLUMNS_UPDATE_VIRTUAL_FIELD(table, field) \ (field->vcol_info->expr_item->save_in_field(field, 0)) diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index e2e786872ba..78ef653e9ab 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. - Copyright (c) 2009, 2017, MariaDB Corporation. + Copyright (c) 2009, 2022, MariaDB Corporation. 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 @@ -730,7 +730,7 @@ static int compute_vcols(MI_INFO *info, uchar *record, int keynum) { Field *f= table->field[kp->fieldnr - 1]; if (f->vcol_info && !f->vcol_info->stored_in_db) - table->update_virtual_field(f); + table->update_virtual_field(f, false); } mysql_mutex_unlock(&info->s->intern_lock); return 0; |