diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 995 |
1 files changed, 781 insertions, 214 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 14ac657862f..66433d11d8f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -23,7 +23,10 @@ // set_handler_table_locks, // lock_global_read_lock, // make_global_read_lock_block_commit -#include "sql_base.h" // find_temporary_table +#include "sql_base.h" // open_tables, open_and_lock_tables, + // lock_tables, unique_table, + // close_thread_tables, is_temporary_table + // table_cache.h #include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE, query_cache_* #include "sql_show.h" // mysqld_list_*, mysqld_show_*, // calc_sum_of_all_status @@ -92,6 +95,7 @@ #include "transaction.h" #include "sql_audit.h" #include "sql_prepare.h" +#include "sql_cte.h" #include "debug_sync.h" #include "probes_mysql.h" #include "set_var.h" @@ -110,7 +114,9 @@ #include "wsrep_thd.h" static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, - Parser_state *parser_state); + Parser_state *parser_state, + bool is_com_multi, + bool is_next_command); /** @defgroup Runtime_Environment Runtime Environment @@ -134,38 +140,263 @@ static bool check_rename_table(THD *, TABLE_LIST *, TABLE_LIST *); const char *any_db="*any*"; // Special symbol for check_access -const LEX_STRING command_name[]={ - { C_STRING_WITH_LEN("Sleep") }, - { C_STRING_WITH_LEN("Quit") }, - { C_STRING_WITH_LEN("Init DB") }, - { C_STRING_WITH_LEN("Query") }, - { C_STRING_WITH_LEN("Field List") }, - { C_STRING_WITH_LEN("Create DB") }, - { C_STRING_WITH_LEN("Drop DB") }, - { C_STRING_WITH_LEN("Refresh") }, - { C_STRING_WITH_LEN("Shutdown") }, - { C_STRING_WITH_LEN("Statistics") }, - { C_STRING_WITH_LEN("Processlist") }, - { C_STRING_WITH_LEN("Connect") }, - { C_STRING_WITH_LEN("Kill") }, - { C_STRING_WITH_LEN("Debug") }, - { C_STRING_WITH_LEN("Ping") }, - { C_STRING_WITH_LEN("Time") }, - { C_STRING_WITH_LEN("Delayed insert") }, - { C_STRING_WITH_LEN("Change user") }, - { C_STRING_WITH_LEN("Binlog Dump") }, - { C_STRING_WITH_LEN("Table Dump") }, - { C_STRING_WITH_LEN("Connect Out") }, - { C_STRING_WITH_LEN("Register Slave") }, - { C_STRING_WITH_LEN("Prepare") }, - { C_STRING_WITH_LEN("Execute") }, - { C_STRING_WITH_LEN("Long Data") }, - { C_STRING_WITH_LEN("Close stmt") }, - { C_STRING_WITH_LEN("Reset stmt") }, - { C_STRING_WITH_LEN("Set option") }, - { C_STRING_WITH_LEN("Fetch") }, - { C_STRING_WITH_LEN("Daemon") }, - { C_STRING_WITH_LEN("Error") } // Last command number +const LEX_STRING command_name[257]={ + { C_STRING_WITH_LEN("Sleep") }, //0 + { C_STRING_WITH_LEN("Quit") }, //1 + { C_STRING_WITH_LEN("Init DB") }, //2 + { C_STRING_WITH_LEN("Query") }, //3 + { C_STRING_WITH_LEN("Field List") }, //4 + { C_STRING_WITH_LEN("Create DB") }, //5 + { C_STRING_WITH_LEN("Drop DB") }, //6 + { C_STRING_WITH_LEN("Refresh") }, //7 + { C_STRING_WITH_LEN("Shutdown") }, //8 + { C_STRING_WITH_LEN("Statistics") }, //9 + { C_STRING_WITH_LEN("Processlist") }, //10 + { C_STRING_WITH_LEN("Connect") }, //11 + { C_STRING_WITH_LEN("Kill") }, //12 + { C_STRING_WITH_LEN("Debug") }, //13 + { C_STRING_WITH_LEN("Ping") }, //14 + { C_STRING_WITH_LEN("Time") }, //15 + { C_STRING_WITH_LEN("Delayed insert") }, //16 + { C_STRING_WITH_LEN("Change user") }, //17 + { C_STRING_WITH_LEN("Binlog Dump") }, //18 + { C_STRING_WITH_LEN("Table Dump") }, //19 + { C_STRING_WITH_LEN("Connect Out") }, //20 + { C_STRING_WITH_LEN("Register Slave") }, //21 + { C_STRING_WITH_LEN("Prepare") }, //22 + { C_STRING_WITH_LEN("Execute") }, //23 + { C_STRING_WITH_LEN("Long Data") }, //24 + { C_STRING_WITH_LEN("Close stmt") }, //25 + { C_STRING_WITH_LEN("Reset stmt") }, //26 + { C_STRING_WITH_LEN("Set option") }, //27 + { C_STRING_WITH_LEN("Fetch") }, //28 + { C_STRING_WITH_LEN("Daemon") }, //29 + { C_STRING_WITH_LEN("Unimpl get tid") }, //30 + { C_STRING_WITH_LEN("Reset connection") },//31 + { 0, 0 }, //32 + { 0, 0 }, //33 + { 0, 0 }, //34 + { 0, 0 }, //35 + { 0, 0 }, //36 + { 0, 0 }, //37 + { 0, 0 }, //38 + { 0, 0 }, //39 + { 0, 0 }, //40 + { 0, 0 }, //41 + { 0, 0 }, //42 + { 0, 0 }, //43 + { 0, 0 }, //44 + { 0, 0 }, //45 + { 0, 0 }, //46 + { 0, 0 }, //47 + { 0, 0 }, //48 + { 0, 0 }, //49 + { 0, 0 }, //50 + { 0, 0 }, //51 + { 0, 0 }, //52 + { 0, 0 }, //53 + { 0, 0 }, //54 + { 0, 0 }, //55 + { 0, 0 }, //56 + { 0, 0 }, //57 + { 0, 0 }, //58 + { 0, 0 }, //59 + { 0, 0 }, //60 + { 0, 0 }, //61 + { 0, 0 }, //62 + { 0, 0 }, //63 + { 0, 0 }, //64 + { 0, 0 }, //65 + { 0, 0 }, //66 + { 0, 0 }, //67 + { 0, 0 }, //68 + { 0, 0 }, //69 + { 0, 0 }, //70 + { 0, 0 }, //71 + { 0, 0 }, //72 + { 0, 0 }, //73 + { 0, 0 }, //74 + { 0, 0 }, //75 + { 0, 0 }, //76 + { 0, 0 }, //77 + { 0, 0 }, //78 + { 0, 0 }, //79 + { 0, 0 }, //80 + { 0, 0 }, //81 + { 0, 0 }, //82 + { 0, 0 }, //83 + { 0, 0 }, //84 + { 0, 0 }, //85 + { 0, 0 }, //86 + { 0, 0 }, //87 + { 0, 0 }, //88 + { 0, 0 }, //89 + { 0, 0 }, //90 + { 0, 0 }, //91 + { 0, 0 }, //92 + { 0, 0 }, //93 + { 0, 0 }, //94 + { 0, 0 }, //95 + { 0, 0 }, //96 + { 0, 0 }, //97 + { 0, 0 }, //98 + { 0, 0 }, //99 + { 0, 0 }, //100 + { 0, 0 }, //101 + { 0, 0 }, //102 + { 0, 0 }, //103 + { 0, 0 }, //104 + { 0, 0 }, //105 + { 0, 0 }, //106 + { 0, 0 }, //107 + { 0, 0 }, //108 + { 0, 0 }, //109 + { 0, 0 }, //110 + { 0, 0 }, //111 + { 0, 0 }, //112 + { 0, 0 }, //113 + { 0, 0 }, //114 + { 0, 0 }, //115 + { 0, 0 }, //116 + { 0, 0 }, //117 + { 0, 0 }, //118 + { 0, 0 }, //119 + { 0, 0 }, //120 + { 0, 0 }, //121 + { 0, 0 }, //122 + { 0, 0 }, //123 + { 0, 0 }, //124 + { 0, 0 }, //125 + { 0, 0 }, //126 + { 0, 0 }, //127 + { 0, 0 }, //128 + { 0, 0 }, //129 + { 0, 0 }, //130 + { 0, 0 }, //131 + { 0, 0 }, //132 + { 0, 0 }, //133 + { 0, 0 }, //134 + { 0, 0 }, //135 + { 0, 0 }, //136 + { 0, 0 }, //137 + { 0, 0 }, //138 + { 0, 0 }, //139 + { 0, 0 }, //140 + { 0, 0 }, //141 + { 0, 0 }, //142 + { 0, 0 }, //143 + { 0, 0 }, //144 + { 0, 0 }, //145 + { 0, 0 }, //146 + { 0, 0 }, //147 + { 0, 0 }, //148 + { 0, 0 }, //149 + { 0, 0 }, //150 + { 0, 0 }, //151 + { 0, 0 }, //152 + { 0, 0 }, //153 + { 0, 0 }, //154 + { 0, 0 }, //155 + { 0, 0 }, //156 + { 0, 0 }, //157 + { 0, 0 }, //158 + { 0, 0 }, //159 + { 0, 0 }, //160 + { 0, 0 }, //161 + { 0, 0 }, //162 + { 0, 0 }, //163 + { 0, 0 }, //164 + { 0, 0 }, //165 + { 0, 0 }, //166 + { 0, 0 }, //167 + { 0, 0 }, //168 + { 0, 0 }, //169 + { 0, 0 }, //170 + { 0, 0 }, //171 + { 0, 0 }, //172 + { 0, 0 }, //173 + { 0, 0 }, //174 + { 0, 0 }, //175 + { 0, 0 }, //176 + { 0, 0 }, //177 + { 0, 0 }, //178 + { 0, 0 }, //179 + { 0, 0 }, //180 + { 0, 0 }, //181 + { 0, 0 }, //182 + { 0, 0 }, //183 + { 0, 0 }, //184 + { 0, 0 }, //185 + { 0, 0 }, //186 + { 0, 0 }, //187 + { 0, 0 }, //188 + { 0, 0 }, //189 + { 0, 0 }, //190 + { 0, 0 }, //191 + { 0, 0 }, //192 + { 0, 0 }, //193 + { 0, 0 }, //194 + { 0, 0 }, //195 + { 0, 0 }, //196 + { 0, 0 }, //197 + { 0, 0 }, //198 + { 0, 0 }, //199 + { 0, 0 }, //200 + { 0, 0 }, //201 + { 0, 0 }, //202 + { 0, 0 }, //203 + { 0, 0 }, //204 + { 0, 0 }, //205 + { 0, 0 }, //206 + { 0, 0 }, //207 + { 0, 0 }, //208 + { 0, 0 }, //209 + { 0, 0 }, //210 + { 0, 0 }, //211 + { 0, 0 }, //212 + { 0, 0 }, //213 + { 0, 0 }, //214 + { 0, 0 }, //215 + { 0, 0 }, //216 + { 0, 0 }, //217 + { 0, 0 }, //218 + { 0, 0 }, //219 + { 0, 0 }, //220 + { 0, 0 }, //221 + { 0, 0 }, //222 + { 0, 0 }, //223 + { 0, 0 }, //224 + { 0, 0 }, //225 + { 0, 0 }, //226 + { 0, 0 }, //227 + { 0, 0 }, //228 + { 0, 0 }, //229 + { 0, 0 }, //230 + { 0, 0 }, //231 + { 0, 0 }, //232 + { 0, 0 }, //233 + { 0, 0 }, //234 + { 0, 0 }, //235 + { 0, 0 }, //236 + { 0, 0 }, //237 + { 0, 0 }, //238 + { 0, 0 }, //239 + { 0, 0 }, //240 + { 0, 0 }, //241 + { 0, 0 }, //242 + { 0, 0 }, //243 + { 0, 0 }, //244 + { 0, 0 }, //245 + { 0, 0 }, //246 + { 0, 0 }, //247 + { 0, 0 }, //248 + { 0, 0 }, //249 + { C_STRING_WITH_LEN("Bulk_execute") }, //250 + { C_STRING_WITH_LEN("Slave_worker") }, //251 + { C_STRING_WITH_LEN("Slave_IO") }, //252 + { C_STRING_WITH_LEN("Slave_SQL") }, //253 + { C_STRING_WITH_LEN("Com_multi") }, //254 + { C_STRING_WITH_LEN("Error") } // Last command number 255 }; const char *xa_state_names[]={ @@ -190,7 +421,7 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) for (TABLE_LIST *table= tables; table; table= table->next_global) { DBUG_ASSERT(table->db && table->table_name); - if (table->updating && !find_temporary_table(thd, table)) + if (table->updating && !thd->find_tmp_table_share(table)) return 1; } return 0; @@ -267,7 +498,7 @@ void init_update_queries(void) memset(server_command_flags, 0, sizeof(server_command_flags)); server_command_flags[COM_STATISTICS]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; - server_command_flags[COM_PING]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; + server_command_flags[COM_PING]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK | CF_NO_COM_MULTI; server_command_flags[COM_QUIT]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_PROCESS_INFO]= CF_SKIP_WSREP_CHECK; @@ -277,6 +508,10 @@ void init_update_queries(void) server_command_flags[COM_TIME]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_INIT_DB]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_END]= CF_SKIP_WSREP_CHECK; + for (uint i= COM_MDB_GAP_BEG; i <= COM_MDB_GAP_END; i++) + { + server_command_flags[i]= CF_SKIP_WSREP_CHECK; + } /* COM_QUERY, COM_SET_OPTION and COM_STMT_XXX are allowed to pass the early @@ -292,6 +527,7 @@ void init_update_queries(void) server_command_flags[COM_STMT_EXECUTE]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_STMT_SEND_LONG_DATA]= CF_SKIP_WSREP_CHECK; server_command_flags[COM_REGISTER_SLAVE]= CF_SKIP_WSREP_CHECK; + server_command_flags[COM_MULTI]= CF_SKIP_WSREP_CHECK | CF_NO_COM_MULTI; /* Initialize the sql command flags array. */ memset(sql_command_flags, 0, sizeof(sql_command_flags)); @@ -341,17 +577,19 @@ void init_update_queries(void) CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED | - CF_UPDATES_DATA; + CF_UPDATES_DATA | CF_SP_BULK_SAFE; sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED | - CF_UPDATES_DATA; + CF_UPDATES_DATA | CF_SP_BULK_SAFE; sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED | - CF_INSERTS_DATA; + CF_INSERTS_DATA | + CF_SP_BULK_SAFE | + CF_SP_BULK_OPTIMIZED; sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | @@ -360,7 +598,8 @@ void init_update_queries(void) sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | - CF_CAN_BE_EXPLAINED; + CF_CAN_BE_EXPLAINED | + CF_SP_BULK_SAFE; sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | @@ -369,7 +608,8 @@ void init_update_queries(void) CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED | - CF_INSERTS_DATA;; + CF_INSERTS_DATA | CF_SP_BULK_SAFE | + CF_SP_BULK_OPTIMIZED; sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | @@ -422,6 +662,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SHOW_EXPLAIN]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_PROCESSLIST]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_GRANTS]= CF_STATUS_COMMAND; + sql_command_flags[SQLCOM_SHOW_CREATE_USER]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND; sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND; @@ -443,6 +684,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CREATE_USER]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_RENAME_USER]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_DROP_USER]= CF_CHANGES_DATA; + sql_command_flags[SQLCOM_ALTER_USER]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_CREATE_ROLE]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_GRANT]= CF_CHANGES_DATA; sql_command_flags[SQLCOM_GRANT_ROLE]= CF_CHANGES_DATA; @@ -473,6 +715,7 @@ void init_update_queries(void) CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE; // (1) sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS; + sql_command_flags[SQLCOM_EXECUTE_IMMEDIATE]= CF_CAN_GENERATE_ROW_EVENTS; sql_command_flags[SQLCOM_COMPOUND]= CF_CAN_GENERATE_ROW_EVENTS; /* @@ -506,6 +749,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CHECKSUM]= CF_REPORT_PROGRESS; sql_command_flags[SQLCOM_CREATE_USER]|= CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_ALTER_USER]|= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_USER]|= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_RENAME_USER]|= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_CREATE_ROLE]|= CF_AUTO_COMMIT_TRANS; @@ -534,7 +778,6 @@ void init_update_queries(void) Note that SQLCOM_RENAME_TABLE should not be in this list! */ sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES; - sql_command_flags[SQLCOM_DROP_TABLE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_TRUNCATE]|= CF_PREOPEN_TMP_TABLES; @@ -601,6 +844,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_ALTER_EVENT]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_EVENT]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_USER]|= CF_DISALLOW_IN_RO_TRANS; + sql_command_flags[SQLCOM_ALTER_USER]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_RENAME_USER]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_DROP_USER]|= CF_DISALLOW_IN_RO_TRANS; sql_command_flags[SQLCOM_CREATE_SERVER]|= CF_DISALLOW_IN_RO_TRANS; @@ -651,7 +895,7 @@ void execute_init_command(THD *thd, LEX_STRING *init_command, mysql_rwlock_t *var_lock) { Vio* save_vio; - ulong save_client_capabilities; + ulonglong save_client_capabilities; mysql_rwlock_rdlock(var_lock); if (!init_command->length) @@ -679,7 +923,7 @@ void execute_init_command(THD *thd, LEX_STRING *init_command, save_vio= thd->net.vio; thd->net.vio= 0; thd->clear_error(1); - dispatch_command(COM_QUERY, thd, buf, len); + dispatch_command(COM_QUERY, thd, buf, len, FALSE, FALSE); thd->client_capabilities= save_client_capabilities; thd->net.vio= save_vio; @@ -794,7 +1038,7 @@ static void handle_bootstrap_impl(THD *thd) break; } - mysql_parse(thd, thd->query(), length, &parser_state); + mysql_parse(thd, thd->query(), length, &parser_state, FALSE, FALSE); bootstrap_error= thd->is_error(); thd->protocol->end_statement(); @@ -851,13 +1095,12 @@ void do_handle_bootstrap(THD *thd) end: delete thd; -#ifndef EMBEDDED_LIBRARY - thread_safe_decrement32(&thread_count); - in_bootstrap= FALSE; - mysql_mutex_lock(&LOCK_thread_count); + in_bootstrap = FALSE; mysql_cond_broadcast(&COND_thread_count); mysql_mutex_unlock(&LOCK_thread_count); + +#ifndef EMBEDDED_LIBRARY my_thread_end(); pthread_exit(0); #endif @@ -866,7 +1109,7 @@ end: } -/* This works because items are allocated with sql_alloc() */ +/* This works because items are allocated on THD::mem_root */ void free_items(Item *item) { @@ -881,7 +1124,7 @@ void free_items(Item *item) } /** - This works because items are allocated with sql_alloc(). + This works because items are allocated on THD::mem_root. @note The function also handles null pointers (empty list). */ void cleanup_items(Item *item) @@ -892,6 +1135,22 @@ void cleanup_items(Item *item) DBUG_VOID_RETURN; } +static enum enum_server_command fetch_command(THD *thd, char *packet) +{ + enum enum_server_command + command= (enum enum_server_command) (uchar) packet[0]; + DBUG_ENTER("fetch_command"); + + if (command >= COM_END || + (command >= COM_MDB_GAP_BEG && command <= COM_MDB_GAP_END)) + command= COM_END; // Wrong command + + DBUG_PRINT("info",("Command on %s = %d (%s)", + vio_description(thd->net.vio), command, + command_name[command].str)); + DBUG_RETURN(command); +} + #ifdef WITH_WSREP static bool wsrep_tables_accessible_when_detached(const TABLE_LIST *tables) @@ -943,7 +1202,7 @@ bool do_command(THD *thd) if (WSREP(thd)) { mysql_mutex_lock(&thd->LOCK_thd_data); - thd->wsrep_query_state= QUERY_IDLE; + wsrep_thd_set_query_state(thd, QUERY_IDLE); if (thd->wsrep_conflict_state==MUST_ABORT) { wsrep_client_rollback(thd); @@ -1011,7 +1270,7 @@ bool do_command(THD *thd) thd->store_globals(); } - thd->wsrep_query_state= QUERY_EXEC; + wsrep_thd_set_query_state(thd, QUERY_EXEC); mysql_mutex_unlock(&thd->LOCK_thd_data); } #endif /* WITH_WSREP */ @@ -1028,7 +1287,8 @@ bool do_command(THD *thd) mysql_mutex_lock(&thd->LOCK_thd_data); if (thd->wsrep_conflict_state == MUST_ABORT) { - DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu", thd->real_id)); + DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu", + (long unsigned int) thd->real_id)); wsrep_client_rollback(thd); } mysql_mutex_unlock(&thd->LOCK_thd_data); @@ -1081,14 +1341,8 @@ bool do_command(THD *thd) /* Do not rely on my_net_read, extra safety against programming errors. */ packet[packet_length]= '\0'; /* safety */ - command= (enum enum_server_command) (uchar) packet[0]; - - if (command >= COM_END) - command= COM_END; // Wrong command - DBUG_PRINT("info",("Command on %s = %d (%s)", - vio_description(net->vio), command, - command_name[command].str)); + command= fetch_command(thd, packet); #ifdef WITH_WSREP if (WSREP(thd)) @@ -1120,7 +1374,8 @@ bool do_command(THD *thd) DBUG_ASSERT(packet_length); DBUG_ASSERT(!thd->apc_target.is_enabled()); - return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1)); + return_value= dispatch_command(command, thd, packet+1, + (uint) (packet_length-1), FALSE, FALSE); #ifdef WITH_WSREP if (WSREP(thd)) { @@ -1139,7 +1394,7 @@ bool do_command(THD *thd) } thd->clear_error(); return_value= dispatch_command(command, thd, thd->wsrep_retry_query, - thd->wsrep_retry_query_len); + thd->wsrep_retry_query_len, FALSE, FALSE); thd->variables.character_set_client = current_charset; } @@ -1221,6 +1476,47 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) /** + check COM_MULTI packet + + @param thd thread handle + @param packet pointer on the packet of commands + @param packet_length length of this packet + + @retval 0 - Error + @retval # - Number of commands in the batch +*/ + +uint maria_multi_check(THD *thd, char *packet, uint packet_length) +{ + uint counter= 0; + DBUG_ENTER("maria_multi_check"); + while (packet_length) + { + char *packet_start= packet; + size_t subpacket_length= net_field_length((uchar **)&packet_start); + size_t length_length= packet_start - packet; + // length of command + 3 bytes where that length was stored + DBUG_PRINT("info", ("sub-packet length: %zu + %zu command: %x", + subpacket_length, length_length, + packet_start[3])); + + if (subpacket_length == 0 || + (subpacket_length + length_length) > packet_length) + { + my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR), + MYF(0)); + DBUG_RETURN(0); + } + + counter++; + packet= packet_start + subpacket_length; + packet_length-= (subpacket_length + length_length); + } + DBUG_RETURN(counter); +} + + +/** Perform one connection-level (COM_XXXX) command. @param command type of command to perform @@ -1229,6 +1525,8 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) @param packet_length length of packet + 1 (to show that data is null-terminated) except for COM_SLEEP, where it can be zero. + @param is_com_multi recursive call from COM_MULTI + @param is_next_command there will be more command in the COM_MULTI batch @todo set thd->lex->sql_command to SQLCOM_END here. @@ -1242,15 +1540,24 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) COM_QUIT/COM_SHUTDOWN */ bool dispatch_command(enum enum_server_command command, THD *thd, - char* packet, uint packet_length) + char* packet, uint packet_length, bool is_com_multi, + bool is_next_command) { NET *net= &thd->net; bool error= 0; bool do_end_of_statement= true; DBUG_ENTER("dispatch_command"); - DBUG_PRINT("info", ("command: %d", command)); + DBUG_PRINT("info", ("command: %d %s", command, + (command_name[command].str != 0 ? + command_name[command].str : + "<?>"))); + bool drop_more_results= 0; + + if (!is_com_multi) + inc_thread_running(); - inc_thread_running(); + /* keep it withing 1 byte */ + compile_time_assert(COM_END == 255); #ifdef WITH_WSREP if (WSREP(thd)) @@ -1261,7 +1568,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } mysql_mutex_lock(&thd->LOCK_thd_data); - thd->wsrep_query_state= QUERY_EXEC; + wsrep_thd_set_query_state(thd, QUERY_EXEC); if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) { thd->wsrep_conflict_state= NO_CONFLICT; @@ -1275,7 +1582,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, command != COM_STMT_CLOSE && command != COM_QUIT) { mysql_mutex_unlock(&thd->LOCK_thd_data); - my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction", + MYF(0)); WSREP_DEBUG("Deadlock error for: %s", thd->query()); thd->reset_killed(); thd->mysys_var->abort = 0; @@ -1338,6 +1646,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd, beginning of each command. */ thd->server_status&= ~SERVER_STATUS_CLEAR_SET; + if (is_next_command) + { + drop_more_results= !MY_TEST(thd->server_status & + SERVER_MORE_RESULTS_EXISTS); + thd->server_status|= SERVER_MORE_RESULTS_EXISTS; + if (is_com_multi) + thd->get_stmt_da()->set_skip_flush(); + } + switch (command) { case COM_INIT_DB: { @@ -1362,6 +1679,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; } #endif + case COM_RESET_CONNECTION: + { + thd->status_var.com_other++; + thd->change_user(); + thd->clear_error(); // if errors from rollback + /* Restore original charset from client authentication packet.*/ + if(thd->org_charset) + thd->update_charset(thd->org_charset,thd->org_charset,thd->org_charset); + my_ok(thd, 0, 0, 0); + break; + } case COM_CHANGE_USER: { int auth_rc; @@ -1411,10 +1739,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, decrease_user_connections(thd->user_connect); thd->user_connect= save_user_connect; thd->reset_db(save_db, save_db_length); - thd->variables.character_set_client= save_character_set_client; - thd->variables.collation_connection= save_collation_connection; - thd->variables.character_set_results= save_character_set_results; - thd->update_charset(); + thd->update_charset(save_character_set_client, save_collation_connection, + save_character_set_results); thd->failed_com_change_user++; my_sleep(1000000); } @@ -1430,6 +1756,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } break; } + case COM_STMT_BULK_EXECUTE: + { + mysqld_stmt_bulk_execute(thd, packet, packet_length); + break; + } case COM_STMT_EXECUTE: { mysqld_stmt_execute(thd, packet, packet_length); @@ -1486,9 +1817,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; if (WSREP(thd)) - wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); + wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state, + is_com_multi, is_next_command); else - mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); + mysql_parse(thd, thd->query(), thd->query_length(), &parser_state, + is_com_multi, is_next_command); while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) && ! thd->is_error()) @@ -1573,9 +1906,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* TODO: set thd->lex->sql_command to SQLCOM_END here */ if (WSREP(thd)) - wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); + wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state, + is_com_multi, is_next_command); else - mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); + mysql_parse(thd, beginning_of_next_stmt, length, &parser_state, + is_com_multi, is_next_command); } @@ -1608,7 +1943,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, (The packet is guaranteed to end with an end zero) */ arg_end= strend(packet); - uint arg_length= arg_end - packet; + uint arg_length= (uint)(arg_end - packet); /* Check given table name length. */ if (packet_length - arg_length > NAME_LEN + 1 || arg_length > SAFE_NAME_LEN) @@ -1627,6 +1962,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } packet= arg_end + 1; thd->reset_for_next_command(0); // Don't clear errors + // thd->reset_for_next_command reset state => restore it + if (is_next_command) + { + thd->server_status|= SERVER_MORE_RESULTS_EXISTS; + if (is_com_multi) + thd->get_stmt_da()->set_skip_flush(); + } + lex_start(thd); /* Must be before we init the table list. */ if (lower_case_table_names) @@ -1659,7 +2002,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->set_query(fields, query_length); general_log_print(thd, command, "%s %s", table_list.table_name, fields); - if (open_temporary_tables(thd, &table_list)) + if (thd->open_temporary_tables(&table_list)) break; if (check_table_access(thd, SELECT_ACL, &table_list, @@ -1731,6 +2074,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, general_log_print(thd, command, "Log: '%s' Pos: %lu", name, pos); if (nlen < FN_REFLEN) mysql_binlog_send(thd, thd->strmake(name, nlen), (my_off_t)pos, flags); + unregister_slave(thd, true, true); // todo: can be extraneous /* fake COM_QUIT -- if we get here, the thread needs to terminate */ error = TRUE; break; @@ -1812,7 +2156,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_PRINT("quit",("Got shutdown command for level %u", level)); general_log_print(thd, command, NullS); my_eof(thd); - kill_mysql(); + kill_mysql(thd); error=TRUE; break; } @@ -1839,7 +2183,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, length= my_snprintf(buff, buff_len - 1, "Uptime: %lu Threads: %d Questions: %lu " - "Slow queries: %lu Opens: %lu Flush tables: %lu " + "Slow queries: %lu Opens: %lu Flush tables: %lld " "Open tables: %u Queries per second avg: %u.%03u", uptime, (int) thread_count, (ulong) thd->query_id, @@ -1909,11 +2253,90 @@ bool dispatch_command(enum enum_server_command command, THD *thd, general_log_print(thd, command, NullS); my_eof(thd); break; + case COM_MULTI: + { + uint counter; + uint current_com= 0; + DBUG_ASSERT(!is_com_multi); + if (!(thd->client_capabilities & CLIENT_MULTI_RESULTS)) + { + /* The client does not support multiple result sets being sent back */ + my_error(ER_COMMULTI_BADCONTEXT, MYF(0)); + break; + } + + if (!(counter= maria_multi_check(thd, packet, packet_length))) + break; + + { + char *packet_start= packet; + /* We have to store next length because it will be destroyed by '\0' */ + size_t next_subpacket_length= net_field_length((uchar **)&packet_start); + size_t next_length_length= packet_start - packet; + unsigned char *readbuff= net->buff; + + if (net_allocate_new_packet(net, thd, MYF(0))) + break; + + PSI_statement_locker *save_locker= thd->m_statement_psi; + sql_digest_state *save_digest= thd->m_digest; + thd->m_statement_psi= NULL; + thd->m_digest= NULL; + + while (packet_length) + { + current_com++; + size_t subpacket_length= next_subpacket_length + next_length_length; + size_t length_length= next_length_length; + if (subpacket_length < packet_length) + { + packet_start= packet + subpacket_length; + next_subpacket_length= net_field_length((uchar**)&packet_start); + next_length_length= packet_start - (packet + subpacket_length); + } + /* safety like in do_command() */ + packet[subpacket_length]= '\0'; + + enum enum_server_command subcommand= + fetch_command(thd, (packet + length_length)); + + if (server_command_flags[subcommand] & CF_NO_COM_MULTI) + { + my_error(ER_BAD_COMMAND_IN_MULTI, MYF(0), + command_name[subcommand].str); + goto com_multi_end; + } + + if (dispatch_command(subcommand, thd, packet + (1 + length_length), + subpacket_length - (1 + length_length), TRUE, + (current_com != counter))) + { + DBUG_ASSERT(thd->is_error()); + goto com_multi_end; + } + + DBUG_ASSERT(subpacket_length <= packet_length); + packet+= subpacket_length; + packet_length-= subpacket_length; + } + +com_multi_end: + thd->m_statement_psi= save_locker; + thd->m_digest= save_digest; + + /* release old buffer */ + net_flush(net); + DBUG_ASSERT(net->buff == net->write_pos); // nothing to send + my_free(readbuff); + } + break; + } case COM_SLEEP: case COM_CONNECT: // Impossible here case COM_TIME: // Impossible from client case COM_DELAYED_INSERT: case COM_END: + case COM_UNIMPLEMENTED: default: my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR), MYF(0)); @@ -1952,9 +2375,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd_proc_info(thd, "updating status"); /* Finalize server status flags after executing a command. */ thd->update_server_status(); - thd->protocol->end_statement(); - query_cache_end_of_result(thd); + if (command != COM_MULTI) + { + thd->protocol->end_statement(); + query_cache_end_of_result(thd); + } } + if (drop_more_results) + thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; if (!thd->is_error() && !thd->killed_errno()) mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0); @@ -1979,8 +2407,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->m_statement_psi= NULL; thd->m_digest= NULL; - dec_thread_running(); - thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory + if (!is_com_multi) + { + dec_thread_running(); + thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory + } thd->reset_kill_query(); /* Ensure that killed_errmsg is released */ /* LEX::m_sql_cmd can point to Sql_cmd allocated on thd->mem_root. @@ -2152,7 +2583,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, { DBUG_RETURN(1); } - schema_select_lex= new SELECT_LEX(); + schema_select_lex= new (thd->mem_root) SELECT_LEX(); db.str= schema_select_lex->db= lex->select_lex.db; schema_select_lex->table_list.first= NULL; db.length= strlen(db.str); @@ -2175,7 +2606,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, { DBUG_ASSERT(table_ident); TABLE_LIST **query_tables_last= lex->query_tables_last; - schema_select_lex= new SELECT_LEX(); + schema_select_lex= new (thd->mem_root) SELECT_LEX(); /* 'parent_lex' is used in init_query() so it must be before it. */ schema_select_lex->parent_lex= lex; schema_select_lex->init_query(); @@ -2373,27 +2804,80 @@ bool sp_process_definer(THD *thd) static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables) { Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; + MDL_deadlock_and_lock_abort_error_handler deadlock_handler; + MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); uint counter; TABLE_LIST *table; thd->in_lock_tables= 1; +retry: + if (open_tables(thd, &tables, &counter, 0, &lock_tables_prelocking_strategy)) goto err; - /* - We allow to change temporary tables even if they were locked for read - by LOCK TABLES. To avoid a discrepancy between lock acquired at LOCK - TABLES time and by the statement which is later executed under LOCK TABLES - we ensure that for temporary tables we always request a write lock (such - discrepancy can cause problems for the storage engine). - We don't set TABLE_LIST::lock_type in this case as this might result in - extra warnings from THD::decide_logging_format() even though binary logging - is totally irrelevant for LOCK TABLES. - */ for (table= tables; table; table= table->next_global) - if (!table->placeholder() && table->table->s->tmp_table) - table->table->reginfo.lock_type= TL_WRITE; + { + if (!table->placeholder()) + { + if (table->table->s->tmp_table) + { + /* + We allow to change temporary tables even if they were locked for read + by LOCK TABLES. To avoid a discrepancy between lock acquired at LOCK + TABLES time and by the statement which is later executed under LOCK + TABLES we ensure that for temporary tables we always request a write + lock (such discrepancy can cause problems for the storage engine). + We don't set TABLE_LIST::lock_type in this case as this might result + in extra warnings from THD::decide_logging_format() even though + binary logging is totally irrelevant for LOCK TABLES. + */ + table->table->reginfo.lock_type= TL_WRITE; + } + else if (table->mdl_request.type == MDL_SHARED_READ && + ! table->prelocking_placeholder && + table->table->file->lock_count() == 0) + { + enum enum_mdl_type lock_type; + /* + In case when LOCK TABLE ... READ LOCAL was issued for table with + storage engine which doesn't support READ LOCAL option and doesn't + use THR_LOCK locks we need to upgrade weak SR metadata lock acquired + in open_tables() to stronger SRO metadata lock. + This is not needed for tables used through stored routines or + triggers as we always acquire SRO (or even stronger SNRW) metadata + lock for them. + */ + deadlock_handler.init(); + thd->push_internal_handler(&deadlock_handler); + + lock_type= table->table->mdl_ticket->get_type() == MDL_SHARED_WRITE ? + MDL_SHARED_NO_READ_WRITE : MDL_SHARED_READ_ONLY; + + bool result= thd->mdl_context.upgrade_shared_lock( + table->table->mdl_ticket, + lock_type, + thd->variables.lock_wait_timeout); + + thd->pop_internal_handler(); + + if (deadlock_handler.need_reopen()) + { + /* + Deadlock occurred during upgrade of metadata lock. + Let us restart acquring and opening tables for LOCK TABLES. + */ + close_tables_for_reopen(thd, &tables, mdl_savepoint); + if (thd->open_temporary_tables(tables)) + goto err; + goto retry; + } + + if (result) + goto err; + } + } + } if (lock_tables(thd, tables, counter, 0) || thd->locked_tables_list.init_locked_tables(thd)) @@ -2445,6 +2929,13 @@ static bool do_execute_sp(THD *thd, sp_head *sp) thd->variables.select_limit= HA_POS_ERROR; /* + Reset current_select as it may point to random data as a + result of previous parsing. + */ + thd->lex->current_select= NULL; + thd->lex->in_sum_func= 0; // For Item_field::fix_fields() + + /* We never write CALL statements into binlog: - If the mode is non-prelocked, each statement will be logged separately. @@ -2554,6 +3045,9 @@ mysql_execute_command(THD *thd) thd->get_stmt_da()->opt_clear_warning_info(thd->query_id); } + if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list)) + DBUG_RETURN(1); + #ifdef HAVE_REPLICATION if (unlikely(thd->slave_thread)) { @@ -2881,7 +3375,8 @@ mysql_execute_command(THD *thd) thd->mdl_context.release_transactional_locks(); if (commit_failed) { - WSREP_DEBUG("implicit commit failed, MDL released: %lu", thd->thread_id); + WSREP_DEBUG("implicit commit failed, MDL released: %lld", + (longlong) thd->thread_id); goto error; } } @@ -2927,7 +3422,7 @@ mysql_execute_command(THD *thd) */ if (sql_command_flags[lex->sql_command] & CF_PREOPEN_TMP_TABLES) { - if (open_temporary_tables(thd, all_tables)) + if (thd->open_temporary_tables(all_tables)) goto error; } @@ -3030,6 +3525,11 @@ mysql_execute_command(THD *thd) break; } + case SQLCOM_EXECUTE_IMMEDIATE: + { + mysql_sql_stmt_execute_immediate(thd); + break; + } case SQLCOM_PREPARE: { mysql_sql_stmt_prepare(thd); @@ -3495,7 +3995,7 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(select_lex->offset_limit == 0); unit->set_limit(select_lex); MYSQL_UPDATE_START(thd->query()); - res= (up_result= mysql_update(thd, all_tables, + res= up_result= mysql_update(thd, all_tables, select_lex->item_list, lex->value_list, select_lex->where, @@ -3503,7 +4003,7 @@ mysql_execute_command(THD *thd) select_lex->order_list.first, unit->select_limit_cnt, lex->duplicates, lex->ignore, - &found, &updated)); + &found, &updated); MYSQL_UPDATE_DONE(res, found, updated); /* mysql_update return 2 if we need to switch to multi-update */ if (up_result != 2) @@ -3647,7 +4147,8 @@ mysql_execute_command(THD *thd) */ if (first_table->lock_type != TL_WRITE_DELAYED) { - if ((res= open_temporary_tables(thd, all_tables))) + res= (thd->open_temporary_tables(all_tables)) ? TRUE : FALSE; + if (res) break; } @@ -3736,7 +4237,7 @@ mysql_execute_command(THD *thd) unit->set_limit(select_lex); - if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0))) + if (!(res=open_and_lock_tables(thd, all_tables, TRUE, 0))) { MYSQL_INSERT_SELECT_START(thd->query()); /* @@ -3915,7 +4416,7 @@ mysql_execute_command(THD *thd) lex->table_count); if (result) { - res= mysql_select(thd, &select_lex->ref_pointer_array, + res= mysql_select(thd, select_lex->get_table_list(), select_lex->with_wild, select_lex->item_list, @@ -3948,7 +4449,14 @@ mysql_execute_command(THD *thd) } case SQLCOM_DROP_TABLE: { + int result; DBUG_ASSERT(first_table == all_tables && first_table != 0); + + thd->open_options|= HA_OPEN_FOR_REPAIR; + result= thd->open_temporary_tables(all_tables); + thd->open_options&= ~HA_OPEN_FOR_REPAIR; + if (result) + goto error; if (!lex->tmp_table()) { if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)) @@ -3978,7 +4486,7 @@ mysql_execute_command(THD *thd) { if (!lex->tmp_table() && (!thd->is_current_stmt_binlog_format_row() || - !find_temporary_table(thd, table))) + !thd->find_temporary_table(table))) { WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables); break; @@ -3988,6 +4496,13 @@ mysql_execute_command(THD *thd) /* DDL and binlog write order are protected by metadata locks. */ res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table()); + + /* when dropping temporary tables if @@session_track_state_change is ON then + send the boolean tracker in the OK packet */ + if(!res && (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) + { + SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL); + } break; } case SQLCOM_SHOW_PROCESSLIST: @@ -4067,7 +4582,8 @@ mysql_execute_command(THD *thd) goto error; if (!(res= sql_set_variables(thd, lex_var_list, true))) { - my_ok(thd); + if (!thd->is_error()) + my_ok(thd); } else { @@ -4122,7 +4638,7 @@ mysql_execute_command(THD *thd) CF_PREOPEN_TMP_TABLES was set and the tables would be pre-opened in a usual way, they would have been closed. */ - if (open_temporary_tables(thd, all_tables)) + if (thd->open_temporary_tables(all_tables)) goto error; if (lock_tables_precheck(thd, all_tables)) @@ -4403,6 +4919,7 @@ mysql_execute_command(THD *thd) my_ok(thd); break; } + case SQLCOM_ALTER_USER: case SQLCOM_RENAME_USER: { if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1) && @@ -4410,7 +4927,11 @@ mysql_execute_command(THD *thd) break; /* Conditionally writes to binlog */ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) - if (!(res= mysql_rename_user(thd, lex->users_list))) + if (lex->sql_command == SQLCOM_ALTER_USER) + res= mysql_alter_user(thd, lex->users_list); + else + res= mysql_rename_user(thd, lex->users_list); + if (!res) my_ok(thd); break; } @@ -4699,7 +5220,7 @@ mysql_execute_command(THD *thd) DBUG_EXECUTE_IF("crash_shutdown", DBUG_SUICIDE();); if (check_global_access(thd,SHUTDOWN_ACL)) goto error; - kill_mysql(); + kill_mysql(thd); my_ok(thd); #else my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server"); @@ -4707,6 +5228,15 @@ mysql_execute_command(THD *thd) break; #ifndef NO_EMBEDDED_ACCESS_CHECKS + case SQLCOM_SHOW_CREATE_USER: + { + LEX_USER *grant_user= lex->grant_user; + if (!grant_user) + goto error; + + res = mysql_show_create_user(thd, grant_user); + break; + } case SQLCOM_SHOW_GRANTS: { LEX_USER *grant_user= lex->grant_user; @@ -4750,7 +5280,8 @@ mysql_execute_command(THD *thd) if (trans_begin(thd, lex->start_transaction_opt)) { thd->mdl_context.release_transactional_locks(); - WSREP_DEBUG("BEGIN failed, MDL released: %lu", thd->thread_id); + WSREP_DEBUG("BEGIN failed, MDL released: %lld", + (longlong) thd->thread_id); goto error; } my_ok(thd); @@ -4769,7 +5300,8 @@ mysql_execute_command(THD *thd) thd->mdl_context.release_transactional_locks(); if (commit_failed) { - WSREP_DEBUG("COMMIT failed, MDL released: %lu", thd->thread_id); + WSREP_DEBUG("COMMIT failed, MDL released: %lld", + (longlong) thd->thread_id); goto error; } /* Begin transaction with the same isolation level. */ @@ -4781,8 +5313,7 @@ mysql_execute_command(THD *thd) else { /* Reset the isolation level and access mode if no chaining transaction.*/ - thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; - thd->tx_read_only= thd->variables.tx_read_only; + trans_reset_one_shot_chistics(thd); } /* Disconnect the current client connection. */ if (tx_release) @@ -4821,7 +5352,8 @@ mysql_execute_command(THD *thd) if (rollback_failed) { - WSREP_DEBUG("rollback failed, MDL released: %lu", thd->thread_id); + WSREP_DEBUG("rollback failed, MDL released: %lld", + (longlong) thd->thread_id); goto error; } /* Begin transaction with the same isolation level. */ @@ -4833,8 +5365,7 @@ mysql_execute_command(THD *thd) else { /* Reset the isolation level and access mode if no chaining transaction.*/ - thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; - thd->tx_read_only= thd->variables.tx_read_only; + trans_reset_one_shot_chistics(thd); } /* Disconnect the current client connection. */ if (tx_release) @@ -4894,7 +5425,7 @@ mysql_execute_command(THD *thd) { if (check_routine_access(thd, ALTER_PROC_ACL, lex->spname->m_db.str, lex->spname->m_name.str, - lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) + lex->sql_command == SQLCOM_CREATE_PROCEDURE, 0)) goto error; } @@ -5300,15 +5831,15 @@ mysql_execute_command(THD *thd) thd->mdl_context.release_transactional_locks(); if (commit_failed) { - WSREP_DEBUG("XA commit failed, MDL released: %lu", thd->thread_id); + WSREP_DEBUG("XA commit failed, MDL released: %lld", + (longlong) thd->thread_id); goto error; } /* We've just done a commit, reset transaction isolation level and access mode to the session default. */ - thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; - thd->tx_read_only= thd->variables.tx_read_only; + trans_reset_one_shot_chistics(thd); my_ok(thd); break; } @@ -5318,15 +5849,15 @@ mysql_execute_command(THD *thd) thd->mdl_context.release_transactional_locks(); if (rollback_failed) { - WSREP_DEBUG("XA rollback failed, MDL released: %lu", thd->thread_id); + WSREP_DEBUG("XA rollback failed, MDL released: %lld", + (longlong) thd->thread_id); goto error; } /* We've just done a rollback, reset transaction isolation level and access mode to the session default. */ - thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; - thd->tx_read_only= thd->variables.tx_read_only; + trans_reset_one_shot_chistics(thd); my_ok(thd); break; } @@ -5459,7 +5990,8 @@ finish: lex->unit.cleanup(); /* close/reopen tables that were marked to need reopen under LOCK TABLES */ - if (! thd->lex->requires_prelocking()) + if (unlikely(thd->locked_tables_list.some_table_marked_for_reopen) && + !thd->lex->requires_prelocking()) thd->locked_tables_list.reopen_tables(thd, true); if (! thd->in_sub_stmt) @@ -5566,6 +6098,9 @@ finish: { thd->mdl_context.release_statement_locks(); } + + TRANSACT_TRACKER(add_trx_state_from_thd(thd)); + WSREP_TO_ISOLATION_END; #ifdef WITH_WSREP @@ -5577,8 +6112,8 @@ finish: ! thd->in_active_multi_stmt_transaction() && thd->mdl_context.has_transactional_locks()) { - WSREP_DEBUG("Forcing release of transactional locks for thd %lu", - thd->thread_id); + WSREP_DEBUG("Forcing release of transactional locks for thd: %lld", + (longlong) thd->thread_id); thd->mdl_context.release_transactional_locks(); } #endif /* WITH_WSREP */ @@ -5600,6 +6135,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) new (thd->mem_root) Item_int(thd, (ulonglong) thd->variables.select_limit); } + if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0))) { if (lex->describe) @@ -5696,7 +6232,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) } } /* Count number of empty select queries */ - if (!thd->get_sent_row_count()) + if (!thd->get_sent_row_count() && !res) status_var_increment(thd->status_var.empty_queries); else status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count()); @@ -5780,7 +6316,7 @@ static TABLE *find_temporary_table_for_rename(THD *thd, } } if (!found) - res= find_temporary_table(thd, table); + res= thd->find_temporary_table(table, THD::TMP_TABLE_ANY); DBUG_RETURN(res); } @@ -5892,11 +6428,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, THD_STAGE_INFO(thd, stage_checking_permissions); if ((!db || !db[0]) && !thd->db && !dont_check_global_grants) { - DBUG_PRINT("error",("No database")); - if (!no_errors) - my_message(ER_NO_DB_ERROR, ER_THD(thd, ER_NO_DB_ERROR), - MYF(0)); /* purecov: tested */ - DBUG_RETURN(TRUE); /* purecov: tested */ + DBUG_RETURN(FALSE); // CTE reference or an error later } if ((db != NULL) && (db != any_db)) @@ -6078,11 +6610,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, bool check_single_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables, bool no_errors) { - Security_context * backup_ctx= thd->security_ctx; - - /* we need to switch to the saved context (if any) */ - if (all_tables->security_ctx) - thd->security_ctx= all_tables->security_ctx; + Switch_to_definer_security_ctx backup_sctx(thd, all_tables); const char *db_name; if ((all_tables->view || all_tables->field_translation) && @@ -6095,20 +6623,15 @@ bool check_single_table_access(THD *thd, ulong privilege, &all_tables->grant.privilege, &all_tables->grant.m_internal, 0, no_errors)) - goto deny; + return 1; /* Show only 1 table for check_grant */ if (!(all_tables->belong_to_view && (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && check_grant(thd, privilege, all_tables, FALSE, 1, no_errors)) - goto deny; + return 1; - thd->security_ctx= backup_ctx; return 0; - -deny: - thd->security_ctx= backup_ctx; - return 1; } /** @@ -6210,7 +6733,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) /* Open temporary tables to be able to detect them during privilege check. */ - if (open_temporary_tables(thd, dst_table)) + if (thd->open_temporary_tables(dst_table)) return TRUE; if (check_access(thd, SELECT_ACL, dst_table->db, @@ -6283,7 +6806,6 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, { TABLE_LIST *org_tables= tables; TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); - Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx; uint i= 0; /* The check that first_not_own_table is not reached is for the case when @@ -6295,12 +6817,9 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, { TABLE_LIST *const table_ref= tables->correspondent_table ? tables->correspondent_table : tables; + Switch_to_definer_security_ctx backup_ctx(thd, table_ref); ulong want_access= requirements; - if (table_ref->security_ctx) - sctx= table_ref->security_ctx; - else - sctx= backup_ctx; /* Register access for view underlying table. @@ -6311,7 +6830,7 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, if (table_ref->schema_table_reformed) { if (check_show_access(thd, table_ref)) - goto deny; + return 1; continue; } @@ -6321,21 +6840,15 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, if (table_ref->is_anonymous_derived_table()) continue; - thd->security_ctx= sctx; - if (check_access(thd, want_access, table_ref->get_db_name(), &table_ref->grant.privilege, &table_ref->grant.m_internal, 0, no_errors)) - goto deny; + return 1; } - thd->security_ctx= backup_ctx; return check_grant(thd,requirements,org_tables, any_combination_of_privileges_will_do, number, no_errors); -deny: - thd->security_ctx= backup_ctx; - return TRUE; } @@ -6775,10 +7288,9 @@ void THD::reset_for_next_command(bool do_clear_error) thd->thread_specific_used= FALSE; if (opt_bin_log) - { reset_dynamic(&thd->user_var_events); - thd->user_var_events_alloc= thd->mem_root; - } + DBUG_ASSERT(thd->user_var_events_alloc == &thd->main_mem_root); + thd->get_stmt_da()->reset_for_next_command(); thd->rand_used= 0; thd->m_sent_row_count= thd->m_examined_row_count= 0; @@ -6885,22 +7397,30 @@ mysql_new_select(LEX *lex, bool move_down) my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO"); DBUG_RETURN(TRUE); } + + /* + This type of query is not possible in the grammar: + SELECT 1 FROM t1 PROCEDURE ANALYSE() UNION ... ; + + But this type of query is still possible: + (SELECT 1 FROM t1 PROCEDURE ANALYSE()) UNION ... ; + and it's not easy to disallow this grammatically, + because there can be any parenthesis nest level: + (((SELECT 1 FROM t1 PROCEDURE ANALYSE()))) UNION ... ; + */ if (lex->proc_list.elements!=0) { my_error(ER_WRONG_USAGE, MYF(0), "UNION", "SELECT ... PROCEDURE ANALYSE()"); DBUG_RETURN(TRUE); } - if (lex->current_select->order_list.first && !lex->current_select->braces) - { - my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY"); - DBUG_RETURN(1); - } - if (lex->current_select->explicit_limit && !lex->current_select->braces) - { - my_error(ER_WRONG_USAGE, MYF(0), "UNION", "LIMIT"); - DBUG_RETURN(1); - } + // SELECT 1 FROM t1 ORDER BY 1 UNION SELECT 1 FROM t1 -- not possible + DBUG_ASSERT(!lex->current_select->order_list.first || + lex->current_select->braces); + // SELECT 1 FROM t1 LIMIT 1 UNION SELECT 1 FROM t1; -- not possible + DBUG_ASSERT(!lex->current_select->explicit_limit || + lex->current_select->braces); + select_lex->include_neighbour(lex->current_select); SELECT_LEX_UNIT *unit= select_lex->master_unit(); if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd)) @@ -6951,7 +7471,7 @@ void create_select_for_variable(const char *var_name) if ((var= get_system_var(thd, OPT_SESSION, tmp, null_lex_str))) { end= strxmov(buff, "@@session.", var_name, NullS); - var->set_name(buff, end-buff, system_charset_info); + var->set_name(thd, buff, (uint)(end-buff), system_charset_info); add_item_to_list(thd, var); } DBUG_VOID_RETURN; @@ -6970,7 +7490,9 @@ void mysql_init_multi_delete(LEX *lex) } static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, - Parser_state *parser_state) + Parser_state *parser_state, + bool is_com_multi, + bool is_next_command) { #ifdef WITH_WSREP bool is_autocommit= @@ -7000,7 +7522,8 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, WSREP_DEBUG("Retry autocommit query: %s", thd->query()); } - mysql_parse(thd, rawbuf, length, parser_state); + mysql_parse(thd, rawbuf, length, parser_state, is_com_multi, + is_next_command); if (WSREP(thd)) { /* wsrep BF abort in query exec phase */ @@ -7054,12 +7577,14 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, { mysql_mutex_unlock(&thd->LOCK_thd_data); // This does dirty read to wsrep variables but it is only a debug code - WSREP_DEBUG("%s, thd: %lu is_AC: %d, retry: %lu - %lu SQL: %s", + WSREP_DEBUG("%s, thd: %lld is_AC: %d, retry: %lu - %lu SQL: %s", (thd->wsrep_conflict_state == ABORTED) ? "BF Aborted" : "cert failure", - thd->thread_id, is_autocommit, thd->wsrep_retry_counter, + (longlong) thd->thread_id, is_autocommit, + thd->wsrep_retry_counter, thd->variables.wsrep_retry_autocommit, thd->query()); - my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction"); + my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction", + MYF(0)); mysql_mutex_lock(&thd->LOCK_thd_data); thd->wsrep_conflict_state= NO_CONFLICT; @@ -7117,10 +7642,13 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, @param length Length of the query text @param[out] found_semicolon For multi queries, position of the character of the next query in the query text. + @param is_next_command there will be more command in the COM_MULTI batch */ void mysql_parse(THD *thd, char *rawbuf, uint length, - Parser_state *parser_state) + Parser_state *parser_state, + bool is_com_multi, + bool is_next_command) { int error __attribute__((unused)); DBUG_ENTER("mysql_parse"); @@ -7144,6 +7672,12 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, */ lex_start(thd); thd->reset_for_next_command(); + if (is_next_command) + { + thd->server_status|= SERVER_MORE_RESULTS_EXISTS; + if (is_com_multi) + thd->get_stmt_da()->set_skip_flush(); + } if (query_cache_send_result_to_client(thd, rawbuf, length) <= 0) { @@ -7177,7 +7711,6 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, and Query_log_event::print() would give ';;' output). This also helps display only the current query in SHOW PROCESSLIST. - Note that we don't need LOCK_thread_count to modify query_length. */ if (found_semicolon && (ulong) (found_semicolon - thd->query())) thd->set_query(thd->query(), @@ -7219,7 +7752,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size); thd->end_statement(); thd->cleanup_after_query(); - DBUG_ASSERT(thd->change_list.is_empty()); + DBUG_ASSERT(thd->Item_change_list::is_empty()); } else { @@ -7275,13 +7808,6 @@ bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length) #endif -/** Store position for column in ALTER TABLE .. ADD column. */ - -void store_position_for_column(const char *name) -{ - current_thd->lex->last_field->after=(char*) (name); -} - bool add_proc_to_list(THD* thd, Item *item) { @@ -7293,7 +7819,6 @@ add_proc_to_list(THD* thd, Item *item) item_ptr = (Item**) (order+1); *item_ptr= item; order->item=item_ptr; - order->free_me=0; thd->lex->proc_list.link_in_list(order, &order->next); return 0; } @@ -7311,8 +7836,7 @@ bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc) DBUG_RETURN(1); order->item_ptr= item; order->item= &order->item_ptr; - order->asc = asc; - order->free_me=0; + order->direction= (asc ? ORDER::ORDER_ASC : ORDER::ORDER_DESC); order->used=0; order->counter_used= 0; order->fast_field_copier_setup= 0; @@ -7418,7 +7942,6 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->derived= table->sel; if (!ptr->derived && is_infoschema_db(ptr->db, ptr->db_length)) { - ST_SCHEMA_TABLE *schema_table; if (ptr->updating && /* Special cases which are processed by commands itself */ lex->sql_command != SQLCOM_CHECK && @@ -7430,20 +7953,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, INFORMATION_SCHEMA_NAME.str); DBUG_RETURN(0); } + ST_SCHEMA_TABLE *schema_table; schema_table= find_schema_table(thd, ptr->table_name); - if (!schema_table || - (schema_table->hidden && - ((sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0 || - /* - this check is used for show columns|keys from I_S hidden table - */ - lex->sql_command == SQLCOM_SHOW_FIELDS || - lex->sql_command == SQLCOM_SHOW_KEYS))) - { - my_error(ER_UNKNOWN_TABLE, MYF(0), - ptr->table_name, INFORMATION_SCHEMA_NAME.str); - DBUG_RETURN(0); - } ptr->schema_table_name= ptr->table_name; ptr->schema_table= schema_table; } @@ -7509,7 +8020,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, lex->add_to_query_tables(ptr); // Pure table aliases do not need to be locked: - if (!MY_TEST(table_options & TL_OPTION_ALIAS)) + if (ptr->db && !(table_options & TL_OPTION_ALIAS)) { ptr->mdl_request.init(MDL_key::TABLE, ptr->db, ptr->table_name, mdl_type, MDL_TRANSACTION); @@ -7868,9 +8379,9 @@ bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op, TABLE_LIST *tbl; List<TABLE_LIST> *right_op_jl= right_op->join_list; - TABLE_LIST *r_tbl= right_op_jl->pop(); + IF_DBUG(const TABLE_LIST *r_tbl=,) right_op_jl->pop(); DBUG_ASSERT(right_op == r_tbl); - TABLE_LIST *l_tbl= right_op_jl->pop(); + IF_DBUG(const TABLE_LIST *l_tbl=,) right_op_jl->pop(); DBUG_ASSERT(left_op == l_tbl); TABLE_LIST *cj_nest; @@ -8011,6 +8522,65 @@ TABLE_LIST *st_select_lex::convert_right_join() DBUG_RETURN(tab1); } + +void st_select_lex::prepare_add_window_spec(THD *thd) +{ + LEX *lex= thd->lex; + lex->save_group_list= group_list; + lex->save_order_list= order_list; + lex->win_ref= NULL; + lex->win_frame= NULL; + lex->frame_top_bound= NULL; + lex->frame_bottom_bound= NULL; + group_list.empty(); + order_list.empty(); +} + +bool st_select_lex::add_window_def(THD *thd, + LEX_STRING *win_name, + LEX_STRING *win_ref, + SQL_I_List<ORDER> win_partition_list, + SQL_I_List<ORDER> win_order_list, + Window_frame *win_frame) +{ + SQL_I_List<ORDER> *win_part_list_ptr= + new (thd->mem_root) SQL_I_List<ORDER> (win_partition_list); + SQL_I_List<ORDER> *win_order_list_ptr= + new (thd->mem_root) SQL_I_List<ORDER> (win_order_list); + if (!(win_part_list_ptr && win_order_list_ptr)) + return true; + Window_def *win_def= new (thd->mem_root) Window_def(win_name, + win_ref, + win_part_list_ptr, + win_order_list_ptr, + win_frame); + group_list= thd->lex->save_group_list; + order_list= thd->lex->save_order_list; + return (win_def == NULL || window_specs.push_back(win_def)); +} + +bool st_select_lex::add_window_spec(THD *thd, + LEX_STRING *win_ref, + SQL_I_List<ORDER> win_partition_list, + SQL_I_List<ORDER> win_order_list, + Window_frame *win_frame) +{ + SQL_I_List<ORDER> *win_part_list_ptr= + new (thd->mem_root) SQL_I_List<ORDER> (win_partition_list); + SQL_I_List<ORDER> *win_order_list_ptr= + new (thd->mem_root) SQL_I_List<ORDER> (win_order_list); + if (!(win_part_list_ptr && win_order_list_ptr)) + return true; + Window_spec *win_spec= new (thd->mem_root) Window_spec(win_ref, + win_part_list_ptr, + win_order_list_ptr, + win_frame); + group_list= thd->lex->save_group_list; + order_list= thd->lex->save_order_list; + thd->lex->win_spec= win_spec; + return (win_spec == NULL || window_specs.push_back(win_spec)); +} + /** Set lock for all tables in current select level. @@ -9242,11 +9812,8 @@ bool check_string_char_length(LEX_STRING *str, uint err_msg, uint max_char_length, CHARSET_INFO *cs, bool no_error) { - int well_formed_error; - uint res= cs->cset->well_formed_len(cs, str->str, str->str + str->length, - max_char_length, &well_formed_error); - - if (!well_formed_error && str->length == res) + Well_formed_prefix prefix(cs, str->str, str->length, max_char_length); + if (!prefix.well_formed_error_pos() && str->length == prefix.length()) return FALSE; if (!no_error) |