diff --git a/mysql-test/r/errors.result b/mysql-test/r/errors.result index 94debb1785f..022a32d9c9b 100644 --- a/mysql-test/r/errors.result +++ b/mysql-test/r/errors.result @@ -41,3 +41,17 @@ SELECT a FROM t1 WHERE a IN(1, (SELECT IF(1=0,1,2/0))); a 1 DROP TABLE t1; +CREATE TABLE t1( a INT ); +SELECT b FROM t1; +ERROR 42S22: Unknown column 'b' in 'field list' +SHOW ERRORS; +Level Code Message +Error 1054 Unknown column 'b' in 'field list' +CREATE TABLE t2 SELECT b FROM t1; +ERROR 42S22: Unknown column 'b' in 'field list' +SHOW ERRORS; +Level Code Message +Error 1054 Unknown column 'b' in 'field list' +INSERT INTO t1 SELECT b FROM t1; +ERROR 42S22: Unknown column 'b' in 'field list' +DROP TABLE t1; diff --git a/mysql-test/t/errors.test b/mysql-test/t/errors.test index 4fbdcba635f..89579ec1739 100644 --- a/mysql-test/t/errors.test +++ b/mysql-test/t/errors.test @@ -53,4 +53,17 @@ INSERT INTO t1 VALUES(2),(3); SELECT a FROM t1 WHERE a IN(1, (SELECT IF(1=0,1,2/0))); DROP TABLE t1; +# +# Bug #28677: SELECT on missing column gives extra error +# +CREATE TABLE t1( a INT ); +--error ER_BAD_FIELD_ERROR +SELECT b FROM t1; +SHOW ERRORS; +--error ER_BAD_FIELD_ERROR +CREATE TABLE t2 SELECT b FROM t1; +SHOW ERRORS; +--error ER_BAD_FIELD_ERROR +INSERT INTO t1 SELECT b FROM t1; +DROP TABLE t1; # End of 5.0 tests diff --git a/sql/sql_class.h b/sql/sql_class.h index c46adc62c7c..abeb8f385f4 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1983,6 +1983,7 @@ class select_insert :public select_result_interceptor { virtual bool can_rollback_data() { return 0; } void send_error(uint errcode,const char *err); bool send_eof(); + void abort(); /* not implemented: select_insert is never re-used in prepared statements */ void cleanup(); }; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index c0efa621422..120187b3939 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3020,57 +3020,8 @@ void select_insert::send_error(uint errcode,const char *err) { DBUG_ENTER("select_insert::send_error"); - /* Avoid an extra 'unknown error' message if we already reported an error */ - if (errcode != ER_UNKNOWN_ERROR && !thd->net.report_error) - my_message(errcode, err, MYF(0)); + my_message(errcode, err, MYF(0)); - /* - If the creation of the table failed (due to a syntax error, for - example), no table will have been opened and therefore 'table' - will be NULL. In that case, we still need to execute the rollback - and the end of the function. - */ - if (table) - { - /* - If we are not in prelocked mode, we end the bulk insert started - before. - */ - if (!thd->prelocked_mode) - table->file->ha_end_bulk_insert(); - - /* - If at least one row has been inserted/modified and will stay in - the table (the table doesn't have transactions) we must write to - the binlog (and the error code will make the slave stop). - - For many errors (example: we got a duplicate key error while - inserting into a MyISAM table), no row will be added to the table, - so passing the error to the slave will not help since there will - be an error code mismatch (the inserts will succeed on the slave - with no error). - - If table creation failed, the number of rows modified will also be - zero, so no check for that is made. - */ - if (info.copied || info.deleted || info.updated) - { - DBUG_ASSERT(table != NULL); - if (!table->file->has_transactions()) - { - if (mysql_bin_log.is_open()) - thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - table->file->has_transactions(), FALSE); - if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table && - !can_rollback_data()) - thd->no_trans_update.all= TRUE; - query_cache_invalidate3(thd, table, 1); - } - } - table->file->ha_release_auto_increment(); - } - - ha_rollback_stmt(thd); DBUG_VOID_RETURN; } @@ -3160,6 +3111,59 @@ bool select_insert::send_eof() DBUG_RETURN(0); } +void select_insert::abort() { + + DBUG_ENTER("select_insert::abort"); + /* + If the creation of the table failed (due to a syntax error, for + example), no table will have been opened and therefore 'table' + will be NULL. In that case, we still need to execute the rollback + and the end of the function. + */ + if (table) + { + /* + If we are not in prelocked mode, we end the bulk insert started + before. + */ + if (!thd->prelocked_mode) + table->file->ha_end_bulk_insert(); + + /* + If at least one row has been inserted/modified and will stay in + the table (the table doesn't have transactions) we must write to + the binlog (and the error code will make the slave stop). + + For many errors (example: we got a duplicate key error while + inserting into a MyISAM table), no row will be added to the table, + so passing the error to the slave will not help since there will + be an error code mismatch (the inserts will succeed on the slave + with no error). + + If table creation failed, the number of rows modified will also be + zero, so no check for that is made. + */ + if (info.copied || info.deleted || info.updated) + { + DBUG_ASSERT(table != NULL); + if (!table->file->has_transactions()) + { + if (mysql_bin_log.is_open()) + thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, + table->file->has_transactions(), FALSE); + if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table && + !can_rollback_data()) + thd->no_trans_update.all= TRUE; + query_cache_invalidate3(thd, table, 1); + } + } + table->file->ha_release_auto_increment(); + } + + ha_rollback_stmt(thd); + DBUG_VOID_RETURN; +} + /*************************************************************************** CREATE TABLE (SELECT) ... @@ -3596,6 +3600,14 @@ void select_create::abort() { DBUG_ENTER("select_create::abort"); + /* + Disable binlog, because we "roll back" partial inserts in ::abort + by removing the table, even for non-transactional tables. + */ + tmp_disable_binlog(thd); + select_insert::abort(); + reenable_binlog(thd); + /* We roll back the statement, including truncating the transaction cache of the binary log, if the statement failed. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 067e334f73d..504046ef43f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -261,11 +261,8 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, thd->net.report_error)); res|= thd->net.report_error; if (unlikely(res)) - { - /* If we had a another error reported earlier then this will be ignored */ - result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); result->abort(); - } + DBUG_RETURN(res); }