bool do_command(THD *thd)
{
  bool return_value;
  char *packet= 0;
  ulong packet_length;
  NET *net= &thd->net;
  enum enum_server_command command;
  DBUG_ENTER("do_command");

  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
  thd->lex->current_select= 0;

  /*
    This thread will do a blocking read from the client which
    will be interrupted when the next command is received from
    the client, the connection is closed or "net_wait_timeout"
    number of seconds has passed.
  */
  if (!thd->skip_wait_timeout)
    my_net_set_read_timeout(net, thd->get_net_wait_timeout());

  /* Errors and diagnostics are cleared once here before query */
  thd->clear_error(1);

  net_new_transaction(net);

  /* Save for user statistics */
  thd->start_bytes_received= thd->status_var.bytes_received;

  /*
    Synchronization point for testing of KILL_CONNECTION.
    This sync point can wait here, to simulate slow code execution
    between the last test of thd->killed and blocking in read().

    The goal of this test is to verify that a connection does not
    hang, if it is killed at this point of execution.
    (Bug#37780 - main.kill fails randomly)

    Note that the sync point wait itself will be terminated by a
    kill. In this case it consumes a condition broadcast, but does
    not change anything else. The consumed broadcast should not
    matter here, because the read/recv() below doesn't use it.
  */
  DEBUG_SYNC(thd, "before_do_command_net_read");

  packet_length= my_net_read_packet(net, 1);

  if (unlikely(packet_length == packet_error))
  {
    DBUG_PRINT("info",("Got error %d reading command from socket %s",
		       net->error,
		       vio_description(net->vio)));

    /* Instrument this broken statement as "statement/com/error" */
    thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
                                                 com_statement_info[COM_END].
                                                 m_key);


    /* Check if we can continue without closing the connection */

    /* The error must be set. */
    DBUG_ASSERT(thd->is_error());
    thd->protocol->end_statement();

    /* Mark the statement completed. */
    MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
    thd->m_statement_psi= NULL;
    thd->m_digest= NULL;

    if (net->error != 3)
    {
      return_value= TRUE;                       // We have to close it.
      goto out;
    }

    net->error= 0;
    return_value= FALSE;
    goto out;
  }

  packet= (char*) net->read_pos;
  /*
    'packet_length' contains length of data, as it was stored in packet
    header. In case of malformed header, my_net_read returns zero.
    If packet_length is not zero, my_net_read ensures that the returned
    number of bytes was actually read from network.
    There is also an extra safety measure in my_net_read:
    it sets packet[packet_length]= 0, but only for non-zero packets.
  */
  if (packet_length == 0)                       /* safety */
  {
    /* Initialize with COM_SLEEP packet */
    packet[0]= (uchar) COM_SLEEP;
    packet_length= 1;
  }
  /* Do not rely on my_net_read, extra safety against programming errors. */
  packet[packet_length]= '\0';                  /* safety */


  command= fetch_command(thd, packet);

#ifdef WITH_WSREP
  DEBUG_SYNC(thd, "wsrep_before_before_command");
  /*
    If this command does not return a result, then we
    instruct wsrep_before_command() to skip result handling.
    This causes BF aborted transaction to roll back but keep
    the error state until next command which is able to return
    a result to the client.
  */
  if (wsrep_before_command(thd, wsrep_command_no_result(command)))
  {
    /*
      Aborted by background rollbacker thread.
      Handle error here and jump straight to out.
      Notice that thd->store_globals() is called
      in wsrep_before_command().
    */
    WSREP_LOG_THD(thd, "enter found BF aborted");
    DBUG_ASSERT(!thd->mdl_context.has_locks());
    DBUG_ASSERT(!thd->get_stmt_da()->is_set());
    /* We let COM_QUIT and COM_STMT_CLOSE to execute even if wsrep aborted. */
    if (command == COM_STMT_EXECUTE)
    {
      WSREP_DEBUG("PS BF aborted at do_command");
      thd->wsrep_delayed_BF_abort= true;
    }
    if (command != COM_STMT_CLOSE   &&
	command != COM_STMT_EXECUTE &&
        command != COM_QUIT)
    {
      my_error(ER_LOCK_DEADLOCK, MYF(0));
      WSREP_DEBUG("Deadlock error for: %s", thd->query());
      thd->reset_killed();
      thd->mysys_var->abort     = 0;
      thd->wsrep_retry_counter  = 0;

      /* Instrument this broken statement as "statement/com/error" */
      thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
                                                 com_statement_info[COM_END].
                                                 m_key);

      thd->protocol->end_statement();

      /* Mark the statement completed. */
      MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
      thd->m_statement_psi= NULL;
      thd->m_digest= NULL;
      return_value= FALSE;

      wsrep_after_command_before_result(thd);
      goto out;
    }
  }

  if (WSREP(thd))
  {
    /*
     * bail out if DB snapshot has not been installed. We however,
     * allow queries "SET" and "SHOW", they are trapped later in execute_command
     */
    if (!(thd->wsrep_applier) &&
        (!wsrep_ready_get() || wsrep_reject_queries != WSREP_REJECT_NONE) &&
        (server_command_flags[command] & CF_SKIP_WSREP_CHECK) == 0)
    {
      my_message(ER_UNKNOWN_COM_ERROR,
                 "WSREP has not yet prepared node for application use", MYF(0));
      thd->protocol->end_statement();

      /* Performance Schema Interface instrumentation end. */
      MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
      thd->m_statement_psi= NULL;
      thd->m_digest= NULL;

      return_value= FALSE;
      wsrep_after_command_before_result(thd);
      goto out;
    }
  }
#endif /* WITH_WSREP */
  /* Restore read timeout value */
  my_net_set_read_timeout(net, thd->variables.net_read_timeout);

  DBUG_ASSERT(packet_length);
  DBUG_ASSERT(!thd->apc_target.is_enabled());
  return_value= dispatch_command(command, thd, packet+1,
                                 (uint) (packet_length-1), FALSE, FALSE);
  DBUG_ASSERT(!thd->apc_target.is_enabled());

out:
  thd->lex->restore_set_statement_var();
  /* The statement instrumentation must be closed in all cases. */
  DBUG_ASSERT(thd->m_digest == NULL);
  DBUG_ASSERT(thd->m_statement_psi == NULL);
#ifdef WITH_WSREP
  if (packet_length != packet_error)
  {
    /* there was a command to process, and before_command() has been called */
    wsrep_after_command_after_result(thd);
  }

  if (thd->wsrep_delayed_BF_abort)
  {
      my_error(ER_LOCK_DEADLOCK, MYF(0));
      WSREP_DEBUG("Deadlock error for PS query: %s", thd->query());
      thd->reset_killed();
      thd->mysys_var->abort     = 0;
      thd->wsrep_retry_counter  = 0;

      thd->wsrep_delayed_BF_abort= false;
  }
#endif /* WITH_WSREP */
  DBUG_RETURN(return_value);
}