/* Copyright (c) 2023, 2025, Oracle and/or its affiliates.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.

This program is designed to work with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation.  The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have either included with
the program or referenced in the documentation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License, version 2.0, for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */

#include "sql/statement/ed_connection.h"

#include "sql/sql_prepare.h"
#include "sql/statement/protocol_local.h"
#include "sql/statement/statement_runnable.h"

/**
  Create a new "execute direct" connection.
*/

Ed_connection::Ed_connection(THD *thd)
    : m_diagnostics_area(false),
      m_thd(thd),
      m_rsets(nullptr),
      m_current_rset(nullptr) {}

/**
  Free all result sets of the previous statement, if any,
  and reset warnings and errors.

  Called before execution of the next query.
*/

void Ed_connection::free_old_result() {
  while (m_rsets) {
    Ed_result_set *rset = m_rsets->m_next_rset;
    delete m_rsets;
    m_rsets = rset;
  }
  m_current_rset = m_rsets;
  m_diagnostics_area.reset_diagnostics_area();
  m_diagnostics_area.reset_condition_info(m_thd);
}

/**
  A simple wrapper that uses a helper class to execute SQL statements.
*/

bool Ed_connection::execute_direct(LEX_STRING sql_text) {
  Statement_runnable execute_sql_statement(sql_text);
  DBUG_PRINT("ed_query", ("%s", sql_text.str));

  return execute_direct(&execute_sql_statement);
}

/**
  Execute a fragment of server functionality without an effect on
  thd, and store results in memory.

  Conventions:
  - the code fragment must finish with OK, EOF or ERROR.
  - the code fragment doesn't have to close thread tables,
  free memory, commit statement transaction or do any other
  cleanup that is normally done in the end of dispatch_command().

  @param server_runnable A code fragment to execute.
*/

bool Ed_connection::execute_direct(Server_runnable *server_runnable) {
  DBUG_TRACE;

  free_old_result(); /* Delete all data from previous execution, if any */

  Protocol_local protocol_local(m_thd, this);
  m_thd->push_protocol(&protocol_local);
  m_thd->push_diagnostics_area(&m_diagnostics_area);

  Prepared_statement stmt(m_thd);
  bool rc = stmt.execute_server_runnable(m_thd, server_runnable);
  m_thd->send_statement_status();

  m_thd->pop_protocol();
  m_thd->pop_diagnostics_area();
  /*
    Protocol_local makes use of m_current_rset to keep
    track of the last result set, while adding result sets to the end.
    Reset it to point to the first result set instead.
  */
  m_current_rset = m_rsets;

  /*
    Reset rewritten (for password obfuscation etc.) query after
    internal call from NDB etc.  Without this, a rewritten query
    would get "stuck" in SHOW PROCESSLIST.
  */
  m_thd->reset_rewritten_query();
  m_thd->reset_query_for_display();

  return rc;
}

/**
  A helper method that is called only during execution.

  Although Ed_connection doesn't support multi-statements,
  a statement may generate many result sets. All subsequent
  result sets are appended to the end.

  @pre This is called only by Protocol_local.
*/

void Ed_connection::add_result_set(Ed_result_set *ed_result_set) {
  if (m_rsets) {
    m_current_rset->m_next_rset = ed_result_set;
    /* While appending, use m_current_rset as a pointer to the tail. */
    m_current_rset = ed_result_set;
  } else
    m_current_rset = m_rsets = ed_result_set;
}
