Commit 323a87b5 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-19888 Add abstract class Item_json_func

parent cff7cf15
...@@ -439,7 +439,17 @@ bool Item_func_json_value::fix_length_and_dec() ...@@ -439,7 +439,17 @@ bool Item_func_json_value::fix_length_and_dec()
{ {
collation.set(args[0]->collation); collation.set(args[0]->collation);
max_length= args[0]->max_length; max_length= args[0]->max_length;
path.set_constant_flag(args[1]->const_item()); set_constant_flag(args[1]->const_item());
maybe_null= 1;
return FALSE;
}
bool Item_func_json_query::fix_length_and_dec()
{
collation.set(args[0]->collation);
max_length= args[0]->max_length;
set_constant_flag(args[1]->const_item());
maybe_null= 1; maybe_null= 1;
return FALSE; return FALSE;
} }
...@@ -449,115 +459,100 @@ bool Item_func_json_value::fix_length_and_dec() ...@@ -449,115 +459,100 @@ bool Item_func_json_value::fix_length_and_dec()
Returns NULL, not an error if the found value Returns NULL, not an error if the found value
is not a scalar. is not a scalar.
*/ */
String *Item_func_json_value::val_str(String *str) bool Json_path_extractor::extract(String *str, Item *item_js, Item *item_jp,
CHARSET_INFO *cs)
{ {
json_engine_t je; String *js= item_js->val_json(&tmp_js);
String *js= args[0]->val_json(&tmp_js);
int error= 0; int error= 0;
uint array_counters[JSON_DEPTH_LIMIT]; uint array_counters[JSON_DEPTH_LIMIT];
if (!path.parsed) if (!parsed)
{ {
String *s_p= args[1]->val_str(&tmp_path); String *s_p= item_jp->val_str(&tmp_path);
if (s_p && if (s_p &&
json_path_setup(&path.p, s_p->charset(), (const uchar *) s_p->ptr(), json_path_setup(&p, s_p->charset(), (const uchar *) s_p->ptr(),
(const uchar *) s_p->ptr() + s_p->length())) (const uchar *) s_p->ptr() + s_p->length()))
goto err_return; return true;
path.parsed= path.constant; parsed= constant;
} }
if ((null_value= args[0]->null_value || args[1]->null_value)) if (item_js->null_value || item_jp->null_value)
return NULL; return true;
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
(const uchar *) js->ptr() + js->length());
Json_engine_scan je(*js);
str->length(0); str->length(0);
str->set_charset(collation.collation); str->set_charset(cs);
path.cur_step= path.p.steps; cur_step= p.steps;
continue_search: continue_search:
if (json_find_path(&je, &path.p, &path.cur_step, array_counters)) if (json_find_path(&je, &p, &cur_step, array_counters))
{ return true;
if (je.s.error)
goto err_return;
null_value= 1;
return 0;
}
if (json_read_value(&je)) if (json_read_value(&je))
goto err_return; return true;
if (unlikely(check_and_get_value(&je, str, &error))) if (unlikely(check_and_get_value(&je, str, &error)))
{ {
if (error) if (error)
goto err_return; return true;
goto continue_search; goto continue_search;
} }
return str; return false;
err_return:
null_value= 1;
return 0;
} }
bool Item_func_json_value::check_and_get_value(json_engine_t *je, String *res, bool Json_engine_scan::check_and_get_value_scalar(String *res, int *error)
int *error)
{ {
CHARSET_INFO *json_cs; CHARSET_INFO *json_cs;
const uchar *js; const uchar *js;
uint js_len; uint js_len;
if (!json_value_scalar(je)) if (!json_value_scalar(this))
{ {
/* We only look for scalar values! */ /* We only look for scalar values! */
if (json_skip_level(je) || json_scan_next(je)) if (json_skip_level(this) || json_scan_next(this))
*error= 1; *error= 1;
return true; return true;
} }
if (je->value_type == JSON_VALUE_TRUE || if (value_type == JSON_VALUE_TRUE ||
je->value_type == JSON_VALUE_FALSE) value_type == JSON_VALUE_FALSE)
{ {
json_cs= &my_charset_utf8mb4_bin; json_cs= &my_charset_utf8mb4_bin;
js= (const uchar *) ((je->value_type == JSON_VALUE_TRUE) ? "1" : "0"); js= (const uchar *) ((value_type == JSON_VALUE_TRUE) ? "1" : "0");
js_len= 1; js_len= 1;
} }
else else
{ {
json_cs= je->s.cs; json_cs= s.cs;
js= je->value; js= value;
js_len= je->value_len; js_len= value_len;
} }
return st_append_json(res, json_cs, js, js_len); return st_append_json(res, json_cs, js, js_len);
} }
bool Item_func_json_query::check_and_get_value(json_engine_t *je, String *res, bool Json_engine_scan::check_and_get_value_complex(String *res, int *error)
int *error)
{ {
const uchar *value; if (json_value_scalar(this))
if (json_value_scalar(je))
{ {
/* We skip scalar values. */ /* We skip scalar values. */
if (json_scan_next(je)) if (json_scan_next(this))
*error= 1; *error= 1;
return true; return true;
} }
value= je->value; const uchar *tmp_value= value;
if (json_skip_level(je)) if (json_skip_level(this))
{ {
*error= 1; *error= 1;
return true; return true;
} }
res->set((const char *) je->value, (uint32)(je->s.c_str - value), je->s.cs); res->set((const char *) value, (uint32)(s.c_str - tmp_value), s.cs);
return false; return false;
} }
......
...@@ -40,6 +40,33 @@ class json_path_with_flags ...@@ -40,6 +40,33 @@ class json_path_with_flags
}; };
class Json_engine_scan: public json_engine_t
{
public:
Json_engine_scan(CHARSET_INFO *i_cs, const uchar *str, const uchar *end)
{
json_scan_start(this, i_cs, str, end);
}
Json_engine_scan(const String &str)
:Json_engine_scan(str.charset(), (const uchar *) str.ptr(),
(const uchar *) str.end())
{ }
bool check_and_get_value_scalar(String *res, int *error);
bool check_and_get_value_complex(String *res, int *error);
};
class Json_path_extractor: public json_path_with_flags
{
protected:
String tmp_js, tmp_path;
virtual ~Json_path_extractor() { }
virtual bool check_and_get_value(Json_engine_scan *je,
String *to, int *error)=0;
bool extract(String *to, Item *js, Item *jp, CHARSET_INFO *cs);
};
class Item_func_json_valid: public Item_bool_func class Item_func_json_valid: public Item_bool_func
{ {
protected: protected:
...@@ -78,32 +105,65 @@ class Item_func_json_exists: public Item_bool_func ...@@ -78,32 +105,65 @@ class Item_func_json_exists: public Item_bool_func
}; };
class Item_func_json_value: public Item_str_func class Item_json_func: public Item_str_func
{
public:
Item_json_func(THD *thd)
:Item_str_func(thd) { }
Item_json_func(THD *thd, Item *a)
:Item_str_func(thd, a) { }
Item_json_func(THD *thd, Item *a, Item *b)
:Item_str_func(thd, a, b) { }
Item_json_func(THD *thd, List<Item> &list)
:Item_str_func(thd, list) { }
bool is_json_type() { return true; }
};
class Item_func_json_value: public Item_str_func,
public Json_path_extractor
{ {
protected:
json_path_with_flags path;
String tmp_js, tmp_path;
public: public:
Item_func_json_value(THD *thd, Item *js, Item *i_path): Item_func_json_value(THD *thd, Item *js, Item *i_path):
Item_str_func(thd, js, i_path) {} Item_str_func(thd, js, i_path) {}
const char *func_name() const { return "json_value"; } const char *func_name() const { return "json_value"; }
bool fix_length_and_dec(); bool fix_length_and_dec();
String *val_str(String *); String *val_str(String *to)
virtual bool check_and_get_value(json_engine_t *je, String *res, int *error); {
null_value= Json_path_extractor::extract(to, args[0], args[1],
collation.collation);
return null_value ? NULL : to;
}
bool check_and_get_value(Json_engine_scan *je,
String *res, int *error) override
{
return je->check_and_get_value_scalar(res, error);
}
Item *get_copy(THD *thd) Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_value>(thd, this); } { return get_item_copy<Item_func_json_value>(thd, this); }
}; };
class Item_func_json_query: public Item_func_json_value class Item_func_json_query: public Item_json_func,
public Json_path_extractor
{ {
public: public:
Item_func_json_query(THD *thd, Item *js, Item *i_path): Item_func_json_query(THD *thd, Item *js, Item *i_path):
Item_func_json_value(thd, js, i_path) {} Item_json_func(thd, js, i_path) {}
bool is_json_type() { return true; }
const char *func_name() const { return "json_query"; } const char *func_name() const { return "json_query"; }
bool check_and_get_value(json_engine_t *je, String *res, int *error); bool fix_length_and_dec();
String *val_str(String *to)
{
null_value= Json_path_extractor::extract(to, args[0], args[1],
collation.collation);
return null_value ? NULL : to;
}
bool check_and_get_value(Json_engine_scan *je,
String *res, int *error) override
{
return je->check_and_get_value_complex(res, error);
}
Item *get_copy(THD *thd) Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_query>(thd, this); } { return get_item_copy<Item_func_json_query>(thd, this); }
}; };
...@@ -139,18 +199,17 @@ class Item_func_json_unquote: public Item_str_func ...@@ -139,18 +199,17 @@ class Item_func_json_unquote: public Item_str_func
}; };
class Item_json_str_multipath: public Item_str_func class Item_json_str_multipath: public Item_json_func
{ {
protected: protected:
json_path_with_flags *paths; json_path_with_flags *paths;
String *tmp_paths; String *tmp_paths;
public: public:
Item_json_str_multipath(THD *thd, List<Item> &list): Item_json_str_multipath(THD *thd, List<Item> &list):
Item_str_func(thd, list), tmp_paths(0) {} Item_json_func(thd, list), tmp_paths(0) {}
bool fix_fields(THD *thd, Item **ref); bool fix_fields(THD *thd, Item **ref);
void cleanup(); void cleanup();
virtual uint get_n_paths() const = 0; virtual uint get_n_paths() const = 0;
bool is_json_type() { return true; }
}; };
...@@ -217,18 +276,17 @@ class Item_func_json_contains_path: public Item_bool_func ...@@ -217,18 +276,17 @@ class Item_func_json_contains_path: public Item_bool_func
}; };
class Item_func_json_array: public Item_str_func class Item_func_json_array: public Item_json_func
{ {
protected: protected:
String tmp_val; String tmp_val;
ulong result_limit; ulong result_limit;
public: public:
Item_func_json_array(THD *thd): Item_func_json_array(THD *thd):
Item_str_func(thd) {} Item_json_func(thd) {}
Item_func_json_array(THD *thd, List<Item> &list): Item_func_json_array(THD *thd, List<Item> &list):
Item_str_func(thd, list) {} Item_json_func(thd, list) {}
String *val_str(String *); String *val_str(String *);
bool is_json_type() { return true; }
bool fix_length_and_dec(); bool fix_length_and_dec();
const char *func_name() const { return "json_array"; } const char *func_name() const { return "json_array"; }
Item *get_copy(THD *thd) Item *get_copy(THD *thd)
...@@ -273,7 +331,6 @@ class Item_func_json_object: public Item_func_json_array ...@@ -273,7 +331,6 @@ class Item_func_json_object: public Item_func_json_array
Item_func_json_object(THD *thd, List<Item> &list): Item_func_json_object(THD *thd, List<Item> &list):
Item_func_json_array(thd, list) {} Item_func_json_array(thd, list) {}
String *val_str(String *); String *val_str(String *);
bool is_json_type() { return true; }
const char *func_name() const { return "json_object"; } const char *func_name() const { return "json_object"; }
Item *get_copy(THD *thd) Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_object>(thd, this); } { return get_item_copy<Item_func_json_object>(thd, this); }
...@@ -288,7 +345,6 @@ class Item_func_json_merge: public Item_func_json_array ...@@ -288,7 +345,6 @@ class Item_func_json_merge: public Item_func_json_array
Item_func_json_merge(THD *thd, List<Item> &list): Item_func_json_merge(THD *thd, List<Item> &list):
Item_func_json_array(thd, list) {} Item_func_json_array(thd, list) {}
String *val_str(String *); String *val_str(String *);
bool is_json_type() { return true; }
const char *func_name() const { return "json_merge_preserve"; } const char *func_name() const { return "json_merge_preserve"; }
Item *get_copy(THD *thd) Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_merge>(thd, this); } { return get_item_copy<Item_func_json_merge>(thd, this); }
...@@ -439,7 +495,7 @@ class Item_func_json_search: public Item_json_str_multipath ...@@ -439,7 +495,7 @@ class Item_func_json_search: public Item_json_str_multipath
}; };
class Item_func_json_format: public Item_str_func class Item_func_json_format: public Item_json_func
{ {
public: public:
enum formats enum formats
...@@ -454,15 +510,14 @@ class Item_func_json_format: public Item_str_func ...@@ -454,15 +510,14 @@ class Item_func_json_format: public Item_str_func
String tmp_js; String tmp_js;
public: public:
Item_func_json_format(THD *thd, Item *js, formats format): Item_func_json_format(THD *thd, Item *js, formats format):
Item_str_func(thd, js), fmt(format) {} Item_json_func(thd, js), fmt(format) {}
Item_func_json_format(THD *thd, List<Item> &list): Item_func_json_format(THD *thd, List<Item> &list):
Item_str_func(thd, list), fmt(DETAILED) {} Item_json_func(thd, list), fmt(DETAILED) {}
const char *func_name() const; const char *func_name() const;
bool fix_length_and_dec(); bool fix_length_and_dec();
String *val_str(String *str); String *val_str(String *str);
String *val_json(String *str); String *val_json(String *str);
bool is_json_type() { return true; }
Item *get_copy(THD *thd) Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_format>(thd, this); } { return get_item_copy<Item_func_json_format>(thd, this); }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment