Skip to content

Commit

Permalink
udpate
Browse files Browse the repository at this point in the history
  • Loading branch information
SeaRise committed Dec 13, 2023
1 parent 045de53 commit 1ef46e7
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 81 deletions.
207 changes: 129 additions & 78 deletions dbms/src/Functions/FunctionsJson.h
Original file line number Diff line number Diff line change
Expand Up @@ -1541,7 +1541,7 @@ class FunctionJsonContainsPath : public IFunction
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
}
if (arguments[0]->onlyNull() || arguments[1]->onlyNull())
if (arguments[0]->onlyNull() || arguments[1]->onlyNull() || arguments[2]->onlyNull())
return makeNullable(std::make_shared<DataTypeNothing>());
else
{
Expand All @@ -1559,7 +1559,7 @@ class FunctionJsonContainsPath : public IFunction
{
const auto & json_col = block.getByPosition(arguments[0]).column;
const auto & type_col = block.getByPosition(arguments[1]).column;
if (json_col->onlyNull() || type_col->onlyNull())
if (json_col->onlyNull() || type_col->onlyNull() || block.getByPosition(arguments[2]).column->onlyNull())
{
block.getByPosition(result).column
= block.getByPosition(result).type->createColumnConst(block.rows(), Null());
Expand All @@ -1571,34 +1571,36 @@ class FunctionJsonContainsPath : public IFunction
auto type_source = createDynamicStringSource(*nested_block.getByPosition(arguments[1]).column);

size_t rows = block.rows();
auto awalys_true_null_map = ColumnUInt8::create(rows, 1);
auto awalys_false_null_map = ColumnUInt8::create(rows, 0);

auto col_to = ColumnUInt8::create(rows, 1);
auto & data_to = col_to->getData();
auto col_null_map = ColumnUInt8::create(rows, 0);
auto & vec_null_map = col_null_map->getData();

StringSources path_sources;
path_sources.reserve(arguments.size() - 2);
bool paths_nullable = false;
std::vector<const NullMap *> path_null_maps;
path_null_maps.reserve(arguments.size() - 2);
for (size_t i = 2; i < arguments.size(); ++i)
{
const auto & path_col = block.getByPosition(arguments[i]).column;
if (path_col->onlyNull())
{
path_sources.push_back(nullptr);
path_null_maps.push_back(&awalys_true_null_map->getData());
paths_nullable = true;
path_null_maps.push_back(nullptr);
}
else if (path_col->isColumnNullable())
{
const auto & path_column_nullable = static_cast<const ColumnNullable &>(*path_col);
path_sources.push_back(createDynamicStringSource(*nested_block.getByPosition(arguments[i]).column));
paths_nullable = true;
const auto & path_column_nullable = static_cast<const ColumnNullable &>(*path_col);
path_null_maps.push_back(&path_column_nullable.getNullMapData());
}
else
{
path_sources.push_back(createDynamicStringSource(*nested_block.getByPosition(arguments[i]).column));
path_null_maps.push_back(&awalys_false_null_map->getData());
path_null_maps.push_back(nullptr);
}
}

Expand All @@ -1608,59 +1610,107 @@ class FunctionJsonContainsPath : public IFunction
if (type_col->isColumnNullable())
{
const auto & type_column_nullable = static_cast<const ColumnNullable &>(*type_col);
doExecute<true, true>(
json_source,
json_column_nullable.getNullMapData(),
type_source,
type_column_nullable.getNullMapData(),
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
if (paths_nullable)
doExecute<true, true, true>(
json_source,
json_column_nullable.getNullMapData(),
type_source,
type_column_nullable.getNullMapData(),
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
else
doExecute<true, true, false>(
json_source,
json_column_nullable.getNullMapData(),
type_source,
type_column_nullable.getNullMapData(),
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
}
else
{
doExecute<true, false>(
json_source,
json_column_nullable.getNullMapData(),
type_source,
{},
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
if (paths_nullable)
doExecute<true, false, true>(
json_source,
json_column_nullable.getNullMapData(),
type_source,
{},
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
else
doExecute<true, false, false>(
json_source,
json_column_nullable.getNullMapData(),
type_source,
{},
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
}
}
else
{
if (type_col->isColumnNullable())
{
const auto & type_column_nullable = static_cast<const ColumnNullable &>(*type_col);
doExecute<false, true>(
json_source,
{},
type_source,
type_column_nullable.getNullMapData(),
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
if (paths_nullable)
doExecute<false, true, true>(
json_source,
{},
type_source,
type_column_nullable.getNullMapData(),
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
else
doExecute<false, true, false>(
json_source,
{},
type_source,
type_column_nullable.getNullMapData(),
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
}
else
{
doExecute<false, false>(
json_source,
{},
type_source,
{},
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
if (paths_nullable)
doExecute<false, false, true>(
json_source,
{},
type_source,
{},
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
else
doExecute<false, false, false>(
json_source,
{},
type_source,
{},
path_sources,
path_null_maps,
rows,
data_to,
vec_null_map);
}
}

Expand All @@ -1672,7 +1722,7 @@ class FunctionJsonContainsPath : public IFunction
}

private:
template <bool is_json_nullable, bool is_type_nullable>
template <bool is_json_nullable, bool is_type_nullable, bool paths_nullable>
void doExecute(
const std::unique_ptr<IStringSource> & json_source,
const NullMap & null_map_json,
Expand Down Expand Up @@ -1727,40 +1777,41 @@ class FunctionJsonContainsPath : public IFunction
auto & res = data_to[row]; // default 1.
for (size_t i = 0; i < path_sources.size(); ++i)
{
if ((*path_null_maps[i])[row])
{
null_map_to[row] = 1;
break;
}
else
if constexpr (paths_nullable)
{
assert(path_sources[i]);
const auto & path_val = path_sources[i]->getWhole();
auto path_expr = JsonPathExpr::parseJsonPathExpr(StringRef{path_val.data, path_val.size});
/// If path_expr failed to parse, throw exception
if unlikely (!path_expr)
throw Exception(
fmt::format("Illegal json path expression of function {}", getName()),
ErrorCodes::ILLEGAL_COLUMN);
auto path_expr_containor = std::make_unique<JsonPathExprRefContainer>(path_expr);
std::vector<JsonPathExprRefContainerPtr> path_expr_containor_vec;
path_expr_containor_vec.push_back(std::move(path_expr_containor));
bool exists = !json_binary.extract(path_expr_containor_vec).empty();
if (exists && JsonBinary::isJSONContainsPathOne(type))
{
res = 1;
break;
}
else if (!exists && JsonBinary::isJSONContainsPathOne(type))
if (!path_sources[i] || (path_null_maps[i] && (*path_null_maps[i])[row]))
{
res = 0;
}
else if (!exists && JsonBinary::isJSONContainsPathAll(type))
{
res = 0;
null_map_to[row] = 1;
break;
}
}

assert(path_sources[i]);
const auto & path_val = path_sources[i]->getWhole();
auto path_expr = JsonPathExpr::parseJsonPathExpr(StringRef{path_val.data, path_val.size});
/// If path_expr failed to parse, throw exception
if unlikely (!path_expr)
throw Exception(
fmt::format("Illegal json path expression of function {}", getName()),
ErrorCodes::ILLEGAL_COLUMN);
auto path_expr_containor = std::make_unique<JsonPathExprRefContainer>(path_expr);
std::vector<JsonPathExprRefContainerPtr> path_expr_containor_vec;
path_expr_containor_vec.push_back(std::move(path_expr_containor));
bool exists = !json_binary.extract(path_expr_containor_vec).empty();
if (exists && JsonBinary::isJSONContainsPathOne(type))
{
res = 1;
break;
}
else if (!exists && JsonBinary::isJSONContainsPathOne(type))
{
res = 0;
}
else if (!exists && JsonBinary::isJSONContainsPathAll(type))
{
res = 0;
break;
}
}

FINISH_PER_ROW
Expand Down
18 changes: 15 additions & 3 deletions dbms/src/Functions/tests/gtest_json_contains_path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,37 @@ try
auto type_column = createColumn<Nullable<String>>({"one", "one"});
ColumnWithTypeAndName path_column = createColumn<Nullable<String>>({"$", "$"});
ColumnWithTypeAndName path_column2 = createColumn<Nullable<String>>({"$.a", "$.a"});
ColumnWithTypeAndName null_string_const = createConstColumn<Nullable<String>>(rows_count, {});
ColumnWithTypeAndName null_bool_const = createConstColumn<Nullable<UInt8>>(rows_count, {});
ColumnWithTypeAndName only_null_const = createOnlyNullColumnConst(rows_count);

ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({true, true}),
executeFunction(func_name, json_column, type_column, path_column));
ASSERT_COLUMN_EQ(only_null_const, executeFunction(func_name, only_null_const, type_column, path_column));
ASSERT_COLUMN_EQ(null_bool_const, executeFunction(func_name, null_string_const, type_column, path_column));
ASSERT_COLUMN_EQ(only_null_const, executeFunction(func_name, json_column, only_null_const, path_column));
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({{}, {}}),
executeFunction(func_name, json_column, type_column, only_null_const));
ASSERT_COLUMN_EQ(null_bool_const, executeFunction(func_name, json_column, null_string_const, path_column));
ASSERT_COLUMN_EQ(only_null_const, executeFunction(func_name, json_column, type_column, only_null_const));
ASSERT_COLUMN_EQ(null_bool_const, executeFunction(func_name, json_column, type_column, null_string_const));
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({true, true}),
executeFunction(func_name, json_column, type_column, path_column, only_null_const));
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({true, true}),
executeFunction(func_name, json_column, type_column, path_column, null_string_const));
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({{}, {}}),
executeFunction(func_name, json_column, type_column, path_column2, only_null_const));
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({{}, {}}),
executeFunction(func_name, json_column, type_column, path_column2, null_string_const));
ASSERT_COLUMN_EQ(
only_null_const,
executeFunction(func_name, json_column, type_column, only_null_const, path_column));
ASSERT_COLUMN_EQ(
null_bool_const,
executeFunction(func_name, json_column, type_column, null_string_const, path_column));
}
CATCH

Expand Down

0 comments on commit 1ef46e7

Please sign in to comment.