summaryrefslogtreecommitdiff
path: root/sql/sql_cmd.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_cmd.h')
-rw-r--r--sql/sql_cmd.h207
1 files changed, 201 insertions, 6 deletions
diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h
index 2623b3703d3..985be776713 100644
--- a/sql/sql_cmd.h
+++ b/sql/sql_cmd.h
@@ -118,6 +118,7 @@ enum enum_sql_command {
SQLCOM_END
};
+struct TABLE_LIST;
class Storage_engine_name
{
@@ -144,6 +145,8 @@ public:
};
+class Prepared_statement;
+
/**
@class Sql_cmd - Representation of an SQL command.
@@ -180,10 +183,28 @@ public:
virtual enum_sql_command sql_command_code() const = 0;
/**
- Execute this SQL statement.
- @param thd the current thread.
- @retval false on success.
- @retval true on error
+ @brief Check whether the statement has been prepared
+ @returns true if this statement is prepared, false otherwise
+ */
+ bool is_prepared() const { return m_prepared; }
+
+ /**
+ @brief Prepare this SQL statement
+ @param thd global context the processed statement
+ @returns false if success, true if error
+ */
+ virtual bool prepare(THD *thd)
+ {
+ /* Default behavior for a statement is to have no preparation code. */
+ DBUG_ASSERT(!is_prepared());
+ set_prepared();
+ return false;
+ }
+
+ /**
+ @brief Execute this SQL statement
+ @param thd global context the processed statement
+ @returns false if success, true if error
*/
virtual bool execute(THD *thd) = 0;
@@ -192,8 +213,40 @@ public:
return NULL;
}
+ /**
+ @brief Set the owning prepared statement
+ */
+ void set_owner(Prepared_statement *stmt) { m_owner = stmt; }
+
+ /**
+ @breaf Get the owning prepared statement
+ */
+ Prepared_statement *get_owner() { return m_owner; }
+
+ /**
+ @brief Check whether this command is a DML statement
+ @return true if SQL command is a DML statement, false otherwise
+ */
+ virtual bool is_dml() const { return false; }
+
+ /**
+ @brief Unprepare prepared statement for the command
+ @param thd global context of the processed statement
+
+ @notes
+ Temporary function used to "unprepare" a prepared statement after
+ preparation, so that a subsequent execute statement will reprepare it.
+ This is done because UNIT::cleanup() will un-resolve all resolved QBs.
+ */
+ virtual void unprepare(THD *thd)
+ {
+ DBUG_ASSERT(is_prepared());
+ m_prepared = false;
+ }
+
protected:
- Sql_cmd() = default;
+ Sql_cmd() : m_prepared(false), m_owner(nullptr)
+ {}
virtual ~Sql_cmd()
{
@@ -203,10 +256,152 @@ protected:
simply destroyed instead.
Do not rely on the destructor for any cleanup.
*/
- DBUG_ASSERT(FALSE);
+ DBUG_ASSERT(false);
}
+
+ /**
+ @brief Set this statement as prepared
+ */
+ void set_prepared() { m_prepared = true; }
+
+ private:
+ /* True when statement has been prepared */
+ bool m_prepared;
+ /* Owning prepared statement, nullptr if not prepared */
+ Prepared_statement *m_owner;
+
};
+struct LEX;
+class select_result;
+class Prelocking_strategy;
+class DML_prelocking_strategy;
+class Protocol;
+
+/**
+ @class Sql_cmd_dml - derivative abstract class used for DML statements
+
+ This class is a class derived from Sql_cmd used when processing such
+ data manipulation commands as SELECT, INSERT, UPDATE, DELETE and others
+ that operate over some tables.
+ After the parser phase all these commands are supposed to be processed
+ by the same schema:
+ - precheck of the access rights is performed for the used tables
+ - the used tables are opened
+ - context analysis phase is performed for the statement
+ - the used tables are locked
+ - the statement is optimized and executed
+ - clean-up is performed for the statement.
+ This schema is reflected in the function Sql_cmd_dml::execute() that
+ uses Sql_cmd_dml::prepare is the statement has not been prepared yet.
+ Precheck of the access right, context analysis are specific for statements
+ of a certain type. That's why the methods implementing this operations are
+ declared as abstract in this class.
+
+ @note
+ Currently this class is used only for UPDATE and DELETE commands.
+*/
+class Sql_cmd_dml : public Sql_cmd
+{
+public:
+
+ /**
+ @brief Check whether the statement changes the contents of used tables
+ @return true if this is data change statement, false otherwise
+ */
+ virtual bool is_data_change_stmt() const { return true; }
+
+ /**
+ @brief Perform context analysis of the statement
+ @param thd global context the processed statement
+ @returns false on success, true on error
+ */
+ virtual bool prepare(THD *thd);
+
+ /**
+ Execute the processed statement once
+ @param thd global context the processed statement
+ @returns false on success, true on error
+ */
+ virtual bool execute(THD *thd);
+
+ virtual bool is_dml() const { return true; }
+
+ select_result *get_result() { return result; }
+
+protected:
+ Sql_cmd_dml()
+ : Sql_cmd(), lex(nullptr), result(nullptr),
+ m_empty_query(false)
+ {}
+
+ /**
+ @brief Check whether query is guaranteed to return no data
+ @return true if query is guaranteed to return no data, false otherwise
+
+ @todo Also check this for the following cases:
+ - Empty source for multi-table UPDATE and DELETE.
+ - Check empty query expression for INSERT
+ */
+ bool is_empty_query() const
+ {
+ DBUG_ASSERT(is_prepared());
+ return m_empty_query;
+ }
+
+ /**
+ @brief Set statement as returning no data
+ */
+ void set_empty_query() { m_empty_query = true; }
+
+ /**
+ @brief Perform precheck of table privileges for the specific command
+ @param thd global context the processed statement
+ @returns false if success, true if false
+
+ @details
+ Check that user has some relevant privileges for all tables involved in
+ the statement, e.g. SELECT privileges for tables selected from, INSERT
+ privileges for tables inserted into, etc. This function will also populate
+ TABLE_LIST::grant with all privileges the user has for each table, which
+ is later used during checking of column privileges.
+ Note that at preparation time, views are not expanded yet. Privilege
+ checking is thus rudimentary and must be complemented with later calls to
+ SELECT_LEX::check_view_privileges().
+ The reason to call this function at such an early stage is to be able to
+ quickly reject statements for which the user obviously has insufficient
+ privileges.
+ */
+ virtual bool precheck(THD *thd) = 0;
+
+ /**
+ @brief Perform the command-specific actions of the context analysis
+ @param thd global context the processed statement
+ @returns false if success, true if error
+
+ @note
+ This function is called from prepare()
+ */
+ virtual bool prepare_inner(THD *thd) = 0;
+
+ /**
+ @brief Perform the command-specific actions of optimization and excution
+ @param thd global context the processed statement
+ @returns false on success, true on error
+ */
+ virtual bool execute_inner(THD *thd);
+
+ virtual DML_prelocking_strategy *get_dml_prelocking_strategy() = 0;
+
+ uint table_count;
+
+ protected:
+ LEX *lex; /**< Pointer to LEX for this statement */
+ select_result *result; /**< Pointer to object for handling of the result */
+ bool m_empty_query; /**< True if query will produce no rows */
+};
+
+
class Sql_cmd_show_slave_status: public Sql_cmd
{
protected: