diff --git a/include/maxscale/pcre2.hh b/include/maxscale/pcre2.hh index f31d2b597..37f42e5d9 100644 --- a/include/maxscale/pcre2.hh +++ b/include/maxscale/pcre2.hh @@ -16,9 +16,23 @@ #include #include +#include + namespace maxscale { + +/** + * Overload that returns a string + * + * @param re Compiled pattern to use + * @param subject Subject string + * @param replace Replacement string + * + * @return The replaced string or the original string if no replacement was made + */ +std::string pcre2_substitute(pcre2_code* re, const std::string& subject, const std::string& replace); + /** * @class CloserTraits pcre2.hh * diff --git a/server/core/maxscale_pcre2.cc b/server/core/maxscale_pcre2.cc index 687b24fd2..67030942e 100644 --- a/server/core/maxscale_pcre2.cc +++ b/server/core/maxscale_pcre2.cc @@ -245,3 +245,26 @@ bool mxs_pcre2_check_match_exclude(pcre2_code* re_match, } return rval; } + +namespace maxscale +{ +std::string pcre2_substitute(pcre2_code* re, const std::string& subject, const std::string& replace) +{ + std::string rval = subject; + size_t size_tmp = rval.size(); + int rc; + + while ((rc = pcre2_substitute(re, (PCRE2_SPTR) subject.c_str(), subject.length(), + 0, PCRE2_SUBSTITUTE_GLOBAL, NULL, NULL, + (PCRE2_SPTR) replace.c_str(), replace.length(), + (PCRE2_UCHAR*) &rval[0], &size_tmp)) == PCRE2_ERROR_NOMEMORY) + { + rval.resize(rval.size() * 2); + size_tmp = rval.size(); + } + + rval.resize(size_tmp); + + return rval; +} +} diff --git a/server/modules/filter/binlogfilter/binlogfilter.cc b/server/modules/filter/binlogfilter/binlogfilter.cc index 9d9bdd25b..13ad718eb 100644 --- a/server/modules/filter/binlogfilter/binlogfilter.cc +++ b/server/modules/filter/binlogfilter/binlogfilter.cc @@ -36,7 +36,7 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE() { {"match", MXS_MODULE_PARAM_REGEX }, {"exclude", MXS_MODULE_PARAM_REGEX }, - {REWRITE_SRC, MXS_MODULE_PARAM_STRING }, + {REWRITE_SRC, MXS_MODULE_PARAM_REGEX }, {REWRITE_DEST, MXS_MODULE_PARAM_STRING }, {MXS_END_MODULE_PARAMS} } diff --git a/server/modules/filter/binlogfilter/binlogfilter.hh b/server/modules/filter/binlogfilter/binlogfilter.hh index 23fa9c616..2f1ed2feb 100644 --- a/server/modules/filter/binlogfilter/binlogfilter.hh +++ b/server/modules/filter/binlogfilter/binlogfilter.hh @@ -29,7 +29,7 @@ struct BinlogConfig , md_match(match ? pcre2_match_data_create_from_pattern(match, nullptr) : nullptr) , exclude(pParams->get_compiled_regex("exclude", 0, nullptr).release()) , md_exclude(exclude ? pcre2_match_data_create_from_pattern(exclude, nullptr) : nullptr) - , rewrite_src(pParams->get_string(REWRITE_SRC)) + , rewrite_src(pParams->get_compiled_regex(REWRITE_SRC, 0, nullptr).release()) , rewrite_dest(pParams->get_string(REWRITE_DEST)) { } @@ -38,7 +38,7 @@ struct BinlogConfig pcre2_match_data* md_match; pcre2_code* exclude; pcre2_match_data* md_exclude; - std::string rewrite_src; + pcre2_code* rewrite_src; std::string rewrite_dest; }; diff --git a/server/modules/filter/binlogfilter/binlogfiltersession.cc b/server/modules/filter/binlogfilter/binlogfiltersession.cc index 83d13131e..166ab5ccc 100644 --- a/server/modules/filter/binlogfilter/binlogfiltersession.cc +++ b/server/modules/filter/binlogfilter/binlogfiltersession.cc @@ -52,6 +52,7 @@ #include #include #include +#include #include "binlogfilter.hh" #include "binlogfiltersession.hh" @@ -138,13 +139,12 @@ int BinlogFilterSession::routeQuery(GWBUF* pPacket) m_state = BINLOG_MODE; MXS_INFO("Slave server %u is waiting for binlog events.", m_serverid); - if (!m_is_gtid - && m_filter.getConfig().rewrite_src.length() != m_filter.getConfig().rewrite_dest.length()) + if (!m_is_gtid) { gwbuf_free(pPacket); std::ostringstream ss; ss << "GTID replication is required when '" - << REWRITE_SRC << "' and '" << REWRITE_DEST << "' are of different length"; + << REWRITE_SRC << "' and '" << REWRITE_DEST << "' are used"; mxs::FilterSession::clientReply( modutil_create_mysql_err_msg(1, 0, ER_MASTER_FATAL_ERROR_READING_BINLOG, "HY000", ss.str().c_str())); @@ -849,30 +849,17 @@ void BinlogFilterSession::checkStatement(GWBUF** buffer, const REP_HEADER& hdr) m_skip = should_skip_query(config, sql, db); MXS_INFO("[%s] (%s) %s", m_skip ? "SKIP" : " ", db.c_str(), sql.c_str()); - if (!m_skip && !config.rewrite_src.empty()) + if (!m_skip && config.rewrite_src) { - bool replace = false; + auto new_db = mxs::pcre2_substitute(config.rewrite_src, db, config.rewrite_dest); + auto new_sql = mxs::pcre2_substitute(config.rewrite_src, sql, config.rewrite_dest); - if (db == config.rewrite_src) - { - replace = true; - db = config.rewrite_dest; - } - - size_t pos = 0; - - while ((pos = sql.find(config.rewrite_src, pos)) != std::string::npos) - { - replace = true; - sql.replace(pos, config.rewrite_src.length(), config.rewrite_dest); - pos += config.rewrite_dest.length(); - } - - if (replace) + if (db != new_db || sql != new_sql) { + db = new_db; + sql = new_sql; int len = sql.length() + db.length() - statement_len - db_name_len; - if (len > 0) { // Buffer is too short, extend it