[db] charting of JSON values was mistakenly limited to very short values

This commit is contained in:
Timothy Stack 2022-07-06 21:10:23 -07:00
parent 7fe91d6186
commit a3e1fd27b8
7 changed files with 97 additions and 16 deletions

View File

@ -138,6 +138,23 @@ struct string_fragment {
return *prefix == '\0';
}
bool endswith(const char* suffix) const
{
auto suffix_len = strlen(suffix);
if (suffix_len > this->length()) {
return false;
}
const auto* curr = this->end() - suffix_len;
while (*suffix != '\0' && *curr == *suffix) {
suffix += 1;
curr += 1;
}
return *suffix == '\0';
}
string_fragment substr(int begin) const
{
return string_fragment{

View File

@ -40,6 +40,7 @@
const char* db_label_source::NULL_STR = "<NULL>";
constexpr size_t MAX_COLUMN_WIDTH = 120;
constexpr size_t MAX_JSON_WIDTH = 16 * 1024;
void
db_label_source::text_value_for_line(textview_curses& tc,
@ -134,7 +135,7 @@ db_label_source::text_attrs_for_line(textview_curses& tc,
tc, left, this->dls_headers[lpc].hm_name, num_value, sa);
}
}
if (row_len > 2 && row_len < MAX_COLUMN_WIDTH
if (row_len > 2 && row_len < MAX_JSON_WIDTH
&& ((row_value[0] == '{' && row_value[row_len - 1] == '}')
|| (row_value[0] == '[' && row_value[row_len - 1] == ']')))
{
@ -143,7 +144,7 @@ db_label_source::text_attrs_for_line(textview_curses& tc,
if (jpw.parse(row_value, row_len) == yajl_status_ok
&& jpw.complete_parse() == yajl_status_ok)
{
for (auto& jpw_value : jpw.jpw_values) {
for (const auto& jpw_value : jpw.jpw_values) {
double num_value;
if (jpw_value.wt_type == yajl_t_number

View File

@ -203,7 +203,7 @@ public:
lr.lr_start = left;
const struct chart_ident& ci = this->sbc_idents[ident_index];
const auto& ci = this->sbc_idents[ident_index];
int amount;
if (value == 0.0) {
@ -240,8 +240,9 @@ public:
struct bucket_stats_t {
bucket_stats_t()
: bs_min_value(std::numeric_limits<double>::max()),
bs_max_value(0){};
: bs_min_value(std::numeric_limits<double>::max()), bs_max_value(0)
{
}
void merge(const bucket_stats_t& rhs, bool do_stacking)
{
@ -252,18 +253,18 @@ public:
this->bs_max_value
= std::max(this->bs_max_value, rhs.bs_max_value);
}
};
}
double width() const
{
return std::fabs(this->bs_max_value - this->bs_min_value);
};
}
void update(double value)
{
this->bs_max_value = std::max(this->bs_max_value, value);
this->bs_min_value = std::min(this->bs_min_value, value);
};
}
double bs_min_value;
double bs_max_value;
@ -278,7 +279,7 @@ public:
protected:
struct chart_ident {
chart_ident(const T& ident) : ci_ident(ident) {}
explicit chart_ident(const T& ident) : ci_ident(ident) {}
T ci_ident;
int ci_attrs{0};
@ -287,12 +288,10 @@ protected:
struct chart_ident& find_ident(const T& ident)
{
typename std::map<T, unsigned int>::iterator iter;
iter = this->sbc_ident_lookup.find(ident);
auto iter = this->sbc_ident_lookup.find(ident);
if (iter == this->sbc_ident_lookup.end()) {
this->sbc_ident_lookup[ident] = this->sbc_idents.size();
this->sbc_idents.push_back(ident);
this->sbc_idents.emplace_back(ident);
return this->sbc_idents.back();
}
return this->sbc_idents[iter->second];

View File

@ -517,7 +517,7 @@ json_concat(nonstd::optional<const char*> json_in,
array.gen(sqlite3_value_double(val));
break;
case SQLITE3_TEXT: {
auto text_val = sqlite3_value_text(val);
const auto* text_val = sqlite3_value_text(val);
if (sqlite3_value_subtype(val) == JSON_SUBTYPE) {
concat_gen_elements(
@ -534,6 +534,47 @@ json_concat(nonstd::optional<const char*> json_in,
return json_string(gen);
}
#if 0
static flattened_json_string
sql_flatten_json_object(string_fragment sf)
{
yajlpp_gen gen;
{
json_ptr jp("/");
json_op jo(jp);
auto_mem<yajl_handle_t> handle(yajl_free);
jo.jo_ptr_data = gen.get_handle();
yajl_gen_config(gen, yajl_gen_beautify, false);
handle.reset(yajl_alloc(&json_op::gen_callbacks, nullptr, &jo));
switch (yajl_parse(
handle.in(), (const unsigned char*) sf.data(), sf.length())) {
case yajl_status_error:
case yajl_status_client_canceled:
throw yajlpp_error(handle.in(), sf.data(), sf.length());
case yajl_status_ok:
break;
}
switch (yajl_complete_parse(handle.in())) {
case yajl_status_error:
case yajl_status_client_canceled:
throw yajlpp_error(handle.in(), sf.data(), sf.length());
case yajl_status_ok:
break;
}
}
auto result = gen.to_string_fragment();
if (!result.startswith("{") || !result.endswith("}")) {
throw std::runtime_error(
"flatten_json_object() requires a JSON object");
}
return flattened_json_string(gen);
}
#endif
struct json_agg_context {
yajl_gen_t* jac_yajl_gen;
};
@ -797,6 +838,14 @@ json_extension_functions(struct FuncDef** basic_funcs,
}),
},
#if 0
sqlite_func_adapter<decltype(&sql_flatten_json_object),
sql_flatten_json_object>::
builder(help_text("flatten_json_object", "hello")
.sql_function()
.with_parameter({"json", "The JSON"})),
#endif
{nullptr},
};

View File

@ -282,7 +282,8 @@ to_sqlite(sqlite3_context* ctx, double val)
sqlite3_result_double(ctx, val);
}
#define JSON_SUBTYPE 74 /* Ascii for "J" */
#define JSON_SUBTYPE 74 /* Ascii for "J" */
#define FLATTEN_SUBTYPE 0x5f
template<typename T>
inline void

View File

@ -35,6 +35,18 @@
#include "vtab_module.hh"
#include "yajlpp/yajlpp.hh"
struct flattened_json_string : json_string {
explicit flattened_json_string(yajl_gen_t* gen) : json_string(gen) {}
};
inline void
to_sqlite(sqlite3_context* ctx, flattened_json_string& val)
{
sqlite3_result_text(
ctx, (const char*) val.js_content.release(), val.js_len, free);
sqlite3_result_subtype(ctx, FLATTEN_SUBTYPE);
}
inline void
to_sqlite(sqlite3_context* ctx, json_string& val)
{

View File

@ -59,7 +59,9 @@ public:
const static yajl_callbacks ptr_callbacks;
explicit json_op(const json_ptr& ptr)
: jo_ptr(ptr), jo_ptr_callbacks(gen_callbacks){};
: jo_ptr(ptr), jo_ptr_callbacks(gen_callbacks)
{
}
bool check_index(bool primitive = true)
{