diff options
Diffstat (limited to 'sql/sql_cmd.h')
-rw-r--r-- | sql/sql_cmd.h | 207 |
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: |