#ifndef QUERY_BUILDER_INCLUDED #define QUERY_BUILDER_INCLUDED /* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. 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 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, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #include "my_config.h" #include #include /** @file query_builder.h */ /** Class that builds the rewritten query by appending literals in the order they appear in the parse tree. */ class Query_builder : public services::Literal_visitor { public: Query_builder(const Pattern *pattern, const Replacement *replacement) : m_previous_slot(0), m_replacement(replacement->query_string), m_slots(replacement->slots()), m_slots_iter(m_slots.begin()), m_pattern_literals(pattern->literals), m_pattern_literals_iter(m_pattern_literals.begin()), m_matches_so_far(true) {} /** Implementation of the visit() function that bridges to add_next_literal(). @param item The current literal. */ bool visit(MYSQL_ITEM item) { return add_next_literal(item); } /** To be called after visit() has been called for all literals in the parse tree that this Query_builder was visiting. This function finishes the string to yield a complete query. */ const std::string &get_built_query() { // Append trailing segment of replacement. m_built_query+= m_replacement.substr(m_previous_slot); return m_built_query; } /** Status of the matching of literals that are not parameter markers. @retval true The parse tree matches the pattern and it is safe to continue adding literals. @retval false Some literal has been found to differ between parse tree and pattern. Execution must end immediately. */ bool matches() const { return m_matches_so_far; } private: /** The index of the character in 'm_replacement' after the last slot that we filled. */ int m_previous_slot; /// Query we copy from (replacement string.) std::string m_replacement; /// The slots in the replacement string. std::vector m_slots; std::vector::iterator m_slots_iter; /// All literals in the pattern, in order of appearance in parse tree. std::vector m_pattern_literals; std::vector::iterator m_pattern_literals_iter; /// The query under construction. std::string m_built_query; /** Whether the literals in the parse tree match those of the pattern so far. */ bool m_matches_so_far; /** Adds a literal, assumed to be the next in the parse tree, from the query's parse tree to this Query_builder. @param item Assumed to be a literal. @retval true The builder is finished. Either it has been detected that the current literal does not match the pattern, or no more literals are needed to build the query. */ bool add_next_literal(MYSQL_ITEM item); }; bool Query_builder::add_next_literal(MYSQL_ITEM item) { std::string query_literal= services::print_item(item); std::string pattern_literal= *m_pattern_literals_iter; if (pattern_literal.compare("?") == 0) { // Literal corresponds to a parameter marker in the pattern. if (m_slots_iter != m_slots.end()) // There are more slots to fill { // The part of the replacement leading up to its corresponding slot. m_built_query+= m_replacement.substr(m_previous_slot, *m_slots_iter - m_previous_slot); m_built_query+= query_literal; m_previous_slot= *m_slots_iter++ + sizeof('?'); } } else if (pattern_literal.compare(query_literal) != 0) { // The literal does not match the pattern nor a parameter marker, we // fail to rewrite. m_matches_so_far= false; return true; } return ++m_pattern_literals_iter == m_pattern_literals.end(); } #endif // QUERY_BUILDER_INCLUDED