bool dispatch_command(enum enum_server_command command, THD *thd,
		      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 %s", command,
                      (command_name[command].str != 0 ?
                       command_name[command].str :
                       "<?>")));
  bool drop_more_results= 0;

  /* keep it withing 1 byte */
  compile_time_assert(COM_END == 255);

#if defined(ENABLED_PROFILING)
  thd->profiling.start_new_query();
#endif
  MYSQL_COMMAND_START(thd->thread_id, command,
                      &thd->security_ctx->priv_user[0],
                      (char *) thd->security_ctx->host_or_ip);
  
  DBUG_EXECUTE_IF("crash_dispatch_command_before",
                  { DBUG_PRINT("crash_dispatch_command_before", ("now"));
                    DBUG_SUICIDE(); });

  /* Performance Schema Interface instrumentation, begin */
  thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
                                               com_statement_info[command].
                                               m_key);
  /*
    We should always call reset_for_next_command() before a query.
    mysql_parse() will do this for queries. Ensure it's also done
    for other commands.
  */
  if (command != COM_QUERY)
    thd->reset_for_next_command();
  thd->set_command(command);

  thd->enable_slow_log= true;
  thd->query_plan_flags= QPLAN_INIT;
  thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
  thd->reset_kill_query();

  DEBUG_SYNC(thd,"dispatch_command_before_set_time");

  thd->set_time();
  if (!(server_command_flags[command] & CF_SKIP_QUERY_ID))
    thd->set_query_id(next_query_id());
  else
  {
    /*
      ping, get statistics or similar stateless command.
      No reason to increase query id here.
    */
    thd->set_query_id(get_query_id());
  }
#ifdef WITH_WSREP
  if (WSREP(thd) && thd->wsrep_next_trx_id() == WSREP_UNDEFINED_TRX_ID)
  {
    thd->set_wsrep_next_trx_id(thd->query_id);
    WSREP_DEBUG("assigned new next trx id: %" PRIu64, thd->wsrep_next_trx_id());
  }
#endif /* WITH_WSREP */

  if (!(server_command_flags[command] & CF_SKIP_QUESTIONS))
    statistic_increment(thd->status_var.questions, &LOCK_status);

  /* Copy data for user stats */
  if ((thd->userstat_running= opt_userstat_running))
  {
    thd->start_cpu_time= my_getcputime();
    memcpy(&thd->org_status_var, &thd->status_var, sizeof(thd->status_var));
    thd->select_commands= thd->update_commands= thd->other_commands= 0;
  }

  /**
    Clear the set of flags that are expected to be cleared at the
    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();
  }

  if (unlikely(thd->security_ctx->password_expired &&
               command != COM_QUERY &&
               command != COM_PING &&
               command != COM_QUIT &&
               command != COM_STMT_PREPARE &&
               command != COM_STMT_EXECUTE))
  {
    my_error(ER_MUST_CHANGE_PASSWORD, MYF(0));
    goto dispatch_end;
  }

  switch (command) {
  case COM_INIT_DB:
  {
    LEX_CSTRING tmp;
    status_var_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB]);
    if (unlikely(thd->copy_with_error(system_charset_info, (LEX_STRING*) &tmp,
                                      thd->charset(), packet, packet_length)))
      break;
    if (!mysql_change_db(thd, &tmp, FALSE))
    {
      general_log_write(thd, command, thd->db.str, thd->db.length);
      my_ok(thd);
    }
    break;
  }
#ifdef HAVE_REPLICATION
  case COM_REGISTER_SLAVE:
  {
    status_var_increment(thd->status_var.com_register_slave);
    if (!thd->register_slave((uchar*) packet, packet_length))
      my_ok(thd);
    break;
  }
#endif
  case COM_RESET_CONNECTION:
  {
    thd->status_var.com_other++;
#ifdef WITH_WSREP
    wsrep_after_command_ignore_result(thd);
    wsrep_close(thd);
#endif /* WITH_WSREP */
    thd->change_user();
    thd->clear_error();                         // if errors from rollback
#ifdef WITH_WSREP
    wsrep_open(thd);
    wsrep_before_command(thd);
#endif /* WITH_WSREP */
    /* 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;
    status_var_increment(thd->status_var.com_other);

#ifdef WITH_WSREP
    wsrep_after_command_ignore_result(thd);
    wsrep_close(thd);
#endif /* WITH_WSREP */
    thd->change_user();
