[perf] fixing slow queries

pull/824/merge
Timothy Stack 2 years ago
parent d5b06fca5f
commit 72c1c48e23

20
NEWS

@ -29,6 +29,9 @@ lnav v0.10.2:
each log message. If the expressions evaluates to true, an each log message. If the expressions evaluates to true, an
event is published to the "lnav_events" table that includes the event is published to the "lnav_events" table that includes the
message contents. message contents.
* Added the "regexp_capture_into_json()" table-valued-function that
is similar to "regexp_capture()", but returns a single row with a
JSON value for each match instead of a row for each capture.
* Added a "top_meta" column to the lnav_views table that contains * Added a "top_meta" column to the lnav_views table that contains
metadata related to the top line in the view. metadata related to the top line in the view.
* Added a "log_opid" hidden column to all log tables that contains * Added a "log_opid" hidden column to all log tables that contains
@ -36,6 +39,9 @@ lnav v0.10.2:
* Moved the "log_format" column from the all_logs table to a hidden * Moved the "log_format" column from the all_logs table to a hidden
column on all tables. column on all tables.
* Add format for UniFi gateway. * Add format for UniFi gateway.
* Added a "glob" property to search tables defined in log formats
to constrain searches to log messages from files that have a
matching log_path value.
Breaking Changes: Breaking Changes:
* Added a 'language' column to the lnav_view_filters table that * Added a 'language' column to the lnav_view_filters table that
@ -46,11 +52,25 @@ lnav v0.10.2:
* Removed the summary overlay at the bottom of the log view that * Removed the summary overlay at the bottom of the log view that
displayed things like "Error rate" and the time span. It doesn't displayed things like "Error rate" and the time span. It doesn't
seem like anyone used it. seem like anyone used it.
* Removed the "log_msg_instance" column from the logline and search
tables since it causes problems with performance.
* Search tables now search for multiple matches within a message
instead of stopping at the first hit. Each additional match is
returned as a separate row. A "match_index" column has been
added to capture the index of the match within the message.
The table regex is also compiled with the "multiline" flag enabled
so the meaning of the '^' and '$' metacharacters are changed
to match the start/end of a line instead of the start/end of
the entire message string.
* Search tables defined in formats are now constrained to only
match log messages that are in that log format instead of all
log messages.
Fixes: Fixes:
* Toggling enabled/disabled filters when there is a SQL expression * Toggling enabled/disabled filters when there is a SQL expression
no longer causes a crash. no longer causes a crash.
* Fix a crash related to long lines that are word wrapped. * Fix a crash related to long lines that are word wrapped.
*
lnav v0.10.1: lnav v0.10.1:
Features: Features:

@ -441,6 +441,11 @@
"title": "/<format_name>/search-table/<table_name>/pattern", "title": "/<format_name>/search-table/<table_name>/pattern",
"description": "The regular expression for this search table.", "description": "The regular expression for this search table.",
"type": "string" "type": "string"
},
"glob": {
"title": "/<format_name>/search-table/<table_name>/glob",
"description": "Glob pattern used to constrain hits to messages that match the given pattern.",
"type": "string"
} }
}, },
"additionalProperties": false "additionalProperties": false

