Skip to content

MDEV-32854: json_depth #3574

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: stable-23.10
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions utils/funcexp/func_json_array_append.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,16 @@ string Func_json_array_append::getStrVal(rowgroup::Row& row, FunctionParm& fp, b
const CHARSET_INFO* cs = getCharset(fp[0]);

json_engine_t jsEg;
int jsEg_stack[JSON_DEPTH_LIMIT];
json_path_step_t p_steps[JSON_DEPTH_LIMIT];
const uchar* arrEnd;
size_t strRestLen;
string retJS;
retJS.reserve(js.length() + padding);

mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&jsEg.stack, sizeof(int), &jsEg_stack,
JSON_DEPTH_LIMIT, 0, MYF(0));
initJSPaths(paths, fp, 1, 2);

utils::NullString tmpJS(js);
Expand All @@ -44,6 +49,10 @@ string Func_json_array_append::getStrVal(rowgroup::Row& row, FunctionParm& fp, b
const size_t jsLen = tmpJS.length();
JSONPath& path = paths[j];

mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&path.p.steps, sizeof(json_path_step_t), &p_steps,
JSON_DEPTH_LIMIT, 0, MYF(0));

if (!path.parsed && parseJSPath(path, row, fp[i], false))
goto error;

Expand Down
24 changes: 19 additions & 5 deletions utils/funcexp/func_json_array_insert.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "functor_json.h"
#include "functioncolumn.h"
#include "constantcolumn.h"
#include "json_lib.h"
#include "my_sys.h"
using namespace execplan;

#include "rowgroup.h"
Expand Down Expand Up @@ -30,11 +32,17 @@ string Func_json_array_insert::getStrVal(rowgroup::Row& row, FunctionParm& fp, b
const CHARSET_INFO* cs = getCharset(fp[0]);

json_engine_t jsEg;
int jsEg_stack[JSON_DEPTH_LIMIT];
string retJS;
retJS.reserve(js.length() + 8);
json_path_step_t p_steps[JSON_DEPTH_LIMIT];

initJSPaths(paths, fp, 1, 2);

mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&jsEg.stack, sizeof(int), &jsEg_stack,
JSON_DEPTH_LIMIT, 0, MYF(0));