#ifdef WITH_WSREP
    wsrep_open(thd);
    wsrep_before_command(thd);
#endif /* WITH_WSREP */
    thd->clear_error();                         // if errors from rollback

    /* acl_authenticate() takes the data from net->read_pos */
    net->read_pos= (uchar*)packet;

    LEX_CSTRING save_db= thd->db;
    USER_CONN *save_user_connect= thd->user_connect;
    Security_context save_security_ctx= *thd->security_ctx;
    CHARSET_INFO *save_character_set_client=
      thd->variables.character_set_client;
    CHARSET_INFO *save_collation_connection=
      thd->variables.collation_connection;
    CHARSET_INFO *save_character_set_results=
      thd->variables.character_set_results;

    /* Ensure we don't free security_ctx->user in case we have to revert */
    thd->security_ctx->user= 0;
    thd->user_connect= 0;

    /*
      to limit COM_CHANGE_USER ability to brute-force passwords,
      we only allow three unsuccessful COM_CHANGE_USER per connection.
    */
    if (thd->failed_com_change_user >= 3)
    {
      my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd,ER_UNKNOWN_COM_ERROR),
                 MYF(0));
      auth_rc= 1;
    }
    else
      auth_rc= acl_authenticate(thd, packet_length);

    mysql_audit_notify_connection_change_user(thd);
    if (auth_rc)
    {
      /* Free user if allocated by acl_authenticate */
      my_free(const_cast<char*>(thd->security_ctx->user));
      *thd->security_ctx= save_security_ctx;
      if (thd->user_connect)
	decrease_user_connections(thd->user_connect);
      thd->user_connect= save_user_connect;
      thd->reset_db(&save_db);
      thd->update_charset(save_character_set_client, save_collation_connection,
                          save_character_set_results);
      thd->failed_com_change_user++;
      my_sleep(1000000);
    }
    else
    {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
      /* we've authenticated new user */
      if (save_user_connect)
	decrease_user_connections(save_user_connect);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
      my_free((char*) save_db.str);
      my_free(const_cast<char*>(save_security_ctx.user));
    }
    break;
  }
  case COM_STMT_BULK_EXECUTE:
  {
    mysqld_stmt_bulk_execute(thd, packet, packet_length);
#ifdef WITH_WSREP
    if (WSREP(thd))
    {
        (void)wsrep_after_statement(thd);
    }
#endif /* WITH_WSREP */
    break;
  }
  case COM_STMT_EXECUTE:
  {
    mysqld_stmt_execute(thd, packet, packet_length);
#ifdef WITH_WSREP
    if (WSREP(thd))
    {
        (void)wsrep_after_statement(thd);
    }
#endif /* WITH_WSREP */
    break;
  }
  case COM_STMT_FETCH:
  {
    mysqld_stmt_fetch(thd, packet, packet_length);
    break;
  }
  case COM_STMT_SEND_LONG_DATA:
  {
    mysql_stmt_get_longdata(thd, packet, packet_length);
    break;
  }
  case COM_STMT_PREPARE:
  {
    mysqld_stmt_prepare(thd, packet, packet_length);
    break;
  }
  case COM_STMT_CLOSE:
  {
    mysqld_stmt_close(thd, packet);
    break;
  }
  case COM_STMT_RESET:
  {
    mysqld_stmt_reset(thd, packet);
    break;
  }
  case COM_QUERY:
  {
    DBUG_ASSERT(thd->m_digest == NULL);
    thd->m_digest= & thd->m_digest_state;
    thd->m_digest->reset(thd->m_token_array, max_digest_length);

    if (unlikely(alloc_query(thd, packet, packet_length)))
      break;					// fatal error is set
    MYSQL_QUERY_START(thd->query(), thd->thread_id,
                      thd->get_db(),
                      &thd->security_ctx->priv_user[0],
                      (char *) thd->security_ctx->host_or_ip);
    char *packet_end= thd->query() + thd->query_length();
    general_log_write(thd, command, thd->query(), thd->query_length());
    DBUG_PRINT("query",("%-.4096s",thd->query()));
#if defined(ENABLED_PROFILING)
    thd->profiling.set_query_source(thd->query(), thd->query_length());
#endif
    MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(),
                             thd->query_length());

    Parser_state parser_state;
    if (unlikely(parser_state.init(thd, thd->query(), thd->query_length())))
      break;