@ -132,6 +132,8 @@ set(FORMAT_FILES
formats/openstack_log.json formats/openstack_log.json
formats/page_log.json formats/page_log.json
formats/papertrail_log.json formats/papertrail_log.json
formats/pcap_log.json
formats/procstate_log.json
formats/snaplogic_log.json formats/snaplogic_log.json
formats/sssd_log.json formats/sssd_log.json
formats/strace_log.json formats/strace_log.json

@ -102,12 +102,5 @@ all_logs_vtab::extract(logfile* lf,
bool bool
all_logs_vtab::next(log_cursor& lc, logfile_sub_source& lss) all_logs_vtab::next(log_cursor& lc, logfile_sub_source& lss)
{ {
lc.lc_curr_line = lc.lc_curr_line + 1_vl; return true;
lc.lc_sub_index = 0;
if (lc.is_eof()) {
return true;
}
return this->is_valid(lc, lss);
} }

@ -35,17 +35,28 @@
#include "base/itertools.hh" #include "base/itertools.hh"
#include "base/lnav_log.hh" #include "base/lnav_log.hh"
#include "base/string_util.hh"
#include "config.h" #include "config.h"
#include "sql_util.hh" #include "sql_util.hh"
const char* column_namer::BUILTIN_COL = "col";
column_namer::column_namer(language lang) : cn_language(lang) {}
bool bool
column_namer::existing_name(const std::string& in_name) const column_namer::existing_name(const string_fragment& in_name) const
{ {
if (std::binary_search( switch (this->cn_language) {
std::begin(sql_keywords), std::end(sql_keywords), toupper(in_name))) case language::SQL: {
{ auto upped = toupper(in_name.to_string());
return true;
if (std::binary_search(
std::begin(sql_keywords), std::end(sql_keywords), upped)) {
return true;
}
break;
}
case language::JSON:
break;
} }
if (this->cn_builtin_names | lnav::itertools::find(in_name)) { if (this->cn_builtin_names | lnav::itertools::find(in_name)) {
@ -59,35 +70,44 @@ column_namer::existing_name(const std::string& in_name) const
return false; return false;
} }
std::string string_fragment
column_namer::add_column(const std::string& in_name) column_namer::add_column(const string_fragment& in_name)
{ {
auto base_name = in_name; string_fragment base_name;
std::string retval; string_fragment retval;
fmt::memory_buffer buf;
int num = 0; int num = 0;
if (in_name.empty()) { if (in_name.empty()) {
base_name = "col"; base_name = string_fragment{BUILTIN_COL};
} else {
base_name = in_name;
} }
retval = base_name; retval = base_name;
auto counter_iter = this->cn_name_counters.find(retval); auto counter_iter = this->cn_name_counters.find(retval);
if (counter_iter != this->cn_name_counters.end()) { if (counter_iter != this->cn_name_counters.end()) {
num = ++counter_iter->second; num = ++counter_iter->second;
retval = fmt::format(FMT_STRING("{}_{}"), base_name, num); fmt::format_to(buf, FMT_STRING("{}_{}"), base_name, num);
retval = string_fragment{buf.data(), 0, (int) buf.size()};
} }
while (this->existing_name(retval)) { while (this->existing_name(retval)) {
if (num == 0) { if (num == 0) {
this->cn_name_counters[retval] = num; this->cn_name_counters[base_name] = num;
} }
log_debug("column name already exists: %s", retval.c_str()); log_debug(
retval = fmt::format(FMT_STRING("{}_{}"), base_name, num); "column name already exists: %.*s", retval.length(), retval.data());
fmt::format_to(buf, FMT_STRING("{}_{}"), base_name, num);
retval = string_fragment{buf.data(), 0, (int) buf.size()};
num += 1; num += 1;
} }
auto* mem = this->cn_alloc.allocate(retval.length() + 1);
memcpy(mem, retval.data(), retval.length());
mem[retval.length()] = '\0';
retval = string_fragment{mem, 0, retval.length()};
this->cn_names.emplace_back(retval); this->cn_names.emplace_back(retval);
return retval; return retval;

@ -36,15 +36,35 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "ArenaAlloc/arenaalloc.h"
#include "base/intern_string.hh"
class column_namer { class column_namer {
public: public:
bool existing_name(const std::string& in_name) const; enum class language {
SQL,
JSON,
};
column_namer(language lang);
bool existing_name(const string_fragment& in_name) const;
string_fragment add_column(const string_fragment& in_name);
std::string add_column(const std::string& in_name); static const char* BUILTIN_COL;
std::vector<std::string> cn_builtin_names{"col"}; ArenaAlloc::Alloc<char> cn_alloc;
std::vector<std::string> cn_names{}; language cn_language;
std::unordered_map<std::string, int> cn_name_counters{}; std::vector<string_fragment> cn_builtin_names{string_fragment(BUILTIN_COL)};
std::vector<string_fragment> cn_names;
std::unordered_map<
string_fragment,
size_t,
frag_hasher,
std::equal_to<string_fragment>,
ArenaAlloc::Alloc<std::pair<const string_fragment, size_t>>>
cn_name_counters;
}; };
#endif #endif

@ -239,7 +239,8 @@ field_overlay_source::build_field_lines(const listview_curses& lv)
= this->fos_log_helper.ldh_parser->get_element_string( = this->fos_log_helper.ldh_parser->get_element_string(
iter->e_sub_elements->front()); iter->e_sub_elements->front());
colname = this->fos_log_helper.ldh_namer->add_column(colname); colname
= this->fos_log_helper.ldh_namer->add_column(colname).to_string();
this->fos_unknown_key_size this->fos_unknown_key_size
= std::max(this->fos_unknown_key_size, (int) colname.length()); = std::max(this->fos_unknown_key_size, (int) colname.length());
} }
@ -410,14 +411,14 @@ field_overlay_source::build_field_lines(const listview_curses& lv)
for (size_t lpc = 0; lpc < this->fos_log_helper.ldh_parser->dp_pairs.size(); for (size_t lpc = 0; lpc < this->fos_log_helper.ldh_parser->dp_pairs.size();
lpc++, ++iter) lpc++, ++iter)
{ {
auto& name = this->fos_log_helper.ldh_namer->cn_names[lpc]; auto name = this->fos_log_helper.ldh_namer->cn_names[lpc];
auto val = this->fos_log_helper.ldh_parser->get_element_string( auto val = this->fos_log_helper.ldh_parser->get_element_string(
iter->e_sub_elements->back()); iter->e_sub_elements->back());
attr_line_t al(fmt::format(FMT_STRING(" {} = {}"), name, val)); attr_line_t al(fmt::format(FMT_STRING(" {} = {}"), name, val));
al.with_attr( al.with_attr(
string_attr(line_range(3, 3 + name.length()), string_attr(line_range(3, 3 + name.length()),
VC_STYLE.value(vc.attrs_for_ident(name)))); VC_STYLE.value(vc.attrs_for_ident(name.to_string()))));
this->fos_lines.emplace_back(al); this->fos_lines.emplace_back(al);
this->add_key_line_attrs( this->add_key_line_attrs(

@ -23,6 +23,7 @@ FORMAT_FILES = \
$(srcdir)/%reldir%/page_log.json \ $(srcdir)/%reldir%/page_log.json \
$(srcdir)/%reldir%/papertrail_log.json \ $(srcdir)/%reldir%/papertrail_log.json \
$(srcdir)/%reldir%/pcap_log.json \ $(srcdir)/%reldir%/pcap_log.json \
$(srcdir)/%reldir%/procstate_log.json \
$(srcdir)/%reldir%/snaplogic_log.json \ $(srcdir)/%reldir%/snaplogic_log.json \
$(srcdir)/%reldir%/sssd_log.json \ $(srcdir)/%reldir%/sssd_log.json \
$(srcdir)/%reldir%/strace_log.json \ $(srcdir)/%reldir%/strace_log.json \

@ -0,0 +1,22 @@
{
"$schema": "https://lnav.org/schemas/format-v1.schema.json",
"procstate_log": {
"title": "Process State",
"description": "Periodic dumps of process state",
"regex": {
"std": {
"pattern": "========== Start of system state dump at (?<timestamp>.*) =========="
}
},
"sample": [
{
"line": "========== Start of system state dump at Thu Jun 2 00:01:01 UTC 2022 =========="
}
],
"search-table": {
"procstate_procs": {
"pattern": "^(?<user>\\S+)\\s+(?<pid>\\d+)\\s+(?<cpu_pct>\\d+\\.\\d+)\\s+(?<mem_pct>\\d+\\.\\d+)\\s+(?<vsz>\\d+)\\s+(?<rss>\\d+)\\s(?<tty>\\S+)\\s+(?<stat>\\S+)\\s+(?<start_time>\\S+)\\s+(?<cpu_time>\\S+)\\s+(?<cmd>(?<cmd_name>[^ \\n]+)(?: (?<cmd_args>[^\\n]+))?)$"
}
}
}
}

@ -93,6 +93,12 @@
"identifier": true "identifier": true
} }
}, },
"search-table": {
"vpxd_session_stats": {
"pattern": "/SessionStats/SessionPool/Session/Id='(?<Id>[^']+)'/Username='(?<Username>[^']+)'/ClientIP='(?<ClientIP>[^']+)'(?<ProfileKey>[^ ]+) (?<ProfileValue>[^\\n]+)",
"glob": "*/vpxd-profile*"
}
},
"sample": [ "sample": [
{ {
"line": "2021-05-24T20:31:05.671Z - last log rotation time, 2021-05-24T09:30:02.683Z - time the service was last started, Section for VMware ESX, pid=1000080910, version=7.0.3, build=0, option=DEBUG" "line": "2021-05-24T20:31:05.671Z - last log rotation time, 2021-05-24T09:30:02.683Z - time the service was last started, Section for VMware ESX, pid=1000080910, version=7.0.3, build=0, option=DEBUG"

@ -772,7 +772,7 @@ char(*X*)
HI HI
**See Also** **See Also**
:ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -805,7 +805,7 @@ charindex(*needle*, *haystack*, *\[start\]*)
0 0
**See Also** **See Also**
:ref:`char`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -1069,7 +1069,7 @@ endswith(*str*, *suffix*)
0 0
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -1124,7 +1124,7 @@ extract(*str*)
{"col_0":1.0,"col_1":2.0} {"col_0":1.0,"col_1":2.0}
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -1325,7 +1325,7 @@ group_concat(*X*, *\[sep\]*)
hw,gw hw,gw
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -1349,7 +1349,7 @@ group_spooky_hash(*str*)
4e7a190aead058cb123c94290f29c34a 4e7a190aead058cb123c94290f29c34a
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -1365,7 +1365,7 @@ gunzip(*b*)
* **b** --- The blob to decompress * **b** --- The blob to decompress
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -1381,7 +1381,7 @@ gzip(*value*)
* **value** --- The value to compress * **value** --- The value to compress
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -1427,7 +1427,7 @@ humanize_file_size(*value*)
10.0MB 10.0MB
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -1475,7 +1475,7 @@ instr(*haystack*, *needle*)
2 2
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -1828,7 +1828,7 @@ leftstr(*str*, *N*)
abc abc
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -1852,7 +1852,7 @@ length(*str*)
3 3
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2042,7 +2042,7 @@ logfmt2json(*str*)
{"foo":1,"bar":2,"name":"Rolo Tomassi"} {"foo":1,"bar":2,"name":"Rolo Tomassi"}
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2066,7 +2066,7 @@ lower(*str*)
abc abc
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2098,7 +2098,7 @@ ltrim(*str*, *\[chars\]*)
c c
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2255,7 +2255,7 @@ padc(*str*, *len*)
abcdef ghi abcdef ghi
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2287,7 +2287,7 @@ padl(*str*, *len*)
abcdef abcdef
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2319,7 +2319,7 @@ padr(*str*, *len*)
abcdefghi abcdefghi
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2417,7 +2417,7 @@ printf(*format*, *X*)
value: 00011 value: 00011
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2441,7 +2441,7 @@ proper(*str*)
Hello, World! Hello, World!
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2624,7 +2624,34 @@ regexp_capture(*string*, *pattern*)
1 2 3 8 9 2 1 2 3 8 9 2
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
----
.. _regexp_capture_into_json:
regexp_capture_into_json(*string*, *pattern*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A table-valued function that executes a regular-expression over a string and returns the captured values as a JSON object. If the regex only matches a subset of the input string, it will be rerun on the remaining parts of the string until no more matches are found.
**Parameters**
* **string\*** --- The string to match against the given pattern.
* **pattern\*** --- The regular expression to match.
**Examples**
To extract the key/value pairs 'a'/1 and 'b'/2 from the string 'a=1; b=2':
.. code-block:: custsqlite
;SELECT * FROM regexp_capture_into_json('a=1; b=2', '(\w+)=(\d+)')
match_index content
0 {"col_0":"a","col_1":1}
1 {"col_0":"b","col_1":2}
**See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2663,7 +2690,7 @@ regexp_match(*re*, *str*)
{"num":123,"str":"four"} {"num":123,"str":"four"}
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_replace`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_replace`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2696,7 +2723,7 @@ regexp_replace(*str*, *re*, *repl*)
<123> <abc> <123> <abc>
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_match`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_match`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2729,7 +2756,7 @@ replace(*str*, *old*, *replacement*)
zbc zbc
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2754,7 +2781,7 @@ replicate(*str*, *N*)
abcabcabc abcabcabc
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2778,7 +2805,7 @@ reverse(*str*)
cba cba
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2810,7 +2837,7 @@ rightstr(*str*, *N*)
abc abc
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2906,7 +2933,7 @@ rtrim(*str*, *\[chars\]*)
a a
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -2976,7 +3003,7 @@ sparkline(*value*, *\[upper\]*)
▁▂▃▄▅▆▇█ ▁▂▃▄▅▆▇█
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -3021,7 +3048,7 @@ spooky_hash(*str*)
f96b3d9c1a19f4394c97a1b79b1880df f96b3d9c1a19f4394c97a1b79b1880df
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -3135,7 +3162,7 @@ startswith(*str*, *prefix*)
0 0
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -3160,7 +3187,7 @@ strfilter(*source*, *include*)
bcbc bcbc
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -3247,7 +3274,7 @@ substr(*str*, *start*, *\[size\]*)
b b
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -3454,7 +3481,7 @@ trim(*str*, *\[chars\]*)
abc abc
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`unicode`, :ref:`upper`, :ref:`xpath`
---- ----
@ -3507,7 +3534,7 @@ unicode(*X*)
97 97
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`upper`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`upper`, :ref:`xpath`
---- ----
@ -3545,7 +3572,7 @@ upper(*str*)
ABC ABC
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`xpath` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`xpath`
---- ----
@ -3588,7 +3615,7 @@ xpath(*xpath*, *xmldoc*)
Hello ★ /abc/def/text() {} Hello ★ Hello ★ /abc/def/text() {} Hello ★
**See Also** **See Also**
:ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper` :ref:`char`, :ref:`charindex`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`printf`, :ref:`proper`, :ref:`regexp_capture_into_json`, :ref:`regexp_capture`, :ref:`regexp_match`, :ref:`regexp_replace`, :ref:`replace`, :ref:`replicate`, :ref:`reverse`, :ref:`rightstr`, :ref:`rtrim`, :ref:`sparkline`, :ref:`spooky_hash`, :ref:`startswith`, :ref:`strfilter`, :ref:`substr`, :ref:`trim`, :ref:`unicode`, :ref:`upper`
---- ----

@ -1460,7 +1460,7 @@ com_pipe_to(exec_context& ec,
lpc++, ++iter) { lpc++, ++iter) {
std::string colname = ldh.ldh_parser->get_element_string( std::string colname = ldh.ldh_parser->get_element_string(
iter->e_sub_elements->front()); iter->e_sub_elements->front());
colname = ldh.ldh_namer->add_column(colname); colname = ldh.ldh_namer->add_column(colname).to_string();
std::string val = ldh.ldh_parser->get_element_string( std::string val = ldh.ldh_parser->get_element_string(
iter->e_sub_elements->back()); iter->e_sub_elements->back());
setenv(colname.c_str(), val.c_str(), 1); setenv(colname.c_str(), val.c_str(), 1);
@ -4832,14 +4832,14 @@ command_prompt(std::vector<std::string>& args)
for (auto& cn_name : ldh.ldh_namer->cn_names) { for (auto& cn_name : ldh.ldh_namer->cn_names) {
lnav_data.ld_rl_view->add_possibility( lnav_data.ld_rl_view->add_possibility(
ln_mode_t::COMMAND, "colname", cn_name); ln_mode_t::COMMAND, "colname", cn_name.to_string());
} }
for (const auto& iter : ldh.ldh_namer->cn_builtin_names) { for (const auto& iter : ldh.ldh_namer->cn_builtin_names) {
if (iter == "col") { if (iter == column_namer::BUILTIN_COL) {
continue; continue;
} }
lnav_data.ld_rl_view->add_possibility( lnav_data.ld_rl_view->add_possibility(
ln_mode_t::COMMAND, "colname", iter); ln_mode_t::COMMAND, "colname", iter.to_string());
} }
ldh.clear(); ldh.clear();

@ -92,7 +92,8 @@ log_data_helper::parse_line(content_line_t line, bool allow_middle)
this->ldh_msg_format.clear(); this->ldh_msg_format.clear();
this->ldh_parser->dp_msg_format = &this->ldh_msg_format; this->ldh_parser->dp_msg_format = &this->ldh_msg_format;
this->ldh_parser->parse(); this->ldh_parser->parse();
this->ldh_namer = std::make_unique<column_namer>(); this->ldh_namer
= std::make_unique<column_namer>(column_namer::language::SQL);
this->ldh_json_pairs.clear(); this->ldh_json_pairs.clear();
this->ldh_xml_pairs.clear(); this->ldh_xml_pairs.clear();

@ -36,7 +36,7 @@ log_data_table::log_data_table(logfile_sub_source& lss,
content_line_t template_line, content_line_t template_line,
intern_string_t table_name) intern_string_t table_name)
: log_vtab_impl(table_name), ldt_log_source(lss), : log_vtab_impl(table_name), ldt_log_source(lss),
ldt_template_line(template_line), ldt_instance(-1) ldt_template_line(template_line)
{ {
std::shared_ptr<logfile> lf = lss.find(template_line); std::shared_ptr<logfile> lf = lss.find(template_line);
auto format = lf->get_format(); auto format = lf->get_format();
@ -49,9 +49,6 @@ log_data_table::log_data_table(logfile_sub_source& lss,
void void
log_data_table::get_columns_int() log_data_table::get_columns_int()
{ {
static intern_string_t instance_name
= intern_string::lookup("log_msg_instance");
auto& cols = this->ldt_cols; auto& cols = this->ldt_cols;
auto& metas = this->ldt_value_metas; auto& metas = this->ldt_value_metas;
content_line_t cl_copy = this->ldt_template_line; content_line_t cl_copy = this->ldt_template_line;
@ -75,19 +72,16 @@ log_data_table::get_columns_int()
data_scanner ds(line, body.lr_start, body.lr_end); data_scanner ds(line, body.lr_start, body.lr_end);
data_parser dp(&ds); data_parser dp(&ds);
column_namer cn; column_namer cn{column_namer::language::SQL};
dp.parse(); dp.parse();
metas.emplace_back(
instance_name, value_kind_t::VALUE_INTEGER, cols.size(), format.get());
cols.emplace_back("log_msg_instance", SQLITE_INTEGER);
for (auto pair_iter = dp.dp_pairs.begin(); pair_iter != dp.dp_pairs.end(); for (auto pair_iter = dp.dp_pairs.begin(); pair_iter != dp.dp_pairs.end();
++pair_iter) ++pair_iter)
{ {
std::string key_str std::string key_str
= dp.get_element_string(pair_iter->e_sub_elements->front()); = dp.get_element_string(pair_iter->e_sub_elements->front());
std::string colname = cn.add_column(key_str); auto colname = cn.add_column(key_str).to_string();
int sql_type = SQLITE3_TEXT; int sql_type = SQLITE3_TEXT;
value_kind_t kind = value_kind_t::VALUE_TEXT; value_kind_t kind = value_kind_t::VALUE_TEXT;
std::string collator; std::string collator;
@ -117,14 +111,7 @@ log_data_table::get_columns_int()
bool bool
log_data_table::next(log_cursor& lc, logfile_sub_source& lss) log_data_table::next(log_cursor& lc, logfile_sub_source& lss)
{ {
if (lc.lc_curr_line == -1_vl) { if (lc.is_eof()) {
this->ldt_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; return true;
} }
@ -168,7 +155,6 @@ log_data_table::next(log_cursor& lc, logfile_sub_source& lss)
this->ldt_pairs.clear(); this->ldt_pairs.clear();
this->ldt_pairs.swap(dp.dp_pairs, __FILE__, __LINE__); this->ldt_pairs.swap(dp.dp_pairs, __FILE__, __LINE__);
this->ldt_instance += 1;
return true; return true;
} }
@ -182,10 +168,8 @@ log_data_table::extract(logfile* lf,
auto meta_iter = this->ldt_value_metas.begin(); auto meta_iter = this->ldt_value_metas.begin();
this->ldt_format_impl->extract(lf, line_number, line, values); this->ldt_format_impl->extract(lf, line_number, line, values);
values.emplace_back(*meta_iter, this->ldt_instance); for (const auto& ldt_pair : this->ldt_pairs) {
++meta_iter; const auto& pvalue = ldt_pair.get_pair_value();
for (auto& ldt_pair : this->ldt_pairs) {
const data_parser::element& pvalue = ldt_pair.get_pair_value();
switch (pvalue.value_token()) { switch (pvalue.value_token()) {
case DT_NUMBER: { case DT_NUMBER: {

@ -58,7 +58,6 @@ public:
void get_foreign_keys(std::vector<std::string>& keys_inout) const override void get_foreign_keys(std::vector<std::string>& keys_inout) const override
{ {
log_vtab_impl::get_foreign_keys(keys_inout); log_vtab_impl::get_foreign_keys(keys_inout);
keys_inout.emplace_back("log_msg_instance");
} }
bool next(log_cursor& lc, logfile_sub_source& lss) override; bool next(log_cursor& lc, logfile_sub_source& lss) override;
@ -75,7 +74,6 @@ private:
shared_buffer_ref ldt_current_line; shared_buffer_ref ldt_current_line;
data_parser::element_list_t ldt_pairs; data_parser::element_list_t ldt_pairs;
std::shared_ptr<log_vtab_impl> ldt_format_impl; std::shared_ptr<log_vtab_impl> ldt_format_impl;
int64_t ldt_instance;
std::vector<vtab_column> ldt_cols; std::vector<vtab_column> ldt_cols;
std::vector<logline_value_meta> ldt_value_metas; std::vector<logline_value_meta> ldt_value_metas;
}; };

@ -556,13 +556,14 @@ json_array_end(void* ctx)
return 1; return 1;
} }
static struct json_path_container json_log_handlers static struct json_path_container json_log_handlers = {
= {json_path_handler(pcrepp("\\w+")) json_path_handler(pcrepp("\\w+"))
.add_cb(read_json_null) .add_cb(read_json_null)
.add_cb(read_json_bool) .add_cb(read_json_bool)
.add_cb(read_json_int) .add_cb(read_json_int)
.add_cb(read_json_double) .add_cb(read_json_double)
.add_cb(read_json_field)}; .add_cb(read_json_field),
};
static int rewrite_json_field(yajlpp_parse_context* ypc, static int rewrite_json_field(yajlpp_parse_context* ypc,
const unsigned char* str, const unsigned char* str,
@ -2307,6 +2308,8 @@ external_log_format::register_vtabs(
auto lst = std::make_shared<log_search_table>( auto lst = std::make_shared<log_search_table>(
*elf_search_table.second.std_pattern, elf_search_table.first); *elf_search_table.second.std_pattern, elf_search_table.first);
lst->lst_format = this;
lst->lst_log_path_glob = elf_search_table.second.std_glob;
auto errmsg = vtab_manager->register_vtab(lst); auto errmsg = vtab_manager->register_vtab(lst);
if (!errmsg.empty()) { if (!errmsg.empty()) {
#if 0 #if 0
@ -2343,10 +2346,12 @@ external_log_format::match_samples(const std::vector<sample>& samples) const
class external_log_table : public log_format_vtab_impl { class external_log_table : public log_format_vtab_impl {
public: public:
external_log_table(const external_log_format& elf) explicit external_log_table(const external_log_format& elf)
: log_format_vtab_impl(elf), elt_format(elf){}; : log_format_vtab_impl(elf), elt_format(elf)
{
}
void get_columns(std::vector<vtab_column>& cols) const void get_columns(std::vector<vtab_column>& cols) const override
{ {
const external_log_format& elf = this->elt_format; const external_log_format& elf = this->elt_format;
@ -2368,9 +2373,9 @@ public:
cols[vd->vd_meta.lvm_column].vc_collator = vd->vd_collate; cols[vd->vd_meta.lvm_column].vc_collator = vd->vd_collate;
cols[vd->vd_meta.lvm_column].vc_comment = vd->vd_description; cols[vd->vd_meta.lvm_column].vc_comment = vd->vd_description;
} }
}; }
void get_foreign_keys(std::vector<std::string>& keys_inout) const void get_foreign_keys(std::vector<std::string>& keys_inout) const override
{ {
log_vtab_impl::get_foreign_keys(keys_inout); log_vtab_impl::get_foreign_keys(keys_inout);
@ -2379,19 +2384,16 @@ public:
keys_inout.emplace_back(elf_value_def.first.to_string()); keys_inout.emplace_back(elf_value_def.first.to_string());
} }
} }
}; }
virtual bool next(log_cursor& lc, logfile_sub_source& lss) bool next(log_cursor& lc, logfile_sub_source& lss) override
{ {
lc.lc_curr_line = lc.lc_curr_line + 1_vl;
lc.lc_sub_index = 0;
if (lc.is_eof()) { if (lc.is_eof()) {
return true; return true;
} }
content_line_t cl(lss.at(lc.lc_curr_line)); content_line_t cl(lss.at(lc.lc_curr_line));
auto lf = lss.find_file_ptr(cl); auto* lf = lss.find_file_ptr(cl);
auto lf_iter = lf->begin() + cl; auto lf_iter = lf->begin() + cl;
uint8_t mod_id = lf_iter->get_module_id(); uint8_t mod_id = lf_iter->get_module_id();
@ -2444,12 +2446,12 @@ public:
} }
return false; return false;
}; }
virtual void extract(logfile* lf, void extract(logfile* lf,
uint64_t line_number, uint64_t line_number,
shared_buffer_ref& line, shared_buffer_ref& line,
std::vector<logline_value>& values) std::vector<logline_value>& values) override
{ {
auto format = lf->get_format(); auto format = lf->get_format();
@ -2467,7 +2469,7 @@ public:
this->vi_attrs.clear(); this->vi_attrs.clear();
format->annotate(line_number, line, this->vi_attrs, values, false); format->annotate(line_number, line, this->vi_attrs, values, false);
} }
}; }
const external_log_format& elt_format; const external_log_format& elt_format;
module_format elt_module_format; module_format elt_module_format;

@ -347,7 +347,9 @@ public:
bool elf_builtin_format{false}; bool elf_builtin_format{false};
struct search_table_def { struct search_table_def {
std::shared_ptr<pcrepp> std_pattern; std::shared_ptr<pcrepp_with_options<PCRE_CASELESS | PCRE_MULTILINE>>
std_pattern;
std::string std_glob;
}; };
std::map<intern_string_t, search_table_def> elf_search_tables; std::map<intern_string_t, search_table_def> elf_search_tables;

@ -745,7 +745,7 @@ public:
class bro_log_table : public log_format_vtab_impl { class bro_log_table : public log_format_vtab_impl {
public: public:
bro_log_table(const bro_log_format& format) explicit bro_log_table(const bro_log_format& format)
: log_format_vtab_impl(format), blt_format(format) : log_format_vtab_impl(format), blt_format(format)
{ {
} }

@ -731,6 +731,11 @@ static struct json_path_container search_table_def_handlers = {
.with_synopsis("<regex>") .with_synopsis("<regex>")
.with_description("The regular expression for this search table.") .with_description("The regular expression for this search table.")
.for_field(&external_log_format::search_table_def::std_pattern), .for_field(&external_log_format::search_table_def::std_pattern),
json_path_handler("glob")
.with_synopsis("<glob>")
.with_description("Glob pattern used to constrain hits to messages "
"that match the given pattern.")
.for_field(&external_log_format::search_table_def::std_glob),
}; };
static struct json_path_container search_table_handlers = { static struct json_path_container search_table_handlers = {

@ -33,30 +33,31 @@
#include "config.h" #include "config.h"
#include "sql_util.hh" #include "sql_util.hh"
const static std::string LOG_MSG_INSTANCE = "log_msg_instance"; const static std::string MATCH_INDEX = "match_index";
static auto instance_name = intern_string::lookup("log_msg_instance"); static auto match_index_name = intern_string::lookup("match_index");
static auto instance_meta static auto match_index_meta
= logline_value_meta(instance_name, value_kind_t::VALUE_INTEGER, 0); = logline_value_meta(match_index_name, value_kind_t::VALUE_INTEGER, 0);
log_search_table::log_search_table(pcrepp pattern, intern_string_t table_name) 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) : log_vtab_impl(table_name), lst_regex(std::move(pattern))
{ {
this->vi_supports_indexes = false;
this->get_columns_int(this->lst_cols); this->get_columns_int(this->lst_cols);
} }
void void
log_search_table::get_columns_int(std::vector<vtab_column>& cols) log_search_table::get_columns_int(std::vector<vtab_column>& cols)
{ {
column_namer cn; column_namer cn{column_namer::language::SQL};
cols.emplace_back(LOG_MSG_INSTANCE, SQLITE_INTEGER); cols.emplace_back(MATCH_INDEX, SQLITE_INTEGER);
for (int lpc = 0; lpc < this->lst_regex.get_capture_count(); lpc++) { for (int lpc = 0; lpc < this->lst_regex.get_capture_count(); lpc++) {
std::string collator; std::string collator;
std::string colname; std::string colname;
int sqlite_type = SQLITE3_TEXT; int sqlite_type = SQLITE3_TEXT;
colname = cn.add_column(this->lst_regex.name_for_capture(lpc)); colname = cn.add_column(
string_fragment{this->lst_regex.name_for_capture(lpc)})
.to_string();
if (this->lst_regex.captures().size() if (this->lst_regex.captures().size()
== (size_t) this->lst_regex.get_capture_count()) == (size_t) this->lst_regex.get_capture_count())
{ {
@ -93,25 +94,39 @@ void
log_search_table::get_foreign_keys(std::vector<std::string>& keys_inout) const log_search_table::get_foreign_keys(std::vector<std::string>& keys_inout) const
{ {
log_vtab_impl::get_foreign_keys(keys_inout); log_vtab_impl::get_foreign_keys(keys_inout);
keys_inout.emplace_back("log_msg_instance"); keys_inout.emplace_back(MATCH_INDEX);
} }
bool bool
log_search_table::next(log_cursor& lc, logfile_sub_source& lss) log_search_table::next(log_cursor& lc, logfile_sub_source& lss)
{ {
if (lc.lc_curr_line == -1_vl) { if (this->lst_match_index >= 0) {
this->lst_instance = -1; this->lst_input.pi_offset = this->lst_input.pi_next_offset;
if (this->lst_regex.match(
this->lst_match_context, this->lst_input, PCRE_NO_UTF8_CHECK))
{
this->lst_match_index += 1;
return true;
}
lc.lc_curr_line += 1_vl;
lc.lc_sub_index = 0;
} }
lc.lc_curr_line = lc.lc_curr_line + 1_vl; this->lst_match_index = -1;
lc.lc_sub_index = 0;
while (!lc.is_eof() && !this->is_valid(lc, lss)) {
lc.lc_curr_line += 1_vl;
lc.lc_sub_index = 0;
}
if (lc.lc_curr_line == (int) lss.text_line_count()) { if (lc.is_eof()) {
return true; return true;
} }
auto cl = lss.at(lc.lc_curr_line); auto cl = lss.at(lc.lc_curr_line);
auto lf = lss.find(cl); auto* lf = lss.find_file_ptr(cl);
auto lf_iter = lf->begin() + cl; auto lf_iter = lf->begin() + cl;
if (!lf_iter->is_message()) { if (!lf_iter->is_message()) {
@ -124,14 +139,16 @@ log_search_table::next(log_cursor& lc, logfile_sub_source& lss)
lf->read_full_message(lf_iter, this->lst_current_line); lf->read_full_message(lf_iter, this->lst_current_line);
lf->get_format()->annotate( lf->get_format()->annotate(
cl, this->lst_current_line, sa, line_values, false); cl, this->lst_current_line, sa, line_values, false);
pcre_input pi( this->lst_input.reset(
this->lst_current_line.get_data(), 0, this->lst_current_line.length()); this->lst_current_line.get_data(), 0, this->lst_current_line.length());
if (!this->lst_regex.match(this->lst_match_context, pi)) { if (!this->lst_regex.match(
this->lst_match_context, this->lst_input, PCRE_NO_UTF8_CHECK))
{
return false; return false;
} }
this->lst_instance += 1; this->lst_match_index = 0;
return true; return true;
} }
@ -142,11 +159,30 @@ log_search_table::extract(logfile* lf,
shared_buffer_ref& line, shared_buffer_ref& line,
std::vector<logline_value>& values) std::vector<logline_value>& values)
{ {
values.emplace_back(instance_meta, this->lst_instance); values.emplace_back(match_index_meta, this->lst_match_index);
for (int lpc = 0; lpc < this->lst_regex.get_capture_count(); lpc++) { for (int lpc = 0; lpc < this->lst_regex.get_capture_count(); lpc++) {
auto cap = this->lst_match_context[lpc]; const auto* cap = this->lst_match_context[lpc];
values.emplace_back(this->lst_column_metas[lpc], values.emplace_back(this->lst_column_metas[lpc],
line, line,
line_range{cap->c_begin, cap->c_end}); line_range{cap->c_begin, cap->c_end});
} }
} }
void
log_search_table::get_primary_keys(std::vector<std::string>& keys_out) const
{
keys_out.emplace_back("log_line");
keys_out.emplace_back("match_index");
}
void
log_search_table::filter(log_cursor& lc, logfile_sub_source& lss)
{
if (this->lst_format != nullptr) {
lc.lc_format_name = this->lst_format->get_name();
}
if (!this->lst_log_path_glob.empty()) {
lc.lc_log_path.emplace_back(SQLITE_INDEX_CONSTRAINT_GLOB,
this->lst_log_path_glob);
}
}

@ -41,19 +41,19 @@
class log_search_table : public log_vtab_impl { class log_search_table : public log_vtab_impl {
public: public:
static int pattern_options() static int pattern_options() { return PCRE_CASELESS | PCRE_MULTILINE; }
{
return PCRE_CASELESS;
}
log_search_table(pcrepp pattern, intern_string_t table_name); log_search_table(pcrepp pattern, intern_string_t table_name);
void get_primary_keys(std::vector<std::string>& keys_out) const override;
void get_columns_int(std::vector<vtab_column>& cols); void get_columns_int(std::vector<vtab_column>& cols);
void get_columns(std::vector<vtab_column>& cols) const override void get_columns(std::vector<vtab_column>& cols) const override
{ {
cols = this->lst_cols; cols = this->lst_cols;
} }
void filter(log_cursor& lc, logfile_sub_source& lss) override;
void get_foreign_keys(std::vector<std::string>& keys_inout) const override; void get_foreign_keys(std::vector<std::string>& keys_inout) const override;
@ -65,10 +65,13 @@ public:
std::vector<logline_value>& values) override; std::vector<logline_value>& values) override;
pcrepp lst_regex; pcrepp lst_regex;
log_format* lst_format{nullptr};
std::string lst_log_path_glob;
shared_buffer_ref lst_current_line; shared_buffer_ref lst_current_line;
pcre_input lst_input{""};
pcre_context_static<128> lst_match_context; pcre_context_static<128> lst_match_context;
std::vector<logline_value_meta> lst_column_metas; std::vector<logline_value_meta> lst_column_metas;
int64_t lst_instance; int64_t lst_match_index{-1};
std::vector<vtab_column> lst_cols; std::vector<vtab_column> lst_cols;
}; };

File diff suppressed because it is too large Load Diff

@ -61,13 +61,28 @@ struct log_cursor {
unsigned int value : 6; unsigned int value : 6;
}; };
struct string_constraint {
unsigned char sc_op;
std::string sc_value;
std::shared_ptr<pcrepp> sc_pattern;
string_constraint(unsigned char op, std::string value);
bool matches(const std::string& sf) const;
};
vis_line_t lc_curr_line; vis_line_t lc_curr_line;
int lc_sub_index; int lc_sub_index;
vis_line_t lc_end_line; vis_line_t lc_end_line;
intern_string_t lc_format_name;
nonstd::optional<opid_hash> lc_opid; nonstd::optional<opid_hash> lc_opid;
nonstd::optional<std::string> lc_log_path; std::vector<string_constraint> lc_log_path;
nonstd::optional<std::string> lc_unique_path; logfile* lc_last_log_path_match{nullptr};
logfile* lc_last_log_path_mismatch{nullptr};
std::vector<string_constraint> lc_unique_path;
logfile* lc_last_unique_path_match{nullptr};
logfile* lc_last_unique_path_mismatch{nullptr};
enum class constraint_t { enum class constraint_t {
none, none,
@ -124,7 +139,7 @@ public:
virtual ~log_vtab_impl() = default; virtual ~log_vtab_impl() = default;
const intern_string_t get_name() const { return this->vi_name; } intern_string_t get_name() const { return this->vi_name; }
intern_string_t get_tags_name() const { return this->vi_tags_name; } intern_string_t get_tags_name() const { return this->vi_tags_name; }
@ -132,12 +147,16 @@ public:
virtual bool is_valid(log_cursor& lc, logfile_sub_source& lss); virtual bool is_valid(log_cursor& lc, logfile_sub_source& lss);
virtual void filter(log_cursor& lc, logfile_sub_source& lss) {}
virtual bool next(log_cursor& lc, logfile_sub_source& lss) = 0; virtual bool next(log_cursor& lc, logfile_sub_source& lss) = 0;
virtual void get_columns(std::vector<vtab_column>& cols) const {} virtual void get_columns(std::vector<vtab_column>& cols) const {}
virtual void get_foreign_keys(std::vector<std::string>& keys_inout) const; virtual void get_foreign_keys(std::vector<std::string>& keys_inout) const;
virtual void get_primary_keys(std::vector<std::string>& keys_out) const {}
virtual void extract(logfile* lf, virtual void extract(logfile* lf,
uint64_t line_number, uint64_t line_number,
shared_buffer_ref& line, shared_buffer_ref& line,

@ -153,6 +153,8 @@ public:
*/ */
std::shared_ptr<log_format> get_format() const { return this->lf_format; } std::shared_ptr<log_format> get_format() const { return this->lf_format; }
log_format* get_format_ptr() const { return this->lf_format.get(); }
intern_string_t get_format_name() const; intern_string_t get_format_name() const;
text_format_t get_text_format() const { return this->lf_text_format; } text_format_t get_text_format() const { return this->lf_text_format; }

@ -28,11 +28,13 @@
*/ */
#include "base/lnav_log.hh" #include "base/lnav_log.hh"
#include "column_namer.hh"
#include "config.h" #include "config.h"
#include "pcrepp/pcrepp.hh" #include "pcrepp/pcrepp.hh"
#include "sql_help.hh" #include "sql_help.hh"
#include "sql_util.hh" #include "sql_util.hh"
#include "vtab_module.hh" #include "vtab_module.hh"
#include "yajlpp/yajlpp.hh"
enum { enum {
RC_COL_MATCH_INDEX, RC_COL_MATCH_INDEX,
@ -71,30 +73,21 @@ CREATE TABLE regexp_capture (
std::unique_ptr<pcre_input> c_input; std::unique_ptr<pcre_input> c_input;
std::string c_content; std::string c_content;
bool c_content_as_blob{false}; bool c_content_as_blob{false};
int c_index; int c_index{0};
int c_start_index;
bool c_matched{false}; bool c_matched{false};
int c_match_index; int c_match_index{0};
sqlite3_int64 c_rowid; sqlite3_int64 c_rowid{0};
cursor(sqlite3_vtab* vt) cursor(sqlite3_vtab* vt) : base({vt}) { this->c_context.set_count(0); }
: base({vt}), c_index(0), c_start_index(0), c_match_index(0),
c_rowid(0)
{
this->c_context.set_count(0);
};
int reset() int reset() { return SQLITE_OK; }
{
return SQLITE_OK;
};
int next() int next()
{ {
if (this->c_index >= (this->c_context.get_count() - 1)) { if (this->c_index >= (this->c_context.get_count() - 1)) {
this->c_input->pi_offset = this->c_input->pi_next_offset; this->c_input->pi_offset = this->c_input->pi_next_offset;
this->c_matched this->c_matched = this->c_pattern.match(
= this->c_pattern.match(this->c_context, *(this->c_input)); this->c_context, *(this->c_input), PCRE_NO_UTF8_CHECK);
this->c_index = -1; this->c_index = -1;
this->c_match_index += 1; this->c_match_index += 1;
} }
@ -106,24 +99,21 @@ CREATE TABLE regexp_capture (
this->c_index += 1; this->c_index += 1;
return SQLITE_OK; return SQLITE_OK;
}; }
int eof() int eof() { return this->c_pattern.empty() || !this->c_matched; }
{
return this->c_pattern.empty() || !this->c_matched;
};
int get_rowid(sqlite3_int64& rowid_out) int get_rowid(sqlite3_int64& rowid_out)
{ {
rowid_out = this->c_rowid; rowid_out = this->c_rowid;
return SQLITE_OK; return SQLITE_OK;
}; }
}; };
int get_column(const cursor& vc, sqlite3_context* ctx, int col) int get_column(const cursor& vc, sqlite3_context* ctx, int col)
{ {
pcre_context::capture_t& cap = vc.c_context.all()[vc.c_index]; auto& cap = vc.c_context.all()[vc.c_index];
switch (col) { switch (col) {
case RC_COL_MATCH_INDEX: case RC_COL_MATCH_INDEX:
@ -246,9 +236,222 @@ rcFilter(sqlite3_vtab_cursor* pVtabCursor,
pCur->c_context.set_count(0); pCur->c_context.set_count(0);
pCur->c_input = std::make_unique<pcre_input>(pCur->c_content); pCur->c_input = std::make_unique<pcre_input>(pCur->c_content);
pCur->c_matched = pCur->c_pattern.match(pCur->c_context, *(pCur->c_input)); pCur->c_matched = pCur->c_pattern.match(
pCur->c_context, *(pCur->c_input), PCRE_NO_UTF8_CHECK);
return SQLITE_OK;
}
enum {
RCJ_COL_MATCH_INDEX,
RCJ_COL_CONTENT,
RCJ_COL_VALUE,
RCJ_COL_PATTERN,
};
log_debug("matched %d", pCur->c_matched); struct regexp_capture_into_json {
static constexpr const char* NAME = "regexp_capture_into_json";
static constexpr const char* CREATE_STMT = R"(
-- The regexp_capture_into_json() table-valued function allows you to execute a
-- regular-expression over a given string and get the captured data as rows in
-- a table.
CREATE TABLE regexp_capture_into_json (
match_index INTEGER,
content TEXT,
value TEXT HIDDEN,
pattern TEXT HIDDEN
);
)";
struct cursor {
sqlite3_vtab_cursor base;
pcrepp c_pattern;
pcre_context_static<30> c_context;
std::unique_ptr<pcre_input> c_input;
std::unique_ptr<column_namer> c_namer;
std::string c_content;
bool c_content_as_blob{false};
bool c_matched{false};
size_t c_match_index{0};
sqlite3_int64 c_rowid{0};
cursor(sqlite3_vtab* vt) : base({vt}) { this->c_context.set_count(0); }
int reset() { return SQLITE_OK; }
int next()
{
this->c_input->pi_offset = this->c_input->pi_next_offset;
this->c_matched = this->c_pattern.match(
this->c_context, *(this->c_input), PCRE_NO_UTF8_CHECK);
this->c_match_index += 1;
if (this->c_pattern.empty() || !this->c_matched) {
return SQLITE_OK;
}
return SQLITE_OK;
}
int eof() { return this->c_pattern.empty() || !this->c_matched; }
int get_rowid(sqlite3_int64& rowid_out)
{
rowid_out = this->c_rowid;
return SQLITE_OK;
}
};
int get_column(const cursor& vc, sqlite3_context* ctx, int col)
{
switch (col) {
case RCJ_COL_MATCH_INDEX:
sqlite3_result_int64(ctx, vc.c_match_index);
break;
case RCJ_COL_CONTENT: {
yajlpp_gen gen;
yajl_gen_config(gen, yajl_gen_beautify, false);
{
yajlpp_map root_map(gen);
for (int lpc = 0; lpc < vc.c_pattern.get_capture_count();
lpc++) {
const auto& colname = vc.c_namer->cn_names[lpc];
const auto* cap = vc.c_context[lpc];
yajl_gen_pstring(gen, colname.data(), colname.length());
if (!cap->is_valid()) {
yajl_gen_null(gen);
} else {
auto* cap_start = vc.c_input->get_substr_start(cap);
char* cap_copy = (char*) alloca(cap->length() + 1);
long long int i_value;
double d_value;
int end_index;
memcpy(cap_copy, cap_start, cap->length());
cap_copy[cap->length()] = '\0';
if (sscanf(cap_copy, "%lld%n", &i_value, &end_index)
== 1
&& (end_index == cap->length()))
{
yajl_gen_integer(gen, i_value);
} else if (sscanf(cap_copy,
"%lf%n",
&d_value,
&end_index)
== 1
&& (end_index == cap->length()))
{
yajl_gen_number(gen, cap_start, cap->length());
} else {
yajl_gen_pstring(gen, cap_start, cap->length());
}
}
}
}
auto sf = gen.to_string_fragment();
sqlite3_result_text(
ctx, sf.data(), sf.length(), SQLITE_TRANSIENT);
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
break;
}
case RCJ_COL_VALUE:
if (vc.c_content_as_blob) {
sqlite3_result_blob64(ctx,
vc.c_content.c_str(),
vc.c_content.length(),
SQLITE_STATIC);
} else {
sqlite3_result_text(ctx,
vc.c_content.c_str(),
vc.c_content.length(),
SQLITE_STATIC);
}
break;
case RCJ_COL_PATTERN: {
auto str = vc.c_pattern.get_pattern();
sqlite3_result_text(
ctx, str.c_str(), str.length(), SQLITE_TRANSIENT);
break;
}
}
return SQLITE_OK;
}
};
static int
rcjBestIndex(sqlite3_vtab* tab, sqlite3_index_info* pIdxInfo)
{
vtab_index_constraints vic(pIdxInfo);
vtab_index_usage viu(pIdxInfo);
for (auto iter = vic.begin(); iter != vic.end(); ++iter) {
if (iter->op != SQLITE_INDEX_CONSTRAINT_EQ) {
continue;
}
switch (iter->iColumn) {
case RCJ_COL_VALUE:
case RCJ_COL_PATTERN:
viu.column_used(iter);
break;
}
}
viu.allocate_args(2);
return SQLITE_OK;
}
static int
rcjFilter(sqlite3_vtab_cursor* pVtabCursor,
int idxNum,
const char* idxStr,
int argc,
sqlite3_value** argv)
{
auto* pCur = (regexp_capture_into_json::cursor*) pVtabCursor;
if (argc != 2) {
pCur->c_content.clear();
pCur->c_pattern.clear();
return SQLITE_OK;
}
auto byte_count = sqlite3_value_bytes(argv[0]);
auto blob = (const char*) sqlite3_value_blob(argv[0]);
pCur->c_content_as_blob = (sqlite3_value_type(argv[0]) == SQLITE_BLOB);
pCur->c_content.assign(blob, byte_count);
const char* pattern = (const char*) sqlite3_value_text(argv[1]);
auto re_res = pcrepp::from_str(pattern);
if (re_res.isErr()) {
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
"Invalid regular expression: %s", re_res.unwrapErr().ce_msg);
return SQLITE_ERROR;
}
pCur->c_pattern = re_res.unwrap();
pCur->c_namer
= std::make_unique<column_namer>(column_namer::language::JSON);
for (int lpc = 0; lpc < pCur->c_pattern.get_capture_count(); lpc++) {
pCur->c_namer->add_column(
string_fragment{pCur->c_pattern.name_for_capture(lpc)});
}
pCur->c_context.set_count(0);
pCur->c_input = std::make_unique<pcre_input>(pCur->c_content);
pCur->c_matched = pCur->c_pattern.match(
pCur->c_context, *(pCur->c_input), PCRE_NO_UTF8_CHECK);
return SQLITE_OK; return SQLITE_OK;
} }
@ -306,5 +509,43 @@ register_regexp_vtab(sqlite3* db)
ensure(rc == SQLITE_OK); ensure(rc == SQLITE_OK);
static vtab_module<tvt_no_update<regexp_capture_into_json>>
REGEXP_CAPTURE_INTO_JSON_MODULE;
static help_text regexp_capture_into_json_help
= help_text(
"regexp_capture_into_json",
"A table-valued function that executes a "
"regular-expression over a string and returns the captured "
"values as a JSON object. If the regex only matches a "
"subset of the input string, it will be rerun on the "
"remaining parts of the string until no more matches are found.")
.sql_table_valued_function()
.with_parameter(
{"string", "The string to match against the given pattern."})
.with_parameter({"pattern", "The regular expression to match."})
.with_result({
"match_index",
"The match iteration. This value will increase "
"each time a new match is found in the input string.",
})
.with_result({"content", "The captured values from the string."})
.with_tags({"string"})
.with_example({
"To extract the key/value pairs 'a'/1 and 'b'/2 "
"from the string 'a=1; b=2'",
"SELECT * FROM regexp_capture_into_json('a=1; b=2', "
"'(\\w+)=(\\d+)')",
});
REGEXP_CAPTURE_INTO_JSON_MODULE.vm_module.xBestIndex = rcjBestIndex;
REGEXP_CAPTURE_INTO_JSON_MODULE.vm_module.xFilter = rcjFilter;
rc = REGEXP_CAPTURE_INTO_JSON_MODULE.create(db, "regexp_capture_into_json");
sqlite_function_help.insert(std::make_pair("regexp_capture_into_json",
&regexp_capture_into_json_help));
regexp_capture_into_json_help.index_tags();
ensure(rc == SQLITE_OK);
return rc; return rc;
} }

@ -256,7 +256,28 @@ const char* sql_function_names[] = {
"julianday(", "julianday(",
"strftime(", "strftime(",
nullptr}; nullptr,
};
const std::unordered_map<unsigned char, const char*> sql_constraint_names = {
{SQLITE_INDEX_CONSTRAINT_EQ, "="},
{SQLITE_INDEX_CONSTRAINT_GT, ">"},
{SQLITE_INDEX_CONSTRAINT_LE, "<="},
{SQLITE_INDEX_CONSTRAINT_LT, "<"},
{SQLITE_INDEX_CONSTRAINT_GE, ">="},
{SQLITE_INDEX_CONSTRAINT_MATCH, "MATCH"},
{SQLITE_INDEX_CONSTRAINT_LIKE, "LIKE"},
{SQLITE_INDEX_CONSTRAINT_GLOB, "GLOB"},
{SQLITE_INDEX_CONSTRAINT_REGEXP, "REGEXP"},
{SQLITE_INDEX_CONSTRAINT_NE, "!="},
{SQLITE_INDEX_CONSTRAINT_ISNOT, "IS NOT"},
{SQLITE_INDEX_CONSTRAINT_ISNOTNULL, "IS NOT NULL"},
{SQLITE_INDEX_CONSTRAINT_ISNULL, "IS NULL"},
{SQLITE_INDEX_CONSTRAINT_IS, "IS"},
{SQLITE_INDEX_CONSTRAINT_LIMIT, "LIMIT"},
{SQLITE_INDEX_CONSTRAINT_OFFSET, "OFFSET"},
{SQLITE_INDEX_CONSTRAINT_FUNCTION, "function"},
};
std::multimap<std::string, help_text*> sqlite_function_help; std::multimap<std::string, help_text*> sqlite_function_help;
@ -917,7 +938,7 @@ annotate_sql_statement(attr_line_t& al)
{ {
static const std::string keyword_re_str = R"(\A)" + sql_keyword_re(); static const std::string keyword_re_str = R"(\A)" + sql_keyword_re();
static struct { static const struct {
pcrepp re; pcrepp re;
string_attr_type<void>* type; string_attr_type<void>* type;
} PATTERNS[] = { } PATTERNS[] = {
@ -926,7 +947,7 @@ annotate_sql_statement(attr_line_t& al)
{pcrepp{R"(\A\(|\A\))"}, &SQL_PAREN_ATTR}, {pcrepp{R"(\A\(|\A\))"}, &SQL_PAREN_ATTR},
{pcrepp{keyword_re_str, PCRE_CASELESS}, &SQL_KEYWORD_ATTR}, {pcrepp{keyword_re_str, PCRE_CASELESS}, &SQL_KEYWORD_ATTR},
{pcrepp{R"(\A'[^']*('(?:'[^']*')*|$))"}, &SQL_STRING_ATTR}, {pcrepp{R"(\A'[^']*('(?:'[^']*')*|$))"}, &SQL_STRING_ATTR},
{pcrepp{R"(\A(\$?\b[a-z_]\w*)|\"([^\"]+)\"|\[([^\]]+)])", {pcrepp{R"(\A(((\$|:|@)?\b[a-z_]\w*)|\"([^\"]+)\"|\[([^\]]+)]))",
PCRE_CASELESS}, PCRE_CASELESS},
&SQL_IDENTIFIER_ATTR}, &SQL_IDENTIFIER_ATTR},
{pcrepp{R"(\A--.*)"}, &SQL_COMMENT_ATTR}, {pcrepp{R"(\A--.*)"}, &SQL_COMMENT_ATTR},
@ -934,7 +955,7 @@ annotate_sql_statement(attr_line_t& al)
{pcrepp{R"(\A.)"}, &SQL_GARBAGE_ATTR}, {pcrepp{R"(\A.)"}, &SQL_GARBAGE_ATTR},
}; };
static pcrepp ws_pattern(R"(\A\s+)"); static const pcrepp ws_pattern(R"(\A\s+)");
pcre_context_static<30> pc; pcre_context_static<30> pc;
pcre_input pi(al.get_string()); pcre_input pi(al.get_string());
@ -947,7 +968,7 @@ annotate_sql_statement(attr_line_t& al)
} }
for (const auto& pat : PATTERNS) { for (const auto& pat : PATTERNS) {
if (pat.re.match(pc, pi, PCRE_ANCHORED)) { if (pat.re.match(pc, pi, PCRE_ANCHORED)) {
pcre_context::capture_t* cap = pc.all(); auto* cap = pc.all();
struct line_range lr(cap->c_begin, cap->c_end); struct line_range lr(cap->c_begin, cap->c_end);
sa.emplace_back(lr, pat.type->value()); sa.emplace_back(lr, pat.type->value());

@ -34,6 +34,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include <unordered_map>
#include <vector> #include <vector>
#include <sqlite3.h> #include <sqlite3.h>
@ -47,10 +48,23 @@
extern const char* sql_keywords[145]; extern const char* sql_keywords[145];
extern const char* sql_function_names[]; extern const char* sql_function_names[];
extern const std::unordered_map<unsigned char, const char*>
sql_constraint_names;
typedef int (*sqlite_exec_callback)(void*, int, char**, char**); inline const char*
sql_constraint_op_name(unsigned char op)
{
auto iter = sql_constraint_names.find(op);
if (iter == sql_constraint_names.end()) {
return "??";
}
return iter->second;
}
using sqlite_exec_callback = int (*)(void*, int, char**, char**);
typedef std::vector<std::string> db_table_list_t; typedef std::vector<std::string> db_table_list_t;
typedef std::map<std::string, db_table_list_t> db_table_map_t; using db_table_map_t = std::map<std::string, db_table_list_t>;
struct sqlite_metadata_callbacks { struct sqlite_metadata_callbacks {
sqlite_exec_callback smc_collation_list; sqlite_exec_callback smc_collation_list;

@ -40,9 +40,11 @@
using namespace mapbox; using namespace mapbox;
typedef struct { struct cache_entry {
std::shared_ptr<pcrepp> re2; std::shared_ptr<pcrepp> re2;
} cache_entry; std::shared_ptr<column_namer> cn{
std::make_shared<column_namer>(column_namer::language::JSON)};
};
static cache_entry* static cache_entry*
find_re(string_fragment re) find_re(string_fragment re)
@ -59,6 +61,10 @@ find_re(string_fragment re)
auto pair = cache.insert( auto pair = cache.insert(
std::make_pair(string_fragment{c.re2->get_pattern()}, c)); std::make_pair(string_fragment{c.re2->get_pattern()}, c));
for (int lpc = 0; lpc < c.re2->get_capture_count(); lpc++) {
c.cn->add_column(string_fragment{c.re2->name_for_capture(lpc)});
}
iter = pair.first; iter = pair.first;
} }
@ -87,7 +93,7 @@ regexp_match(string_fragment re, const char* str)
throw pcrepp::error("regular expression does not have any captures"); throw pcrepp::error("regular expression does not have any captures");
} }
if (!extractor.match(pc, pi)) { if (!extractor.match(pc, pi, PCRE_NO_UTF8_CHECK)) {
return static_cast<const char*>(nullptr); return static_cast<const char*>(nullptr);
} }
@ -123,14 +129,12 @@ regexp_match(string_fragment re, const char* str)
return string_fragment(str, cap->c_begin, cap->c_end); return string_fragment(str, cap->c_begin, cap->c_end);
} else { } else {
yajlpp_map root_map(gen); yajlpp_map root_map(gen);
column_namer cn;
for (int lpc = 0; lpc < extractor.get_capture_count(); lpc++) { for (int lpc = 0; lpc < extractor.get_capture_count(); lpc++) {
std::string colname const auto& colname = reobj->cn->cn_names[lpc];
= cn.add_column(extractor.name_for_capture(lpc)); const auto* cap = pc[lpc];
pcre_context::capture_t* cap = pc[lpc];
yajl_gen_string(gen, colname); yajl_gen_pstring(gen, colname.data(), colname.length());
if (!cap->is_valid()) { if (!cap->is_valid()) {
yajl_gen_null(gen); yajl_gen_null(gen);

@ -25,6 +25,7 @@ TIME_FORMATS = \
"%a %b %d %H:%M:%S " \ "%a %b %d %H:%M:%S " \
"%a %b %d %H:%M:%S.%L " \ "%a %b %d %H:%M:%S.%L " \
"%a %b %d %H:%M " \ "%a %b %d %H:%M " \
"%a %b %e %H:%M:%S %Z %Y" \
"%d/%b/%Y:%H:%M:%S +0000" \ "%d/%b/%Y:%H:%M:%S +0000" \
"%d/%b/%Y:%H:%M:%S %z" \ "%d/%b/%Y:%H:%M:%S %z" \
"%d-%b-%Y %H:%M:%S %z" \ "%d-%b-%Y %H:%M:%S %z" \

@ -20,6 +20,11 @@ add_executable(test_auto_mem test_auto_mem.cc test_stubs.cc)
target_link_libraries(test_auto_mem diag) target_link_libraries(test_auto_mem diag)
add_test(NAME test_auto_mem COMMAND test_auto_mem) add_test(NAME test_auto_mem COMMAND test_auto_mem)
add_executable(test_column_namer test_column_namer.cc test_stubs.cc)
target_include_directories(test_column_namer PUBLIC ../src/third-party/doctest-root)
target_link_libraries(test_column_namer diag)
add_test(NAME test_column_namer COMMAND test_column_namer)
add_executable(document.sections.tests document.sections.tests.cc test_stubs.cc) add_executable(document.sections.tests document.sections.tests.cc test_stubs.cc)
target_include_directories(document.sections.tests PUBLIC ../src/third-party/doctest-root) target_include_directories(document.sections.tests PUBLIC ../src/third-party/doctest-root)
target_link_libraries(document.sections.tests diag) target_link_libraries(document.sections.tests diag)

@ -197,11 +197,13 @@ dist_noinst_SCRIPTS = \
test_sql.sh \ test_sql.sh \
test_sql_anno.sh \ test_sql_anno.sh \
test_sql_coll_func.sh \ test_sql_coll_func.sh \
test_sql_fs_func.sh \
test_sql_indexes.sh \
test_sql_json_func.sh \ test_sql_json_func.sh \
test_sql_search_table.sh \
test_sql_str_func.sh \ test_sql_str_func.sh \
test_sql_time_func.sh \ test_sql_time_func.sh \
test_sql_xml_func.sh \ test_sql_xml_func.sh \
test_sql_fs_func.sh \
test_tui.sh \ test_tui.sh \
test_view_colors.sh \ test_view_colors.sh \
test_vt52_curses.sh \ test_vt52_curses.sh \
@ -297,6 +299,7 @@ dist_noinst_DATA = \
logfile_openam.0 \ logfile_openam.0 \
logfile_plain.0 \ logfile_plain.0 \
logfile_pretty.0 \ logfile_pretty.0 \
logfile_procstate.0 \
logfile_rollover.0 \ logfile_rollover.0 \
logfile_rollover.1 \ logfile_rollover.1 \
logfile_strace_log.0 \ logfile_strace_log.0 \
@ -389,8 +392,10 @@ TESTS = \
test_sql.sh \ test_sql.sh \
test_sql_anno.sh \ test_sql_anno.sh \
test_sql_coll_func.sh \ test_sql_coll_func.sh \
test_sql_json_func.sh \
test_sql_fs_func.sh \ test_sql_fs_func.sh \
test_sql_indexes.sh \
test_sql_json_func.sh \
test_sql_search_table.sh \
test_sql_str_func.sh \ test_sql_str_func.sh \
test_sql_time_func.sh \ test_sql_time_func.sh \
test_sql_xml_func.sh \ test_sql_xml_func.sh \

@ -420,6 +420,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_sql.sh_50c0b2c93b646b848a017764bde8a4282c556e2d.out \ $(srcdir)/%reldir%/test_sql.sh_50c0b2c93b646b848a017764bde8a4282c556e2d.out \
$(srcdir)/%reldir%/test_sql.sh_528e48a03cdfa7cfbe263a6e22a65606247a8a95.err \ $(srcdir)/%reldir%/test_sql.sh_528e48a03cdfa7cfbe263a6e22a65606247a8a95.err \
$(srcdir)/%reldir%/test_sql.sh_528e48a03cdfa7cfbe263a6e22a65606247a8a95.out \ $(srcdir)/%reldir%/test_sql.sh_528e48a03cdfa7cfbe263a6e22a65606247a8a95.out \
$(srcdir)/%reldir%/test_sql.sh_5532c7a21e3f6b7df3aad10d7bdfbb7a812ae6c7.err \
$(srcdir)/%reldir%/test_sql.sh_5532c7a21e3f6b7df3aad10d7bdfbb7a812ae6c7.out \
$(srcdir)/%reldir%/test_sql.sh_56047c9470e515bc3e3709354c01e5d50462cde7.err \ $(srcdir)/%reldir%/test_sql.sh_56047c9470e515bc3e3709354c01e5d50462cde7.err \
$(srcdir)/%reldir%/test_sql.sh_56047c9470e515bc3e3709354c01e5d50462cde7.out \ $(srcdir)/%reldir%/test_sql.sh_56047c9470e515bc3e3709354c01e5d50462cde7.out \
$(srcdir)/%reldir%/test_sql.sh_57427f3c4b4ec785ffff7c5802c10db0d3e547cf.err \ $(srcdir)/%reldir%/test_sql.sh_57427f3c4b4ec785ffff7c5802c10db0d3e547cf.err \
@ -440,6 +442,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_sql.sh_6ffd89498b9a7758ded6717148fc2ce77a12621b.out \ $(srcdir)/%reldir%/test_sql.sh_6ffd89498b9a7758ded6717148fc2ce77a12621b.out \
$(srcdir)/%reldir%/test_sql.sh_753c343a256d1286750314957d1b4e155464e03e.err \ $(srcdir)/%reldir%/test_sql.sh_753c343a256d1286750314957d1b4e155464e03e.err \
$(srcdir)/%reldir%/test_sql.sh_753c343a256d1286750314957d1b4e155464e03e.out \ $(srcdir)/%reldir%/test_sql.sh_753c343a256d1286750314957d1b4e155464e03e.out \
$(srcdir)/%reldir%/test_sql.sh_764306f0e5f610ba71f521ba3d19fe158ece0ba5.err \
$(srcdir)/%reldir%/test_sql.sh_764306f0e5f610ba71f521ba3d19fe158ece0ba5.out \
$(srcdir)/%reldir%/test_sql.sh_764ea85863d4f0ea3b7cb40850ac7c8fde682d57.err \ $(srcdir)/%reldir%/test_sql.sh_764ea85863d4f0ea3b7cb40850ac7c8fde682d57.err \
$(srcdir)/%reldir%/test_sql.sh_764ea85863d4f0ea3b7cb40850ac7c8fde682d57.out \ $(srcdir)/%reldir%/test_sql.sh_764ea85863d4f0ea3b7cb40850ac7c8fde682d57.out \
$(srcdir)/%reldir%/test_sql.sh_7f664c9cda0ae1c48333e21051b5e0eeafd5b4bc.err \ $(srcdir)/%reldir%/test_sql.sh_7f664c9cda0ae1c48333e21051b5e0eeafd5b4bc.err \
@ -484,6 +488,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_sql.sh_c20b0320096342c180146a5d18a6de82319d70b2.out \ $(srcdir)/%reldir%/test_sql.sh_c20b0320096342c180146a5d18a6de82319d70b2.out \
$(srcdir)/%reldir%/test_sql.sh_c353ef036c505b75996252138fbd4c8d22e8149c.err \ $(srcdir)/%reldir%/test_sql.sh_c353ef036c505b75996252138fbd4c8d22e8149c.err \
$(srcdir)/%reldir%/test_sql.sh_c353ef036c505b75996252138fbd4c8d22e8149c.out \ $(srcdir)/%reldir%/test_sql.sh_c353ef036c505b75996252138fbd4c8d22e8149c.out \
$(srcdir)/%reldir%/test_sql.sh_c5b8da04734fadf3b9eea80e0af997e38e0fb811.err \
$(srcdir)/%reldir%/test_sql.sh_c5b8da04734fadf3b9eea80e0af997e38e0fb811.out \
$(srcdir)/%reldir%/test_sql.sh_c73dec2706fc0b9a124f5da3a83f40d8d3255beb.err \ $(srcdir)/%reldir%/test_sql.sh_c73dec2706fc0b9a124f5da3a83f40d8d3255beb.err \
$(srcdir)/%reldir%/test_sql.sh_c73dec2706fc0b9a124f5da3a83f40d8d3255beb.out \ $(srcdir)/%reldir%/test_sql.sh_c73dec2706fc0b9a124f5da3a83f40d8d3255beb.out \
$(srcdir)/%reldir%/test_sql.sh_c7e1dbf4605914720b55787785abfafdf2c4178a.err \ $(srcdir)/%reldir%/test_sql.sh_c7e1dbf4605914720b55787785abfafdf2c4178a.err \
@ -506,6 +512,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_sql.sh_f8340cb4c62aabd839ea09235b6ebe41b2bb48f4.out \ $(srcdir)/%reldir%/test_sql.sh_f8340cb4c62aabd839ea09235b6ebe41b2bb48f4.out \
$(srcdir)/%reldir%/test_sql_anno.sh_028d5d5af2f3519b59d349d41cb7ecf385253b51.err \ $(srcdir)/%reldir%/test_sql_anno.sh_028d5d5af2f3519b59d349d41cb7ecf385253b51.err \
$(srcdir)/%reldir%/test_sql_anno.sh_028d5d5af2f3519b59d349d41cb7ecf385253b51.out \ $(srcdir)/%reldir%/test_sql_anno.sh_028d5d5af2f3519b59d349d41cb7ecf385253b51.out \
$(srcdir)/%reldir%/test_sql_anno.sh_08f137b4b2e1dcc15efa8c0164a13e5db4e8856b.err \
$(srcdir)/%reldir%/test_sql_anno.sh_08f137b4b2e1dcc15efa8c0164a13e5db4e8856b.out \
$(srcdir)/%reldir%/test_sql_anno.sh_0a37c43350ddd7a2d0d75695be32fac083ad04a4.err \ $(srcdir)/%reldir%/test_sql_anno.sh_0a37c43350ddd7a2d0d75695be32fac083ad04a4.err \
$(srcdir)/%reldir%/test_sql_anno.sh_0a37c43350ddd7a2d0d75695be32fac083ad04a4.out \ $(srcdir)/%reldir%/test_sql_anno.sh_0a37c43350ddd7a2d0d75695be32fac083ad04a4.out \
$(srcdir)/%reldir%/test_sql_anno.sh_1151e5b727f6b57070bf2c8f047f1d7e02b803a6.err \ $(srcdir)/%reldir%/test_sql_anno.sh_1151e5b727f6b57070bf2c8f047f1d7e02b803a6.err \
@ -606,6 +614,10 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_sql_fs_func.sh_e24cf3f35643f945392e7d7a4ca82fea98b4519e.out \ $(srcdir)/%reldir%/test_sql_fs_func.sh_e24cf3f35643f945392e7d7a4ca82fea98b4519e.out \
$(srcdir)/%reldir%/test_sql_fs_func.sh_f31f240313ddec806aa6f353ceed707dfd9aaf16.err \ $(srcdir)/%reldir%/test_sql_fs_func.sh_f31f240313ddec806aa6f353ceed707dfd9aaf16.err \
$(srcdir)/%reldir%/test_sql_fs_func.sh_f31f240313ddec806aa6f353ceed707dfd9aaf16.out \ $(srcdir)/%reldir%/test_sql_fs_func.sh_f31f240313ddec806aa6f353ceed707dfd9aaf16.out \
$(srcdir)/%reldir%/test_sql_indexes.sh_52a024607c9339423b749ac1a2eb3e49fe9776e5.err \
$(srcdir)/%reldir%/test_sql_indexes.sh_52a024607c9339423b749ac1a2eb3e49fe9776e5.out \
$(srcdir)/%reldir%/test_sql_indexes.sh_5815cff21c4a1b7c4a976b5574eb930b2605cd2f.err \
$(srcdir)/%reldir%/test_sql_indexes.sh_5815cff21c4a1b7c4a976b5574eb930b2605cd2f.out \
$(srcdir)/%reldir%/test_sql_json_func.sh_017d24148f3e28f719429b709f4aa5478f458443.err \ $(srcdir)/%reldir%/test_sql_json_func.sh_017d24148f3e28f719429b709f4aa5478f458443.err \
$(srcdir)/%reldir%/test_sql_json_func.sh_017d24148f3e28f719429b709f4aa5478f458443.out \ $(srcdir)/%reldir%/test_sql_json_func.sh_017d24148f3e28f719429b709f4aa5478f458443.out \
$(srcdir)/%reldir%/test_sql_json_func.sh_191436b38db80b1dd9e7e0814c31c5fa7239dc51.err \ $(srcdir)/%reldir%/test_sql_json_func.sh_191436b38db80b1dd9e7e0814c31c5fa7239dc51.err \
@ -674,6 +686,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_sql_json_func.sh_f34205b59e04f261897ad89f659595c743a18ca9.out \ $(srcdir)/%reldir%/test_sql_json_func.sh_f34205b59e04f261897ad89f659595c743a18ca9.out \
$(srcdir)/%reldir%/test_sql_json_func.sh_f34f5dfa938a1ac7721f924beb16bbceec127a1b.err \ $(srcdir)/%reldir%/test_sql_json_func.sh_f34f5dfa938a1ac7721f924beb16bbceec127a1b.err \
$(srcdir)/%reldir%/test_sql_json_func.sh_f34f5dfa938a1ac7721f924beb16bbceec127a1b.out \ $(srcdir)/%reldir%/test_sql_json_func.sh_f34f5dfa938a1ac7721f924beb16bbceec127a1b.out \
$(srcdir)/%reldir%/test_sql_search_table.sh_df0fd242f57a96d40f466493938cda0789a094fa.err \
$(srcdir)/%reldir%/test_sql_search_table.sh_df0fd242f57a96d40f466493938cda0789a094fa.out \
$(srcdir)/%reldir%/test_sql_str_func.sh_005b9365ac99596e539f47c9fe432668c209b21f.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_005b9365ac99596e539f47c9fe432668c209b21f.err \
$(srcdir)/%reldir%/test_sql_str_func.sh_005b9365ac99596e539f47c9fe432668c209b21f.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_005b9365ac99596e539f47c9fe432668c209b21f.out \
$(srcdir)/%reldir%/test_sql_str_func.sh_04712488fe50554eb36d3ced80f9a033602f3daa.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_04712488fe50554eb36d3ced80f9a033602f3daa.err \
@ -714,6 +728,8 @@ EXPECTED_FILES = \
$(srcdir)/%reldir%/test_sql_str_func.sh_660288b48d9b30244621d873944938f7ef043976.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_660288b48d9b30244621d873944938f7ef043976.out \
$(srcdir)/%reldir%/test_sql_str_func.sh_6607c0dd8baff16930eb3e0daf6354af5b50052b.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_6607c0dd8baff16930eb3e0daf6354af5b50052b.err \
$(srcdir)/%reldir%/test_sql_str_func.sh_6607c0dd8baff16930eb3e0daf6354af5b50052b.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_6607c0dd8baff16930eb3e0daf6354af5b50052b.out \
$(srcdir)/%reldir%/test_sql_str_func.sh_69f5d49e62da48e188bd9d6af4bd3adeb21eb7d1.err \
$(srcdir)/%reldir%/test_sql_str_func.sh_69f5d49e62da48e188bd9d6af4bd3adeb21eb7d1.out \
$(srcdir)/%reldir%/test_sql_str_func.sh_71f37db33504b2c08a7a3323c482556f53d88100.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_71f37db33504b2c08a7a3323c482556f53d88100.err \
$(srcdir)/%reldir%/test_sql_str_func.sh_71f37db33504b2c08a7a3323c482556f53d88100.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_71f37db33504b2c08a7a3323c482556f53d88100.out \
$(srcdir)/%reldir%/test_sql_str_func.sh_77fc174faeec1eda687a9373dbdbdd1aaef56e20.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_77fc174faeec1eda687a9373dbdbdd1aaef56e20.err \

@ -1,6 +1,6 @@
✘ error: filter expression failed with: unable to parse time slice value: bad -- Unrecognized input ✘ error: filter expression failed with: unable to parse time slice value: bad -- Unrecognized input
 --> command-option:1  --> command-option:1
 | :filter-expr timeslice(:log_time_msecs, 'bad') is not null  | :filter-expr timeslice(:log_time_msecs, 'bad') is not null
 = help: :filter-expr expr  = help: :filter-expr expr
══════════════════════════════════════════════════════════════════════ ══════════════════════════════════════════════════════════════════════
Set the filter expression Set the filter expression

@ -1,4 +1,4 @@
✘ error: invalid filter expression: :sc_bytes # ff ✘ error: invalid filter expression: :sc_bytes # ff
reason: unrecognized token: "#" reason: unrecognized token: "#"
 --> command-option:1  --> command-option:1
 | :filter-expr :sc_bytes # ff   | :filter-expr :sc_bytes # ff 

@ -966,12 +966,12 @@ lnav@googlegroups.com[1] support@lnav.org[2]
:hide-lines-before, :hide-unmarked-lines, :toggle-filtering :hide-lines-before, :hide-unmarked-lines, :toggle-filtering
Examples Examples
#1 To set a filter expression that matched syslog messages from 'syslogd': #1 To set a filter expression that matched syslog messages from 'syslogd':
:filter-expr :log_procname = 'syslogd'  :filter-expr :log_procname = 'syslogd' 
#2 To set a filter expression that matches log messages where 'id' is followed by a #2 To set a filter expression that matches log messages where 'id' is followed by a
number and contains the string 'foo': number and contains the string 'foo':
:filter-expr :log_body REGEXP 'id\d+' AND :log_body REGEXP 'foo' :filter-expr :log_body REGEXP 'id\d+' AND :log_body REGEXP 'foo'
@ -1140,7 +1140,7 @@ lnav@googlegroups.com[1] support@lnav.org[2]
:clear-mark-expr, :hide-unmarked-lines, :mark, :next-mark, :prev-mark :clear-mark-expr, :hide-unmarked-lines, :mark, :next-mark, :prev-mark
Example Example
#1 To mark lines from 'dhclient' that mention 'eth0': #1 To mark lines from 'dhclient' that mention 'eth0':
:mark-expr :log_procname = 'dhclient' AND :log_body LIKE '%eth0%' :mark-expr :log_procname = 'dhclient' AND :log_body LIKE '%eth0%'
@ -1958,10 +1958,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
charindex(), endswith(), extract(), group_concat(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
substr(), trim(), unicode(), upper(), xpath() spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(),
upper(), xpath()
Example Example
#1 To get a string with the code points 0x48 and 0x49: #1 To get a string with the code points 0x48 and 0x49:
;SELECT char(0x48, 0x49)  ;SELECT char(0x48, 0x49) 
@ -1982,10 +1983,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), endswith(), extract(), group_concat(), group_spooky_hash(), char(), endswith(), extract(), group_concat(), group_spooky_hash(),
gunzip(), gzip(), humanize_file_size(), instr(), leftstr(), length(), gunzip(), gzip(), humanize_file_size(), instr(), leftstr(), length(),
logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(),
proper(), regexp_capture(), regexp_match(), regexp_replace(), proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_replace(), replace(), replicate(), reverse(), rightstr(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(),
upper(), xpath() substr(), trim(), unicode(), upper(), xpath()
Examples Examples
#1 To search for the string 'abc' within 'abcabc' and starting at position 2: #1 To search for the string 'abc' within 'abcabc' and starting at position 2:
;SELECT charindex('abc', 'abcabc', 2)  ;SELECT charindex('abc', 'abcabc', 2) 
@ -2143,10 +2144,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), extract(), group_concat(), group_spooky_hash(), char(), charindex(), extract(), group_concat(), group_spooky_hash(),
gunzip(), gzip(), humanize_file_size(), instr(), leftstr(), length(), gunzip(), gzip(), humanize_file_size(), instr(), leftstr(), length(),
logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(),
proper(), regexp_capture(), regexp_match(), regexp_replace(), proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_replace(), replace(), replicate(), reverse(), rightstr(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(),
upper(), xpath() substr(), trim(), unicode(), upper(), xpath()
Examples Examples
#1 To test if the string 'notbad.jpg' ends with '.jpg': #1 To test if the string 'notbad.jpg' ends with '.jpg':
;SELECT endswith('notbad.jpg', '.jpg')  ;SELECT endswith('notbad.jpg', '.jpg') 
@ -2182,10 +2183,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), group_concat(), group_spooky_hash(), char(), charindex(), endswith(), group_concat(), group_spooky_hash(),
gunzip(), gzip(), humanize_file_size(), instr(), leftstr(), length(), gunzip(), gzip(), humanize_file_size(), instr(), leftstr(), length(),
logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(),
proper(), regexp_capture(), regexp_match(), regexp_replace(), proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_replace(), replace(), replicate(), reverse(), rightstr(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(),
upper(), xpath() substr(), trim(), unicode(), upper(), xpath()
Examples Examples
#1 To extract key/value pairs from a string: #1 To extract key/value pairs from a string:
;SELECT extract('foo=1 bar=2 name="Rolo Tomassi"')  ;SELECT extract('foo=1 bar=2 name="Rolo Tomassi"') 
@ -2296,10 +2297,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_spooky_hash(), char(), charindex(), endswith(), extract(), group_spooky_hash(),
gunzip(), gzip(), humanize_file_size(), instr(), leftstr(), length(), gunzip(), gzip(), humanize_file_size(), instr(), leftstr(), length(),
logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(),
proper(), regexp_capture(), regexp_match(), regexp_replace(), proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_replace(), replace(), replicate(), reverse(), rightstr(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(),
upper(), xpath() substr(), trim(), unicode(), upper(), xpath()
Examples Examples
#1 To concatenate the values of the column 'ex_procname' from the table #1 To concatenate the values of the column 'ex_procname' from the table
'lnav_example_log': 'lnav_example_log':
@ -2325,10 +2326,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), gunzip(), char(), charindex(), endswith(), extract(), group_concat(), gunzip(),
gzip(), humanize_file_size(), instr(), leftstr(), length(), gzip(), humanize_file_size(), instr(), leftstr(), length(),
logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(),
proper(), regexp_capture(), regexp_match(), regexp_replace(), proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_replace(), replace(), replicate(), reverse(), rightstr(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(),
upper(), xpath() substr(), trim(), unicode(), upper(), xpath()
Example Example
#1 To produce a hash of all of the values of 'column1': #1 To produce a hash of all of the values of 'column1':
;SELECT group_spooky_hash(column1) FROM (VALUES ('abc'), ('123')) ;SELECT group_spooky_hash(column1) FROM (VALUES ('abc'), ('123'))
@ -2344,10 +2345,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gzip(), humanize_file_size(), instr(), leftstr(), group_spooky_hash(), gzip(), humanize_file_size(), instr(), leftstr(),
length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(),
printf(), proper(), regexp_capture(), regexp_match(), regexp_replace(), printf(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
gzip(value, ...) gzip(value, ...)
══════════════════════════════════════════════════════════════════════ ══════════════════════════════════════════════════════════════════════
@ -2358,10 +2359,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
substr(), trim(), unicode(), upper(), xpath() spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(),
upper(), xpath()
hex(X) hex(X)
══════════════════════════════════════════════════════════════════════ ══════════════════════════════════════════════════════════════════════
@ -2385,10 +2387,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), instr(), leftstr(), length(), group_spooky_hash(), gunzip(), gzip(), instr(), leftstr(), length(),
logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(),
proper(), regexp_capture(), regexp_match(), regexp_replace(), proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_replace(), replace(), replicate(), reverse(), rightstr(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(),
upper(), xpath() substr(), trim(), unicode(), upper(), xpath()
Example Example
#1 To format an amount: #1 To format an amount:
;SELECT humanize_file_size(10 * 1024 * 1024)  ;SELECT humanize_file_size(10 * 1024 * 1024) 
@ -2421,10 +2423,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), leftstr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), leftstr(),
length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(),
printf(), proper(), regexp_capture(), regexp_match(), regexp_replace(), printf(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Example Example
#1 To test get the position of 'b' in the string 'abc': #1 To test get the position of 'b' in the string 'abc':
;SELECT instr('abc', 'b')  ;SELECT instr('abc', 'b') 
@ -2640,10 +2642,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(),
printf(), proper(), regexp_capture(), regexp_match(), regexp_replace(), printf(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Examples Examples
#1 To get the first character of the string 'abc': #1 To get the first character of the string 'abc':
;SELECT leftstr('abc', 1)  ;SELECT leftstr('abc', 1) 
@ -2664,10 +2666,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), leftstr(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(),
printf(), proper(), regexp_capture(), regexp_match(), regexp_replace(), printf(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Example Example
#1 To get the length of the string 'abc': #1 To get the length of the string 'abc':
;SELECT length('abc')  ;SELECT length('abc') 
@ -2783,10 +2785,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), lower(), ltrim(), padc(), padl(), padr(), leftstr(), length(), lower(), ltrim(), padc(), padl(), padr(),
printf(), proper(), regexp_capture(), regexp_match(), regexp_replace(), printf(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Example Example
#1 To extract key/value pairs from a log message: #1 To extract key/value pairs from a log message:
;SELECT logfmt2json('foo=1 bar=2 name="Rolo Tomassi"') ;SELECT logfmt2json('foo=1 bar=2 name="Rolo Tomassi"')
@ -2803,10 +2805,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), ltrim(), padc(), padl(), padr(), leftstr(), length(), logfmt2json(), ltrim(), padc(), padl(), padr(),
printf(), proper(), regexp_capture(), regexp_match(), regexp_replace(), printf(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Example Example
#1 To lowercase the string 'AbC': #1 To lowercase the string 'AbC':
;SELECT lower('AbC')  ;SELECT lower('AbC') 
@ -2824,10 +2826,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), padc(), padl(), padr(), leftstr(), length(), logfmt2json(), lower(), padc(), padl(), padr(),
printf(), proper(), regexp_capture(), regexp_match(), regexp_replace(), printf(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Examples Examples
#1 To trim the leading whitespace from the string ' abc': #1 To trim the leading whitespace from the string ' abc':
;SELECT ltrim(' abc')  ;SELECT ltrim(' abc') 
@ -2931,10 +2933,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padl(), padr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padl(), padr(),
printf(), proper(), regexp_capture(), regexp_match(), regexp_replace(), printf(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Examples Examples
#1 To pad the string 'abc' to a length of six characters: #1 To pad the string 'abc' to a length of six characters:
;SELECT padc('abc', 6) || 'def'  ;SELECT padc('abc', 6) || 'def' 
@ -2956,10 +2958,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padr(),
printf(), proper(), regexp_capture(), regexp_match(), regexp_replace(), printf(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Examples Examples
#1 To pad the string 'abc' to a length of six characters: #1 To pad the string 'abc' to a length of six characters:
;SELECT padl('abc', 6)  ;SELECT padl('abc', 6) 
@ -2981,10 +2983,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
printf(), proper(), regexp_capture(), regexp_match(), regexp_replace(), printf(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Examples Examples
#1 To pad the string 'abc' to a length of six characters: #1 To pad the string 'abc' to a length of six characters:
;SELECT padr('abc', 6) || 'def'  ;SELECT padr('abc', 6) || 'def' 
@ -3046,10 +3048,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), proper(), regexp_capture(), regexp_match(), regexp_replace(), padr(), proper(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Examples Examples
#1 To substitute 'World' into the string 'Hello, %s!': #1 To substitute 'World' into the string 'Hello, %s!':
;SELECT printf('Hello, %s!', 'World')  ;SELECT printf('Hello, %s!', 'World') 
@ -3073,10 +3075,10 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), regexp_capture(), regexp_match(), regexp_replace(), padr(), printf(), regexp_capture(), regexp_capture_into_json(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(),
upper(), xpath() strfilter(), substr(), trim(), unicode(), upper(), xpath()
Example Example
#1 To capitalize the words in the string 'hello, world!': #1 To capitalize the words in the string 'hello, world!':
;SELECT proper('hello, world!')  ;SELECT proper('hello, world!') 
@ -3195,16 +3197,44 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_match(), regexp_replace(), padr(), printf(), proper(), regexp_capture_into_json(), regexp_match(),
replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), regexp_replace(), replace(), replicate(), reverse(), rightstr(),
spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(),
upper(), xpath() substr(), trim(), unicode(), upper(), xpath()
Example Example
#1 To extract the key/value pairs 'a'/1 and 'b'/2 from the string 'a=1; b=2': #1 To extract the key/value pairs 'a'/1 and 'b'/2 from the string 'a=1; b=2':
;SELECT * FROM regexp_capture('a=1; b=2', '(\w+)=(\d+)') ;SELECT * FROM regexp_capture('a=1; b=2', '(\w+)=(\d+)')
regexp_capture_into_json(string, pattern)
══════════════════════════════════════════════════════════════════════
A table-valued function that executes a regular-expression over a
string and returns the captured values as a JSON object. If the
regex only matches a subset of the input string, it will be rerun on
the remaining parts of the string until no more matches are found.
Parameters
string The string to match against the given pattern.
pattern The regular expression to match.
Results
match_index The match iteration. This value will
increase each time a new match is found in the input
string.
content The captured values from the string.
See Also
char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(),
rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(),
substr(), trim(), unicode(), upper(), xpath()
Example
#1 To extract the key/value pairs 'a'/1 and 'b'/2 from the string 'a=1; b=2':
;SELECT * FROM regexp_capture_into_json('a=1; b=2', '(\w+)=(\d+)')
regexp_match(re, str) regexp_match(re, str)
══════════════════════════════════════════════════════════════════════ ══════════════════════════════════════════════════════════════════════
Match a string against a regular expression and return the capture Match a string against a regular expression and return the capture
@ -3216,10 +3246,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_replace(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_replace(), regexp_replace(),
rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
substr(), trim(), unicode(), upper(), xpath() spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(),
upper(), xpath()
Examples Examples
#1 To capture the digits from the string '123': #1 To capture the digits from the string '123':
;SELECT regexp_match('(\d+)', '123')  ;SELECT regexp_match('(\d+)', '123') 
@ -3249,10 +3280,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_match(), replace(), replicate(), reverse(), rightstr(), rtrim(), regexp_capture_into_json(), regexp_match(), regexp_match(), replace(),
sparkline(), spooky_hash(), startswith(), strfilter(), substr(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
trim(), unicode(), upper(), xpath() spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(),
upper(), xpath()
Examples Examples
#1 To replace the word at the start of the string 'Hello, World!' with 'Goodbye': #1 To replace the word at the start of the string 'Hello, World!' with 'Goodbye':
;SELECT regexp_replace('Hello, World!', '^(\w+)', 'Goodbye') ;SELECT regexp_replace('Hello, World!', '^(\w+)', 'Goodbye')
@ -3276,10 +3308,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replicate(), reverse(), rightstr(), rtrim(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
sparkline(), spooky_hash(), startswith(), strfilter(), substr(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
trim(), unicode(), upper(), xpath() spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(),
upper(), xpath()
Examples Examples
#1 To replace the string 'x' with 'z' in 'abc': #1 To replace the string 'x' with 'z' in 'abc':
;SELECT replace('abc', 'x', 'z')  ;SELECT replace('abc', 'x', 'z') 
@ -3300,10 +3333,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), reverse(), rightstr(), rtrim(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
sparkline(), spooky_hash(), startswith(), strfilter(), substr(), replace(), reverse(), rightstr(), rtrim(), sparkline(), spooky_hash(),
trim(), unicode(), upper(), xpath() startswith(), strfilter(), substr(), trim(), unicode(), upper(),
xpath()
Example Example
#1 To repeat the string 'abc' three times: #1 To repeat the string 'abc' three times:
;SELECT replicate('abc', 3)  ;SELECT replicate('abc', 3) 
@ -3319,10 +3353,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), rightstr(), rtrim(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
sparkline(), spooky_hash(), startswith(), strfilter(), substr(), replace(), replicate(), rightstr(), rtrim(), sparkline(),
trim(), unicode(), upper(), xpath() spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(),
upper(), xpath()
Example Example
#1 To reverse the string 'abc': #1 To reverse the string 'abc':
;SELECT reverse('abc')  ;SELECT reverse('abc') 
@ -3340,10 +3375,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rtrim(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
sparkline(), spooky_hash(), startswith(), strfilter(), substr(), replace(), replicate(), reverse(), rtrim(), sparkline(), spooky_hash(),
trim(), unicode(), upper(), xpath() startswith(), strfilter(), substr(), trim(), unicode(), upper(),
xpath()
Examples Examples
#1 To get the last character of the string 'abc': #1 To get the last character of the string 'abc':
;SELECT rightstr('abc', 1)  ;SELECT rightstr('abc', 1) 
@ -3406,10 +3442,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
sparkline(), spooky_hash(), startswith(), strfilter(), substr(), replace(), replicate(), reverse(), rightstr(), sparkline(),
trim(), unicode(), upper(), xpath() spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(),
upper(), xpath()
Examples Examples
#1 To trim the whitespace from the end of the string 'abc ': #1 To trim the whitespace from the end of the string 'abc ':
;SELECT rtrim('abc ')  ;SELECT rtrim('abc ') 
@ -3459,10 +3496,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), spooky_hash(), startswith(), strfilter(), substr(), trim(), replace(), replicate(), reverse(), rightstr(), rtrim(), spooky_hash(),
unicode(), upper(), xpath() startswith(), strfilter(), substr(), trim(), unicode(), upper(),
xpath()
Examples Examples
#1 To get the unicode block element for the value 32 in the range of 0-128: #1 To get the unicode block element for the value 32 in the range of 0-128:
;SELECT sparkline(32, 128)  ;SELECT sparkline(32, 128) 
@ -3482,10 +3520,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), sparkline(), startswith(), strfilter(), substr(), trim(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
unicode(), upper(), xpath() startswith(), strfilter(), substr(), trim(), unicode(), upper(),
xpath()
Examples Examples
#1 To produce a hash for the string 'Hello, World!': #1 To produce a hash for the string 'Hello, World!':
;SELECT spooky_hash('Hello, World!')  ;SELECT spooky_hash('Hello, World!') 
@ -3562,10 +3601,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), sparkline(), spooky_hash(), strfilter(), substr(), trim(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
unicode(), upper(), xpath() spooky_hash(), strfilter(), substr(), trim(), unicode(), upper(),
xpath()
Examples Examples
#1 To test if the string 'foobar' starts with 'foo': #1 To test if the string 'foobar' starts with 'foo':
;SELECT startswith('foobar', 'foo')  ;SELECT startswith('foobar', 'foo') 
@ -3587,10 +3627,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), sparkline(), spooky_hash(), startswith(), substr(), trim(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
unicode(), upper(), xpath() spooky_hash(), startswith(), substr(), trim(), unicode(), upper(),
xpath()
Example Example
#1 To get the 'b', 'c', and 'd' characters from the string 'abcabc': #1 To get the 'b', 'c', and 'd' characters from the string 'abcabc':
;SELECT strfilter('abcabc', 'bcd')  ;SELECT strfilter('abcabc', 'bcd') 
@ -3642,10 +3683,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), trim(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
unicode(), upper(), xpath() spooky_hash(), startswith(), strfilter(), trim(), unicode(), upper(),
xpath()
Examples Examples
#1 To get the substring starting at the second character until the end of the string #1 To get the substring starting at the second character until the end of the string
'abc': 'abc':
@ -3787,10 +3829,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
substr(), unicode(), upper(), xpath() spooky_hash(), startswith(), strfilter(), substr(), unicode(), upper(),
xpath()
Examples Examples
#1 To trim whitespace from the start and end of the string ' abc ': #1 To trim whitespace from the start and end of the string ' abc ':
;SELECT trim(' abc ')  ;SELECT trim(' abc ') 
@ -3828,10 +3871,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
substr(), trim(), upper(), xpath() spooky_hash(), startswith(), strfilter(), substr(), trim(), upper(),
xpath()
Example Example
#1 To get the unicode code point for the first character of 'abc': #1 To get the unicode code point for the first character of 'abc':
;SELECT unicode('abc')  ;SELECT unicode('abc') 
@ -3855,10 +3899,11 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
substr(), trim(), unicode(), xpath() spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(),
xpath()
Example Example
#1 To uppercase the string 'aBc': #1 To uppercase the string 'aBc':
;SELECT upper('aBc')  ;SELECT upper('aBc') 
@ -3883,21 +3928,22 @@ lnav@googlegroups.com[1] support@lnav.org[2]
char(), charindex(), endswith(), extract(), group_concat(), char(), charindex(), endswith(), extract(), group_concat(),
group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(),
leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(),
padr(), printf(), proper(), regexp_capture(), regexp_match(), padr(), printf(), proper(), regexp_capture(),
regexp_replace(), replace(), replicate(), reverse(), rightstr(), regexp_capture_into_json(), regexp_match(), regexp_replace(),
rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(),
substr(), trim(), unicode(), upper() spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(),
upper()
Examples Examples
#1 To select the XML nodes on the path '/abc/def': #1 To select the XML nodes on the path '/abc/def':
;SELECT * FROM xpath('/abc/def', '<abc><def a="b">Hello</def><def>Bye</def></abc>') ;SELECT * FROM xpath('/abc/def', '<abc><def a="b">Hello</def><def>Bye</def></abc>')
#2 To select all 'a' attributes on the path '/abc/def': #2 To select all 'a' attributes on the path '/abc/def':
;SELECT * FROM xpath('/abc/def/@a', '<abc><def a="b">Hello</def><def>Bye</def></abc>') ;SELECT * FROM xpath('/abc/def/@a', '<abc><def a="b">Hello</def><def>Bye</def></abc>')
#3 To select the text nodes on the path '/abc/def': #3 To select the text nodes on the path '/abc/def':
;SELECT * FROM xpath('/abc/def/text()', '<abc><def a="b">Hello &#x2605;</def></abc>') ;SELECT * FROM xpath('/abc/def/text()', '<abc><def a="b">Hello &#x2605;</def></abc>')

@ -1,4 +1,4 @@
✘ error: invalid mark expression: :log_procname lik ✘ error: invalid mark expression: :log_procname lik
reason: near "lik": syntax error reason: near "lik": syntax error
 --> command-option:1  --> command-option:1
 | :mark-expr :log_procname lik   | :mark-expr :log_procname lik 

@ -1,3 +1,3 @@
log_line log_part log_time log_idle_msecs log_level log_mark log_comment log_tags log_filters log_msg_instance col_0 col_1 log_line log_part log_time log_idle_msecs log_level log_mark log_comment log_tags log_filters col_0 col_1
0 <NULL> 2021-05-19 08:00:01.000 0 info 0 <NULL> <NULL> <NULL> 0 1.0 /abc/def 0 <NULL> 2021-05-19 08:00:01.000 0 info 0 <NULL> <NULL> <NULL> 1.0 /abc/def
2 <NULL> 2021-05-19 08:00:03.000 2000 info 0 <NULL> <NULL> <NULL> 1 3.0 /ghi/jkl 2 <NULL> 2021-05-19 08:00:03.000 2000 info 0 <NULL> <NULL> <NULL> 3.0 /ghi/jkl

@ -0,0 +1,2 @@
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,log_filters,log_hostname,log_msgid,log_pid,log_pri,log_procname,log_struct,log_syslog_tag,syslog_version,col_0,TTY,PWD,USER,COMMAND
0,<NULL>,2007-11-03 09:47:02.000,0,info,0,<NULL>,<NULL>,[1],veridian,<NULL>,<NULL>,<NULL>,sudo,<NULL>,sudo,<NULL>,timstack,pts/6,/auto/wstimstack/rpms/lbuild/test,root,/usr/bin/tail /var/log/messages

@ -0,0 +1,3 @@
log_line  col_0 
 0 eth0.IPv4 
7 eth0.IPv4

@ -0,0 +1,11 @@
SELECT * from vmw_log, regexp_capture(log_body, '--> /SessionStats/SessionPool/Session/(?<line>[^\n]+)')
sql_keyword ------
sql_oper -
sql_keyword ----
sql_ident -------
sql_comma -
sql_ident --------------
sql_func --------------------------------------------------------------------------------
sql_ident --------
sql_comma -
sql_string -------------------------------------------------------

@ -0,0 +1,2 @@
id parent notused  detail 
 2  0  0 SCAN syslog_log VIRTUAL TABLE INDEX 1:SEARCH syslog_log USING log_path GLOB ? 

@ -0,0 +1,12 @@
log_line log_part  log_time log_idle_msecs log_level log_mark log_comment log_tags log_filters log_hostname log_msgid log_pid log_pri log_procname log_struct  log_syslog_tag syslog_version 
 0  <NULL> 2006-12-03 09:23:38.000  0 error   0  <NULL>  <NULL>  <NULL> veridian   <NULL> 7998   <NULL> automount   <NULL> automount[7998]   <NULL> 
1 <NULL> 2006-12-03 09:23:38.000 0 info 0 <NULL> <NULL> <NULL> veridian <NULL> 16442 <NULL> automount <NULL> automount[16442] <NULL>
 2  <NULL> 2006-12-03 09:23:38.000  0 error   0  <NULL>  <NULL>  <NULL> veridian   <NULL> 7999   <NULL> automount   <NULL> automount[7999]   <NULL> 
  3 <NULL> 2007-01-03 09:47:02.000 2679804000 info 0 <NULL> <NULL> <NULL> veridian <NULL> <NULL> <NULL> sudo <NULL> sudo <NULL>
 4  <NULL> 2007-11-03 09:23:38.000  26264196000 error   0  <NULL>  <NULL>  <NULL> veridian   <NULL> 7998   <NULL> automount   <NULL> automount[7998]   <NULL> 
5 <NULL> 2007-11-03 09:23:38.000 0 info 0 <NULL> <NULL> <NULL> veridian <NULL> 16442 <NULL> automount <NULL> automount[16442] <NULL>
 6  <NULL> 2007-11-03 09:23:38.000  0 error   0  <NULL>  <NULL>  <NULL> veridian   <NULL> 7999   <NULL> automount   <NULL> automount[7999]   <NULL> 
  7 <NULL> 2007-11-03 09:47:02.000 1404000 info 0 <NULL> <NULL> <NULL> veridian <NULL> <NULL> <NULL> sudo <NULL> sudo <NULL>
 8  <NULL> 2021-11-03 09:23:38.000  441848196000 info   0  <NULL>  <NULL>  <NULL> veridian   <NULL> 7998   <NULL> foo   <NULL> foo[7998]   <NULL> 
9 <NULL> 2021-11-03 09:23:38.000 0 info 0 <NULL> <NULL> <NULL> veridian <NULL> 16442 <NULL> foo <NULL> foo[16442] <NULL>
 10  <NULL> 2021-11-03 09:23:38.000  0 info   0  <NULL>  <NULL>  <NULL> veridian   <NULL> 7999   <NULL> foo   <NULL> foo[7999]   <NULL> 

@ -0,0 +1,6 @@
Row 0:
Column match_index: 0
Column content: {"col_0":1,"col_1":2}
Row 1:
Column match_index: 1
Column content: {"col_0":3,"col_1":4}

@ -0,0 +1,43 @@
========== Start of system state dump at Thu Jun 2 00:01:01 UTC 2022 ==========
/bin/ps auxww
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 158392 7792 ? Ss Jun01 0:14 /lib/systemd/systemd --switched-root --system --deserialize 16
root 2 0.0 0.0 0 0 ? S Jun01 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< Jun01 0:00 [rcu_gp]
root 4 0.0 0.0 0 0 ? I< Jun01 0:00 [rcu_par_gp]
root 6 0.0 0.0 0 0 ? I< Jun01 0:00 [kworker/0:0H-kblockd]
========== End of system state dump ==========
========== Start of system state dump at Thu Jun 2 00:02:01 UTC 2022 ==========
/bin/ps auxww
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 158392 7792 ? Ss Jun01 0:14 /lib/systemd/systemd --switched-root --system --deserialize 16
root 2 0.0 0.0 0 0 ? S Jun01 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< Jun01 0:00 [rcu_gp]
root 4 0.0 0.0 0 0 ? I< Jun01 0:00 [rcu_par_gp]
root 6 0.0 0.0 0 0 ? I< Jun01 0:00 [kworker/0:0H-kblockd]
root 8 0.0 0.0 0 0 ? I< Jun01 0:00 [mm_percpu_wq]
root 9 0.0 0.0 0 0 ? S Jun01 0:00 [ksoftirqd/0]
root 10 0.0 0.0 0 0 ? I Jun01 0:23 [rcu_sched]
root 11 0.0 0.0 0 0 ? I Jun01 0:00 [rcu_bh]
root 12 0.0 0.0 0 0 ? S Jun01 0:00 [migration/0]
root 14 0.0 0.0 0 0 ? S Jun01 0:00 [cpuhp/0]
========== End of system state dump ==========
========== Start of system state dump at Thu Jun 2 00:03:01 UTC 2022 ==========
/bin/ps auxww
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 158392 7792 ? Ss Jun01 0:14 /lib/systemd/systemd --switched-root --system --deserialize 16
root 2 0.0 0.0 0 0 ? S Jun01 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< Jun01 0:00 [rcu_gp]
root 4 0.0 0.0 0 0 ? I< Jun01 0:00 [rcu_par_gp]
root 6 0.0 0.0 0 0 ? I< Jun01 0:00 [kworker/0:0H-kblockd]
root 8 0.0 0.0 0 0 ? I< Jun01 0:00 [mm_percpu_wq]
root 9 0.0 0.0 0 0 ? S Jun01 0:00 [ksoftirqd/0]
========== End of system state dump ==========

@ -0,0 +1,68 @@
/**
* Copyright (c) 2022, 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 <iostream>
#include "config.h"
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "column_namer.hh"
#include "doctest/doctest.h"
TEST_CASE("column_namer::default")
{
column_namer cn{column_namer::language::SQL};
auto def_name0 = cn.add_column(string_fragment{});
CHECK(def_name0 == "col_0");
auto def_name1 = cn.add_column(string_fragment{});
CHECK(def_name1 == "col_1");
}
TEST_CASE("column_namer::no-collision")
{
column_namer cn{column_namer::language::SQL};
auto name0 = cn.add_column(string_fragment{"abc"});
CHECK(name0 == "abc");
auto name1 = cn.add_column(string_fragment{"def"});
CHECK(name1 == "def");
}
TEST_CASE("column_namer::collisions")
{
column_namer cn{column_namer::language::SQL};
auto name0 = cn.add_column(string_fragment{"abc"});
CHECK(name0 == "abc");
auto name1 = cn.add_column(string_fragment{"abc"});
CHECK(name1 == "abc_0");
auto name2 = cn.add_column(string_fragment{"abc"});
CHECK(name2 == "abc_1");
}

@ -645,18 +645,12 @@ log_line
EOF EOF
run_test ${lnav_test} -n \ run_cap_test ${lnav_test} -n \
-c ':filter-in sudo' \ -c ':filter-in sudo' \
-c ";select * from logline" \ -c ";select * from logline" \
-c ':write-csv-to -' \ -c ':write-csv-to -' \
${test_dir}/logfile_syslog.0 ${test_dir}/logfile_syslog.0
check_output "logline table is not working" <<EOF
log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,log_comment,log_tags,log_filters,log_hostname,log_msgid,log_pid,log_pri,log_procname,log_struct,log_syslog_tag,syslog_version,log_msg_instance,col_0,TTY,PWD,USER,COMMAND
0,<NULL>,2007-11-03 09:47:02.000,0,info,0,<NULL>,<NULL>,[1],veridian,<NULL>,<NULL>,<NULL>,sudo,<NULL>,sudo,<NULL>,0,timstack,pts/6,/auto/wstimstack/rpms/lbuild/test,root,/usr/bin/tail /var/log/messages
EOF
run_test ${lnav_test} -n \ run_test ${lnav_test} -n \
-c ':goto 1' \ -c ':goto 1' \
-c ";select log_line, log_pid, col_0 from logline" \ -c ";select log_line, log_pid, col_0 from logline" \
@ -884,6 +878,7 @@ CREATE VIRTUAL TABLE lnav_file USING lnav_file_impl();
CREATE VIEW lnav_view_filters_and_stats AS CREATE VIEW lnav_view_filters_and_stats AS
SELECT * FROM lnav_view_filters LEFT NATURAL JOIN lnav_view_filter_stats; SELECT * FROM lnav_view_filters LEFT NATURAL JOIN lnav_view_filter_stats;
CREATE VIRTUAL TABLE regexp_capture USING regexp_capture_impl(); CREATE VIRTUAL TABLE regexp_capture USING regexp_capture_impl();
CREATE VIRTUAL TABLE regexp_capture_into_json USING regexp_capture_into_json_impl();
CREATE VIRTUAL TABLE xpath USING xpath_impl(); CREATE VIRTUAL TABLE xpath USING xpath_impl();
CREATE VIRTUAL TABLE fstat USING fstat_impl(); CREATE VIRTUAL TABLE fstat USING fstat_impl();
CREATE TABLE lnav_events ( CREATE TABLE lnav_events (
@ -891,7 +886,6 @@ CREATE TABLE lnav_events (
content TEXT content TEXT
); );
CREATE TABLE http_status_codes ( CREATE TABLE http_status_codes (
status integer PRIMARY KEY,
EOF EOF
@ -1008,11 +1002,11 @@ check_output "write-json-to isn't working?" <<EOF
EOF EOF
run_cap_test ${lnav_test} -d "/tmp/lnav.err" -n \ run_cap_test ${lnav_test} -d "/tmp/lnav.err" -n \
-c ";select log_line, log_msg_instance, col_0 from logline" \ -c ";select log_line, col_0 from logline" \
${test_dir}/logfile_for_join.0 ${test_dir}/logfile_for_join.0
run_cap_test ${lnav_test} -d "/tmp/lnav.err" -n \ run_cap_test ${lnav_test} -d "/tmp/lnav.err" -n \
-c ";select log_msg_instance, col_0 from logline where log_line > 4" \ -c ";select col_0 from logline where log_line > 4" \
${test_dir}/logfile_for_join.0 ${test_dir}/logfile_for_join.0
run_test ${lnav_test} -d "/tmp/lnav.err" -n \ run_test ${lnav_test} -d "/tmp/lnav.err" -n \
@ -1129,25 +1123,25 @@ EOF
run_test ${lnav_test} -n \ run_test ${lnav_test} -n \
-c ":create-search-table search_test1 (\w+), world!" \ -c ":create-search-table search_test1 (\w+), world!" \
-c ";select log_msg_instance, col_0 from search_test1" \ -c ";select col_0 from search_test1" \
-c ":write-csv-to -" \ -c ":write-csv-to -" \
${test_dir}/logfile_multiline.0 ${test_dir}/logfile_multiline.0
check_output "create-search-table is not working?" <<EOF check_output "create-search-table is not working?" <<EOF
log_msg_instance,col_0 col_0
0,Hello Hello
1,Goodbye Goodbye
EOF EOF
run_test ${lnav_test} -n \ run_test ${lnav_test} -n \
-c ":create-search-table search_test1 (\w+), World!" \ -c ":create-search-table search_test1 (\w+), World!" \
-c ";select log_msg_instance, col_0 from search_test1 where log_line > 0" \ -c ";select col_0 from search_test1 where log_line > 0" \
-c ":write-csv-to -" \ -c ":write-csv-to -" \
${test_dir}/logfile_multiline.0 ${test_dir}/logfile_multiline.0
check_output "create-search-table is not working with where clause?" <<EOF check_output "create-search-table is not working with where clause?" <<EOF
log_msg_instance,col_0 col_0
1,Goodbye Goodbye
EOF EOF
run_test ${lnav_test} -n \ run_test ${lnav_test} -n \

@ -41,3 +41,6 @@ run_cap_test ./drive_sql_anno "SELECT (1 + 2) AS three"
# subqueries # subqueries
run_cap_test ./drive_sql_anno "SELECT * FROM (SELECT foo, bar FROM baz)" run_cap_test ./drive_sql_anno "SELECT * FROM (SELECT foo, bar FROM baz)"
run_cap_test ./drive_sql_anno \
"SELECT * from vmw_log, regexp_capture(log_body, '--> /SessionStats/SessionPool/Session/(?<line>[^\n]+)')"

@ -0,0 +1,12 @@
#! /bin/bash
export YES_COLOR=1
run_cap_test ${lnav_test} -n \
-c ";EXPLAIN QUERY PLAN SELECT * FROM syslog_log WHERE log_path GLOB '*/logfile_syslog.*'" \
${test_dir}/logfile_syslog.*
run_cap_test ${lnav_test} -n \
-c ";SELECT * FROM syslog_log WHERE log_path GLOB '*/logfile_syslog.*'" \
${test_dir}/logfile_syslog.*

@ -0,0 +1,7 @@
#! /bin/bash
export YES_COLOR=1
run_cap_test ${lnav_test} -n \
-c ';SELECT * FROM procstate_procs' \
${test_dir}/logfile_procstate.0

@ -97,3 +97,5 @@ run_cap_test ./drive_sql "SELECT * FROM regexp_capture('foo bar', '(')"
run_cap_test ./drive_sql "SELECT * FROM regexp_capture('1 2 3 45', '(\d+)')" run_cap_test ./drive_sql "SELECT * FROM regexp_capture('1 2 3 45', '(\d+)')"
run_cap_test ./drive_sql "SELECT * FROM regexp_capture('foo foo', '^foo')" run_cap_test ./drive_sql "SELECT * FROM regexp_capture('foo foo', '^foo')"
run_cap_test ./drive_sql "SELECT * FROM regexp_capture_into_json('foo=1 bar=2; foo=3 bar=4', 'foo=(\d+) bar=(\d+)')"

Loading…
Cancel
Save