in sql/sql_prepare.cc [1204:1427]
bool Prepared_statement::prepare_query(THD *thd) {
DBUG_TRACE;
assert(m_lex == thd->lex); // set_n_backup_active_arena() guarantees that
Query_block *query_block = m_lex->query_block;
enum enum_sql_command sql_command = m_lex->sql_command;
int res = 0;
DBUG_PRINT("enter",
("command: %d param_count: %u", sql_command, m_param_count));
m_lex->first_lists_tables_same();
Table_ref *const tables = m_lex->query_tables;
/* set context for commands which do not use setup_tables */
query_block->context.resolve_in_table_list_only(
query_block->get_table_list());
/*
For the optimizer trace, this is the symmetric, for statement preparation,
of what is done at statement execution (in mysql_execute_command()).
*/
Opt_trace_start ots(thd, tables, sql_command, &m_lex->var_list,
thd->query().str, thd->query().length, nullptr,
thd->variables.character_set_client);
const Opt_trace_object trace_command(&thd->opt_trace);
const Opt_trace_array trace_command_steps(&thd->opt_trace, "steps");
if ((m_lex->keep_diagnostics == DA_KEEP_COUNTS) ||
(m_lex->keep_diagnostics == DA_KEEP_DIAGNOSTICS &&
// keep_diagnostics can be set if DECLARE EXIT HANDLER is
// used in the event body. But this is ok since the body is
// not prepared.
sql_command != SQLCOM_CREATE_EVENT &&
sql_command != SQLCOM_ALTER_EVENT)) {
my_error(ER_UNSUPPORTED_PS, MYF(0));
return true;
}
if (sql_command_flags[sql_command] & CF_HA_CLOSE)
mysql_ha_rm_tables(thd, tables);
/*
Open temporary tables that are known now. Temporary tables added by
prelocking will be opened afterwards (during open_tables()).
*/
if (sql_command_flags[sql_command] & CF_PREOPEN_TMP_TABLES) {
if (open_temporary_tables(thd, tables)) return true;
}
switch (sql_command) {
case SQLCOM_CREATE_VIEW:
if (m_lex->create_view_mode == enum_view_create_mode::VIEW_ALTER) {
my_error(ER_UNSUPPORTED_PS, MYF(0));
return true;
}
res = mysql_test_create_view(thd, this);
break;
case SQLCOM_SET_PASSWORD:
case SQLCOM_SET_OPTION:
res = mysql_test_set_fields(thd, this, tables, &m_lex->var_list);
break;
/*
Note that we don't need to have cases in this list if they are
marked with CF_STATUS_COMMAND in sql_command_flags
*/
case SQLCOM_DROP_TABLE:
case SQLCOM_RENAME_TABLE:
case SQLCOM_ALTER_TABLE:
case SQLCOM_COMMIT:
case SQLCOM_CREATE_INDEX:
case SQLCOM_DROP_INDEX:
case SQLCOM_ROLLBACK:
case SQLCOM_TRUNCATE:
case SQLCOM_DROP_VIEW:
case SQLCOM_REPAIR:
case SQLCOM_ANALYZE:
case SQLCOM_OPTIMIZE:
case SQLCOM_CHANGE_REPLICATION_SOURCE:
case SQLCOM_CHANGE_REPLICATION_FILTER:
case SQLCOM_RESET:
case SQLCOM_FLUSH:
case SQLCOM_REPLICA_START:
case SQLCOM_REPLICA_STOP:
case SQLCOM_INSTALL_PLUGIN:
case SQLCOM_UNINSTALL_PLUGIN:
case SQLCOM_CREATE_DB:
case SQLCOM_DROP_DB:
case SQLCOM_CHECKSUM:
case SQLCOM_CREATE_USER:
case SQLCOM_RENAME_USER:
case SQLCOM_DROP_USER:
case SQLCOM_ALTER_USER:
case SQLCOM_ASSIGN_TO_KEYCACHE:
case SQLCOM_PRELOAD_KEYS:
case SQLCOM_GRANT:
case SQLCOM_GRANT_ROLE:
case SQLCOM_REVOKE:
case SQLCOM_REVOKE_ALL:
case SQLCOM_REVOKE_ROLE:
case SQLCOM_KILL:
case SQLCOM_ALTER_INSTANCE:
case SQLCOM_SET_ROLE:
case SQLCOM_ALTER_USER_DEFAULT_ROLE:
break;
case SQLCOM_CREATE_TABLE:
/*
CREATE TABLE ... START TRANSACTION is not supported with
prepared statements
*/
if (m_lex->create_info->m_transactional_ddl) {
my_error(ER_UNSUPPORTED_PS, MYF(0));
return true;
}
#if defined(__has_cpp_attribute)
#if __has_cpp_attribute(fallthrough)
[[fallthrough]];
#endif
#endif
case SQLCOM_CREATE_EVENT:
case SQLCOM_ALTER_EVENT:
case SQLCOM_DROP_EVENT:
case SQLCOM_CREATE_LIBRARY:
case SQLCOM_DROP_LIBRARY:
case SQLCOM_ALTER_LIBRARY:
case SQLCOM_SELECT:
case SQLCOM_DO:
case SQLCOM_DELETE:
case SQLCOM_DELETE_MULTI:
case SQLCOM_UPDATE:
case SQLCOM_UPDATE_MULTI:
case SQLCOM_INSERT:
case SQLCOM_INSERT_SELECT:
case SQLCOM_REPLACE:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_CALL:
case SQLCOM_SHOW_BINLOG_EVENTS:
case SQLCOM_SHOW_BINLOGS:
case SQLCOM_SHOW_CHARSETS:
case SQLCOM_SHOW_COLLATIONS:
case SQLCOM_SHOW_CREATE_DB:
case SQLCOM_SHOW_CREATE_EVENT:
case SQLCOM_SHOW_CREATE_FUNC:
case SQLCOM_SHOW_CREATE_PROC:
case SQLCOM_SHOW_CREATE:
case SQLCOM_SHOW_CREATE_LIBRARY:
case SQLCOM_SHOW_CREATE_TRIGGER:
case SQLCOM_SHOW_CREATE_USER:
case SQLCOM_SHOW_DATABASES:
case SQLCOM_SHOW_ENGINE_LOGS:
case SQLCOM_SHOW_ENGINE_MUTEX:
case SQLCOM_SHOW_ENGINE_STATUS:
case SQLCOM_SHOW_ERRORS:
case SQLCOM_SHOW_EVENTS:
case SQLCOM_SHOW_FIELDS:
case SQLCOM_SHOW_FUNC_CODE:
case SQLCOM_SHOW_GRANTS:
case SQLCOM_SHOW_KEYS:
case SQLCOM_SHOW_BINLOG_STATUS:
case SQLCOM_SHOW_OPEN_TABLES:
case SQLCOM_SHOW_PLUGINS:
case SQLCOM_SHOW_PRIVILEGES:
case SQLCOM_SHOW_PROC_CODE:
case SQLCOM_SHOW_PROCESSLIST:
case SQLCOM_SHOW_PROFILE:
case SQLCOM_SHOW_PROFILES:
case SQLCOM_SHOW_RELAYLOG_EVENTS:
case SQLCOM_SHOW_REPLICAS:
case SQLCOM_SHOW_REPLICA_STATUS:
case SQLCOM_SHOW_STATUS:
case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STATUS_FUNC:
case SQLCOM_SHOW_STATUS_LIBRARY:
case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_TABLE_STATUS:
case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_TRIGGERS:
case SQLCOM_SHOW_VARIABLES:
case SQLCOM_SET_RESOURCE_GROUP:
case SQLCOM_SHOW_WARNS:
res = m_lex->m_sql_cmd->prepare(thd);
break;
case SQLCOM_PREPARE:
case SQLCOM_EXECUTE:
case SQLCOM_DEALLOCATE_PREPARE:
default:
/*
Trivial check of all status commands and diagnostic commands.
This is easier than having things in the above case list,
as it's less chance for mistakes.
*/
if (!(sql_command_flags[sql_command] & CF_STATUS_COMMAND) ||
(sql_command_flags[sql_command] & CF_DIAGNOSTIC_STMT)) {
/* All other statements are not supported yet. */
my_error(ER_UNSUPPORTED_PS, MYF(0));
return true;
}
break;
}
if (res) return true;
trace_parameter_types(thd);
if (is_sql_prepare()) return false;
mem_root_deque<Item *> *types = nullptr;
Query_result *result = nullptr;
uint no_columns = 0;
if ((sql_command_flags[sql_command] & CF_HAS_RESULT_SET) &&
!m_lex->is_explain()) {
Query_expression *unit = m_lex->unit;
result = unit->query_result();
if (result == nullptr) result = unit->first_query_block()->query_result();
if (result == nullptr) result = m_lex->result;
types = unit->get_unit_column_types();
no_columns = result->field_count(*types);
}
return send_statement(thd, this, no_columns, result, types);
}