diff options
Diffstat (limited to 'sql/sql_prepare.cc')
-rw-r--r-- | sql/sql_prepare.cc | 200 |
1 files changed, 83 insertions, 117 deletions
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3652a6ab086..ea6bfe03be5 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -112,6 +112,7 @@ When one supplies long data for a placeholder: #include "sp_cache.h" #include "sql_handler.h" // mysql_ha_rm_tables #include "probes_mysql.h" +#include "opt_trace.h" #ifdef EMBEDDED_LIBRARY /* include MYSQL_BIND headers */ #include <mysql.h> @@ -124,7 +125,10 @@ static const uint PARAMETER_FLAG_UNSIGNED= 128U << 8; #include "log_event.h" // class Log_event #include "sql_handler.h" #include "transaction.h" // trans_rollback_implicit +#ifdef WITH_WSREP #include "wsrep_mysqld.h" +#include "wsrep_trans_observer.h" +#endif /* WITH_WSREP */ /** A result class used to send cursor rows using the binary protocol. @@ -192,7 +196,7 @@ public: void setup_set_params(); virtual Query_arena::Type type() const; virtual void cleanup_stmt(); - bool set_name(LEX_CSTRING *name); + bool set_name(const LEX_CSTRING *name); inline void close_cursor() { delete cursor; cursor= 0; } inline bool is_in_use() { return flags & (uint) IS_IN_USE; } inline bool is_sql_prepare() const { return flags & (uint) IS_SQL_PREPARE; } @@ -1426,7 +1430,7 @@ static int mysql_test_update(Prepared_statement *stmt, THD *thd= stmt->thd; uint table_count= 0; TABLE_LIST *update_source_table; - SELECT_LEX *select= &stmt->lex->select_lex; + SELECT_LEX *select= stmt->lex->first_select_lex(); #ifndef NO_EMBEDDED_ACCESS_CHECKS uint want_privilege; #endif @@ -1482,10 +1486,10 @@ static int mysql_test_update(Prepared_statement *stmt, table_list->table->grant.want_privilege= want_privilege; table_list->register_want_access(want_privilege); #endif - thd->lex->select_lex.no_wrap_view_item= TRUE; + thd->lex->first_select_lex()->no_wrap_view_item= TRUE; res= setup_fields(thd, Ref_ptr_array(), select->item_list, MARK_COLUMNS_READ, 0, NULL, 0); - thd->lex->select_lex.no_wrap_view_item= FALSE; + thd->lex->first_select_lex()->no_wrap_view_item= FALSE; if (res) goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1550,10 +1554,10 @@ static bool mysql_test_delete(Prepared_statement *stmt, goto error; } - DBUG_RETURN(mysql_prepare_delete(thd, table_list, - lex->select_lex.with_wild, - lex->select_lex.item_list, - &lex->select_lex.where, + DBUG_RETURN(mysql_prepare_delete(thd, table_list, + lex->first_select_lex()->with_wild, + lex->first_select_lex()->item_list, + &lex->first_select_lex()->where, &delete_while_scanning)); error: DBUG_RETURN(TRUE); @@ -1585,7 +1589,7 @@ static int mysql_test_select(Prepared_statement *stmt, SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_test_select"); - lex->select_lex.context.resolve_in_select_list= TRUE; + lex->first_select_lex()->context.resolve_in_select_list= TRUE; ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL; if (tables) @@ -1598,7 +1602,7 @@ static int mysql_test_select(Prepared_statement *stmt, if (!lex->result && !(lex->result= new (stmt->mem_root) select_send(thd))) { - my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), static_cast<int>(sizeof(select_send))); goto error; } @@ -1619,7 +1623,7 @@ static int mysql_test_select(Prepared_statement *stmt, if (!lex->describe && !thd->lex->analyze_stmt && !stmt->is_sql_prepare()) { /* Make copy of item list, as change_columns may change it */ - List<Item> fields(lex->select_lex.item_list); + List<Item> fields(lex->first_select_lex()->item_list); /* Change columns if a procedure like analyse() */ if (unit->last_procedure && unit->last_procedure->change_columns(thd, fields)) @@ -1777,7 +1781,7 @@ static bool select_like_stmt_test(Prepared_statement *stmt, THD *thd= stmt->thd; LEX *lex= stmt->lex; - lex->select_lex.context.resolve_in_select_list= TRUE; + lex->first_select_lex()->context.resolve_in_select_list= TRUE; if (specific_prepare && (*specific_prepare)(thd)) DBUG_RETURN(TRUE); @@ -1845,7 +1849,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt) DBUG_ENTER("mysql_test_create_table"); THD *thd= stmt->thd; LEX *lex= stmt->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); bool res= FALSE; bool link_to_local; TABLE_LIST *create_table= lex->query_tables; @@ -2177,11 +2181,11 @@ static bool mysql_test_multidelete(Prepared_statement *stmt, { THD *thd= stmt->thd; - thd->lex->current_select= &thd->lex->select_lex; + thd->lex->current_select= thd->lex->first_select_lex(); if (add_item_to_list(thd, new (thd->mem_root) Item_null(thd))) { - my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), 0); + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 0); goto error; } @@ -2216,13 +2220,14 @@ error: static int mysql_insert_select_prepare_tester(THD *thd) { - SELECT_LEX *first_select= &thd->lex->select_lex; + SELECT_LEX *first_select= thd->lex->first_select_lex(); TABLE_LIST *second_table= first_select->table_list.first->next_local; /* Skip first table, which is the table we are inserting in */ first_select->table_list.first= second_table; - thd->lex->select_lex.context.table_list= - thd->lex->select_lex.context.first_name_resolution_table= second_table; + thd->lex->first_select_lex()->context.table_list= + thd->lex->first_select_lex()->context.first_name_resolution_table= + second_table; return mysql_insert_select_prepare(thd); } @@ -2257,7 +2262,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, return 1; /* store it, because mysql_insert_select_prepare_tester change it */ - first_local_table= lex->select_lex.table_list.first; + first_local_table= lex->first_select_lex()->table_list.first; DBUG_ASSERT(first_local_table != 0); res= @@ -2265,7 +2270,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, &mysql_insert_select_prepare_tester, OPTION_SETUP_TABLES_DONE); /* revert changes made by mysql_insert_select_prepare_tester */ - lex->select_lex.table_list.first= first_local_table; + lex->first_select_lex()->table_list.first= first_local_table; return res; } @@ -2291,7 +2296,7 @@ static int mysql_test_handler_read(Prepared_statement *stmt, SQL_HANDLER *ha_table; DBUG_ENTER("mysql_test_handler_read"); - lex->select_lex.context.resolve_in_select_list= TRUE; + lex->first_select_lex()->context.resolve_in_select_list= TRUE; /* We don't have to test for permissions as this is already done during @@ -2301,7 +2306,7 @@ static int mysql_test_handler_read(Prepared_statement *stmt, lex->ident.str, lex->insert_list, lex->ha_rkey_mode, - lex->select_lex.where))) + lex->first_select_lex()->where))) DBUG_RETURN(1); if (!stmt->is_sql_prepare()) @@ -2340,7 +2345,7 @@ static bool check_prepared_statement(Prepared_statement *stmt) { THD *thd= stmt->thd; LEX *lex= stmt->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); TABLE_LIST *tables; enum enum_sql_command sql_command= lex->sql_command; int res= 0; @@ -2349,12 +2354,24 @@ static bool check_prepared_statement(Prepared_statement *stmt) sql_command, stmt->param_count)); lex->first_lists_tables_same(); + lex->fix_first_select_number(); tables= lex->query_tables; /* set context for commands which do not use setup_tables */ - lex->select_lex.context.resolve_in_table_list_only(select_lex-> + lex->first_select_lex()->context.resolve_in_table_list_only(select_lex-> get_table_list()); + /* + For the optimizer trace, this is the symmetric, for statement preparation, + of what is done at statement execution (in mysql_execute_command()). + */ + Opt_trace_start ots(thd, tables, lex->sql_command, &lex->var_list, + thd->query(), thd->query_length(), + thd->variables.character_set_client); + + Json_writer_object trace_command(thd); + Json_writer_array trace_command_steps(thd, "steps"); + /* Reset warning count for each query that uses tables */ if (tables) thd->get_stmt_da()->opt_clear_warning_info(thd->query_id); @@ -2745,7 +2762,7 @@ end: } /** - Get an SQL statement from an item in lex->prepared_stmt_code. + Get an SQL statement from an item in m_code. This function can return pointers to very different memory classes: - a static string "NULL", if the item returned NULL @@ -2770,13 +2787,15 @@ end: @retval true on error (out of memory) */ -bool LEX::get_dynamic_sql_string(LEX_CSTRING *dst, String *buffer) +bool Lex_prepared_stmt::get_dynamic_sql_string(THD *thd, + LEX_CSTRING *dst, + String *buffer) { - if (prepared_stmt_code->fix_fields_if_needed_for_scalar(thd, NULL)) + if (m_code->fix_fields_if_needed_for_scalar(thd, NULL)) return true; - const String *str= prepared_stmt_code->val_str(buffer); - if (prepared_stmt_code->null_value) + const String *str= m_code->val_str(buffer); + if (m_code->null_value) { /* Prepare source was NULL, so we need to set "str" to @@ -2857,7 +2876,7 @@ bool LEX::get_dynamic_sql_string(LEX_CSTRING *dst, String *buffer) void mysql_sql_stmt_prepare(THD *thd) { LEX *lex= thd->lex; - LEX_CSTRING *name= &lex->prepared_stmt_name; + const LEX_CSTRING *name= &lex->prepared_stmt.name(); Prepared_statement *stmt; LEX_CSTRING query; DBUG_ENTER("mysql_sql_stmt_prepare"); @@ -2882,7 +2901,7 @@ void mysql_sql_stmt_prepare(THD *thd) See comments in get_dynamic_sql_string(). */ StringBuffer<256> buffer; - if (lex->get_dynamic_sql_string(&query, &buffer) || + if (lex->prepared_stmt.get_dynamic_sql_string(thd, &query, &buffer) || ! (stmt= new Prepared_statement(thd))) { DBUG_VOID_RETURN; /* out of memory */ @@ -2945,7 +2964,7 @@ void mysql_sql_stmt_execute_immediate(THD *thd) LEX_CSTRING query; DBUG_ENTER("mysql_sql_stmt_execute_immediate"); - if (lex->prepared_stmt_params_fix_fields(thd)) + if (lex->prepared_stmt.params_fix_fields(thd)) DBUG_VOID_RETURN; /* @@ -2957,7 +2976,7 @@ void mysql_sql_stmt_execute_immediate(THD *thd) See comments in get_dynamic_sql_string(). */ StringBuffer<256> buffer; - if (lex->get_dynamic_sql_string(&query, &buffer) || + if (lex->prepared_stmt.get_dynamic_sql_string(thd, &query, &buffer) || !(stmt= new Prepared_statement(thd))) DBUG_VOID_RETURN; // out of memory @@ -3092,6 +3111,10 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) for (order= win_spec->order_list->first; order; order= order->next) order->item= &order->item_ptr; } + + // Reinit Pushdown + sl->cond_pushed_into_where= NULL; + sl->cond_pushed_into_having= NULL; } if (sl->changed_elements & TOUCHED_SEL_DERIVED) { @@ -3146,7 +3169,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) { tables->reinit_before_use(thd); } - lex->current_select= &lex->select_lex; + lex->current_select= lex->first_select_lex(); if (lex->result) @@ -3470,7 +3493,7 @@ void mysql_sql_stmt_execute(THD *thd) { LEX *lex= thd->lex; Prepared_statement *stmt; - LEX_CSTRING *name= &lex->prepared_stmt_name; + const LEX_CSTRING *name= &lex->prepared_stmt.name(); /* Query text for binary, general or slow log, if any of them is open */ String expanded_query; DBUG_ENTER("mysql_sql_stmt_execute"); @@ -3483,7 +3506,7 @@ void mysql_sql_stmt_execute(THD *thd) DBUG_VOID_RETURN; } - if (stmt->param_count != lex->prepared_stmt_params.elements) + if (stmt->param_count != lex->prepared_stmt.param_count()) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); DBUG_VOID_RETURN; @@ -3491,7 +3514,7 @@ void mysql_sql_stmt_execute(THD *thd) DBUG_PRINT("info",("stmt: %p", stmt)); - if (lex->prepared_stmt_params_fix_fields(thd)) + if (lex->prepared_stmt.params_fix_fields(thd)) DBUG_VOID_RETURN; /* @@ -3711,7 +3734,7 @@ void mysqld_stmt_close(THD *thd, char *packet) void mysql_sql_stmt_close(THD *thd) { Prepared_statement* stmt; - LEX_CSTRING *name= &thd->lex->prepared_stmt_name; + const LEX_CSTRING *name= &thd->lex->prepared_stmt.name(); DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s", (int) name->length, name->str)); @@ -4076,7 +4099,7 @@ void Prepared_statement::cleanup_stmt() } -bool Prepared_statement::set_name(LEX_CSTRING *name_arg) +bool Prepared_statement::set_name(const LEX_CSTRING *name_arg) { name.length= name_arg->length; name.str= (char*) memdup_root(mem_root, name_arg->str, name_arg->length); @@ -4325,7 +4348,7 @@ Prepared_statement::set_parameters(String *expanded_query, if (is_sql_ps) { /* SQL prepared statement */ - res= set_params_from_actual_params(this, thd->lex->prepared_stmt_params, + res= set_params_from_actual_params(this, thd->lex->prepared_stmt.params(), expanded_query); } else if (param_count) @@ -4405,15 +4428,6 @@ Prepared_statement::execute_loop(String *expanded_query, if (set_parameters(expanded_query, packet, packet_end)) return TRUE; -#ifdef NOT_YET_FROM_MYSQL_5_6 - if (unlikely(thd->security_ctx->password_expired && - !lex->is_change_password)) - { - my_error(ER_MUST_CHANGE_PASSWORD, MYF(0)); - return true; - } -#endif - reexecute: // Make sure that reprepare() did not create any new Items. DBUG_ASSERT(thd->free_list == NULL); @@ -4435,30 +4449,6 @@ reexecute: error= execute(expanded_query, open_cursor) || thd->is_error(); thd->m_reprepare_observer= NULL; -#ifdef WITH_WSREP - - if (WSREP_ON) - { - mysql_mutex_lock(&thd->LOCK_thd_data); - switch (thd->wsrep_conflict_state) - { - case CERT_FAILURE: - WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %lld err: %d", - (longlong) thd->thread_id, - thd->get_stmt_da()->sql_errno() ); - thd->wsrep_conflict_state = NO_CONFLICT; - break; - - case MUST_REPLAY: - (void) wsrep_replay_transaction(thd); - break; - - default: - break; - } - mysql_mutex_unlock(&thd->LOCK_thd_data); - } -#endif /* WITH_WSREP */ if (unlikely(error) && (sql_command_flags[lex->sql_command] & CF_REEXECUTION_FRAGILE) && @@ -4578,16 +4568,6 @@ Prepared_statement::execute_bulk_loop(String *expanded_query, } read_types= FALSE; -#ifdef NOT_YET_FROM_MYSQL_5_6 - if (unlikely(thd->security_ctx->password_expired && - !lex->is_change_password)) - { - my_error(ER_MUST_CHANGE_PASSWORD, MYF(0)); - thd->set_bulk_execution(0); - return true; - } -#endif - // iterations changed by set_bulk_parameters while ((iterations || start_param) && !error && !thd->is_error()) { @@ -4631,31 +4611,24 @@ reexecute: error= execute(expanded_query, open_cursor) || thd->is_error(); thd->m_reprepare_observer= NULL; -#ifdef WITH_WSREP - if (WSREP_ON) +#ifdef WITH_WSREP + if (!(sql_command_flags[lex->sql_command] & CF_PS_ARRAY_BINDING_OPTIMIZED) && + WSREP(thd)) { - mysql_mutex_lock(&thd->LOCK_thd_data); - switch (thd->wsrep_conflict_state) + if (wsrep_after_statement(thd)) { - case CERT_FAILURE: - WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %lld err: %d", - (longlong) thd->thread_id, - thd->get_stmt_da()->sql_errno() ); - thd->wsrep_conflict_state = NO_CONFLICT; - break; - - case MUST_REPLAY: - (void) wsrep_replay_transaction(thd); - break; - - default: - break; + /* + Re-execution success is unlikely after an error from + wsrep_after_statement(), so retrun error immediately. + */ + thd->get_stmt_da()->reset_diagnostics_area(); + wsrep_override_error(thd, thd->wsrep_cs().current_error(), + thd->wsrep_cs().current_error_status()); } - mysql_mutex_unlock(&thd->LOCK_thd_data); } + else #endif /* WITH_WSREP */ - if (unlikely(error) && (sql_command_flags[lex->sql_command] & CF_REEXECUTION_FRAGILE) && !thd->is_fatal_error && !thd->killed && @@ -4802,8 +4775,8 @@ bool Prepared_statement::validate_metadata(Prepared_statement *copy) if (is_sql_prepare() || lex->describe) return FALSE; - if (lex->select_lex.item_list.elements != - copy->lex->select_lex.item_list.elements) + if (lex->first_select_lex()->item_list.elements != + copy->lex->first_select_lex()->item_list.elements) { /** Column counts mismatch, update the client */ thd->server_status|= SERVER_STATUS_METADATA_CHANGED; @@ -4960,7 +4933,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) alloc_query(thd, (char*) expanded_query->ptr(), expanded_query->length())) { - my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), expanded_query->length()); + my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), expanded_query->length()); goto error; } /* @@ -5121,7 +5094,7 @@ bool Prepared_statement::execute_immediate(const char *query, uint query_len) if (unlikely(prepare(query, query_len))) DBUG_RETURN(true); - if (param_count != thd->lex->prepared_stmt_params.elements) + if (param_count != thd->lex->prepared_stmt.param_count()) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); deallocate_immediate(); @@ -5540,16 +5513,9 @@ bool Protocol_local::store_longlong(longlong value, bool unsigned_flag) bool Protocol_local::store_decimal(const my_decimal *value) { - char buf[DECIMAL_MAX_STR_LENGTH]; - String str(buf, sizeof (buf), &my_charset_bin); - int rc; - - rc= my_decimal2string(E_DEC_FATAL_ERROR, value, 0, 0, 0, &str); - - if (rc) - return TRUE; - - return store_column(str.ptr(), str.length()); + DBUG_ASSERT(0); // This method is not used yet + StringBuffer<DECIMAL_MAX_STR_LENGTH> str; + return value->to_string(&str) ? store_column(str.ptr(), str.length()) : true; } @@ -5579,7 +5545,7 @@ bool Protocol_local::store(const char *str, size_t length, bool Protocol_local::store(MYSQL_TIME *time, int decimals) { if (decimals != AUTO_SEC_PART_DIGITS) - my_time_trunc(time, decimals); + my_datetime_trunc(time, decimals); return store_column(time, sizeof(MYSQL_TIME)); } |