From 1effd99e5c654729be4fd00611da9cea76bac03f Mon Sep 17 00:00:00 2001 From: Tim Stack Date: Sun, 18 Sep 2022 06:51:04 -0700 Subject: [PATCH] [sql] add parse_url()/unparse_url() functions Fixes #44 --- NEWS | 5 + aminclude_static.am | 2 +- conanfile.py | 2 +- m4/libcurl.m4 | 5 +- src/base/intern_string.hh | 31 +- src/curl_looper.cc | 71 ++- src/internals/sql-ref.rst | 139 ++++-- src/string-extension-functions.cc | 309 +++++++++++- src/text_anonymizer.cc | 5 +- src/yajlpp/yajlpp.hh | 1 + src/yajlpp/yajlpp_def.hh | 63 +++ test/expected/expected.am | 24 + ...a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out | 440 +++++++++++------- ...47bfe7ec626eaa0409a45b10fcbb634fb12eb7.err | 0 ...47bfe7ec626eaa0409a45b10fcbb634fb12eb7.out | 2 + ...f65162174b886130b94a5dd1f094e7f09debed.err | 0 ...f65162174b886130b94a5dd1f094e7f09debed.out | 2 + ...55d2cc0ab29171cae8e722f130adec25eae36e.err | 1 + ...55d2cc0ab29171cae8e722f130adec25eae36e.out | 0 ...766b600fd158a9e0677f6b0fa31b83537b2e5b.err | 0 ...766b600fd158a9e0677f6b0fa31b83537b2e5b.out | 2 + ...f984d8ed3e5099376d19f0dd20d5fd1ed42494.err | 0 ...f984d8ed3e5099376d19f0dd20d5fd1ed42494.out | 2 + ...6e7c26e8a80459fef55d56156d6ff93c00bd49.err | 0 ...6e7c26e8a80459fef55d56156d6ff93c00bd49.out | 2 + ...1e7604ac050e7047201638dca0a6b0fcfd8bdf.err | 0 ...1e7604ac050e7047201638dca0a6b0fcfd8bdf.out | 2 + ...5ca5e97fbf1ed56f2e920befd963255ba190b6.err | 0 ...5ca5e97fbf1ed56f2e920befd963255ba190b6.out | 2 + ...15ba81cc3655c602da28cd0fa1a186d5e9a6e1.err | 1 + ...15ba81cc3655c602da28cd0fa1a186d5e9a6e1.out | 0 ...88735cf46f23ca3d5fb3da41f07a6a3b1cba35.err | 0 ...88735cf46f23ca3d5fb3da41f07a6a3b1cba35.out | 2 + ...1b27abfafbd357d41c407428d41ae0f4bb75e2.err | 0 ...1b27abfafbd357d41c407428d41ae0f4bb75e2.out | 2 + ...c7f6531a2adf70cd1871fb13eab26dff133b7c.err | 0 ...c7f6531a2adf70cd1871fb13eab26dff133b7c.out | 2 + test/test_sql_str_func.sh | 49 ++ 38 files changed, 945 insertions(+), 223 deletions(-) create mode 100644 test/expected/test_sql_str_func.sh_0947bfe7ec626eaa0409a45b10fcbb634fb12eb7.err create mode 100644 test/expected/test_sql_str_func.sh_0947bfe7ec626eaa0409a45b10fcbb634fb12eb7.out create mode 100644 test/expected/test_sql_str_func.sh_30f65162174b886130b94a5dd1f094e7f09debed.err create mode 100644 test/expected/test_sql_str_func.sh_30f65162174b886130b94a5dd1f094e7f09debed.out create mode 100644 test/expected/test_sql_str_func.sh_3855d2cc0ab29171cae8e722f130adec25eae36e.err create mode 100644 test/expected/test_sql_str_func.sh_3855d2cc0ab29171cae8e722f130adec25eae36e.out create mode 100644 test/expected/test_sql_str_func.sh_51766b600fd158a9e0677f6b0fa31b83537b2e5b.err create mode 100644 test/expected/test_sql_str_func.sh_51766b600fd158a9e0677f6b0fa31b83537b2e5b.out create mode 100644 test/expected/test_sql_str_func.sh_6ff984d8ed3e5099376d19f0dd20d5fd1ed42494.err create mode 100644 test/expected/test_sql_str_func.sh_6ff984d8ed3e5099376d19f0dd20d5fd1ed42494.out create mode 100644 test/expected/test_sql_str_func.sh_7b6e7c26e8a80459fef55d56156d6ff93c00bd49.err create mode 100644 test/expected/test_sql_str_func.sh_7b6e7c26e8a80459fef55d56156d6ff93c00bd49.out create mode 100644 test/expected/test_sql_str_func.sh_7c1e7604ac050e7047201638dca0a6b0fcfd8bdf.err create mode 100644 test/expected/test_sql_str_func.sh_7c1e7604ac050e7047201638dca0a6b0fcfd8bdf.out create mode 100644 test/expected/test_sql_str_func.sh_805ca5e97fbf1ed56f2e920befd963255ba190b6.err create mode 100644 test/expected/test_sql_str_func.sh_805ca5e97fbf1ed56f2e920befd963255ba190b6.out create mode 100644 test/expected/test_sql_str_func.sh_a515ba81cc3655c602da28cd0fa1a186d5e9a6e1.err create mode 100644 test/expected/test_sql_str_func.sh_a515ba81cc3655c602da28cd0fa1a186d5e9a6e1.out create mode 100644 test/expected/test_sql_str_func.sh_b088735cf46f23ca3d5fb3da41f07a6a3b1cba35.err create mode 100644 test/expected/test_sql_str_func.sh_b088735cf46f23ca3d5fb3da41f07a6a3b1cba35.out create mode 100644 test/expected/test_sql_str_func.sh_b81b27abfafbd357d41c407428d41ae0f4bb75e2.err create mode 100644 test/expected/test_sql_str_func.sh_b81b27abfafbd357d41c407428d41ae0f4bb75e2.out create mode 100644 test/expected/test_sql_str_func.sh_bac7f6531a2adf70cd1871fb13eab26dff133b7c.err create mode 100644 test/expected/test_sql_str_func.sh_bac7f6531a2adf70cd1871fb13eab26dff133b7c.out diff --git a/NEWS b/NEWS index c63c7f69..16179046 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,11 @@ lnav v0.11.1: (This feature is mainly intended to help with providing information to lnav support that does not have sensitive values.) + * Added `parse_url()` and `unparse_url()` SQL functions for + parsing URLs into a JSON object and then back again. Note + that the implementation relies on libcurl which has some + limitations, like not supporting all types of schemes + (e.g. mailto:). Breaking changes: * The regexp_capture() table-valued-function now returns NULL diff --git a/aminclude_static.am b/aminclude_static.am index cefa385d..509c830c 100644 --- a/aminclude_static.am +++ b/aminclude_static.am @@ -1,6 +1,6 @@ # aminclude_static.am generated automatically by Autoconf -# from AX_AM_MACROS_STATIC on Sat Sep 10 10:36:17 PDT 2022 +# from AX_AM_MACROS_STATIC on Sat Sep 17 06:59:15 PDT 2022 # Code coverage diff --git a/conanfile.py b/conanfile.py index e903c779..787a829c 100644 --- a/conanfile.py +++ b/conanfile.py @@ -18,7 +18,7 @@ class LnavConan(ConanFile): requires = ( "bzip2/1.0.8", "libarchive/3.6.0", - "libcurl/7.80.0", + "libcurl/7.85.0", "ncurses/6.3", "pcre2/10.40", "readline/8.1.2", diff --git a/m4/libcurl.m4 b/m4/libcurl.m4 index d2768d92..02d00a7e 100644 --- a/m4/libcurl.m4 +++ b/m4/libcurl.m4 @@ -185,7 +185,7 @@ AC_DEFUN([LIBCURL_CHECK_CONFIG], # we didn't find curl-config, so let's see if the user-supplied # link line (or failing that, "-lcurl") is enough. - LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} + # LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} AC_CACHE_CHECK([whether libcurl is usable], [libcurl_cv_lib_curl_usable], @@ -193,7 +193,7 @@ AC_DEFUN([LIBCURL_CHECK_CONFIG], _libcurl_save_cppflags=$CPPFLAGS CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" _libcurl_save_libs=$LIBS - LIBS="$LIBCURL $LIBS" + LIBS="$_libcurl_ldflags $LIBCURL $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],[[ /* Try and use a few common options to force a failure if we are @@ -224,6 +224,7 @@ if (x) {;} CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" _libcurl_save_libs=$LIBS LIBS="$LIBS $LIBCURL" + LDFLAGS="$_libcurl_ldflags $LDFLAGS" AC_CHECK_FUNC(curl_free,, AC_DEFINE(curl_free,free, diff --git a/src/base/intern_string.hh b/src/base/intern_string.hh index 9beb0aa1..3be806ee 100644 --- a/src/base/intern_string.hh +++ b/src/base/intern_string.hh @@ -276,7 +276,7 @@ struct string_fragment { { for (int lpc = this->sf_begin; lpc < this->sf_end; lpc++) { if (this->sf_string[lpc] == ch) { - return lpc; + return lpc - this->sf_begin; } } @@ -415,6 +415,35 @@ struct string_fragment { }); } + template + split_result split_when(P&& predicate) const + { + int consumed = 0; + while (consumed < this->length()) { + if (predicate(this->data()[consumed])) { + break; + } + + consumed += 1; + } + + if (consumed == 0) { + return nonstd::nullopt; + } + + return std::make_pair( + string_fragment{ + this->sf_string, + this->sf_begin, + this->sf_begin + consumed, + }, + string_fragment{ + this->sf_string, + this->sf_begin + consumed + 1, + this->sf_end, + }); + } + split_result split_n(int amount) const; std::vector split_lines() const; diff --git a/src/curl_looper.cc b/src/curl_looper.cc index 597f1a08..3b7bb4ea 100644 --- a/src/curl_looper.cc +++ b/src/curl_looper.cc @@ -40,6 +40,74 @@ using namespace std::chrono_literals; +# if !CURL_AT_LEAST_VERSION(7, 80, 0) +extern "C" +{ +const char* +curl_url_strerror(CURLUcode error) +{ + switch (error) { + case CURLUE_OK: + return "No error"; + + case CURLUE_BAD_HANDLE: + return "An invalid CURLU pointer was passed as argument"; + + case CURLUE_BAD_PARTPOINTER: + return "An invalid 'part' argument was passed as argument"; + + case CURLUE_MALFORMED_INPUT: + return "Malformed input to a URL function"; + + case CURLUE_BAD_PORT_NUMBER: + return "Port number was not a decimal number between 0 and 65535"; + + case CURLUE_UNSUPPORTED_SCHEME: + return "Unsupported URL scheme"; + + case CURLUE_URLDECODE: + return "URL decode error, most likely because of rubbish in the " + "input"; + + case CURLUE_OUT_OF_MEMORY: + return "A memory function failed"; + + case CURLUE_USER_NOT_ALLOWED: + return "Credentials was passed in the URL when prohibited"; + + case CURLUE_UNKNOWN_PART: + return "An unknown part ID was passed to a URL API function"; + + case CURLUE_NO_SCHEME: + return "No scheme part in the URL"; + + case CURLUE_NO_USER: + return "No user part in the URL"; + + case CURLUE_NO_PASSWORD: + return "No password part in the URL"; + + case CURLUE_NO_OPTIONS: + return "No options part in the URL"; + + case CURLUE_NO_HOST: + return "No host part in the URL"; + + case CURLUE_NO_PORT: + return "No port part in the URL"; + + case CURLUE_NO_QUERY: + return "No query part in the URL"; + + case CURLUE_NO_FRAGMENT: + return "No fragment part in the URL"; + } + + return "CURLUcode unknown"; +} +} +# endif + struct curl_request_eq { explicit curl_request_eq(const std::string& name) : cre_name(name){}; @@ -203,7 +271,8 @@ curl_looper::check_for_finished_requests() int msgs_left; while ((msg = curl_multi_info_read(this->cl_curl_multi, &msgs_left)) - != nullptr) { + != nullptr) + { if (msg->msg != CURLMSG_DONE) { continue; } diff --git a/src/internals/sql-ref.rst b/src/internals/sql-ref.rst index 9d7d6e10..a1780892 100644 --- a/src/internals/sql-ref.rst +++ b/src/internals/sql-ref.rst @@ -499,7 +499,7 @@ anonymize(*value*) Aback, 10.0.0.1 **See Also** - :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -796,7 +796,7 @@ char(*X*) HI **See Also** - :ref:`anonymize`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -829,7 +829,7 @@ charindex(*needle*, *haystack*, *\[start\]*) 0 **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -997,7 +997,7 @@ decode(*value*, *algorithm*) curl **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1141,7 +1141,7 @@ encode(*value*, *algorithm*) Hello%2C%20World%21 **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1173,7 +1173,7 @@ endswith(*str*, *suffix*) 0 **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1228,7 +1228,7 @@ extract(*str*) {"col_0":1.0,"col_1":2.0} **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1429,7 +1429,7 @@ group_concat(*X*, *\[sep\]*) hw,gw **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1453,7 +1453,7 @@ group_spooky_hash(*str*) 4e7a190aead058cb123c94290f29c34a **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1469,7 +1469,7 @@ gunzip(*b*) * **b** --- The blob to decompress **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1485,7 +1485,7 @@ gzip(*value*) * **value** --- The value to compress **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1538,7 +1538,7 @@ humanize_duration(*secs*) 1s500 **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`date`, :ref:`datetime`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`julianday`, :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:`strftime`, :ref:`substr`, :ref:`time`, :ref:`timediff`, :ref:`timeslice`, :ref:`trim`, :ref:`unicode`, :ref:`upper`, :ref:`xpath` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`date`, :ref:`datetime`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`julianday`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`strftime`, :ref:`substr`, :ref:`time`, :ref:`timediff`, :ref:`timeslice`, :ref:`trim`, :ref:`unicode`, :ref:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1562,7 +1562,7 @@ humanize_file_size(*value*) 10.0MB **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1610,7 +1610,7 @@ instr(*haystack*, *needle*) 2 **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1963,7 +1963,7 @@ leftstr(*str*, *N*) abc **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -1987,7 +1987,7 @@ length(*str*) 3 **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2177,7 +2177,7 @@ logfmt2json(*str*) {"foo":1,"bar":2,"name":"Rolo Tomassi"} **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2201,7 +2201,7 @@ lower(*str*) abc **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2233,7 +2233,7 @@ ltrim(*str*, *\[chars\]*) c **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2390,7 +2390,7 @@ padc(*str*, *len*) abcdef ghi **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2422,7 +2422,7 @@ padl(*str*, *len*) abcdef **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2454,7 +2454,38 @@ padr(*str*, *len*) abcdefghi **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` + +---- + + +.. _parse_url: + +parse_url(*url*) +^^^^^^^^^^^^^^^^ + + Parse a URL and return the components in a JSON object. Limitations: not all URL schemes are supported and repeated query parameters are not captured. + + **Parameters** + * **url\*** --- The URL to parse + + **Examples** + To parse the URL 'https://example.com/search?q=hello%20world': + + .. code-block:: custsqlite + + ;SELECT parse_url('https://example.com/search?q=hello%20world') + {"scheme":"https","user":null,"password":null,"host":"example.com","port":null,"path":"/search","query":{"q":"hello world"},"fragment":null} + + To parse the URL 'https://alice@[fe80::14ff:4ee5:1215:2fb2]': + + .. code-block:: custsqlite + + ;SELECT parse_url('https://alice@[fe80::14ff:4ee5:1215:2fb2]') + {"scheme":"https","user":"alice","password":null,"host":"[fe80::14ff:4ee5:1215:2fb2]","port":null,"path":"/","query":null,"fragment":null} + + **See Also** + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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:`unparse_url`, :ref:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2552,7 +2583,7 @@ printf(*format*, *X*) value: 00011 **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2576,7 +2607,7 @@ proper(*str*) Hello, World! **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2759,7 +2790,7 @@ regexp_capture(*string*, *pattern*) 1 2 3 8 9 2 **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2787,7 +2818,7 @@ regexp_capture_into_json(*string*, *pattern*, *\[options\]*) 1 {"col_0":"b","col_1":2} **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2826,7 +2857,7 @@ regexp_match(*re*, *str*) {"num":123,"str":"four"} **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2859,7 +2890,7 @@ regexp_replace(*str*, *re*, *repl*) <123> **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2892,7 +2923,7 @@ replace(*str*, *old*, *replacement*) zbc **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2917,7 +2948,7 @@ replicate(*str*, *N*) abcabcabc **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2941,7 +2972,7 @@ reverse(*str*) cba **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -2973,7 +3004,7 @@ rightstr(*str*, *N*) abc **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -3069,7 +3100,7 @@ rtrim(*str*, *\[chars\]*) a **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -3139,7 +3170,7 @@ sparkline(*value*, *\[upper\]*) ▁▂▃▄▅▆▇█ **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -3184,7 +3215,7 @@ spooky_hash(*str*) f96b3d9c1a19f4394c97a1b79b1880df **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -3298,7 +3329,7 @@ startswith(*str*, *prefix*) 0 **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -3323,7 +3354,7 @@ strfilter(*source*, *include*) bcbc **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -3410,7 +3441,7 @@ substr(*str*, *start*, *\[size\]*) b **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -3617,7 +3648,7 @@ trim(*str*, *\[chars\]*) abc **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -3670,7 +3701,7 @@ unicode(*X*) 97 **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper`, :ref:`xpath` ---- @@ -3689,6 +3720,30 @@ unlikely(*value*) ---- +.. _unparse_url: + +unparse_url(*obj*) +^^^^^^^^^^^^^^^^^^ + + Convert a JSON object containing the parts of a URL into a URL string + + **Parameters** + * **obj\*** --- The JSON object containing the URL parts + + **Examples** + To unparse the object '{"scheme": "https", "host": "example.com"}': + + .. code-block:: custsqlite + + ;SELECT unparse_url('{"scheme": "https", "host": "example.com"}') + https://example.com/ + + **See Also** + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :ref:`parse_url`, :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` + +---- + + .. _upper: upper(*str*) @@ -3708,7 +3763,7 @@ upper(*str*) ABC **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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` + :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`xpath` ---- @@ -3751,7 +3806,7 @@ xpath(*xpath*, *xmldoc*) Hello ★ /abc/def/text() {} Hello ★ **See Also** - :ref:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :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:`anonymize`, :ref:`char`, :ref:`charindex`, :ref:`decode`, :ref:`encode`, :ref:`endswith`, :ref:`extract`, :ref:`group_concat`, :ref:`group_spooky_hash_agg`, :ref:`gunzip`, :ref:`gzip`, :ref:`humanize_duration`, :ref:`humanize_file_size`, :ref:`instr`, :ref:`leftstr`, :ref:`length`, :ref:`logfmt2json`, :ref:`lower`, :ref:`ltrim`, :ref:`padc`, :ref:`padl`, :ref:`padr`, :ref:`parse_url`, :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:`unparse_url`, :ref:`upper` ---- diff --git a/src/string-extension-functions.cc b/src/string-extension-functions.cc index a2fe02b1..0ef4fd96 100644 --- a/src/string-extension-functions.cc +++ b/src/string-extension-functions.cc @@ -40,6 +40,7 @@ #include "yajl/api/yajl_gen.h" #include "yajlpp/json_op.hh" #include "yajlpp/yajlpp.hh" +#include "yajlpp/yajlpp_def.hh" #if defined(HAVE_LIBCURL) # include @@ -618,7 +619,7 @@ sql_humanize_file_size(file_ssize_t value) return humanize::file_size(value, humanize::alignment::columnar); } -std::string +static std::string sql_anonymize(string_fragment frag) { static safe::Safe ta; @@ -626,6 +627,242 @@ sql_anonymize(string_fragment frag) return ta.writeAccess()->next(frag); } +#if !CURL_AT_LEAST_VERSION(7, 80, 0) +extern "C" +{ +const char* curl_url_strerror(CURLUcode error); +} +#endif + +static json_string +sql_parse_url(string_fragment url_frag) +{ + static auto* CURL_HANDLE = get_curl_easy(); + + auto_mem cu(curl_url_cleanup); + cu = curl_url(); + + auto rc = curl_url_set(cu, CURLUPART_URL, url_frag.data(), 0); + if (rc != CURLUE_OK) { + throw lnav::console::user_message::error( + attr_line_t("invalid URL: ").append_quoted(url_frag.to_string())) + .with_reason(curl_url_strerror(rc)); + } + + auto_mem url_part(curl_free); + yajlpp_gen gen; + yajl_gen_config(gen, yajl_gen_beautify, false); + + { + yajlpp_map root(gen); + + root.gen("scheme"); + rc = curl_url_get(cu, CURLUPART_SCHEME, url_part.out(), 0); + if (rc == CURLUE_OK) { + root.gen(string_fragment::from_c_str(url_part.in())); + } else { + root.gen(); + } + root.gen("user"); + rc = curl_url_get(cu, CURLUPART_USER, url_part.out(), CURLU_URLDECODE); + if (rc == CURLUE_OK) { + root.gen(string_fragment::from_c_str(url_part.in())); + } else { + root.gen(); + } + root.gen("password"); + rc = curl_url_get( + cu, CURLUPART_PASSWORD, url_part.out(), CURLU_URLDECODE); + if (rc == CURLUE_OK) { + root.gen(string_fragment::from_c_str(url_part.in())); + } else { + root.gen(); + } + root.gen("host"); + rc = curl_url_get(cu, CURLUPART_HOST, url_part.out(), CURLU_URLDECODE); + if (rc == CURLUE_OK) { + root.gen(string_fragment::from_c_str(url_part.in())); + } else { + root.gen(); + } + root.gen("port"); + rc = curl_url_get(cu, CURLUPART_PORT, url_part.out(), 0); + if (rc == CURLUE_OK) { + root.gen(string_fragment::from_c_str(url_part.in())); + } else { + root.gen(); + } + root.gen("path"); + rc = curl_url_get(cu, CURLUPART_PATH, url_part.out(), CURLU_URLDECODE); + if (rc == CURLUE_OK) { + root.gen(string_fragment::from_c_str(url_part.in())); + } else { + root.gen(); + } + root.gen("query"); + rc = curl_url_get(cu, CURLUPART_QUERY, url_part.out(), 0); + if (rc == CURLUE_OK) { + robin_hood::unordered_set seen_keys; + yajlpp_map query_map(gen); + + auto query_frag = string_fragment::from_c_str(url_part.in()); + auto remaining = query_frag; + + while (true) { + auto split_res + = remaining.split_when(string_fragment::tag1{'&'}); + + if (!split_res) { + break; + } + + auto_mem kv_pair(curl_free); + auto kv_pair_encoded = split_res->first; + int out_len = 0; + + kv_pair = curl_easy_unescape(CURL_HANDLE, + kv_pair_encoded.data(), + kv_pair_encoded.length(), + &out_len); + auto kv_pair_frag + = string_fragment::from_bytes(kv_pair.in(), out_len); + auto eq_index_opt = kv_pair_frag.find('='); + if (eq_index_opt) { + auto key = kv_pair_frag.sub_range(0, eq_index_opt.value()); + auto val = kv_pair_frag.substr(eq_index_opt.value() + 1); + auto key_str = key.to_string(); + + if (seen_keys.count(key_str) == 0) { + seen_keys.emplace(key_str); + query_map.gen(key); + query_map.gen(val); + } + } else { + auto val_str = split_res->first.to_string(); + + if (seen_keys.count(val_str) == 0) { + seen_keys.insert(val_str); + query_map.gen(split_res->first); + query_map.gen(); + } + } + + if (split_res->second.empty()) { + break; + } + + remaining = split_res->second; + } + } else { + root.gen(); + } + root.gen("fragment"); + rc = curl_url_get( + cu, CURLUPART_FRAGMENT, url_part.out(), CURLU_URLDECODE); + if (rc == CURLUE_OK) { + root.gen(string_fragment::from_c_str(url_part.in())); + } else { + root.gen(); + } + } + + return json_string(gen); +} + +struct url_parts { + nonstd::optional up_scheme; + nonstd::optional up_username; + nonstd::optional up_password; + nonstd::optional up_host; + nonstd::optional up_port; + nonstd::optional up_path; + std::map> up_query; + nonstd::optional up_fragment; +}; + +static const json_path_container url_query_handlers = { + yajlpp::pattern_property_handler("(?.+)") + .for_field(&url_parts::up_query), +}; + +static const typed_json_path_container url_parts_handlers = { + yajlpp::property_handler("scheme").for_field(&url_parts::up_scheme), + yajlpp::property_handler("username").for_field(&url_parts::up_username), + yajlpp::property_handler("password").for_field(&url_parts::up_password), + yajlpp::property_handler("host").for_field(&url_parts::up_host), + yajlpp::property_handler("port").for_field(&url_parts::up_port), + yajlpp::property_handler("path").for_field(&url_parts::up_path), + yajlpp::property_handler("query").with_children(url_query_handlers), + yajlpp::property_handler("fragment").for_field(&url_parts::up_fragment), +}; + +static auto_mem +sql_unparse_url(string_fragment in) +{ + static auto* CURL_HANDLE = get_curl_easy(); + static intern_string_t SRC = intern_string::lookup("arg"); + + auto parse_res = url_parts_handlers.parser_for(SRC).of(in); + if (parse_res.isErr()) { + throw parse_res.unwrapErr(); + } + + auto up = parse_res.unwrap(); + auto_mem cu(curl_url_cleanup); + cu = curl_url(); + + if (up.up_scheme) { + curl_url_set( + cu, CURLUPART_SCHEME, up.up_scheme->c_str(), CURLU_URLENCODE); + } + if (up.up_username) { + curl_url_set( + cu, CURLUPART_USER, up.up_username->c_str(), CURLU_URLENCODE); + } + if (up.up_password) { + curl_url_set( + cu, CURLUPART_PASSWORD, up.up_password->c_str(), CURLU_URLENCODE); + } + if (up.up_host) { + curl_url_set(cu, CURLUPART_HOST, up.up_host->c_str(), CURLU_URLENCODE); + } + if (up.up_port) { + curl_url_set(cu, CURLUPART_PORT, up.up_port->c_str(), 0); + } + if (up.up_path) { + curl_url_set(cu, CURLUPART_PATH, up.up_path->c_str(), CURLU_URLENCODE); + } + if (!up.up_query.empty()) { + for (const auto& pair : up.up_query) { + auto_mem key(curl_free); + auto_mem value(curl_free); + std::string qparam; + + key = curl_easy_escape( + CURL_HANDLE, pair.first.c_str(), pair.first.length()); + if (pair.second) { + value = curl_easy_escape( + CURL_HANDLE, pair.second->c_str(), pair.second->length()); + qparam = fmt::format(FMT_STRING("{}={}"), key.in(), value.in()); + } else { + qparam = key.in(); + } + + curl_url_set( + cu, CURLUPART_QUERY, qparam.c_str(), CURLU_APPENDQUERY); + } + } + if (up.up_fragment) { + curl_url_set( + cu, CURLUPART_FRAGMENT, up.up_fragment->c_str(), CURLU_URLENCODE); + } + + auto_mem retval(curl_free); + + curl_url_get(cu, CURLUPART_URL, retval.out(), 0); + return retval; +} + int string_extension_functions(struct FuncDef** basic_funcs, struct FuncDefAgg** agg_funcs) @@ -889,6 +1126,76 @@ string_extension_functions(struct FuncDef** basic_funcs, "SELECT decode('%63%75%72%6c', 'uri')", })), + sqlite_func_adapter::builder( + help_text("parse_url", + "Parse a URL and return the components in a JSON object. " + "Limitations: not all URL schemes are supported and " + "repeated query parameters are not captured.") + .sql_function() + .with_parameter(help_text("url", "The URL to parse")) + .with_result({ + "scheme", + "The URL's scheme", + }) + .with_result({ + "username", + "The name of the user specified in the URL", + }) + .with_result({ + "password", + "The password specified in the URL", + }) + .with_result({ + "host", + "The host name / IP specified in the URL", + }) + .with_result({ + "port", + "The port specified in the URL", + }) + .with_result({ + "path", + "The path specified in the URL", + }) + .with_result({ + "query", + "An object containing the query parameters", + }) + .with_result({ + "fragment", + "The fragment specified in the URL", + }) + .with_tags({"string", "url"}) + .with_example({ + "To parse the URL " + "'https://example.com/search?q=hello%20world'", + "SELECT " + "parse_url('https://example.com/search?q=hello%20world')", + }) + .with_example({ + "To parse the URL " + "'https://alice@[fe80::14ff:4ee5:1215:2fb2]'", + "SELECT " + "parse_url('https://alice@[fe80::14ff:4ee5:1215:2fb2]')", + })), + + sqlite_func_adapter:: + builder( + help_text("unparse_url", + "Convert a JSON object containing the parts of a " + "URL into a URL string") + .sql_function() + .with_parameter(help_text( + "obj", "The JSON object containing the URL parts")) + .with_tags({"string", "url"}) + .with_example({ + "To unparse the object " + "'{\"scheme\": \"https\", \"host\": \"example.com\"}'", + "SELECT " + "unparse_url('{\"scheme\": \"https\", \"host\": " + "\"example.com\"}')", + })), + {nullptr}, }; diff --git a/src/text_anonymizer.cc b/src/text_anonymizer.cc index 8f4532fd..0a2d37a8 100644 --- a/src/text_anonymizer.cc +++ b/src/text_anonymizer.cc @@ -139,7 +139,8 @@ text_anonymizer::next(string_fragment line) switch (tok_res->tr_token) { case DT_URL: { auto url_str = tok_res->to_string(); - auto* cu = curl_url(); + auto_mem cu(curl_url_cleanup); + cu = curl_url(); if (curl_url_set(cu, CURLUPART_URL, url_str.c_str(), 0) != CURLUE_OK) @@ -232,7 +233,7 @@ text_anonymizer::next(string_fragment line) auto url_query = string_fragment::from_c_str(url_part.in()); - auto replacer = [this, cu](const std::string& comp) { + auto replacer = [this, &cu](const std::string& comp) { std::string anon_query; auto eq_index = comp.find('='); diff --git a/src/yajlpp/yajlpp.hh b/src/yajlpp/yajlpp.hh index 46fcbf2b..bddf4d70 100644 --- a/src/yajlpp/yajlpp.hh +++ b/src/yajlpp/yajlpp.hh @@ -264,6 +264,7 @@ struct json_path_handler_base { bool jph_is_pattern_property{false}; std::vector jph_examples; + std::function jph_null_cb; std::function jph_bool_cb; std::function jph_integer_cb; std::functionypc_current_handler->jph_null_cb(ypc); + } + static int bool_field_cb(yajlpp_parse_context* ypc, int val) { return ypc->ypc_current_handler->jph_bool_cb(ypc, val); @@ -777,6 +782,64 @@ struct json_path_handler : public json_path_handler_base { return *this; } + template>, + Args...>::value, + bool> + = true> + json_path_handler& for_field(Args... args) + { + this->add_cb(str_field_cb2); + this->jph_str_cb = [args...](yajlpp_parse_context* ypc, + const unsigned char* str, + size_t len) { + auto obj = ypc->ypc_obj_stack.top(); + auto key = ypc->get_path_fragment(-1); + + json_path_handler::get_field(obj, args...)[key] + = std::string((const char*) str, len); + + return 1; + }; + this->add_cb(null_field_cb); + this->jph_null_cb = [args...](yajlpp_parse_context* ypc) { + auto* obj = ypc->ypc_obj_stack.top(); + auto key = ypc->get_path_fragment(-1); + + json_path_handler::get_field(obj, args...)[key] = nonstd::nullopt; + + return 1; + }; + this->jph_gen_callback = [args...](yajlpp_gen_context& ygc, + const json_path_handler_base& jph, + yajl_gen handle) { + const auto& field = json_path_handler::get_field( + ygc.ygc_obj_stack.top(), args...); + + if (!ygc.ygc_default_stack.empty()) { + const auto& field_def = json_path_handler::get_field( + ygc.ygc_default_stack.top(), args...); + + if (field == field_def) { + return yajl_gen_status_ok; + } + } + + { + yajlpp_generator gen(handle); + + for (const auto& pair : field) { + gen(pair.first); + gen(pair.second); + } + } + + return yajl_gen_status_ok; + }; + return *this; + } + template, Args...>::value, diff --git a/test/expected/expected.am b/test/expected/expected.am index f2d709a9..08dd2ad6 100644 --- a/test/expected/expected.am +++ b/test/expected/expected.am @@ -742,6 +742,8 @@ EXPECTED_FILES = \ $(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.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_0947bfe7ec626eaa0409a45b10fcbb634fb12eb7.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_0947bfe7ec626eaa0409a45b10fcbb634fb12eb7.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_11bcc5d32eabbedb6974f160dace9ef1ef0009e9.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_11bcc5d32eabbedb6974f160dace9ef1ef0009e9.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_11d458fdadd00df1239a0eeaac049abb49ed212d.err \ @@ -756,16 +758,22 @@ EXPECTED_FILES = \ $(srcdir)/%reldir%/test_sql_str_func.sh_211c5428db0590795072c31cb116ef35281e02b5.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_2f189f0785bb81a1298db35e9e166983b633c73f.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_2f189f0785bb81a1298db35e9e166983b633c73f.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_30f65162174b886130b94a5dd1f094e7f09debed.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_30f65162174b886130b94a5dd1f094e7f09debed.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_352434d199f7b493668c9f2774472eb69ef0d9f0.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_352434d199f7b493668c9f2774472eb69ef0d9f0.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_36fc9005464f1106f969559e640d9fa36d5fadad.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_36fc9005464f1106f969559e640d9fa36d5fadad.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_3855d2cc0ab29171cae8e722f130adec25eae36e.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_3855d2cc0ab29171cae8e722f130adec25eae36e.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_3de72fe5c1751dd212a1cd45cf2caa7f3b52bced.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_3de72fe5c1751dd212a1cd45cf2caa7f3b52bced.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_4b402274da152135c6c99456b693e1ecabca0256.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_4b402274da152135c6c99456b693e1ecabca0256.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_51055e40d709332ee772ba5719039314bbf5e411.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_51055e40d709332ee772ba5719039314bbf5e411.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_51766b600fd158a9e0677f6b0fa31b83537b2e5b.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_51766b600fd158a9e0677f6b0fa31b83537b2e5b.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_5203db1a4a81e43a693f339fd26e1ed635da9d5a.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_5203db1a4a81e43a693f339fd26e1ed635da9d5a.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_5abe3717393fba14ec510a37b4b94fedc67aae8e.err \ @@ -782,6 +790,8 @@ EXPECTED_FILES = \ $(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_6ff984d8ed3e5099376d19f0dd20d5fd1ed42494.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_6ff984d8ed3e5099376d19f0dd20d5fd1ed42494.out \ $(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_77fc174faeec1eda687a9373dbdbdd1aaef56e20.err \ @@ -790,8 +800,14 @@ EXPECTED_FILES = \ $(srcdir)/%reldir%/test_sql_str_func.sh_790da4aab5af901feeff5426790876eb91b967cb.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_7a544cd702579c1fab35870428788ad763cf1143.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_7a544cd702579c1fab35870428788ad763cf1143.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_7b6e7c26e8a80459fef55d56156d6ff93c00bd49.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_7b6e7c26e8a80459fef55d56156d6ff93c00bd49.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_7c1e7604ac050e7047201638dca0a6b0fcfd8bdf.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_7c1e7604ac050e7047201638dca0a6b0fcfd8bdf.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_7f751009d0db15fc97f9113c5c84db05ff1de9c3.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_7f751009d0db15fc97f9113c5c84db05ff1de9c3.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_805ca5e97fbf1ed56f2e920befd963255ba190b6.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_805ca5e97fbf1ed56f2e920befd963255ba190b6.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_80c1fb9affbfac609ebf1cc5556aafb1ecd223c1.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_80c1fb9affbfac609ebf1cc5556aafb1ecd223c1.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_836e3f721a0f945ad27e7aa241121ba739aab618.err \ @@ -812,14 +828,22 @@ EXPECTED_FILES = \ $(srcdir)/%reldir%/test_sql_str_func.sh_949ffd5b2ef9fbcbe17f2e61ef7750f7038f6fd6.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_a4d84a0082a7df34c95c2e6e070bbf6effaa5594.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_a4d84a0082a7df34c95c2e6e070bbf6effaa5594.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_a515ba81cc3655c602da28cd0fa1a186d5e9a6e1.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_a515ba81cc3655c602da28cd0fa1a186d5e9a6e1.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_a65d2fb2f841578619528ca10168ca4d650218e9.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_a65d2fb2f841578619528ca10168ca4d650218e9.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_ac7ecdda0fcc4279a4694291edaa2f1411f5262e.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_ac7ecdda0fcc4279a4694291edaa2f1411f5262e.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_b088735cf46f23ca3d5fb3da41f07a6a3b1cba35.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_b088735cf46f23ca3d5fb3da41f07a6a3b1cba35.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_b0e5bf23bbbc0defa8bb26817782c9d46a778ad8.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_b0e5bf23bbbc0defa8bb26817782c9d46a778ad8.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_b2aafbcaa7befe426d3f9df71c24f16fdc9d2856.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_b2aafbcaa7befe426d3f9df71c24f16fdc9d2856.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_b81b27abfafbd357d41c407428d41ae0f4bb75e2.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_b81b27abfafbd357d41c407428d41ae0f4bb75e2.out \ + $(srcdir)/%reldir%/test_sql_str_func.sh_bac7f6531a2adf70cd1871fb13eab26dff133b7c.err \ + $(srcdir)/%reldir%/test_sql_str_func.sh_bac7f6531a2adf70cd1871fb13eab26dff133b7c.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_bfb7088916412360f77683009058b0747784630a.err \ $(srcdir)/%reldir%/test_sql_str_func.sh_bfb7088916412360f77683009058b0747784630a.out \ $(srcdir)/%reldir%/test_sql_str_func.sh_bfe8b09e23389af0ef14359b66d68228d0285185.err \ diff --git a/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out b/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out index 9ac4ea2d..553d97c6 100644 --- a/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out +++ b/test/expected/test_cmds.sh_b6a3bb78e9d60e5e1f5ce5b18e40d2f1662707ab.out @@ -1861,10 +1861,11 @@ For support questions, email: group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Example #1 To anonymize an IP address: ;SELECT anonymize('Hello, 192.168.1.2')  @@ -2051,10 +2052,11 @@ For support questions, email: group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Example #1 To get a string with the code points 0x48 and 0x49: ;SELECT char(0x48, 0x49)  @@ -2076,10 +2078,11 @@ For support questions, email: group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Examples #1 To search for the string 'abc' within 'abcabc' and starting at position 2: ;SELECT charindex('abc', 'abcabc', 2)  @@ -2189,10 +2192,11 @@ For support questions, email: group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Example #1 To decode the URI-encoded string '%63%75%72%6c': ;SELECT decode('%63%75%72%6c', 'uri')  @@ -2274,10 +2278,11 @@ For support questions, email: group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Examples #1 To base64-encode 'Hello, World!': ;SELECT encode('Hello, World!', 'base64')  @@ -2303,10 +2308,11 @@ For support questions, email: group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Examples #1 To test if the string 'notbad.jpg' ends with '.jpg': ;SELECT endswith('notbad.jpg', '.jpg')  @@ -2343,10 +2349,11 @@ For support questions, email: group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Examples #1 To extract key/value pairs from a string: ;SELECT extract('foo=1 bar=2 name="Rolo Tomassi"')  @@ -2457,11 +2464,11 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), - lower(), ltrim(), padc(), padl(), padr(), printf(), proper(), - regexp_capture(), regexp_capture_into_json(), regexp_match(), + lower(), ltrim(), padc(), padl(), padr(), parse_url(), printf(), + proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + substr(), trim(), unicode(), unparse_url(), upper(), xpath() Examples #1 To concatenate the values of the column 'ex_procname' from the table 'lnav_example_log': @@ -2487,11 +2494,11 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), - lower(), ltrim(), padc(), padl(), padr(), printf(), proper(), - regexp_capture(), regexp_capture_into_json(), regexp_match(), + lower(), ltrim(), padc(), padl(), padr(), parse_url(), printf(), + proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + substr(), trim(), unicode(), unparse_url(), upper(), xpath() Example #1 To produce a hash of all of the values of 'column1': ;SELECT group_spooky_hash(column1) FROM (VALUES ('abc'), ('123')) @@ -2508,10 +2515,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() gzip(value, ...) ══════════════════════════════════════════════════════════════════════ @@ -2523,10 +2531,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() hex(X) ══════════════════════════════════════════════════════════════════════ @@ -2551,11 +2560,12 @@ For support questions, email: encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_file_size(), instr(), julianday(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), - padr(), printf(), proper(), regexp_capture(), + padr(), parse_url(), printf(), proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), strftime(), substr(), time(), - timediff(), timeslice(), trim(), unicode(), upper(), xpath() + timediff(), timeslice(), trim(), unicode(), unparse_url(), upper(), + xpath() Examples #1 To format a duration: ;SELECT humanize_duration(15 * 60)  @@ -2575,11 +2585,11 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), instr(), leftstr(), length(), logfmt2json(), - lower(), ltrim(), padc(), padl(), padr(), printf(), proper(), - regexp_capture(), regexp_capture_into_json(), regexp_match(), + lower(), ltrim(), padc(), padl(), padr(), parse_url(), printf(), + proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), regexp_replace(), replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + substr(), trim(), unicode(), unparse_url(), upper(), xpath() Example #1 To format an amount: ;SELECT humanize_file_size(10 * 1024 * 1024)  @@ -2612,11 +2622,12 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), leftstr(), length(), - logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(), - proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), parse_url(), + printf(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Example #1 To test get the position of 'b' in the string 'abc': ;SELECT instr('abc', 'b')  @@ -2837,11 +2848,12 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), length(), - logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(), - proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), parse_url(), + printf(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Examples #1 To get the first character of the string 'abc': ;SELECT leftstr('abc', 1)  @@ -2862,11 +2874,12 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), - logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), printf(), - proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), parse_url(), + printf(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Example #1 To get the length of the string 'abc': ;SELECT length('abc')  @@ -2982,11 +2995,12 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), - length(), lower(), ltrim(), padc(), padl(), padr(), printf(), proper(), - regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + length(), lower(), ltrim(), padc(), padl(), padr(), parse_url(), + printf(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Example #1 To extract key/value pairs from a log message: ;SELECT logfmt2json('foo=1 bar=2 name="Rolo Tomassi"') @@ -3003,11 +3017,12 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), - length(), logfmt2json(), ltrim(), padc(), padl(), padr(), printf(), - proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + length(), logfmt2json(), ltrim(), padc(), padl(), padr(), parse_url(), + printf(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Example #1 To lowercase the string 'AbC': ;SELECT lower('AbC')  @@ -3025,11 +3040,12 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), - length(), logfmt2json(), lower(), padc(), padl(), padr(), printf(), - proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + length(), logfmt2json(), lower(), padc(), padl(), padr(), parse_url(), + printf(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Examples #1 To trim the leading space characters from the string ' abc': ;SELECT ltrim(' abc')  @@ -3133,11 +3149,12 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), - length(), logfmt2json(), lower(), ltrim(), padl(), padr(), printf(), - proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + length(), logfmt2json(), lower(), ltrim(), padl(), padr(), parse_url(), + printf(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Examples #1 To pad the string 'abc' to a length of six characters: ;SELECT padc('abc', 6) || 'def'  @@ -3159,11 +3176,12 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), - length(), logfmt2json(), lower(), ltrim(), padc(), padr(), printf(), - proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + length(), logfmt2json(), lower(), ltrim(), padc(), padr(), parse_url(), + printf(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Examples #1 To pad the string 'abc' to a length of six characters: ;SELECT padl('abc', 6)  @@ -3185,11 +3203,12 @@ For support questions, email: anonymize(), char(), charindex(), decode(), encode(), endswith(), extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), - length(), logfmt2json(), lower(), ltrim(), padc(), padl(), printf(), - proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + length(), logfmt2json(), lower(), ltrim(), padc(), padl(), parse_url(), + printf(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Examples #1 To pad the string 'abc' to a length of six characters: ;SELECT padr('abc', 6) || 'def'  @@ -3200,6 +3219,42 @@ For support questions, email: +parse_url(url) +══════════════════════════════════════════════════════════════════════ + Parse a URL and return the components in a JSON object. Limitations: + not all URL schemes are supported and repeated query parameters are + not captured. +Parameter + url The URL to parse +Results + scheme The URL's scheme + username The name of the user specified in the URL + password The password specified in the URL + host The host name / IP specified in the URL + port The port specified in the URL + path The path specified in the URL + query An object containing the query parameters + fragment The fragment specified in the URL +See Also + anonymize(), char(), charindex(), decode(), encode(), endswith(), + extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), + humanize_duration(), humanize_file_size(), instr(), leftstr(), + length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), + printf(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), unparse_url(), + upper(), xpath() +Examples +#1 To parse the URL 'https://example.com/search?q=hello%20world': + ;SELECT parse_url('https://example.com/search?q=hello%20world') + + +#2 To parse the URL 'https://alice@[fe80::14ff:4ee5:1215:2fb2]': + ;SELECT parse_url('https://alice@[fe80::14ff:4ee5:1215:2fb2]') + + + percent_rank() ══════════════════════════════════════════════════════════════════════ Returns (rank - 1) / (partition-rows - 1) @@ -3252,10 +3307,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - proper(), regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + parse_url(), proper(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Examples #1 To substitute 'World' into the string 'Hello, %s!': ;SELECT printf('Hello, %s!', 'World')  @@ -3280,10 +3336,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), regexp_capture(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), regexp_capture(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), upper(), + xpath() Example #1 To capitalize the words in the string 'hello, world!': ;SELECT proper('hello, world!')  @@ -3403,10 +3460,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture_into_json(), regexp_match(), - regexp_replace(), replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture_into_json(), + regexp_match(), regexp_replace(), replace(), replicate(), reverse(), + rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), + strfilter(), substr(), trim(), unicode(), unparse_url(), 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('a=1; b=2', '(\w+)=(\d+)') @@ -3436,10 +3494,10 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), 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() + parse_url(), printf(), proper(), regexp_capture(), regexp_match(), + regexp_replace(), replace(), replicate(), reverse(), rightstr(), + rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), + substr(), trim(), unicode(), unparse_url(), 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+)') @@ -3458,10 +3516,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_replace(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_replace(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Examples #1 To capture the digits from the string '123': ;SELECT regexp_match('(\d+)', '123')  @@ -3492,10 +3551,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_match(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_match(), replace(), + replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Examples #1 To replace the word at the start of the string 'Hello, World!' with 'Goodbye': ;SELECT regexp_replace('Hello, World!', '^(\w+)', 'Goodbye') @@ -3520,10 +3580,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replicate(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Examples #1 To replace the string 'x' with 'z' in 'abc': ;SELECT replace('abc', 'x', 'z')  @@ -3545,10 +3606,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), reverse(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), reverse(), rightstr(), rtrim(), sparkline(), spooky_hash(), + startswith(), strfilter(), substr(), trim(), unicode(), unparse_url(), + upper(), xpath() Example #1 To repeat the string 'abc' three times: ;SELECT replicate('abc', 3)  @@ -3565,10 +3627,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), rightstr(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Example #1 To reverse the string 'abc': ;SELECT reverse('abc')  @@ -3587,10 +3650,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rtrim(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rtrim(), sparkline(), spooky_hash(), + startswith(), strfilter(), substr(), trim(), unicode(), unparse_url(), + upper(), xpath() Examples #1 To get the last character of the string 'abc': ;SELECT rightstr('abc', 1)  @@ -3654,10 +3718,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), sparkline(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Examples #1 To trim the space characters from the end of the string 'abc ': ;SELECT rtrim('abc ')  @@ -3708,10 +3773,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), spooky_hash(), startswith(), strfilter(), - substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), spooky_hash(), + startswith(), strfilter(), substr(), trim(), unicode(), unparse_url(), + upper(), xpath() Examples #1 To get the unicode block element for the value 32 in the range of 0-128: ;SELECT sparkline(32, 128)  @@ -3732,10 +3798,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), startswith(), strfilter(), substr(), - trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + startswith(), strfilter(), substr(), trim(), unicode(), unparse_url(), + upper(), xpath() Examples #1 To produce a hash for the string 'Hello, World!': ;SELECT spooky_hash('Hello, World!')  @@ -3813,10 +3880,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), strfilter(), substr(), - trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), strfilter(), substr(), trim(), unicode(), unparse_url(), + upper(), xpath() Examples #1 To test if the string 'foobar' starts with 'foo': ;SELECT startswith('foobar', 'foo')  @@ -3839,10 +3907,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - substr(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), substr(), trim(), unicode(), + unparse_url(), upper(), xpath() Example #1 To get the 'b', 'c', and 'd' characters from the string 'abcabc': ;SELECT strfilter('abcabc', 'bcd')  @@ -3896,10 +3965,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), trim(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), trim(), unicode(), + unparse_url(), upper(), xpath() Examples #1 To get the substring starting at the second character until the end of the string 'abc': @@ -4045,10 +4115,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), unicode(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), unicode(), + unparse_url(), upper(), xpath() Examples #1 To trim spaces from the start and end of the string ' abc ': ;SELECT trim(' abc ')  @@ -4087,10 +4158,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), upper(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), + unparse_url(), upper(), xpath() Example #1 To get the unicode code point for the first character of 'abc': ;SELECT unicode('abc')  @@ -4104,6 +4176,28 @@ For support questions, email: value The boolean value to return +unparse_url(obj) +══════════════════════════════════════════════════════════════════════ + Convert a JSON object containing the parts of a URL into a URL + string +Parameter + obj The JSON object containing the URL parts +See Also + anonymize(), char(), charindex(), decode(), encode(), endswith(), + extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), + humanize_duration(), humanize_file_size(), instr(), leftstr(), + length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), + parse_url(), parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + upper(), xpath() +Example +#1 To unparse the object '{"scheme": "https", "host": "example.com"}': + ;SELECT unparse_url('{"scheme": "https", "host": "example.com"}') + + + upper(str) ══════════════════════════════════════════════════════════════════════ Returns a copy of the given string with all ASCII characters @@ -4115,10 +4209,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), xpath() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), xpath() Example #1 To uppercase the string 'aBc': ;SELECT upper('aBc')  @@ -4144,10 +4239,11 @@ For support questions, email: extract(), group_concat(), group_spooky_hash(), gunzip(), gzip(), humanize_duration(), humanize_file_size(), instr(), leftstr(), length(), logfmt2json(), lower(), ltrim(), padc(), padl(), padr(), - printf(), proper(), regexp_capture(), regexp_capture_into_json(), - regexp_match(), regexp_replace(), replace(), replicate(), reverse(), - rightstr(), rtrim(), sparkline(), spooky_hash(), startswith(), - strfilter(), substr(), trim(), unicode(), upper() + parse_url(), printf(), proper(), regexp_capture(), + regexp_capture_into_json(), regexp_match(), regexp_replace(), + replace(), replicate(), reverse(), rightstr(), rtrim(), sparkline(), + spooky_hash(), startswith(), strfilter(), substr(), trim(), unicode(), + unparse_url(), upper() Examples #1 To select the XML nodes on the path '/abc/def': ;SELECT * FROM xpath('/abc/def', 'HelloBye') diff --git a/test/expected/test_sql_str_func.sh_0947bfe7ec626eaa0409a45b10fcbb634fb12eb7.err b/test/expected/test_sql_str_func.sh_0947bfe7ec626eaa0409a45b10fcbb634fb12eb7.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_0947bfe7ec626eaa0409a45b10fcbb634fb12eb7.out b/test/expected/test_sql_str_func.sh_0947bfe7ec626eaa0409a45b10fcbb634fb12eb7.out new file mode 100644 index 00000000..85d52c0c --- /dev/null +++ b/test/expected/test_sql_str_func.sh_0947bfe7ec626eaa0409a45b10fcbb634fb12eb7.out @@ -0,0 +1,2 @@ +Row 0: + Column parse_url('https://example.com/'): {"scheme":"https","user":null,"password":null,"host":"example.com","port":null,"path":"/","query":null,"fragment":null} diff --git a/test/expected/test_sql_str_func.sh_30f65162174b886130b94a5dd1f094e7f09debed.err b/test/expected/test_sql_str_func.sh_30f65162174b886130b94a5dd1f094e7f09debed.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_30f65162174b886130b94a5dd1f094e7f09debed.out b/test/expected/test_sql_str_func.sh_30f65162174b886130b94a5dd1f094e7f09debed.out new file mode 100644 index 00000000..19997214 --- /dev/null +++ b/test/expected/test_sql_str_func.sh_30f65162174b886130b94a5dd1f094e7f09debed.out @@ -0,0 +1,2 @@ +Row 0: + Column unparse_url(parse_url('https://example.com/search?flag&flag2&=def#frag1%20space')): https://example.com/search?flag&flag2#frag1%20space diff --git a/test/expected/test_sql_str_func.sh_3855d2cc0ab29171cae8e722f130adec25eae36e.err b/test/expected/test_sql_str_func.sh_3855d2cc0ab29171cae8e722f130adec25eae36e.err new file mode 100644 index 00000000..e3d40abf --- /dev/null +++ b/test/expected/test_sql_str_func.sh_3855d2cc0ab29171cae8e722f130adec25eae36e.err @@ -0,0 +1 @@ +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"invalid URL: “https://bad@[fe::”","attrs":[]},"reason":{"str":"Port number was not a decimal number between 0 and 65535","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_sql_str_func.sh_3855d2cc0ab29171cae8e722f130adec25eae36e.out b/test/expected/test_sql_str_func.sh_3855d2cc0ab29171cae8e722f130adec25eae36e.out new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_51766b600fd158a9e0677f6b0fa31b83537b2e5b.err b/test/expected/test_sql_str_func.sh_51766b600fd158a9e0677f6b0fa31b83537b2e5b.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_51766b600fd158a9e0677f6b0fa31b83537b2e5b.out b/test/expected/test_sql_str_func.sh_51766b600fd158a9e0677f6b0fa31b83537b2e5b.out new file mode 100644 index 00000000..04033728 --- /dev/null +++ b/test/expected/test_sql_str_func.sh_51766b600fd158a9e0677f6b0fa31b83537b2e5b.out @@ -0,0 +1,2 @@ +Row 0: + Column parse_url('https://example.com/search?flag&flag2&=def'): {"scheme":"https","user":null,"password":null,"host":"example.com","port":null,"path":"/search","query":{"flag":null,"flag2":null,"":"def"},"fragment":null} diff --git a/test/expected/test_sql_str_func.sh_6ff984d8ed3e5099376d19f0dd20d5fd1ed42494.err b/test/expected/test_sql_str_func.sh_6ff984d8ed3e5099376d19f0dd20d5fd1ed42494.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_6ff984d8ed3e5099376d19f0dd20d5fd1ed42494.out b/test/expected/test_sql_str_func.sh_6ff984d8ed3e5099376d19f0dd20d5fd1ed42494.out new file mode 100644 index 00000000..fecdc781 --- /dev/null +++ b/test/expected/test_sql_str_func.sh_6ff984d8ed3e5099376d19f0dd20d5fd1ed42494.out @@ -0,0 +1,2 @@ +Row 0: + Column parse_url('https://example.com/sea%26rch?flag&flag2&=def#frag1%20space'): {"scheme":"https","user":null,"password":null,"host":"example.com","port":null,"path":"/sea&rch","query":{"flag":null,"flag2":null,"":"def"},"fragment":"frag1 space"} diff --git a/test/expected/test_sql_str_func.sh_7b6e7c26e8a80459fef55d56156d6ff93c00bd49.err b/test/expected/test_sql_str_func.sh_7b6e7c26e8a80459fef55d56156d6ff93c00bd49.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_7b6e7c26e8a80459fef55d56156d6ff93c00bd49.out b/test/expected/test_sql_str_func.sh_7b6e7c26e8a80459fef55d56156d6ff93c00bd49.out new file mode 100644 index 00000000..476390e9 --- /dev/null +++ b/test/expected/test_sql_str_func.sh_7b6e7c26e8a80459fef55d56156d6ff93c00bd49.out @@ -0,0 +1,2 @@ +Row 0: + Column unparse_url(parse_url('https://example.com/search?flag&flag2&=def')): https://example.com/search?flag&flag2 diff --git a/test/expected/test_sql_str_func.sh_7c1e7604ac050e7047201638dca0a6b0fcfd8bdf.err b/test/expected/test_sql_str_func.sh_7c1e7604ac050e7047201638dca0a6b0fcfd8bdf.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_7c1e7604ac050e7047201638dca0a6b0fcfd8bdf.out b/test/expected/test_sql_str_func.sh_7c1e7604ac050e7047201638dca0a6b0fcfd8bdf.out new file mode 100644 index 00000000..6233470f --- /dev/null +++ b/test/expected/test_sql_str_func.sh_7c1e7604ac050e7047201638dca0a6b0fcfd8bdf.out @@ -0,0 +1,2 @@ +Row 0: + Column unparse_url(parse_url('https://example.com/search?flag&flag2')): https://example.com/search?flag&flag2 diff --git a/test/expected/test_sql_str_func.sh_805ca5e97fbf1ed56f2e920befd963255ba190b6.err b/test/expected/test_sql_str_func.sh_805ca5e97fbf1ed56f2e920befd963255ba190b6.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_805ca5e97fbf1ed56f2e920befd963255ba190b6.out b/test/expected/test_sql_str_func.sh_805ca5e97fbf1ed56f2e920befd963255ba190b6.out new file mode 100644 index 00000000..edc76f47 --- /dev/null +++ b/test/expected/test_sql_str_func.sh_805ca5e97fbf1ed56f2e920befd963255ba190b6.out @@ -0,0 +1,2 @@ +Row 0: + Column parse_url('https://example.com/search?flag&flag2'): {"scheme":"https","user":null,"password":null,"host":"example.com","port":null,"path":"/search","query":{"flag":null,"flag2":null},"fragment":null} diff --git a/test/expected/test_sql_str_func.sh_a515ba81cc3655c602da28cd0fa1a186d5e9a6e1.err b/test/expected/test_sql_str_func.sh_a515ba81cc3655c602da28cd0fa1a186d5e9a6e1.err new file mode 100644 index 00000000..475a9b23 --- /dev/null +++ b/test/expected/test_sql_str_func.sh_a515ba81cc3655c602da28cd0fa1a186d5e9a6e1.err @@ -0,0 +1 @@ +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"invalid URL: “https://example.com:100000”","attrs":[]},"reason":{"str":"Port number was not a decimal number between 0 and 65535","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_sql_str_func.sh_a515ba81cc3655c602da28cd0fa1a186d5e9a6e1.out b/test/expected/test_sql_str_func.sh_a515ba81cc3655c602da28cd0fa1a186d5e9a6e1.out new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_b088735cf46f23ca3d5fb3da41f07a6a3b1cba35.err b/test/expected/test_sql_str_func.sh_b088735cf46f23ca3d5fb3da41f07a6a3b1cba35.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_b088735cf46f23ca3d5fb3da41f07a6a3b1cba35.out b/test/expected/test_sql_str_func.sh_b088735cf46f23ca3d5fb3da41f07a6a3b1cba35.out new file mode 100644 index 00000000..3a2427a5 --- /dev/null +++ b/test/expected/test_sql_str_func.sh_b088735cf46f23ca3d5fb3da41f07a6a3b1cba35.out @@ -0,0 +1,2 @@ +Row 0: + Column parse_url('https://example.com'): {"scheme":"https","user":null,"password":null,"host":"example.com","port":null,"path":"/","query":null,"fragment":null} diff --git a/test/expected/test_sql_str_func.sh_b81b27abfafbd357d41c407428d41ae0f4bb75e2.err b/test/expected/test_sql_str_func.sh_b81b27abfafbd357d41c407428d41ae0f4bb75e2.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_b81b27abfafbd357d41c407428d41ae0f4bb75e2.out b/test/expected/test_sql_str_func.sh_b81b27abfafbd357d41c407428d41ae0f4bb75e2.out new file mode 100644 index 00000000..70e423e1 --- /dev/null +++ b/test/expected/test_sql_str_func.sh_b81b27abfafbd357d41c407428d41ae0f4bb75e2.out @@ -0,0 +1,2 @@ +Row 0: + Column unparse_url(parse_url('https://example.com/search?flag')): https://example.com/search?flag diff --git a/test/expected/test_sql_str_func.sh_bac7f6531a2adf70cd1871fb13eab26dff133b7c.err b/test/expected/test_sql_str_func.sh_bac7f6531a2adf70cd1871fb13eab26dff133b7c.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_bac7f6531a2adf70cd1871fb13eab26dff133b7c.out b/test/expected/test_sql_str_func.sh_bac7f6531a2adf70cd1871fb13eab26dff133b7c.out new file mode 100644 index 00000000..4a16523e --- /dev/null +++ b/test/expected/test_sql_str_func.sh_bac7f6531a2adf70cd1871fb13eab26dff133b7c.out @@ -0,0 +1,2 @@ +Row 0: + Column parse_url('https://example.com/search?flag'): {"scheme":"https","user":null,"password":null,"host":"example.com","port":null,"path":"/search","query":{"flag":null},"fragment":null} diff --git a/test/test_sql_str_func.sh b/test/test_sql_str_func.sh index 6e60996a..4c582148 100644 --- a/test/test_sql_str_func.sh +++ b/test/test_sql_str_func.sh @@ -111,6 +111,55 @@ run_cap_test ./drive_sql "SELECT encode(null, 'base64')" run_cap_test ./drive_sql "SELECT gunzip(decode(encode(gzip('Hello, World!'), 'base64'), 'base64'))" +run_cap_test env TEST_COMMENT=invalid_url ./drive_sql <<'EOF' +SELECT parse_url('https://bad@[fe::') +EOF + +run_cap_test env TEST_COMMENT=unsupported_url ./drive_sql <<'EOF' +SELECT parse_url('https://example.com:100000') +EOF + +run_cap_test env TEST_COMMENT=parse_url1 ./drive_sql <<'EOF' +SELECT parse_url('https://example.com') +EOF + +run_cap_test env TEST_COMMENT=parse_url2 ./drive_sql <<'EOF' +SELECT parse_url('https://example.com/') +EOF + +run_cap_test env TEST_COMMENT=parse_url3 ./drive_sql <<'EOF' +SELECT parse_url('https://example.com/search?flag') +EOF + +run_cap_test env TEST_COMMENT=parse_url4 ./drive_sql <<'EOF' +SELECT parse_url('https://example.com/search?flag&flag2') +EOF + +run_cap_test env TEST_COMMENT=parse_url5 ./drive_sql <<'EOF' +SELECT parse_url('https://example.com/search?flag&flag2&=def') +EOF + +run_cap_test env TEST_COMMENT=parse_url6 ./drive_sql <<'EOF' +SELECT parse_url('https://example.com/sea%26rch?flag&flag2&=def#frag1%20space') +EOF + + +run_cap_test env TEST_COMMENT=unparse_url3 ./drive_sql <<'EOF' +SELECT unparse_url(parse_url('https://example.com/search?flag')) +EOF + +run_cap_test env TEST_COMMENT=unparse_url4 ./drive_sql <<'EOF' +SELECT unparse_url(parse_url('https://example.com/search?flag&flag2')) +EOF + +run_cap_test env TEST_COMMENT=unparse_url5 ./drive_sql <<'EOF' +SELECT unparse_url(parse_url('https://example.com/search?flag&flag2&=def')) +EOF + +run_cap_test env TEST_COMMENT=unparse_url6 ./drive_sql <<'EOF' +SELECT unparse_url(parse_url('https://example.com/search?flag&flag2&=def#frag1%20space')) +EOF + run_cap_test ${lnav_test} -n \ -c ';SELECT log_body, extract(log_body) from vmw_log' \ -c ':write-json-to -' \