/** * Copyright (c) 2020, Timothy Stack * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Timothy Stack nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "sql_util.hh" #include "column_namer.hh" #include "log_search_table.hh" const static std::string LOG_MSG_INSTANCE = "log_msg_instance"; static auto instance_name = intern_string::lookup("log_msg_instance"); static auto instance_meta = logline_value_meta( instance_name, value_kind_t::VALUE_INTEGER, 0); log_search_table::log_search_table(pcrepp pattern, intern_string_t table_name) : log_vtab_impl(table_name), lst_regex(std::move(pattern)), lst_instance(-1) { this->vi_supports_indexes = false; this->get_columns_int(this->lst_cols); } void log_search_table::get_columns_int(std::vector &cols) { column_namer cn; cols.emplace_back(LOG_MSG_INSTANCE, SQLITE_INTEGER); for (int lpc = 0; lpc < this->lst_regex.get_capture_count(); lpc++) { std::string collator; std::string colname; int sqlite_type = SQLITE3_TEXT; colname = cn.add_column(this->lst_regex.name_for_capture(lpc)); if (this->lst_regex.captures().size() == (size_t) this->lst_regex.get_capture_count()) { auto iter = this->lst_regex.cap_begin() + lpc; auto cap_re = this->lst_regex.get_pattern() .substr(iter->c_begin, iter->length()); sqlite_type = guess_type_from_pcre(cap_re, collator); switch (sqlite_type) { case SQLITE_FLOAT: this->lst_column_metas.emplace_back( intern_string::lookup(colname), value_kind_t::VALUE_FLOAT, cols.size()); break; case SQLITE_INTEGER: this->lst_column_metas.emplace_back( intern_string::lookup(colname), value_kind_t::VALUE_INTEGER, cols.size()); break; default: this->lst_column_metas.emplace_back( intern_string::lookup(colname), value_kind_t::VALUE_TEXT, cols.size()); break; } } cols.emplace_back(colname, sqlite_type, collator); } } void log_search_table::get_foreign_keys(std::vector &keys_inout) const { log_vtab_impl::get_foreign_keys(keys_inout); keys_inout.emplace_back("log_msg_instance"); } bool log_search_table::next(log_cursor &lc, logfile_sub_source &lss) { if (lc.lc_curr_line == -1_vl) { this->lst_instance = -1; } lc.lc_curr_line = lc.lc_curr_line + 1_vl; lc.lc_sub_index = 0; if (lc.lc_curr_line == (int) lss.text_line_count()) { return true; } auto cl = lss.at(lc.lc_curr_line); auto lf = lss.find(cl); auto lf_iter = lf->begin() + cl; if (!lf_iter->is_message()) { return false; } string_attrs_t sa; std::vector line_values; lf->read_full_message(lf_iter, this->lst_current_line); lf->get_format()->annotate(cl, this->lst_current_line, sa, line_values, false); pcre_input pi(this->lst_current_line.get_data(), 0, this->lst_current_line.length()); if (!this->lst_regex.match(this->lst_match_context, pi)) { return false; } this->lst_instance += 1; return true; } void log_search_table::extract(std::shared_ptr lf, uint64_t line_number, shared_buffer_ref &line, std::vector &values) { values.emplace_back(instance_meta, this->lst_instance); for (int lpc = 0; lpc < this->lst_regex.get_capture_count(); lpc++) { auto cap = this->lst_match_context[lpc]; values.emplace_back(this->lst_column_metas[lpc], line, line_range{cap->c_begin, cap->c_end}); } }