utils::NullString tmpJS(js);
for (size_t i = 1, j = 0; i < fp.size(); i += 2, j++)
{
Expand All @@ -43,19 +51,23 @@ string Func_json_array_insert::getStrVal(rowgroup::Row& row, FunctionParm& fp, b
JSONPath& path = paths[j];
if (!path.parsed)
{
if (parseJSPath(path, row, fp[i]) || path.p.last_step - 1 < path.p.steps ||
path.p.last_step->type != JSON_PATH_ARRAY)
mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&path.p.steps, sizeof(json_path_step_t), &p_steps,
JSON_DEPTH_LIMIT, 0, MYF(0));
json_path_step_t *last_step= (json_path_step_t*)(mem_root_dynamic_array_get_val(&path.p.steps, path.p.last_step_idx)),
*initial_step= (json_path_step_t*)path.p.steps.buffer;
if (parseJSPath(path, row, fp[i]) || (last_step - 1) < initial_step ||
last_step->type != JSON_PATH_ARRAY)
{
if (path.p.s.error == 0)
path.p.s.error = SHOULD_END_WITH_ARRAY;
goto error;
}
path.p.last_step--;
path.p.last_step_idx--;
}

initJSEngine(jsEg, cs, tmpJS);

path.currStep = path.p.steps;

int jsErr = 0;
if (locateJSPath(jsEg, path, &jsErr))
Expand All @@ -82,7 +94,9 @@ string Func_json_array_insert::getStrVal(rowgroup::Row& row, FunctionParm& fp, b
while (json_scan_next(&jsEg) == 0 && jsEg.state != JST_ARRAY_END)
{
DBUG_ASSERT(jsEg.state == JST_VALUE);
if (itemSize == path.p.last_step[1].n_item)
if (itemSize == (((json_path_step_t*)
(mem_root_dynamic_array_get_val(&path.p.steps,
path.p.last_step_idx)))[1].n_item))
{
itemPos = (const char*)jsEg.s.c_str;
break;
Expand Down
14 changes: 14 additions & 0 deletions utils/funcexp/func_json_contains.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "functor_json.h"
#include "functioncolumn.h"
#include "constantcolumn.h"
#include "json_lib.h"
#include "rowgroup.h"
using namespace execplan;
using namespace rowgroup;
Expand Down Expand Up @@ -160,6 +161,9 @@ bool Func_json_contains::getBoolVal(Row& row, FunctionParm& fp, bool& isNull,
CalpontSystemCatalog::ColType& /*type*/)
{
bool isNullJS = false, isNullVal = false;
int jsEg_stack[JSON_DEPTH_LIMIT], valEg_stack[JSON_DEPTH_LIMIT];
json_path_step_t p_steps[JSON_DEPTH_LIMIT];

const auto& js = fp[0]->data()->getStrVal(row, isNullJS);
const auto& val = fp[1]->data()->getStrVal(row, isNullVal);
if (isNullJS || isNullVal)
Expand All @@ -182,10 +186,17 @@ bool Func_json_contains::getBoolVal(Row& row, FunctionParm& fp, bool& isNull,
}

json_engine_t jsEg;
mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&jsEg.stack, sizeof(int), &jsEg_stack,
JSON_DEPTH_LIMIT, 0, MYF(0));
initJSEngine(jsEg, getCharset(fp[0]), js);

if (fp.size() > 2)
{
mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&path.p.steps, sizeof(json_path_step_t), &p_steps,
JSON_DEPTH_LIMIT, 0, MYF(0));

if (!path.parsed && parseJSPath(path, row, fp[2], false))
goto error;

Expand All @@ -194,6 +205,9 @@ bool Func_json_contains::getBoolVal(Row& row, FunctionParm& fp, bool& isNull,
}

json_engine_t valEg;
mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&valEg.stack, sizeof(int), &valEg_stack,
JSON_DEPTH_LIMIT, 0, MYF(0));
initJSEngine(valEg, getCharset(fp[1]), arg2Val);

if (json_read_value(&jsEg) || json_read_value(&valEg))
Expand Down
21 changes: 19 additions & 2 deletions utils/funcexp/func_json_contains_path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,17 @@ bool Func_json_contains_path::getBoolVal(Row& row, FunctionParm& fp, bool& isNul
if (paths.size() == 0)
hasFound.assign(argSize, false);

vector<vector<json_path_step_t>> p_steps_arr(paths.size(), vector<json_path_step_t>(32));

for (size_t i = 2; i < fp.size(); i++)
{
JSONPath& path = paths[i - 2];

if (!path.parsed)
{
mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&path.p.steps, sizeof(json_path_step_t), &p_steps_arr[i-4],
JSON_DEPTH_LIMIT, 0, MYF(0));
if (parseJSPath(path, row, fp[i]))
{
isNull = true;
Expand All @@ -83,7 +88,17 @@ bool Func_json_contains_path::getBoolVal(Row& row, FunctionParm& fp, bool& isNul
}

json_engine_t jsEg;
int jsEg_stack[JSON_DEPTH_LIMIT];
json_path_t p;
json_path_step_t p_steps[JSON_DEPTH_LIMIT];

mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&p.steps, sizeof(json_path_step_t), &p_steps,
JSON_DEPTH_LIMIT, 0, MYF(0));
mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&jsEg.stack, sizeof(int), &jsEg_stack,
JSON_DEPTH_LIMIT, 0, MYF(0));

json_get_path_start(&jsEg, getCharset(fp[0]), (const uchar*)js.data(), (const uchar*)js.data() + js.size(),
&p);

Expand All @@ -98,9 +113,11 @@ bool Func_json_contains_path::getBoolVal(Row& row, FunctionParm& fp, bool& isNul

while (json_get_path_next(&jsEg, &p) == 0)
{
#if MYSQL_VERSION_ID >= 100900
json_path_step_t *last_step= (json_path_step_t*)
(mem_root_dynamic_array_get_val(&p.steps,
p.last_step_idx));
if (hasNegPath && jsEg.value_type == JSON_VALUE_ARRAY &&
json_skip_array_and_count(&jsEg, arrayCounters + (p.last_step - p.steps)))
json_skip_array_and_count(&jsEg, arrayCounters + (last_step - (json_path_step_t*)p.steps.buffer)))
{
result = true;
break;
Expand Down
5 changes: 5 additions & 0 deletions utils/funcexp/func_json_depth.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "functor_json.h"
#include "functioncolumn.h"
#include "json_lib.h"
using namespace execplan;

#include "rowgroup.h"
Expand Down Expand Up @@ -28,8 +29,12 @@ int64_t Func_json_depth::getIntVal(rowgroup::Row& row, FunctionParm& fp, bool& i

int depth = 0, currDepth = 0;
bool incDepth = true;
int jsEg_stack[JSON_DEPTH_LIMIT];

json_engine_t jsEg;
mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&jsEg.stack, sizeof(int), &jsEg_stack,
JSON_DEPTH_LIMIT, 0, MYF(0));
initJSEngine(jsEg, getCharset(fp[0]), js);

do
Expand Down
18 changes: 16 additions & 2 deletions utils/funcexp/func_json_equals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,20 @@ CalpontSystemCatalog::ColType Func_json_equals::operationType(FunctionParm& fp,
bool Func_json_equals::getBoolVal(Row& row, FunctionParm& fp, bool& isNull,
CalpontSystemCatalog::ColType& /*type*/)
{
json_engine_t je;
MEM_ROOT_DYNAMIC_ARRAY array;
int je_stack[JSON_DEPTH_LIMIT], buffer_array[JSON_DEPTH_LIMIT];

// auto release the DYNAMIC_STRING
using DynamicString = unique_ptr<DYNAMIC_STRING, decltype(&dynstr_free)>;

mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&je.stack, sizeof(int), &je_stack,
JSON_DEPTH_DEFAULT, 0, MYF(0));
mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&array, sizeof(int), &buffer_array,
JSON_DEPTH_DEFAULT, 0, MYF(0));

DynamicString str1{new DYNAMIC_STRING(), dynstr_free};
if (init_dynamic_string(str1.get(), NULL, 0, 0))
{
Expand All @@ -56,13 +67,16 @@ bool Func_json_equals::getBoolVal(Row& row, FunctionParm& fp, bool& isNull,
const string_view js2 = js2_ns.unsafeStringRef();

bool result = false;
if (json_normalize(str1.get(), js1.data(), js1.size(), getCharset(fp[0])))
if (json_normalize(str1.get(), js1.data(), js1.size(), getCharset(fp[0]), NULL, &je, &array))
{
isNull = true;
return result;
}

if (json_normalize(str2.get(), js2.data(), js2.size(), getCharset(fp[1])))
memset(je_stack, 0, sizeof(je_stack));
memset(buffer_array, 0, sizeof(buffer_array));

if (json_normalize(str2.get(), js2.data(), js2.size(), getCharset(fp[1]), NULL, &je, &array))
{
isNull = true;
return result;
Expand Down
11 changes: 11 additions & 0 deletions utils/funcexp/func_json_exists.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "functor_json.h"
#include "functioncolumn.h"
#include "constantcolumn.h"
#include "json_lib.h"
#include "rowgroup.h"
using namespace execplan;
using namespace rowgroup;
Expand Down Expand Up @@ -30,8 +31,18 @@ bool Func_json_exists::getBoolVal(Row& row, FunctionParm& fp, bool& isNull,

int jsErr = 0;
json_engine_t jsEg;
int jsEg_stack[JSON_DEPTH_LIMIT];
json_path_step_t p_steps[JSON_DEPTH_LIMIT];

mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&jsEg.stack, sizeof(int), &jsEg_stack,
JSON_DEPTH_LIMIT, 0, MYF(0));
initJSEngine(jsEg, getCharset(fp[0]), js);

mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&path.p.steps, sizeof(json_path_step_t), &p_steps,
JSON_DEPTH_LIMIT, 0, MYF(0));

if (!path.parsed && parseJSPath(path, row, fp[1]))
goto error;

Expand Down
21 changes: 19 additions & 2 deletions utils/funcexp/func_json_extract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ int Func_json_extract::doExtract(Row& row, FunctionParm& fp, json_value_types* t
return 1;
const char* rawJS = js.str();
json_engine_t jsEg, savJSEg;
int jsEg_stack[JSON_DEPTH_LIMIT], savJSEg_stack[JSON_DEPTH_LIMIT];
json_path_t p;
json_path_step_t p_steps[JSON_DEPTH_LIMIT];
const uchar* value;
bool notFirstVal = false;
size_t valLen;
Expand All @@ -37,10 +39,25 @@ int Func_json_extract::doExtract(Row& row, FunctionParm& fp, json_value_types* t
string tmp;

initJSPaths(paths, fp, 1, 1);
vector<vector<json_path_step_t>> p_steps_arr(paths.size(), vector<json_path_step_t>(32));

mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&p.steps, sizeof(json_path_step_t), &p_steps,
JSON_DEPTH_LIMIT, 0, MYF(0));

mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&jsEg.stack, sizeof(int), &jsEg_stack,
JSON_DEPTH_LIMIT, 0, MYF(0));
mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&savJSEg.stack, sizeof(int), &savJSEg_stack,
JSON_DEPTH_LIMIT, 0, MYF(0));

for (size_t i = 1; i < argSize; i++)
{
JSONPath& path = paths[i - 1];
mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&path.p.steps, sizeof(json_path_step_t), &p_steps_arr[i-1],
JSON_DEPTH_LIMIT, 0, MYF(0));
path.p.types_used = JSON_PATH_KEY_NULL;
if (!path.parsed && parseJSPath(path, row, fp[i]))
return 1;
Expand Down Expand Up @@ -70,9 +87,9 @@ int Func_json_extract::doExtract(Row& row, FunctionParm& fp, json_value_types* t

while (json_get_path_next(&jsEg, &p) == 0)
{
#if MYSQL_VERSION_ID >= 100900
json_path_step_t *last_step= (json_path_step_t*)(mem_root_dynamic_array_get_val(&p.steps, p.last_step_idx));
if (hasNegPath && jsEg.value_type == JSON_VALUE_ARRAY &&
json_skip_array_and_count(&jsEg, arrayCounter + (p.last_step - p.steps)))
json_skip_array_and_count(&jsEg, arrayCounter + (last_step - (json_path_step_t*)(p.steps.buffer))))
return 1;
#endif

Expand Down
6 changes: 6 additions & 0 deletions utils/funcexp/func_json_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@ string Func_json_format::getStrVal(rowgroup::Row& row, FunctionParm& fp, bool& i
}

json_engine_t jsEg;
int jsEg_stack [JSON_DEPTH_LIMIT];

mem_root_dynamic_array_init(NULL, PSI_INSTRUMENT_MEM | MY_INIT_BUFFER_USED | MY_BUFFER_NO_RESIZE,
&jsEg.stack, sizeof(int), &jsEg_stack,
JSON_DEPTH_LIMIT, 0, MYF(0));
initJSEngine(jsEg, getCharset(fp[0]), js);

string ret;
if (doFormat(&jsEg, ret, fmt, tabSize))
{
Expand Down
Loading