summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc949
1 files changed, 767 insertions, 182 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index adead650029..461c4a419be 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,8 @@ 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;
+ server_command_flags[CF_NO_COM_MULTI]= CF_NO_COM_MULTI;
/* Initialize the sql command flags array. */
memset(sql_command_flags, 0, sizeof(sql_command_flags));
@@ -341,17 +578,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 +599,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 +609,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 +663,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 +685,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 +716,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 +750,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 +779,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 +845,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 +896,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)
@@ -684,7 +929,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;
@@ -802,7 +1047,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();
@@ -859,13 +1104,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
@@ -874,7 +1118,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)
{
@@ -889,7 +1133,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)
@@ -900,6 +1144,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)
@@ -1089,14 +1349,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))
@@ -1128,7 +1382,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))
{
@@ -1147,7 +1402,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;
}
@@ -1229,6 +1484,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
@@ -1237,6 +1533,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.
@@ -1250,15 +1548,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;
- inc_thread_running();
+ if (!is_com_multi)
+ inc_thread_running();
+
+ /* keep it withing 1 byte */
+ compile_time_assert(COM_END == 255);
#ifdef WITH_WSREP
if (WSREP(thd))
@@ -1283,7 +1590,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;
@@ -1346,6 +1654,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:
{
@@ -1370,6 +1687,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;
@@ -1419,10 +1747,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);
}
@@ -1438,6 +1764,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);
@@ -1494,13 +1825,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
if (WSREP_ON)
- 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())
{
+ thd->get_stmt_da()->set_skip_flush();
/*
Multiple queries exist, execute them individually
*/
@@ -1581,9 +1915,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
if (WSREP_ON)
- 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);
}
@@ -1616,7 +1952,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)
@@ -1635,6 +1971,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)
@@ -1667,7 +2011,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,
@@ -1821,7 +2165,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;
}
@@ -1848,7 +2192,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,
@@ -1918,11 +2262,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));
@@ -1961,9 +2384,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);
@@ -1988,8 +2416,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.
@@ -2161,7 +2592,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);
@@ -2184,7 +2615,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();
@@ -2382,27 +2813,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))
@@ -2454,6 +2938,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.
@@ -2563,6 +3054,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))
{
@@ -2890,7 +3384,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;
}
}
@@ -2936,7 +3431,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;
}
@@ -3039,6 +3534,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);
@@ -3504,7 +4004,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,
@@ -3512,7 +4012,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)
@@ -3656,7 +4156,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;
}
@@ -3745,7 +4246,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());
/*
@@ -3924,7 +4425,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,
@@ -3957,7 +4458,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))
@@ -3987,7 +4495,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;
@@ -3997,6 +4505,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:
@@ -4076,7 +4591,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
{
@@ -4131,7 +4647,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))
@@ -4412,6 +4928,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) &&
@@ -4419,7 +4936,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;
}
@@ -4708,7 +5229,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");
@@ -4716,6 +5237,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;
@@ -4759,7 +5289,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);
@@ -4778,7 +5309,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. */
@@ -4790,8 +5322,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)
@@ -4830,7 +5361,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. */
@@ -4842,8 +5374,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)
@@ -4903,7 +5434,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;
}
@@ -5309,15 +5840,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;
}
@@ -5327,15 +5858,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;
}
@@ -5575,6 +6106,9 @@ finish:
{
thd->mdl_context.release_statement_locks();
}
+
+ TRANSACT_TRACKER(add_trx_state_from_thd(thd));
+
WSREP_TO_ISOLATION_END;
#ifdef WITH_WSREP
@@ -5586,8 +6120,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 */
@@ -5609,6 +6143,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)
@@ -5705,7 +6240,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());
@@ -5789,7 +6324,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);
}
@@ -5901,11 +6436,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))
@@ -6219,7 +6750,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,
@@ -6784,10 +7315,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;
@@ -6894,22 +7424,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))
@@ -6960,7 +7498,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;
@@ -6979,7 +7517,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=
@@ -7009,7 +7549,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 */
@@ -7063,12 +7604,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;
@@ -7126,10 +7669,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");
@@ -7153,6 +7699,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)
{
@@ -7186,7 +7738,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(),
@@ -7228,7 +7779,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
{
@@ -7284,13 +7835,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)
{
@@ -7302,7 +7846,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;
}
@@ -7320,8 +7863,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;
@@ -7427,7 +7969,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 &&
@@ -7439,20 +7980,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;
}
@@ -7518,7 +8047,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);
@@ -7973,6 +8502,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.
@@ -9204,11 +9792,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)