#ifdef WITH_WSREP
    if (WSREP(thd))
    {
      if (wsrep_mysql_parse(thd, thd->query(), thd->query_length(),
                            &parser_state,
                            is_com_multi, is_next_command))
      {
        WSREP_DEBUG("Deadlock error for: %s", thd->query());
        mysql_mutex_lock(&thd->LOCK_thd_data);
        thd->reset_kill_query();
        thd->wsrep_retry_counter  = 0;
        mysql_mutex_unlock(&thd->LOCK_thd_data);
        goto dispatch_end;
      }
    }
    else
#endif /* WITH_WSREP */
      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())
    {
      /*
        Multiple queries exist, execute them individually
      */
      char *beginning_of_next_stmt= (char*) parser_state.m_lip.found_semicolon;

      ha_maria_implicit_commit(thd, FALSE);

      /* Finalize server status flags after executing a statement. */
      thd->update_server_status();
      thd->protocol->end_statement();
      query_cache_end_of_result(thd);

      mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_STATUS,
                          thd->get_stmt_da()->is_error()
                            ? thd->get_stmt_da()->sql_errno()
                            : 0,
                          command_name[command].str);

      ulong length= (ulong)(packet_end - beginning_of_next_stmt);

      log_slow_statement(thd);
      DBUG_ASSERT(!thd->apc_target.is_enabled());

      /* Remove garbage at start of query */
      while (length > 0 && my_isspace(thd->charset(), *beginning_of_next_stmt))
      {
        beginning_of_next_stmt++;
        length--;
      }

      /* PSI end */
      MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
      thd->m_statement_psi= NULL;
      thd->m_digest= NULL;

      /* DTRACE end */
      if (MYSQL_QUERY_DONE_ENABLED())
      {
        MYSQL_QUERY_DONE(thd->is_error());
      }

#if defined(ENABLED_PROFILING)
      thd->profiling.finish_current_query();
      thd->profiling.start_new_query("continuing");
      thd->profiling.set_query_source(beginning_of_next_stmt, length);
#endif

      /* DTRACE begin */
      MYSQL_QUERY_START(beginning_of_next_stmt, thd->thread_id,
                        thd->get_db(),
                        &thd->security_ctx->priv_user[0],
                        (char *) thd->security_ctx->host_or_ip);

      /* PSI begin */
      thd->m_digest= & thd->m_digest_state;

      thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
                                                  com_statement_info[command].m_key,
                                                  thd->db.str, thd->db.length,
                                                  thd->charset());
      THD_STAGE_INFO(thd, stage_init);
      MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, beginning_of_next_stmt,
                               length);

      thd->set_query_and_id(beginning_of_next_stmt, length,
                            thd->charset(), next_query_id());

      /*
        Count each statement from the client.
      */
      statistic_increment(thd->status_var.questions, &LOCK_status);

      if (!WSREP(thd))
        thd->set_time(); /* Reset the query start time. */

      parser_state.reset(beginning_of_next_stmt, length);

#ifdef WITH_WSREP
      if (WSREP(thd))
      {
        if (wsrep_mysql_parse(thd, beginning_of_next_stmt,
                              length, &parser_state,
                              is_com_multi, is_next_command))
        {
          WSREP_DEBUG("Deadlock error for: %s", thd->query());
          mysql_mutex_lock(&thd->LOCK_thd_data);
          thd->reset_kill_query();
          thd->wsrep_retry_counter  = 0;
          mysql_mutex_unlock(&thd->LOCK_thd_data);

          goto dispatch_end;
        }
      }
      else
#endif /* WITH_WSREP */
      mysql_parse(thd, beginning_of_next_stmt, length, &parser_state,
                  is_com_multi, is_next_command);

    }

    DBUG_PRINT("info",("query ready"));
    break;
  }
  case COM_FIELD_LIST:				// This isn't actually needed
#ifdef DONT_ALLOW_SHOW_COMMANDS
    my_message(ER_NOT_ALLOWED_COMMAND, ER_THD(thd, ER_NOT_ALLOWED_COMMAND),
               MYF(0));	/* purecov: inspected */
    break;
