From d44dd54bc838e6679f451a8faf07a7f44efe2fa4 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 17 Oct 2014 14:18:10 +0400 Subject: [PATCH] MDEV-6400: "ANALYZE SELECT ... INTO @var" doesn't set @var Make ANALYZE work for - ANALYZE SELECT ... INTO @var - ANALYZE INSERT SELECT ...; - ANALYZE SELECT .. INTO OUTFILE --- mysql-test/r/analyze_stmt.result | 17 +++++++++++++++++ mysql-test/t/analyze_stmt.test | 16 ++++++++++++++++ sql/sql_class.cc | 7 +++++-- sql/sql_class.h | 22 +++++++++++++++++++++- sql/sql_insert.cc | 4 ++++ sql/sql_parse.cc | 26 +++++++++++++++++++------- 6 files changed, 82 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/analyze_stmt.result b/mysql-test/r/analyze_stmt.result index e5b3b804202..628c7859e6c 100644 --- a/mysql-test/r/analyze_stmt.result +++ b/mysql-test/r/analyze_stmt.result @@ -276,3 +276,20 @@ select * from t1; a b 1 2 drop table t1; +# +# MDEV-6400 "ANALYZE SELECT ... INTO @var" doesn't set @var +# +create table t1(a int); +insert into t1 values (1),(2); +analyze select a from t1 where a <2 into @var; +id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2 100.00 50.00 Using where +analyze select a from t1 into @var; +ERROR 42000: Result consisted of more than one row +analyze insert into t1 select * from t1; +id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 2 100.00 100.00 Using temporary +analyze select * into outfile '../../tmp/data1.tmp' from t1; +id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 4 100.00 100.00 +drop table t1; diff --git a/mysql-test/t/analyze_stmt.test b/mysql-test/t/analyze_stmt.test index 4c89890ac29..f5c5c432434 100644 --- a/mysql-test/t/analyze_stmt.test +++ b/mysql-test/t/analyze_stmt.test @@ -217,3 +217,19 @@ analyze replace t1 values (1,2); select * from t1; drop table t1; +--echo # +--echo # MDEV-6400 "ANALYZE SELECT ... INTO @var" doesn't set @var +--echo # +create table t1(a int); +insert into t1 values (1),(2); + +analyze select a from t1 where a <2 into @var; +--error ER_TOO_MANY_ROWS +analyze select a from t1 into @var; + +analyze insert into t1 select * from t1; + +analyze select * into outfile '../../tmp/data1.tmp' from t1; +--remove_file $MYSQLTEST_VARDIR/tmp/data1.tmp + +drop table t1; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 430bfbf760d..5a4feac727b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2710,7 +2710,7 @@ bool select_to_file::send_eof() if (mysql_file_close(file, MYF(MY_WME)) || thd->is_error()) error= true; - if (!error) + if (!error && !suppress_my_ok) { ::my_ok(thd,row_count); } @@ -3786,11 +3786,14 @@ bool select_dumpvar::send_eof() if (thd->is_error()) return true; - ::my_ok(thd,row_count); + if (!suppress_my_ok) + ::my_ok(thd,row_count); + return 0; } + bool select_materialize_with_stats:: create_result_table(THD *thd_arg, List *column_types, diff --git a/sql/sql_class.h b/sql/sql_class.h index d7bbfc3799d..9964d52a766 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3956,6 +3956,14 @@ public: { unit->offset_limit_cnt= 0; } + + /* + This returns + - FALSE if the class sends output row to the client + - TRUE if the output is set elsewhere (a file, @variable, or table). + Currently all intercepting classes derive from select_result_interceptor. + */ + virtual bool is_result_interceptor()=0; }; @@ -3986,6 +3994,8 @@ public: /* This is a select_result_sink which stores the data in text form. + + It is only used to save EXPLAIN output. */ class select_result_text_buffer : public select_result_sink @@ -4014,7 +4024,7 @@ private: class select_result_interceptor: public select_result { public: - select_result_interceptor() + select_result_interceptor() : suppress_my_ok(false) { DBUG_ENTER("select_result_interceptor::select_result_interceptor"); DBUG_PRINT("enter", ("this 0x%lx", (ulong) this)); @@ -4022,6 +4032,15 @@ public: } /* Remove gcc warning */ uint field_count(List &fields) const { return 0; } bool send_result_set_metadata(List &fields, uint flag) { return FALSE; } + bool is_result_interceptor() { return true; } + + /* + Instruct the object to not call my_ok(). Client output will be handled + elsewhere. (this is used by ANALYZE $stmt feature). + */ + void disable_my_ok_calls() { suppress_my_ok= true; } +protected: + bool suppress_my_ok; }; @@ -4040,6 +4059,7 @@ public: virtual bool check_simple_select() const { return FALSE; } void abort_result_set(); virtual void cleanup(); + bool is_result_interceptor() { return true; } }; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2b68f7766ac..d9982cb7ebe 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3712,6 +3712,10 @@ bool select_insert::send_eof() table->file->print_error(error,MYF(0)); DBUG_RETURN(1); } + + if (suppress_my_ok) + DBUG_RETURN(0); + char buff[160]; if (info.ignore) sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d8906b2d578..1962666f6b9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3814,6 +3814,9 @@ end_with_restore_list: lex->duplicates, lex->ignore))) { + if (lex->analyze_stmt) + ((select_result_interceptor*)sel_result)->disable_my_ok_calls(); + res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE); /* Invalidate the table in the query cache if something changed @@ -3833,7 +3836,7 @@ end_with_restore_list: delete sel_result; } - if (!res && explain) + if (!res && (explain || lex->analyze_stmt)) res= thd->lex->explain->send_explain(thd); /* revert changes for SP */ @@ -5649,12 +5652,18 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) } else { - Protocol *save_protocol; + Protocol *save_protocol= NULL; if (lex->analyze_stmt) { - result= new select_send_analyze(); - save_protocol= thd->protocol; - thd->protocol= new Protocol_discard(thd); + if (result && result->is_result_interceptor()) + ((select_result_interceptor*)result)->disable_my_ok_calls(); + else + { + DBUG_ASSERT(thd->protocol); + result= new select_send_analyze(); + save_protocol= thd->protocol; + thd->protocol= new Protocol_discard(thd); + } } else { @@ -5668,8 +5677,11 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) if (lex->analyze_stmt) { - delete thd->protocol; - thd->protocol= save_protocol; + if (save_protocol) + { + delete thd->protocol; + thd->protocol= save_protocol; + } if (!res) res= thd->lex->explain->send_explain(thd); }