 c447e5cf15
			
		
	
	c447e5cf15
	
	
	
		
			
			See script directory for method. The script to run in the top level MaxScale directory is called maxscale-uncrustify.sh, which uses another script, list-src, from the same directory (so you need to set your PATH). The uncrustify version was 0.66.
		
			
				
	
	
		
			401 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			401 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2018 MariaDB Corporation Ab
 | |
|  *
 | |
|  * Use of this software is governed by the Business Source License included
 | |
|  * in the LICENSE.TXT file and at www.mariadb.com/bsl11.
 | |
|  *
 | |
|  * Change Date: 2022-01-01
 | |
|  *
 | |
|  * On the date above, in accordance with the Business Source License, use
 | |
|  * of this software will be governed by version 2 or later of the General
 | |
|  * Public License.
 | |
|  */
 | |
| #pragma once
 | |
| 
 | |
| #include <maxscale/ccdefs.hh>
 | |
| #include <string>
 | |
| #include <memory>
 | |
| #include <unordered_map>
 | |
| #include <unordered_set>
 | |
| #include <maxscale/hint.h>
 | |
| #include <maxscale/router.h>
 | |
| #include <maxscale/session.h>
 | |
| 
 | |
| namespace maxscale
 | |
| {
 | |
| 
 | |
| class QueryClassifier
 | |
| {
 | |
|     QueryClassifier(const QueryClassifier&) = delete;
 | |
|     QueryClassifier& operator=(const QueryClassifier&) = delete;
 | |
| 
 | |
| public:
 | |
|     class RouteInfo
 | |
|     {
 | |
|     public:
 | |
|         RouteInfo();
 | |
|         RouteInfo(uint32_t target,
 | |
|                   uint8_t  command,
 | |
|                   uint32_t type_mask,
 | |
|                   uint32_t stmt_id);
 | |
| 
 | |
|         void reset();
 | |
| 
 | |
|         uint32_t target() const
 | |
|         {
 | |
|             return m_target;
 | |
|         }
 | |
| 
 | |
|         uint8_t command() const
 | |
|         {
 | |
|             return m_command;
 | |
|         }
 | |
| 
 | |
|         uint32_t type_mask() const
 | |
|         {
 | |
|             return m_type_mask;
 | |
|         }
 | |
| 
 | |
|         uint32_t stmt_id() const
 | |
|         {
 | |
|             return m_stmt_id;
 | |
|         }
 | |
| 
 | |
|         void set_command(uint8_t c)
 | |
|         {
 | |
|             m_command = c;
 | |
|         }
 | |
| 
 | |
|         void set_target(uint32_t t)
 | |
|         {
 | |
|             m_target = t;
 | |
|         }
 | |
| 
 | |
|         void or_target(uint32_t t)
 | |
|         {
 | |
|             m_target |= t;
 | |
|         }
 | |
| 
 | |
|         void set_type_mask(uint32_t t)
 | |
|         {
 | |
|             m_type_mask = t;
 | |
|         }
 | |
| 
 | |
|         void or_type_mask(uint32_t t)
 | |
|         {
 | |
|             m_type_mask |= t;
 | |
|         }
 | |
| 
 | |
|         void set_stmt_id(uint32_t stmt_id)
 | |
|         {
 | |
|             m_stmt_id = stmt_id;
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         uint32_t m_target;      /**< Route target type, TARGET_UNDEFINED for unknown */
 | |
|         uint8_t  m_command;     /**< The command byte, 0xff for unknown commands */
 | |
|         uint32_t m_type_mask;   /**< The query type, QUERY_TYPE_UNKNOWN for unknown types*/
 | |
|         uint32_t m_stmt_id;     /**< Prepared statement ID, 0 for unknown */
 | |
|     };
 | |
| 
 | |
|     class Handler
 | |
|     {
 | |
|     public:
 | |
|         virtual bool lock_to_master() = 0;
 | |
|         virtual bool is_locked_to_master() const = 0;
 | |
| 
 | |
|         virtual bool supports_hint(HINT_TYPE hint_type) const = 0;
 | |
|     };
 | |
| 
 | |
|     typedef std::unordered_set<std::string> TableSet;
 | |
| 
 | |
|     // NOTE: For the time being these must be exactly like the ones in readwritesplit.hh
 | |
|     enum
 | |
|     {
 | |
|         TARGET_UNDEFINED    = 0x00,
 | |
|         TARGET_MASTER       = 0x01,
 | |
|         TARGET_SLAVE        = 0x02,
 | |
|         TARGET_NAMED_SERVER = 0x04,
 | |
|         TARGET_ALL          = 0x08,
 | |
|         TARGET_RLAG_MAX     = 0x10,
 | |
|         TARGET_LAST_USED    = 0x20
 | |
|     };
 | |
| 
 | |
|     static bool target_is_master(uint32_t t)
 | |
|     {
 | |
|         return t & TARGET_MASTER;
 | |
|     }
 | |
| 
 | |
|     static bool target_is_slave(uint32_t t)
 | |
|     {
 | |
|         return t & TARGET_SLAVE;
 | |
|     }
 | |
| 
 | |
|     static bool target_is_named_server(uint32_t t)
 | |
|     {
 | |
|         return t & TARGET_NAMED_SERVER;
 | |
|     }
 | |
| 
 | |
|     static bool target_is_all(uint32_t t)
 | |
|     {
 | |
|         return t & TARGET_ALL;
 | |
|     }
 | |
| 
 | |
|     static bool target_is_rlag_max(uint32_t t)
 | |
|     {
 | |
|         return t & TARGET_RLAG_MAX;
 | |
|     }
 | |
| 
 | |
|     static bool target_is_last_used(uint32_t t)
 | |
|     {
 | |
|         return t & TARGET_LAST_USED;
 | |
|     }
 | |
| 
 | |
|     enum current_target_t
 | |
|     {
 | |
|         CURRENT_TARGET_UNDEFINED,   /**< Current target has not been set. */
 | |
|         CURRENT_TARGET_MASTER,      /**< Current target is master */
 | |
|         CURRENT_TARGET_SLAVE        /**< Current target is a slave */
 | |
|     };
 | |
| 
 | |
|     /** States of a LOAD DATA LOCAL INFILE */
 | |
|     enum load_data_state_t
 | |
|     {
 | |
|         LOAD_DATA_INACTIVE,         /**< Not active */
 | |
|         LOAD_DATA_ACTIVE,           /**< Load is active */
 | |
|         LOAD_DATA_END               /**< Current query contains an empty packet that ends the load */
 | |
|     };
 | |
| 
 | |
|     QueryClassifier(Handler* pHandler,
 | |
|                     MXS_SESSION* pSession,
 | |
|                     mxs_target_t use_sql_variables_in);
 | |
| 
 | |
|     /**
 | |
|      * @brief Return the current route info. A call to update_route_info()
 | |
|      *        will change the values.
 | |
|      *
 | |
|      * @return The current RouteInfo.
 | |
|      */
 | |
|     const RouteInfo& current_route_info()
 | |
|     {
 | |
|         return m_route_info;
 | |
|     }
 | |
| 
 | |
|     void master_replaced()
 | |
|     {
 | |
|         // As the master has changed, we can reset the temporary table information
 | |
|         set_have_tmp_tables(false);
 | |
|         clear_tmp_tables();
 | |
|     }
 | |
| 
 | |
|     bool large_query() const
 | |
|     {
 | |
|         return m_large_query;
 | |
|     }
 | |
| 
 | |
|     void set_large_query(bool large_query)
 | |
|     {
 | |
|         m_large_query = large_query;
 | |
|     }
 | |
| 
 | |
|     load_data_state_t load_data_state() const
 | |
|     {
 | |
|         return m_load_data_state;
 | |
|     }
 | |
| 
 | |
|     void set_load_data_state(load_data_state_t state)
 | |
|     {
 | |
|         if (state == LOAD_DATA_ACTIVE)
 | |
|         {
 | |
|             mxb_assert(m_load_data_state == LOAD_DATA_INACTIVE);
 | |
|             reset_load_data_sent();
 | |
|         }
 | |
| 
 | |
|         m_load_data_state = state;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Check if current transaction is still a read-only transaction
 | |
|      *
 | |
|      * @return True if no statements have been executed that modify data
 | |
|      */
 | |
|     bool is_trx_still_read_only() const
 | |
|     {
 | |
|         return m_trx_is_read_only;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Check if current transaction is still a read-only transaction
 | |
|      *
 | |
|      * @return True if no statements have been executed that modify data
 | |
|      */
 | |
|     bool is_trx_starting() const
 | |
|     {
 | |
|         return qc_query_is_type(m_route_info.type_mask(), QUERY_TYPE_BEGIN_TRX);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Store and process a prepared statement
 | |
|      *
 | |
|      * @param buffer Buffer containing either a text or a binary protocol
 | |
|      *               prepared statement
 | |
|      * @param id     The unique ID for this statement
 | |
|      */
 | |
|     void ps_store(GWBUF* buffer, uint32_t id);
 | |
| 
 | |
|     /**
 | |
|      * @brief Remove a prepared statement
 | |
|      *
 | |
|      * @param buffer Buffer containing a DEALLOCATE statement or a binary protocol command
 | |
|      */
 | |
|     void ps_erase(GWBUF* buffer);
 | |
| 
 | |
|     /**
 | |
|      * @brief Store a mapping from an external id to the corresponding internal id
 | |
|      *
 | |
|      * @param external_id  The external id as seen by the client.
 | |
|      * @param internal_id  The corresponding internal id.
 | |
|      */
 | |
|     void ps_id_internal_put(uint32_t external_id, uint32_t internal_id);
 | |
| 
 | |
|     /**
 | |
|      * @brief Update the current RouteInfo.
 | |
|      *
 | |
|      * @param current_target  What the current target is.
 | |
|      * @param pBuffer         A request buffer.
 | |
|      *
 | |
|      * @return A copy of the current route info.
 | |
|      */
 | |
|     RouteInfo update_route_info(QueryClassifier::current_target_t current_target, GWBUF* pBuffer);
 | |
| 
 | |
| private:
 | |
|     bool multi_statements_allowed() const
 | |
|     {
 | |
|         return m_multi_statements_allowed;
 | |
|     }
 | |
| 
 | |
|     uint64_t load_data_sent() const
 | |
|     {
 | |
|         return m_load_data_sent;
 | |
|     }
 | |
| 
 | |
|     void append_load_data_sent(GWBUF* pBuffer)
 | |
|     {
 | |
|         m_load_data_sent += gwbuf_length(pBuffer);
 | |
|     }
 | |
| 
 | |
|     void reset_load_data_sent()
 | |
|     {
 | |
|         m_load_data_sent = 0;
 | |
|     }
 | |
| 
 | |
|     bool have_tmp_tables() const
 | |
|     {
 | |
|         return m_have_tmp_tables;
 | |
|     }
 | |
| 
 | |
|     void set_have_tmp_tables(bool have_tmp_tables)
 | |
|     {
 | |
|         m_have_tmp_tables = have_tmp_tables;
 | |
|     }
 | |
| 
 | |
|     void add_tmp_table(const std::string& table)
 | |
|     {
 | |
|         m_tmp_tables.insert(table);
 | |
|     }
 | |
| 
 | |
|     void remove_tmp_table(const std::string& table)
 | |
|     {
 | |
|         m_tmp_tables.erase(table);
 | |
|     }
 | |
| 
 | |
|     void clear_tmp_tables()
 | |
|     {
 | |
|         m_tmp_tables.clear();
 | |
|     }
 | |
| 
 | |
|     bool is_tmp_table(const std::string& table)
 | |
|     {
 | |
|         return m_tmp_tables.find(table) != m_tmp_tables.end();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Get the type of a stored prepared statement
 | |
|      *
 | |
|      * @param id The unique identifier for the prepared statement or the plaintext
 | |
|      *           name of the prepared statement
 | |
|      *
 | |
|      * @return The type of the prepared statement
 | |
|      */
 | |
|     uint32_t ps_get_type(uint32_t id) const;
 | |
|     uint32_t ps_get_type(std::string id) const;
 | |
| 
 | |
|     /**
 | |
|      * @brief Get the internal ID for the given binary prepared statement
 | |
|      *
 | |
|      * @param buffer Buffer containing a binary protocol statement other than COM_STMT_PREPARE
 | |
|      *
 | |
|      * @return The internal ID of the prepared statement that the buffer contents refer to
 | |
|      */
 | |
|     uint32_t ps_id_internal_get(GWBUF* pBuffer);
 | |
| 
 | |
|     /**
 | |
|      * Check if the query type is that of a read-only query
 | |
|      *
 | |
|      * @param qtype Query type mask
 | |
|      *
 | |
|      * @return True if the query type is that of a read-only query
 | |
|      */
 | |
|     bool query_type_is_read_only(uint32_t qtype) const;
 | |
| 
 | |
|     uint32_t get_route_target(uint8_t command, uint32_t qtype, HINT* pHints);
 | |
| 
 | |
|     MXS_SESSION* session() const
 | |
|     {
 | |
|         return m_pSession;
 | |
|     }
 | |
| 
 | |
|     void log_transaction_status(GWBUF* querybuf, uint32_t qtype);
 | |
| 
 | |
|     static uint32_t determine_query_type(GWBUF* querybuf, int command);
 | |
| 
 | |
|     void check_create_tmp_table(GWBUF* querybuf, uint32_t type);
 | |
| 
 | |
|     bool is_read_tmp_table(GWBUF* querybuf, uint32_t qtype);
 | |
| 
 | |
|     void check_drop_tmp_table(GWBUF* querybuf);
 | |
| 
 | |
|     bool check_for_multi_stmt(GWBUF* buf, uint8_t packet_type);
 | |
| 
 | |
|     current_target_t handle_multi_temp_and_load(QueryClassifier::current_target_t current_target,
 | |
|                                                 GWBUF* querybuf,
 | |
|                                                 uint8_t packet_type,
 | |
|                                                 uint32_t* qtype);
 | |
| 
 | |
| private:
 | |
|     class PSManager;
 | |
|     typedef std::shared_ptr<PSManager> SPSManager;
 | |
| 
 | |
|     typedef std::unordered_map<uint32_t, uint32_t> HandleMap;
 | |
| 
 | |
|     static bool find_table(QueryClassifier& qc, const std::string& table);
 | |
|     static bool delete_table(QueryClassifier& qc, const std::string& table);
 | |
| 
 | |
| 
 | |
| private:
 | |
|     Handler*          m_pHandler;
 | |
|     MXS_SESSION*      m_pSession;
 | |
|     mxs_target_t      m_use_sql_variables_in;
 | |
|     load_data_state_t m_load_data_state;            /**< The LOAD DATA state */
 | |
|     uint64_t          m_load_data_sent;             /**< How much data has been sent */
 | |
|     bool              m_have_tmp_tables;
 | |
|     TableSet          m_tmp_tables;                 /**< Set of temporary tables */
 | |
|     bool              m_large_query;                /**< Set to true when processing payloads >= 2^24 bytes */
 | |
|     bool              m_multi_statements_allowed;   /**< Are multi-statements allowed */
 | |
|     SPSManager        m_sPs_manager;
 | |
|     HandleMap         m_ps_handles;                 /** External ID to internal ID */
 | |
|     RouteInfo         m_route_info;
 | |
|     bool              m_trx_is_read_only;
 | |
| };
 | |
| }
 |