diff --git a/mysql-test/main/cte_recursive.result b/mysql-test/main/cte_recursive.result index 0c98530c9bf..7bf85016f11 100644 --- a/mysql-test/main/cte_recursive.result +++ b/mysql-test/main/cte_recursive.result @@ -4873,4 +4873,149 @@ a 0 NULL DROP TABLE t1; +# +# MDEV-12325 Unexpected data type and truncation when using CTE +# +CREATE TABLE t1 +( +id INT, mid INT, name TEXT +); +INSERT INTO t1 VALUES (0,NULL,'Name'),(1,0,'Name1'),(2,0,'Name2'),(11,1,'Name11'),(12,1,'Name12'); +WITH RECURSIVE +cteReports (level, id, mid, name) AS +( +SELECT 1, id, mid, name FROM t1 WHERE mid IS NULL +UNION ALL +SELECT r.level + 1, e.id, e.mid + 1000000000000, e.name FROM t1 e +INNER JOIN cteReports r ON e.mid = r.id +) +SELECT +level, id, mid, name, +(SELECT name FROM t1 WHERE id= cteReports.mid) AS mname +FROM cteReports ORDER BY level, mid; +ERROR 22003: Out of range value for column 'mid' at row 2 +create table t2 as WITH RECURSIVE +cteReports (level, id, mid, name) AS +( +SELECT 1, id, mid, name FROM t1 WHERE mid IS NULL +UNION ALL +SELECT r.level + 1, e.id, e.mid + 1000000000000, e.name FROM t1 e +INNER JOIN cteReports r ON e.mid = r.id +) +SELECT +level, id, mid, name, +(SELECT name FROM t1 WHERE id= cteReports.mid) AS mname +FROM cteReports ORDER BY level, mid;; +ERROR 22003: Out of range value for column 'mid' at row 2 +create table t2 ignore as WITH RECURSIVE +cteReports (level, id, mid, name) AS +( +SELECT 1, id, mid, name FROM t1 WHERE mid IS NULL +UNION ALL +SELECT r.level + 1, e.id, e.mid + 1000000000000, e.name FROM t1 e +INNER JOIN cteReports r ON e.mid = r.id +) +SELECT +level, id, mid, name, +(SELECT name FROM t1 WHERE id= cteReports.mid) AS mname +FROM cteReports ORDER BY level, mid;; +Warnings: +Warning 1264 Out of range value for column 'mid' at row 2 +Warning 1264 Out of range value for column 'mid' at row 3 +Warning 1264 Out of range value for column 'mid' at row 4 +Warning 1264 Out of range value for column 'mid' at row 5 +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `level` int(1) DEFAULT NULL, + `id` int(11) DEFAULT NULL, + `mid` int(11) DEFAULT NULL, + `name` text DEFAULT NULL, + `mname` text DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t2 WITH RECURSIVE +cteReports (level, id, mid, name) AS +( +SELECT 1, id, mid, name FROM t1 WHERE mid IS NULL +UNION ALL +SELECT r.level + 1, e.id, e.mid + 1000000000000, e.name FROM t1 e +INNER JOIN cteReports r ON e.mid = r.id +) +SELECT +level, id, mid, name, +(SELECT name FROM t1 WHERE id= cteReports.mid) AS mname +FROM cteReports ORDER BY level, mid;; +ERROR 22003: Out of range value for column 'mid' at row 2 +insert ignore into t2 WITH RECURSIVE +cteReports (level, id, mid, name) AS +( +SELECT 1, id, mid, name FROM t1 WHERE mid IS NULL +UNION ALL +SELECT r.level + 1, e.id, e.mid + 1000000000000, e.name FROM t1 e +INNER JOIN cteReports r ON e.mid = r.id +) +SELECT +level, id, mid, name, +(SELECT name FROM t1 WHERE id= cteReports.mid) AS mname +FROM cteReports ORDER BY level, mid;; +Warnings: +Warning 1264 Out of range value for column 'mid' at row 2 +Warning 1264 Out of range value for column 'mid' at row 3 +Warning 1264 Out of range value for column 'mid' at row 4 +Warning 1264 Out of range value for column 'mid' at row 5 +drop table t2; +set @@sql_mode=""; +WITH RECURSIVE +cteReports (level, id, mid, name) AS +( +SELECT 1, id, mid, name FROM t1 WHERE mid IS NULL +UNION ALL +SELECT r.level + 1, e.id, e.mid + 1000000000000, e.name FROM t1 e +INNER JOIN cteReports r ON e.mid = r.id +) +SELECT +level, id, mid, name, +(SELECT name FROM t1 WHERE id= cteReports.mid) AS mname +FROM cteReports ORDER BY level, mid; +level id mid name mname +1 0 NULL Name NULL +2 1 2147483647 Name1 NULL +2 2 2147483647 Name2 NULL +3 11 2147483647 Name11 NULL +3 12 2147483647 Name12 NULL +Warnings: +Warning 1264 Out of range value for column 'mid' at row 2 +Warning 1264 Out of range value for column 'mid' at row 3 +Warning 1264 Out of range value for column 'mid' at row 4 +Warning 1264 Out of range value for column 'mid' at row 5 +create table t2 as WITH RECURSIVE +cteReports (level, id, mid, name) AS +( +SELECT 1, id, mid, name FROM t1 WHERE mid IS NULL +UNION ALL +SELECT r.level + 1, e.id, e.mid + 1000000000000, e.name FROM t1 e +INNER JOIN cteReports r ON e.mid = r.id +) +SELECT +level, id, mid, name, +(SELECT name FROM t1 WHERE id= cteReports.mid) AS mname +FROM cteReports ORDER BY level, mid;; +Warnings: +Warning 1264 Out of range value for column 'mid' at row 2 +Warning 1264 Out of range value for column 'mid' at row 3 +Warning 1264 Out of range value for column 'mid' at row 4 +Warning 1264 Out of range value for column 'mid' at row 5 +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `level` int(1) DEFAULT NULL, + `id` int(11) DEFAULT NULL, + `mid` int(11) DEFAULT NULL, + `name` text DEFAULT NULL, + `mname` text DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +set @@sql_mode=default; +drop table t1,t2; +# # End of 10.3 tests +# diff --git a/mysql-test/main/cte_recursive.test b/mysql-test/main/cte_recursive.test index 4c4bd99c24c..ca97c2d2900 100644 --- a/mysql-test/main/cte_recursive.test +++ b/mysql-test/main/cte_recursive.test @@ -3165,4 +3165,47 @@ SELECT * FROM cte; DROP TABLE t1; +--echo # +--echo # MDEV-12325 Unexpected data type and truncation when using CTE +--echo # + +CREATE TABLE t1 +( + id INT, mid INT, name TEXT +); +INSERT INTO t1 VALUES (0,NULL,'Name'),(1,0,'Name1'),(2,0,'Name2'),(11,1,'Name11'),(12,1,'Name12'); + +let $query= +WITH RECURSIVE +cteReports (level, id, mid, name) AS +( + SELECT 1, id, mid, name FROM t1 WHERE mid IS NULL + UNION ALL + SELECT r.level + 1, e.id, e.mid + 1000000000000, e.name FROM t1 e + INNER JOIN cteReports r ON e.mid = r.id +) +SELECT + level, id, mid, name, + (SELECT name FROM t1 WHERE id= cteReports.mid) AS mname +FROM cteReports ORDER BY level, mid; + +--error ER_WARN_DATA_OUT_OF_RANGE +--eval $query +--error ER_WARN_DATA_OUT_OF_RANGE +--eval create table t2 as $query; +--eval create table t2 ignore as $query; +show create table t2; +--error ER_WARN_DATA_OUT_OF_RANGE +--eval insert into t2 $query; +--eval insert ignore into t2 $query; +drop table t2; +set @@sql_mode=""; +--eval $query +--eval create table t2 as $query; +show create table t2; +set @@sql_mode=default; +drop table t1,t2; + +--echo # --echo # End of 10.3 tests +--echo # diff --git a/sql/sql_class.h b/sql/sql_class.h index 850a8364adc..05b8f7eb443 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5691,10 +5691,12 @@ class select_union_recursive :public select_unit or for the unit specifying a CTE that mutually recursive with this CTE. */ uint cleanup_count; + long row_counter; select_union_recursive(THD *thd_arg): select_unit(thd_arg), - incr_table(0), first_rec_table_to_update(0), cleanup_count(0) + incr_table(0), first_rec_table_to_update(0), cleanup_count(0), + row_counter(0) { incr_table_param.init(); }; int send_data(List &items); diff --git a/sql/sql_error.h b/sql/sql_error.h index 3b29f7aba06..ec52724b6da 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -722,6 +722,13 @@ private: /** Reset the current row counter. Start counting from the first row. */ void reset_current_row_for_warning() { m_current_row_for_warning= 1; } + ulong set_current_row_for_warning(ulong row) + { + ulong old_row= m_current_row_for_warning; + m_current_row_for_warning= row; + return old_row; + } + /** Return the current counter value. */ ulong current_row_for_warning() const { return m_current_row_for_warning; } @@ -1099,6 +1106,9 @@ public: void opt_clear_warning_info(ulonglong query_id) { get_warning_info()->opt_clear(query_id); } + long set_current_row_for_warning(long row) + { return get_warning_info()->set_current_row_for_warning(row); } + ulong current_row_for_warning() const { return get_warning_info()->current_row_for_warning(); } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 48d8c16db68..32d307de5e8 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -297,7 +297,27 @@ bool select_unit::send_eof() int select_union_recursive::send_data(List &values) { - int rc= select_unit::send_data(values); + + int rc; + bool save_abort_on_warning= thd->abort_on_warning; + enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; + long save_counter; + + /* + For recursive CTE's give warnings for wrong field info + However, we don't do that for CREATE TABLE ... SELECT or INSERT ... SELECT + as the upper level code for these handles setting of abort_on_warning + depending on if 'IGNORE' is used. + */ + if (thd->lex->sql_command != SQLCOM_CREATE_TABLE && + thd->lex->sql_command != SQLCOM_INSERT_SELECT) + thd->abort_on_warning= thd->is_strict_mode(); + thd->count_cuted_fields= CHECK_FIELD_WARN; + save_counter= thd->get_stmt_da()->set_current_row_for_warning(++row_counter); + rc= select_unit::send_data(values); + thd->get_stmt_da()->set_current_row_for_warning(save_counter); + thd->count_cuted_fields= save_count_cuted_fields; + thd->abort_on_warning= save_abort_on_warning; if (rc == 0 && write_err != HA_ERR_FOUND_DUPP_KEY && @@ -476,6 +496,7 @@ void select_union_recursive::cleanup() thd->rec_tables= tab; tbl->derived_result= 0; } + row_counter= 0; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 770e5e1c3e7..577405725ca 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -15373,7 +15373,6 @@ with_clause: MYSQL_YYABORT; Lex->derived_tables|= DERIVED_WITH; Lex->with_cte_resolution= true; - Lex->with_cte_resolution= true; Lex->curr_with_clause= with_clause; with_clause->add_to_list(Lex->with_clauses_list_last_next); }