#else
  {
    char *fields, *packet_end= packet + packet_length, *arg_end;
    /* Locked closure of all tables */
    TABLE_LIST table_list;
    LEX_STRING table_name;
    LEX_CSTRING db;
    /*
      SHOW statements should not add the used tables to the list of tables
      used in a transaction.
    */
    MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();

    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]);
    if (thd->copy_db_to(&db))
      break;
    /*
      We have name + wildcard in packet, separated by endzero
      (The packet is guaranteed to end with an end zero)
    */
    arg_end= strend(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)
    {
      my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR),
                 MYF(0));
      break;
    }
    thd->convert_string(&table_name, system_charset_info,
			packet, arg_length, thd->charset());
    if (check_table_name(table_name.str, table_name.length, FALSE))
    {
      /* this is OK due to convert_string() null-terminating the string */
      my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str);
      break;
    }
    packet= arg_end + 1;
    // 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)
    {
      table_name.length= my_casedn_str(files_charset_info, table_name.str);
      db.length= my_casedn_str(files_charset_info, (char*) db.str);
    }
    table_list.init_one_table(&db, (LEX_CSTRING*) &table_name, 0, TL_READ);
    /*
      Init TABLE_LIST members necessary when the undelrying
      table is view.
    */
    table_list.select_lex= thd->lex->first_select_lex();
    thd->lex->
      first_select_lex()->table_list.link_in_list(&table_list,
                                                  &table_list.next_local);
    thd->lex->add_to_query_tables(&table_list);

    if (is_infoschema_db(&table_list.db))
    {
      ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, &table_list.alias);
      if (schema_table)
        table_list.schema_table= schema_table;
    }

    uint query_length= (uint) (packet_end - packet); // Don't count end \0
    if (!(fields= (char *) thd->memdup(packet, query_length + 1)))
      break;
    thd->set_query(fields, query_length);
    general_log_print(thd, command, "%s %s", table_list.table_name.str,
                      fields);

    if (thd->open_temporary_tables(&table_list))
      break;

    if (check_table_access(thd, SELECT_ACL, &table_list,
                           TRUE, UINT_MAX, FALSE))
      break;
    /*
      Turn on an optimization relevant if the underlying table
      is a view: do not fill derived tables.
    */
    thd->lex->sql_command= SQLCOM_SHOW_FIELDS;

    mysqld_list_fields(thd,&table_list,fields);
    thd->lex->unit.cleanup();
    /* No need to rollback statement transaction, it's not started. */
    DBUG_ASSERT(thd->transaction.stmt.is_empty());
    close_thread_tables(thd);
    thd->mdl_context.rollback_to_savepoint(mdl_savepoint);

    if (thd->transaction_rollback_request)
    {
      /*
        Transaction rollback was requested since MDL deadlock was
        discovered while trying to open tables. Rollback transaction
        in all storage engines including binary log and release all
        locks.
      */
      trans_rollback_implicit(thd);
      thd->release_transactional_locks();
    }

    thd->cleanup_after_query();
    break;
  }
#endif
  case COM_QUIT:
    /* Note: We don't calculate statistics for this command */

    /* Ensure that quit works even if max_mem_used is set */
    thd->variables.max_mem_used= LONGLONG_MAX;
    general_log_print(thd, command, NullS);
    net->error=0;				// Don't give 'abort' message
    thd->get_stmt_da()->disable_status();       // Don't send anything back
    error=TRUE;					// End server
    break;
#ifndef EMBEDDED_LIBRARY
  case COM_BINLOG_DUMP:
    {
      ulong pos;
      ushort flags;
      uint32 slave_server_id;

      status_var_increment(thd->status_var.com_other);

      thd->query_plan_flags|= QPLAN_ADMIN;
      if (check_global_access(thd, REPL_SLAVE_ACL))
	break;

      /* TODO: The following has to be changed to an 8 byte integer */
      pos = uint4korr(packet);
      flags = uint2korr(packet + 4);
      thd->variables.server_id=0; /* avoid suicide */
      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
	kill_zombie_dump_threads(slave_server_id);
      thd->variables.server_id = slave_server_id;

      const char *name= packet + 10;
      size_t nlen= strlen(name);

      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);
      thd->unregister_slave(); // todo: can be extraneous
      /*  fake COM_QUIT -- if we get here, the thread needs to terminate */
      error = TRUE;
      break;
    }
