blob: a77ca7699cd0fb5114ebfdb207b5fc66a0834a55 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <DataTypes/DataTypeArray.h>
#include <DataTypes/DataTypeFunction.h>
#include <DataTypes/DataTypeMap.h>
#include <DataTypes/DataTypeNullable.h>
#include <Functions/FunctionHelpers.h>
#include <Parser/FunctionParser.h>
#include <Parser/TypeParser.h>
#include <Parser/scalar_function_parser/lambdaFunction.h>
#include <Common/BlockTypeUtils.h>
#include <Common/CHUtil.h>
#include <Common/Exception.h>
#include <Common/logger_useful.h>
namespace DB::ErrorCodes
{
extern const int SIZES_OF_COLUMNS_DOESNT_MATCH;
extern const int BAD_ARGUMENTS;
}
using namespace DB;
namespace local_engine
{
template <bool transform_keys = true>
class FunctionParserMapTransformImpl : public FunctionParser
{
public:
static constexpr auto name = transform_keys ? "transform_keys" : "transform_values";
String getName() const override { return name; }
explicit FunctionParserMapTransformImpl(ParserContextPtr parser_context_) : FunctionParser(parser_context_) {}
~FunctionParserMapTransformImpl() override = default;
const ActionsDAG::Node *
parse(const substrait::Expression_ScalarFunction & substrait_func, ActionsDAG & actions_dag) const override
{
/// Parse spark transform_keys(map, func) as CH mapFromArrays(arrayMap(func, cast(map as array)), mapValues(map))
/// Parse spark transform_values(map, func) as CH mapFromArrays(mapKeys(map), arrayMap(func, cast(map as array)))
auto parsed_args = parseFunctionArguments(substrait_func, actions_dag);
if (parsed_args.size() != 2)
throw Exception(ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH, "{} function must have three arguments", getName());
auto lambda_args = collectLambdaArguments(parser_context, substrait_func.arguments()[1].value().scalar_function());
if (lambda_args.size() != 2)
throw Exception(
ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH, "The lambda function in {} must have two arguments", getName());
const auto * map_node = parsed_args[0];
const auto * func_node = parsed_args[1];
const auto & map_type = map_node->result_type;
auto array_type = checkAndGetDataType<DataTypeMap>(removeNullable(map_type).get())->getNestedType();
if (map_type->isNullable())
array_type = std::make_shared<DataTypeNullable>(array_type);
const auto * array_node = ActionsDAGUtil::convertNodeTypeIfNeeded(actions_dag, map_node, array_type);
const auto * transformed_node = toFunctionNode(actions_dag, "arrayMap", {func_node, array_node});
const ActionsDAG::Node * result_node = nullptr;
if constexpr (transform_keys)
{
const auto * nontransformed_node = toFunctionNode(actions_dag, "mapValues", {parsed_args[0]});
result_node = toFunctionNode(actions_dag, "mapFromArrays", {transformed_node, nontransformed_node});
}
else
{
const auto * nontransformed_node = toFunctionNode(actions_dag, "mapKeys", {parsed_args[0]});
result_node = toFunctionNode(actions_dag, "mapFromArrays", {nontransformed_node, transformed_node});
}
return convertNodeTypeIfNeeded(substrait_func, result_node, actions_dag);
}
};
using FunctionParserTransformKeys = FunctionParserMapTransformImpl<true>;
using FunctionParserTransformValues = FunctionParserMapTransformImpl<false>;
static FunctionParserRegister<FunctionParserTransformKeys> register_transform_keys;
static FunctionParserRegister<FunctionParserTransformValues> register_transform_values;
}