146 lines
4.3 KiB
C++

#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 <vector>
#include <string>
/**
@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<int> m_slots;
std::vector<int>::iterator m_slots_iter;
/// All literals in the pattern, in order of appearance in parse tree.
std::vector<std::string> m_pattern_literals;
std::vector<std::string>::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