#endif
  case COM_REFRESH:
  {
    int not_used;

    /*
      Initialize thd->lex since it's used in many base functions, such as
      open_tables(). Otherwise, it remains unitialized and may cause crash
      during execution of COM_REFRESH.
    */
    lex_start(thd);
    
    status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
    ulonglong options= (ulonglong) (uchar) packet[0];
    if (trans_commit_implicit(thd))
      break;
    thd->release_transactional_locks();
    if (check_global_access(thd,RELOAD_ACL))
      break;
    general_log_print(thd, command, NullS);
#ifndef DBUG_OFF
    bool debug_simulate= FALSE;
    DBUG_EXECUTE_IF("simulate_detached_thread_refresh", debug_simulate= TRUE;);
    if (debug_simulate)
    {
      /* This code doesn't work under FTWRL */
      DBUG_ASSERT(! (options & REFRESH_READ_LOCK));
      /*
        Simulate a reload without a attached thread session.
        Provides a environment similar to that of when the
        server receives a SIGHUP signal and reloads caches
        and flushes tables.
      */
      bool res;
      set_current_thd(0);
      res= reload_acl_and_cache(NULL, options | REFRESH_FAST,
                                NULL, &not_used);
      set_current_thd(thd);
      if (res)
        break;
    }
    else
#endif
    {
      thd->lex->relay_log_connection_name= empty_clex_str;
      if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
        break;
    }
    if (trans_commit_implicit(thd))
      break;
    close_thread_tables(thd);
    thd->release_transactional_locks();
    my_ok(thd);
    break;
  }
#ifndef EMBEDDED_LIBRARY
  case COM_SHUTDOWN:
  {
    status_var_increment(thd->status_var.com_other);
    if (check_global_access(thd,SHUTDOWN_ACL))
      break; /* purecov: inspected */
    /*
      If the client is < 4.1.3, it is going to send us no argument; then
      packet_length is 0, packet[0] is the end 0 of the packet. Note that
      SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in
      packet[0].
    */
    enum mysql_enum_shutdown_level level;
    level= (enum mysql_enum_shutdown_level) (uchar) packet[0];
    thd->lex->is_shutdown_wait_for_slaves= false;  // "deferred" cleanup
    if (level == SHUTDOWN_DEFAULT)
      level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable
    else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
    {
      my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level");
      break;
    }
    DBUG_PRINT("quit",("Got shutdown command for level %u", level));
    general_log_print(thd, command, NullS);
    my_eof(thd);
    kill_mysql(thd);
    error=TRUE;
    break;
  }
#endif
  case COM_STATISTICS:
  {
    STATUS_VAR *current_global_status_var;      // Big; Don't allocate on stack
    ulong uptime;
    ulonglong queries_per_second1000;
    char buff[250];
    uint buff_len= sizeof(buff);

    if (!(current_global_status_var= (STATUS_VAR*)
          thd->alloc(sizeof(STATUS_VAR))))
      break;
    general_log_print(thd, command, NullS);
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]);
    *current_global_status_var= global_status_var;
    calc_sum_of_all_status(current_global_status_var);
    if (!(uptime= (ulong) (thd->start_time - server_start_time)))
      queries_per_second1000= 0;
    else
      queries_per_second1000= thd->query_id * 1000 / uptime;
#ifndef EMBEDDED_LIBRARY
    size_t length=
#endif
    my_snprintf(buff, buff_len - 1,
                        "Uptime: %lu  Threads: %u  Questions: %lu  "
                        "Slow queries: %lu  Opens: %lu  Flush tables: %lld  "
                        "Open tables: %u  Queries per second avg: %u.%03u",
                        uptime, THD_count::value(), (ulong) thd->query_id,
                        current_global_status_var->long_query_count,
                        current_global_status_var->opened_tables,
                        tdc_refresh_version(), tc_records(),
                        (uint) (queries_per_second1000 / 1000),
                        (uint) (queries_per_second1000 % 1000));
#ifdef EMBEDDED_LIBRARY
    /* Store the buffer in permanent memory */
    my_ok(thd, 0, 0, buff);
#else
    (void) my_net_write(net, (uchar*) buff, length);
    (void) net_flush(net);
    thd->get_stmt_da()->disable_status();
