diff options
author | unknown <timour@askmonty.org> | 2012-03-12 00:45:18 +0200 |
---|---|---|
committer | unknown <timour@askmonty.org> | 2012-03-12 00:45:18 +0200 |
commit | ecbd868f58db42e52a2dd8f46c6ee39dc4425cc5 (patch) | |
tree | 56fd7bd0b23d301d39db1b98d969e1fd5942a665 /sql | |
parent | 96a21ab324d02b53cbc7ee8d4585d66eda6dd429 (diff) | |
parent | 8aebd44e0ea9c4ae6f573f1ece27b276452122b8 (diff) | |
download | mariadb-git-ecbd868f58db42e52a2dd8f46c6ee39dc4425cc5.tar.gz |
Merged the implementation of MDEV-28 LIMIT ROWS EXAMINED into MariaDB 5.5.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/filesort.cc | 7 | ||||
-rw-r--r-- | sql/lex.h | 1 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 2 | ||||
-rw-r--r-- | sql/signal_handler.cc | 4 | ||||
-rw-r--r-- | sql/sql_class.cc | 29 | ||||
-rw-r--r-- | sql/sql_class.h | 44 | ||||
-rw-r--r-- | sql/sql_insert.cc | 2 | ||||
-rw-r--r-- | sql/sql_lex.cc | 5 | ||||
-rw-r--r-- | sql/sql_lex.h | 16 | ||||
-rw-r--r-- | sql/sql_parse.cc | 1 | ||||
-rw-r--r-- | sql/sql_select.cc | 94 | ||||
-rw-r--r-- | sql/sql_union.cc | 25 | ||||
-rw-r--r-- | sql/sql_view.cc | 11 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 21 |
14 files changed, 215 insertions, 47 deletions
diff --git a/sql/filesort.cc b/sql/filesort.cc index f9fe0d731cd..b531c4d8026 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -329,13 +329,14 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, if (error) { int kill_errno= thd->killed_errno(); - DBUG_ASSERT(thd->is_error() || kill_errno); + DBUG_ASSERT(thd->is_error() || kill_errno || thd->killed == ABORT_QUERY); my_printf_error(ER_FILSORT_ABORT, "%s: %s", MYF(0), ER_THD(thd, ER_FILSORT_ABORT), - kill_errno ? ER(kill_errno) : thd->stmt_da->message()); - + kill_errno ? ER(kill_errno) : + thd->killed == ABORT_QUERY ? "" : thd->stmt_da->message()); + if (global_system_variables.log_warnings > 1) { sql_print_warning("%s, host: %s, user: %s, thread: %lu, query: %-.4096s", diff --git a/sql/lex.h b/sql/lex.h index bb8f5825879..9f4369630a0 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -212,6 +212,7 @@ static SYMBOL symbols[] = { { "EVENT", SYM(EVENT_SYM)}, { "EVENTS", SYM(EVENTS_SYM)}, { "EVERY", SYM(EVERY_SYM)}, + { "EXAMINED", SYM(EXAMINED_SYM)}, { "EXECUTE", SYM(EXECUTE_SYM)}, { "EXISTS", SYM(EXISTS)}, { "EXIT", SYM(EXIT_SYM)}, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 90cee00fde4..73357b6c4a2 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6561,3 +6561,5 @@ ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION eng "Cannot modify @@session.skip_replication inside a transaction" ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION eng "Cannot modify @@session.skip_replication inside a stored function or trigger" +ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT + eng "Query execution was interrupted. The query examined at least %llu rows, which exceeds LIMIT ROWS EXAMINED (%llu). The query result may be incomplete." diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index dd50854d818..61b67c9d229 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -196,6 +196,10 @@ extern "C" sig_handler handle_fatal_signal(int sig) case KILL_SERVER_HARD: kreason= "KILL_SERVER"; break; + case ABORT_QUERY: + case ABORT_QUERY_HARD: + kreason= "ABORT_QUERY"; + break; } my_safe_printf_stderr("%s", "\n" "Trying to get some variables.\n" diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f970f6a4f26..d7d0c8d3f68 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -737,6 +737,7 @@ THD::THD() first_successful_insert_id_in_cur_stmt(0), stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE), examined_row_count(0), + accessed_rows_and_keys(0), warning_info(&main_warning_info), stmt_da(&main_da), global_disable_checkpoint(0), @@ -1644,26 +1645,31 @@ void THD::disconnect() int killed_errno(killed_state killed) { + DBUG_ENTER("killed_errno"); + DBUG_PRINT("enter", ("killed: %d", killed)); + switch (killed) { case NOT_KILLED: case KILL_HARD_BIT: - return 0; // Probably wrong usage + DBUG_RETURN(0); // Probably wrong usage case KILL_BAD_DATA: case KILL_BAD_DATA_HARD: - return 0; // Not a real error + case ABORT_QUERY_HARD: + case ABORT_QUERY: + DBUG_RETURN(0); // Not a real error case KILL_CONNECTION: case KILL_CONNECTION_HARD: case KILL_SYSTEM_THREAD: case KILL_SYSTEM_THREAD_HARD: - return ER_CONNECTION_KILLED; + DBUG_RETURN(ER_CONNECTION_KILLED); case KILL_QUERY: case KILL_QUERY_HARD: - return ER_QUERY_INTERRUPTED; + DBUG_RETURN(ER_QUERY_INTERRUPTED); case KILL_SERVER: case KILL_SERVER_HARD: - return ER_SERVER_SHUTDOWN; + DBUG_RETURN(ER_SERVER_SHUTDOWN); } - return 0; // Keep compiler happy + DBUG_RETURN(0); // Keep compiler happy } @@ -2248,6 +2254,8 @@ int select_send::send_data(List<Item> &items) unit->offset_limit_cnt--; DBUG_RETURN(FALSE); } + if (thd->killed == ABORT_QUERY) + DBUG_RETURN(FALSE); /* We may be passing the control from mysqld to the client: release the @@ -2541,6 +2549,8 @@ int select_export::send_data(List<Item> &items) unit->offset_limit_cnt--; DBUG_RETURN(0); } + if (thd->killed == ABORT_QUERY) + DBUG_RETURN(0); row_count++; Item *item; uint used_length=0,items_left=items.elements; @@ -2796,6 +2806,9 @@ int select_dump::send_data(List<Item> &items) unit->offset_limit_cnt--; DBUG_RETURN(0); } + if (thd->killed == ABORT_QUERY) + DBUG_RETURN(0); + if (row_count++ > 1) { my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0)); @@ -2842,6 +2855,8 @@ int select_singlerow_subselect::send_data(List<Item> &items) unit->offset_limit_cnt--; DBUG_RETURN(0); } + if (thd->killed == ABORT_QUERY) + DBUG_RETURN(0); List_iterator_fast<Item> li(items); Item *val_item; for (uint i= 0; (val_item= li++); i++) @@ -2985,6 +3000,8 @@ int select_exists_subselect::send_data(List<Item> &items) unit->offset_limit_cnt--; DBUG_RETURN(0); } + if (thd->killed == ABORT_QUERY) + DBUG_RETURN(0); it->value= 1; it->assigned(1); DBUG_RETURN(0); diff --git a/sql/sql_class.h b/sql/sql_class.h index 5c35bc37623..c6c46975076 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -396,7 +396,10 @@ typedef enum enum_diag_condition_item_name */ extern const LEX_STRING Diag_condition_item_names[]; -/* Note: these states are actually bit coded with HARD */ +/** + These states are bit coded with HARD. For each state there must be a pair + <state_even_num>, and <state_odd_num>_HARD. +*/ enum killed_state { NOT_KILLED= 0, @@ -406,15 +409,23 @@ enum killed_state KILL_QUERY= 4, KILL_QUERY_HARD= 5, /* + ABORT_QUERY signals to the query processor to stop execution ASAP without + issuing an error. Instead a warning is issued, and when possible a partial + query result is returned to the client. + */ + ABORT_QUERY= 6, + ABORT_QUERY_HARD= 7, + /* All of the following killed states will kill the connection - KILL_CONNECTION must be the first of these! - */ - KILL_CONNECTION= 6, - KILL_CONNECTION_HARD= 7, - KILL_SYSTEM_THREAD= 8, - KILL_SYSTEM_THREAD_HARD= 9, - KILL_SERVER= 10, - KILL_SERVER_HARD= 11 + KILL_CONNECTION must be the first of these and it must start with + an even number (becasue of HARD bit)! + */ + KILL_CONNECTION= 8, + KILL_CONNECTION_HARD= 9, + KILL_SYSTEM_THREAD= 10, + KILL_SYSTEM_THREAD_HARD= 11, + KILL_SERVER= 12, + KILL_SERVER_HARD= 13 }; extern int killed_errno(killed_state killed); @@ -2091,6 +2102,20 @@ public: filesort() before reading it for e.g. update. */ ha_rows examined_row_count; + /** + The number of rows and/or keys examined by the query, both read, + changed or written. + */ + ulonglong accessed_rows_and_keys; + /** + Check if the number of rows accessed by a statement exceeded + LIMIT ROWS EXAMINED. If so, signal the query engine to stop execution. + */ + void check_limit_rows_examined() + { + if (++accessed_rows_and_keys > lex->limit_rows_examined_cnt) + killed= ABORT_QUERY; + } USER_CONN *user_connect; CHARSET_INFO *db_charset; @@ -4102,6 +4127,7 @@ inline bool add_group_to_list(THD *thd, Item *item, bool asc) inline void handler::increment_statistics(ulong SSV::*offset) const { status_var_increment(table->in_use->status_var.*offset); + table->in_use->check_limit_rows_examined(); } inline void handler::decrement_statistics(ulong SSV::*offset) const diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2209a62d7ed..54f94ce78c1 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3476,6 +3476,8 @@ int select_insert::send_data(List<Item> &values) unit->offset_limit_cnt--; DBUG_RETURN(0); } + if (thd->killed == ABORT_QUERY) + DBUG_RETURN(0); thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields store_values(values); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 56e05c3dcad..b2dfae5ded4 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -526,6 +526,8 @@ void lex_start(THD *thd) lex->is_lex_started= TRUE; lex->used_tables= 0; lex->reset_slave_info.all= false; + lex->limit_rows_examined= 0; + lex->limit_rows_examined_cnt= ULONGLONG_MAX; DBUG_VOID_RETURN; } @@ -2523,7 +2525,8 @@ void Query_tables_list::destroy_query_tables_list() */ LEX::LEX() - :result(0), option_type(OPT_DEFAULT), is_lex_started(0) + :result(0), option_type(OPT_DEFAULT), is_lex_started(0), + limit_rows_examined_cnt(ULONGLONG_MAX) { my_init_dynamic_array2(&plugins, sizeof(plugin_ref), diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d4e94c8d2d8..718c9c7e6a2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2568,6 +2568,22 @@ struct LEX: public Query_tables_list into the select_lex. */ table_map used_tables; + /** + Maximum number of rows and/or keys examined by the query, both read, + changed or written. This is the argument of LIMIT ROWS EXAMINED. + The limit is represented by two variables - the Item is needed because + in case of parameters we have to delay its evaluation until execution. + Once evaluated, its value is stored in examined_rows_limit_cnt. + */ + Item *limit_rows_examined; + ulonglong limit_rows_examined_cnt; + inline void set_limit_rows_examined() + { + if (limit_rows_examined) + limit_rows_examined_cnt= limit_rows_examined->val_uint(); + else + limit_rows_examined_cnt= ULONGLONG_MAX; + } LEX(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d1b2eade165..e0b2acd199d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5460,6 +5460,7 @@ void THD::reset_for_next_command(bool calculate_userstat) thd->warning_info->reset_for_next_command(); thd->rand_used= 0; thd->sent_row_count= thd->examined_row_count= 0; + thd->accessed_rows_and_keys= 0; /* Copy data for user stats */ if ((thd->userstat_running= calculate_userstat)) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7cacf0fd811..2e63a16d4e6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -314,6 +314,21 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, res|= thd->is_error(); if (unlikely(res)) result->abort_result_set(); + if (thd->killed == ABORT_QUERY) + { + /* + If LIMIT ROWS EXAMINED interrupted query execution, issue a warning, + continue with normal processing and produce an incomplete query result. + */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT, + ER(ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT), + thd->accessed_rows_and_keys, + thd->lex->limit_rows_examined->val_uint()); + thd->killed= NOT_KILLED; + } + /* Disable LIMIT ROWS EXAMINED after query execution. */ + thd->lex->limit_rows_examined_cnt= ULONGLONG_MAX; MYSQL_SELECT_DONE((int) res, (ulong) thd->limit_found_rows); DBUG_RETURN(res); @@ -1725,6 +1740,19 @@ int JOIN::init_execution() DBUG_ASSERT(!(select_options & SELECT_DESCRIBE)); initialized= true; + /* + Enable LIMIT ROWS EXAMINED during query execution if: + (1) This JOIN is the outermost query (not a subquery or derived table) + This ensures that the limit is enabled when actual execution begins, and + not if a subquery is evaluated during optimization of the outer query. + (2) This JOIN is not the result of a UNION. In this case do not apply the + limit in order to produce the partial query result stored in the + UNION temp table. + */ + if (!select_lex->outer_select() && // (1) + select_lex != select_lex->master_unit()->fake_select_lex) // (2) + thd->lex->set_limit_rows_examined(); + /* Create a tmp table if distinct or if the sort is too complicated */ if (need_tmp) { @@ -15377,12 +15405,13 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) error= NESTED_LOOP_NO_MORE_ROWS; else error= sub_select(join,join_tab,0); - if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) + if ((error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) && + join->thd->killed != ABORT_QUERY) error= sub_select(join,join_tab,1); if (error == NESTED_LOOP_QUERY_LIMIT) error= NESTED_LOOP_OK; /* select_limit used */ } - if (error == NESTED_LOOP_NO_MORE_ROWS) + if (error == NESTED_LOOP_NO_MORE_ROWS || join->thd->killed == ABORT_QUERY) error= NESTED_LOOP_OK; if (table) @@ -16953,11 +16982,6 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), TABLE *table=join->tmp_table; DBUG_ENTER("end_write"); - if (join->thd->killed) // Aborted by user - { - join->thd->send_kill_message(); - DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ - } if (!end_of_records) { copy_fields(&join->tmp_table_param); @@ -16986,11 +17010,15 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); join->do_send_rows=0; join->unit->select_limit_cnt = HA_POS_ERROR; - DBUG_RETURN(NESTED_LOOP_OK); } } } end: + if (join->thd->killed) + { + join->thd->send_kill_message(); + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ + } DBUG_RETURN(NESTED_LOOP_OK); } @@ -17008,11 +17036,6 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (end_of_records) DBUG_RETURN(NESTED_LOOP_OK); - if (join->thd->killed) // Aborted by user - { - join->thd->send_kill_message(); - DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ - } join->found_records++; copy_fields(&join->tmp_table_param); // Groups are copied twice. @@ -17038,7 +17061,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), table->file->print_error(error,MYF(0)); /* purecov: inspected */ DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ } - DBUG_RETURN(NESTED_LOOP_OK); + goto end; } /* @@ -17073,6 +17096,12 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), join->join_tab[join->top_join_tab_count-1].next_select=end_unique_update; } join->send_records++; +end: + if (join->thd->killed) + { + join->thd->send_kill_message(); + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ + } DBUG_RETURN(NESTED_LOOP_OK); } @@ -17089,11 +17118,6 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (end_of_records) DBUG_RETURN(NESTED_LOOP_OK); - if (join->thd->killed) // Aborted by user - { - join->thd->send_kill_message(); - DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ - } init_tmptable_sum_functions(join->sum_funcs); copy_fields(&join->tmp_table_param); // Groups are copied twice. @@ -17123,6 +17147,11 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ } } + if (join->thd->killed) + { + join->thd->send_kill_message(); + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ + } DBUG_RETURN(NESTED_LOOP_OK); } @@ -17136,11 +17165,6 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), int idx= -1; DBUG_ENTER("end_write_group"); - if (join->thd->killed) - { // Aborted by user - join->thd->send_kill_message(); - DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ - } if (!join->first_record || end_of_records || (idx=test_if_group_changed(join->group_fields)) >= 0) { @@ -17174,13 +17198,13 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), DBUG_RETURN(NESTED_LOOP_ERROR); } if (end_of_records) - DBUG_RETURN(NESTED_LOOP_OK); + goto end; } } else { if (end_of_records) - DBUG_RETURN(NESTED_LOOP_OK); + goto end; join->first_record=1; (void) test_if_group_changed(join->group_fields); } @@ -17193,13 +17217,19 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) join->procedure->add(); - DBUG_RETURN(NESTED_LOOP_OK); + goto end; } } if (update_sum_func(join->sum_funcs)) DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) join->procedure->add(); +end: + if (join->thd->killed) + { + join->thd->send_kill_message(); + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ + } DBUG_RETURN(NESTED_LOOP_OK); } @@ -18586,6 +18616,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) ulong reclength,offset; uint field_count; THD *thd= join->thd; + DBUG_ENTER("remove_duplicates"); entry->reginfo.lock_type=TL_WRITE; @@ -18611,6 +18642,13 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) offset(entry->record[0]) : 0); reclength=entry->s->reclength-offset; + /* + Disable LIMIT ROWS EXAMINED in order to avoid interrupting prematurely + duplicate removal, and produce a possibly incomplete query result. + */ + thd->lex->limit_rows_examined_cnt= ULONGLONG_MAX; + if (thd->killed == ABORT_QUERY) + thd->killed= NOT_KILLED; free_io_cache(entry); // Safety entry->file->info(HA_STATUS_VARIABLE); if (entry->s->db_type() == heap_hton || @@ -18624,6 +18662,8 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) error=remove_dup_with_compare(join->thd, entry, first_field, offset, having); + if (join->select_lex != join->select_lex->master_unit()->fake_select_lex) + thd->lex->set_limit_rows_examined(); free_blobs(first_field); DBUG_RETURN(error); } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 2118bc8c30d..021267b53bd 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -59,6 +59,8 @@ int select_union::send_data(List<Item> &values) unit->offset_limit_cnt--; return 0; } + if (thd->killed == ABORT_QUERY) + return 0; if (table->no_rows_with_nulls) table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT; fill_record(thd, table->field, values, TRUE, FALSE); @@ -701,6 +703,20 @@ bool st_select_lex_unit::exec() add_rows+= (ulonglong) (thd->limit_found_rows - (ulonglong) ((table->file->stats.records - records_at_start))); } + if (thd->killed == ABORT_QUERY) + { + /* + Stop execution of the remaining queries in the UNIONS, and produce + the current result. + */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT, + ER(ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT), + thd->accessed_rows_and_keys, + thd->lex->limit_rows_examined->val_uint()); + thd->killed= NOT_KILLED; + break; + } } } @@ -709,6 +725,11 @@ bool st_select_lex_unit::exec() { List<Item_func_match> empty_list; empty_list.empty(); + /* + Disable LIMIT ROWS EXAMINED in order to produce the possibly incomplete + result of the UNION without interruption due to exceeding the limit. + */ + thd->lex->limit_rows_examined_cnt= ULONGLONG_MAX; if (!thd->is_fatal_error) // Check if EOM { @@ -729,7 +750,7 @@ bool st_select_lex_unit::exec() fake_select_lex->options, result))) { fake_select_lex->table_list.empty(); - DBUG_RETURN(TRUE); + goto err; } fake_select_lex->join->no_const_tables= TRUE; @@ -801,6 +822,8 @@ bool st_select_lex_unit::exec() } } thd->lex->current_select= lex_select_save; +err: + thd->lex->set_limit_rows_examined(); DBUG_RETURN(saved_error); } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index a307ebecca1..0db69af094f 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -451,6 +451,17 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, goto err; } + if (lex->limit_rows_examined) + { + /* + LIMIT ROWS EXAMINED is not supported inside views to avoid complicated + side-effects and semantics of the clause. + */ + my_error(ER_NOT_SUPPORTED_YET, MYF(0), "LIMIT ROWS EXAMINED inside views"); + res= TRUE; + goto err; + } + sp_cache_invalidate(); if (!lex->definer) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 54e2f3012ff..5f9066afd39 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -977,6 +977,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token EVENTS_SYM %token EVENT_SYM %token EVERY_SYM /* SQL-2003-N */ +%token EXAMINED_SYM %token EXECUTE_SYM /* SQL-2003-R */ %token EXISTS /* SQL-2003-R */ %token EXIT_SYM @@ -10304,6 +10305,7 @@ opt_limit_clause_init: SELECT_LEX *sel= lex->current_select; sel->offset_limit= 0; sel->select_limit= 0; + lex->limit_rows_examined= 0; } | limit_clause {} ; @@ -10318,6 +10320,14 @@ limit_clause: { Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); } + | LIMIT limit_options ROWS_SYM EXAMINED_SYM limit_rows_option + { + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); + } + | LIMIT ROWS_SYM EXAMINED_SYM limit_rows_option + { + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); + } ; limit_options: @@ -10403,6 +10413,13 @@ limit_option: } ; +limit_rows_option: + limit_option + { + LEX *lex=Lex; + lex->limit_rows_examined= $1; + } + delete_limit_clause: /* empty */ { @@ -10416,6 +10433,8 @@ delete_limit_clause: Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); sel->explicit_limit= 1; } + | LIMIT ROWS_SYM EXAMINED_SYM { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } + | LIMIT limit_option ROWS_SYM EXAMINED_SYM { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } ; int_num: @@ -12892,6 +12911,7 @@ keyword: | DEALLOCATE_SYM {} | DO_SYM {} | END {} + | EXAMINED_SYM {} | EXECUTE_SYM {} | FLUSH_SYM {} | HANDLER_SYM {} @@ -13793,6 +13813,7 @@ handler: MYSQL_YYABORT; lex->current_select->select_limit= one; lex->current_select->offset_limit= 0; + lex->limit_rows_examined= 0; if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) MYSQL_YYABORT; } |