#endif
    break;
  }
  case COM_PING:
    status_var_increment(thd->status_var.com_other);
    my_ok(thd);				// Tell client we are alive
    break;
  case COM_PROCESS_INFO:
    status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]);
    if (!thd->security_ctx->priv_user[0] &&
        check_global_access(thd, PROCESS_ACL))
      break;
    general_log_print(thd, command, NullS);
    mysqld_list_processes(thd,
			  thd->security_ctx->master_access & PROCESS_ACL ? 
			  NullS : thd->security_ctx->priv_user, 0);
    break;
  case COM_PROCESS_KILL:
  {
    status_var_increment(thd->status_var.com_stat[SQLCOM_KILL]);
    ulong id=(ulong) uint4korr(packet);
    sql_kill(thd, id, KILL_CONNECTION_HARD, KILL_TYPE_ID);
    break;
  }
  case COM_SET_OPTION:
  {
    status_var_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION]);
    uint opt_command= uint2korr(packet);

    switch (opt_command) {
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON:
      thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
      my_eof(thd);
      break;
    case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF:
      thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
      my_eof(thd);
      break;
    default:
      my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR),
                 MYF(0));
      break;
    }
    break;
  }
  case COM_DEBUG:
    status_var_increment(thd->status_var.com_other);
    if (check_global_access(thd, SUPER_ACL))
      break;					/* purecov: inspected */
    mysql_print_status();
    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),
                             (uint)(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-= (uint)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));
    break;
  }

dispatch_end:
#ifdef WITH_WSREP
  /*
    BF aborted before sending response back to client
  */
  if (thd->killed == KILL_QUERY)
  {
    WSREP_DEBUG("THD is killed at dispatch_end");
  }
  wsrep_after_command_before_result(thd);
  if (wsrep_current_error(thd) && !wsrep_command_no_result(command))
  {
    /* todo: Pass wsrep client state current error to override */
    wsrep_override_error(thd, wsrep_current_error(thd),
                         wsrep_current_error_status(thd));
    WSREP_LOG_THD(thd, "leave");
  }
  if (WSREP(thd))
  {
    /*
      MDEV-10812
      In the case of COM_QUIT/COM_STMT_CLOSE thread status should be disabled.
    */
    DBUG_ASSERT((command != COM_QUIT && command != COM_STMT_CLOSE)
                  || thd->get_stmt_da()->is_disabled());
    DBUG_ASSERT(thd->wsrep_trx().state() != wsrep::transaction::s_replaying);
    /* wsrep BF abort in query exec phase */
    mysql_mutex_lock(&thd->LOCK_thd_kill);
    do_end_of_statement= thd_is_connection_alive(thd);
    mysql_mutex_unlock(&thd->LOCK_thd_kill);
  }
  else
    do_end_of_statement= true;

#endif /* WITH_WSREP */

  if (do_end_of_statement)
  {
    DBUG_ASSERT(thd->derived_tables == NULL &&
               (thd->open_tables == NULL ||
               (thd->locked_tables_mode == LTM_LOCK_TABLES)));

    thd_proc_info(thd, "Updating status");
    /* Finalize server status flags after executing a command. */
    thd->update_server_status();
    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 (likely(!thd->is_error() && !thd->killed_errno()))
    mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0);

  mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_STATUS,
                      thd->get_stmt_da()->is_error() ?
                      thd->get_stmt_da()->sql_errno() : 0,
                      command_name[command].str);

  thd->update_all_stats();

  log_slow_statement(thd);

  THD_STAGE_INFO(thd, stage_cleaning_up);
  thd->reset_query();

  /* Performance Schema Interface instrumentation, end */
  MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
  thd->set_examined_row_count(0);                   // For processlist
  thd->set_command(COM_SLEEP);

  thd->m_statement_psi= NULL;
  thd->m_digest= NULL;

  if (!is_com_multi)
    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.
    Unlink it now, before freeing the root.
  */
  thd->lex->m_sql_cmd= NULL;
  free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));

#if defined(ENABLED_PROFILING)
  thd->profiling.finish_current_query();
#endif
  if (MYSQL_QUERY_DONE_ENABLED() || MYSQL_COMMAND_DONE_ENABLED())
  {
    int res __attribute__((unused));
    res= (int) thd->is_error();
    if (command == COM_QUERY)
    {
      MYSQL_QUERY_DONE(res);
    }
    MYSQL_COMMAND_DONE(res);
  }
  DEBUG_SYNC(thd,"dispatch_command_end");

  /* Check that some variables are reset properly */
  DBUG_ASSERT(thd->abort_on_warning == 0);
  thd->lex->restore_set_statement_var();
  DBUG_RETURN(error);
}