Skip to content
Closed
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
43 changes: 8 additions & 35 deletions be/src/vec/data_types/data_type_ipv4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ std::string DataTypeIPv4::to_string(const IColumn& column, size_t row_num) const
auto result = check_column_const_set_readability(column, row_num);
ColumnPtr ptr = result.first;
row_num = result.second;
IPv4 value = assert_cast<const ColumnIPv4&>(*ptr).get_element(row_num);
return convert_ipv4_to_string(value);
IPv4 ipv4_val = assert_cast<const ColumnIPv4&>(*ptr).get_element(row_num);
auto value = IPv4Value(ipv4_val);
return value.to_string();
}

void DataTypeIPv4::to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const {
Expand All @@ -48,43 +49,15 @@ void DataTypeIPv4::to_string(const IColumn& column, size_t row_num, BufferWritab

Status DataTypeIPv4::from_string(ReadBuffer& rb, IColumn* column) const {
auto* column_data = static_cast<ColumnIPv4*>(column);
StringParser::ParseResult result;
IPv4 val = StringParser::string_to_unsigned_int<IPv4>(rb.position(), rb.count(), &result);
IPv4 val = 0;
if (!read_ipv4_text_impl<IPv4>(val, rb)) {
return Status::InvalidArgument("parse ipv4 fail, string: '{}'",
std::string(rb.position(), rb.count()).c_str());
}
column_data->insert_value(val);
return Status::OK();
}

std::string DataTypeIPv4::convert_ipv4_to_string(IPv4 ipv4) {
std::stringstream ss;
ss << ((ipv4 >> 24) & 0xFF) << '.' << ((ipv4 >> 16) & 0xFF) << '.' << ((ipv4 >> 8) & 0xFF)
<< '.' << (ipv4 & 0xFF);
return ss.str();
}

bool DataTypeIPv4::convert_string_to_ipv4(IPv4& x, std::string ipv4) {
const static int IPV4_PARTS_NUM = 4;
IPv4 parts[IPV4_PARTS_NUM];
int part_index = 0;
std::stringstream ss(ipv4);
std::string part;
StringParser::ParseResult result;

while (std::getline(ss, part, '.')) {
IPv4 val = StringParser::string_to_unsigned_int<IPv4>(part.data(), part.size(), &result);
if (UNLIKELY(result != StringParser::PARSE_SUCCESS) || val > 255) {
return false;
}
parts[part_index++] = val;
}

if (part_index != 4) {
return false;
}

x = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
return true;
}

MutableColumnPtr DataTypeIPv4::create_column() const {
return ColumnIPv4::create();
}
Expand Down
3 changes: 0 additions & 3 deletions be/src/vec/data_types/data_type_ipv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ class DataTypeIPv4 final : public DataTypeNumberBase<IPv4> {
void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override;
Status from_string(ReadBuffer& rb, IColumn* column) const override;

static std::string convert_ipv4_to_string(IPv4 ipv4);
static bool convert_string_to_ipv4(IPv4& x, std::string ipv4);

Field get_field(const TExprNode& node) const override { return (IPv4)node.ipv4_literal.value; }

MutableColumnPtr create_column() const override;
Expand Down
23 changes: 8 additions & 15 deletions be/src/vec/data_types/data_type_ipv6.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ std::string DataTypeIPv6::to_string(const IColumn& column, size_t row_num) const
auto result = check_column_const_set_readability(column, row_num);
ColumnPtr ptr = result.first;
row_num = result.second;
IPv6 value = assert_cast<const ColumnIPv6&>(*ptr).get_element(row_num);
return convert_ipv6_to_string(value);
IPv6 ipv6_val = assert_cast<const ColumnIPv6&>(*ptr).get_element(row_num);
auto value = IPv6Value(ipv6_val);
return value.to_string();
}

void DataTypeIPv6::to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const {
Expand All @@ -48,23 +49,15 @@ void DataTypeIPv6::to_string(const IColumn& column, size_t row_num, BufferWritab

Status DataTypeIPv6::from_string(ReadBuffer& rb, IColumn* column) const {
auto* column_data = static_cast<ColumnIPv6*>(column);
IPv6 value;
if (!convert_string_to_ipv6(value, rb.to_string())) {
throw doris::Exception(doris::ErrorCode::INVALID_ARGUMENT,
"Invalid value: {} for type IPv6", rb.to_string());
IPv6 val = 0;
if (!read_ipv6_text_impl<IPv6>(val, rb)) {
return Status::InvalidArgument("parse ipv6 fail, string: '{}'",
std::string(rb.position(), rb.count()).c_str());
}
column_data->insert_value(value);
column_data->insert_value(val);
return Status::OK();
}

std::string DataTypeIPv6::convert_ipv6_to_string(IPv6 ipv6) {
return IPv6Value::to_string(ipv6);
}

bool DataTypeIPv6::convert_string_to_ipv6(IPv6& x, std::string ipv6) {
return IPv6Value::from_string(x, ipv6);
}

MutableColumnPtr DataTypeIPv6::create_column() const {
return ColumnIPv6::create();
}
Expand Down
5 changes: 1 addition & 4 deletions be/src/vec/data_types/data_type_ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,9 @@ class DataTypeIPv6 final : public DataTypeNumberBase<IPv6> {
void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override;
Status from_string(ReadBuffer& rb, IColumn* column) const override;

static std::string convert_ipv6_to_string(IPv6 ipv6);
static bool convert_string_to_ipv6(IPv6& x, std::string ipv6);

Field get_field(const TExprNode& node) const override {
IPv6 value;
if (!convert_string_to_ipv6(value, node.ipv6_literal.value)) {
if (!IPv6Value::from_string(value, node.ipv6_literal.value)) {
throw doris::Exception(doris::ErrorCode::INVALID_ARGUMENT,
"Invalid value: {} for type IPv6", node.ipv6_literal.value);
}
Expand Down
2 changes: 2 additions & 0 deletions be/src/vec/functions/function_ip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@ void register_function_ip(SimpleFunctionFactory& factory) {
"inet_aton");
factory.register_function<FunctionIPv6NumToString>();
factory.register_alias(FunctionIPv6NumToString::name, "inet6_ntoa");
factory.register_function<FunctionIsIPv4String>();
factory.register_function<FunctionIsIPv6String>();
}
} // namespace doris::vectorized
104 changes: 104 additions & 0 deletions be/src/vec/functions/function_ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -348,4 +348,108 @@ class FunctionIPv6NumToString : public IFunction {
}
};

class FunctionIsIPv4String : public IFunction {
private:
Status execute_type(Block& block, const ColumnWithTypeAndName& argument, size_t result) const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: method 'execute_type' can be made static [readability-convert-member-functions-to-static]

Suggested change
Status execute_type(Block& block, const ColumnWithTypeAndName& argument, size_t result) const {
static Status execute_type(Block& block, const ColumnWithTypeAndName& argument, size_t result) {

const ColumnPtr& column = argument.column;

if (const auto* col_src = typeid_cast<const ColumnString*>(column.get())) {
auto col_res = ColumnInt8::create();

for (size_t i = 0; i < col_src->size(); ++i) {
auto ipv4_str = col_src->get_data_at(i).to_string();
if (ipv4_str.size() > IPV4_MAX_TEXT_LENGTH || !IPv4Value::is_valid_string(ipv4_str)) {
col_res->insert_value(0);
} else {
col_res->insert_value(1);
}
}

DCHECK_EQ(col_res->size(), col_src->size());

block.replace_by_position(
result, ColumnNullable::create(std::move(col_res), ColumnUInt8::create(col_src->size(), 0)));
return Status::OK();
}

return Status::RuntimeError("Illegal column {} of argument of function {}",
argument.column->get_name(), get_name());
}

public:
static constexpr auto name = "isipv4string";
static FunctionPtr create() {
return std::make_shared<FunctionIsIPv4String>();
}

String get_name() const override { return name; }

size_t get_number_of_arguments() const override { return 1; }

DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: method 'get_return_type_impl' can be made static [readability-convert-member-functions-to-static]

Suggested change
DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
static DataTypePtr get_return_type_impl(const DataTypes& arguments) override {

return make_nullable(std::make_shared<DataTypeInt8>());
}

bool use_default_implementation_for_nulls() const override { return true; }

Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
size_t result, size_t input_rows_count) const override {
ColumnWithTypeAndName& argument = block.get_by_position(arguments[0]);
DCHECK(argument.type->get_type_id() == TypeIndex::String);
return execute_type(block, argument, result);
}
};

class FunctionIsIPv6String : public IFunction {
private:
Status execute_type(Block& block, const ColumnWithTypeAndName& argument, size_t result) const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: method 'execute_type' can be made static [readability-convert-member-functions-to-static]

Suggested change
Status execute_type(Block& block, const ColumnWithTypeAndName& argument, size_t result) const {
static Status execute_type(Block& block, const ColumnWithTypeAndName& argument, size_t result) {

const ColumnPtr& column = argument.column;

if (const auto* col_src = typeid_cast<const ColumnString*>(column.get())) {
auto col_res = ColumnInt8::create();

for (size_t i = 0; i < col_src->size(); ++i) {
auto ipv6_str = col_src->get_data_at(i).to_string();
if (ipv6_str.size() > IPV6_MAX_TEXT_LENGTH || !IPv6Value::is_valid_string(ipv6_str)) {
col_res->insert_value(0);
} else {
col_res->insert_value(1);
}
}

DCHECK_EQ(col_res->size(), col_src->size());

block.replace_by_position(
result, ColumnNullable::create(std::move(col_res), ColumnUInt8::create(col_src->size(), 0)));
return Status::OK();
}

return Status::RuntimeError("Illegal column {} of argument of function {}",
argument.column->get_name(), get_name());
}

public:
static constexpr auto name = "isipv6string";
static FunctionPtr create() {
return std::make_shared<FunctionIsIPv6String>();
}

String get_name() const override { return name; }

size_t get_number_of_arguments() const override { return 1; }

DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: method 'get_return_type_impl' can be made static [readability-convert-member-functions-to-static]

Suggested change
DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
static DataTypePtr get_return_type_impl(const DataTypes& arguments) override {

return make_nullable(std::make_shared<DataTypeInt8>());
}

bool use_default_implementation_for_nulls() const override { return true; }

Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
size_t result, size_t input_rows_count) const override {
ColumnWithTypeAndName& argument = block.get_by_position(arguments[0]);
DCHECK(argument.type->get_type_id() == TypeIndex::String);
return execute_type(block, argument, result);
}
};

} // namespace doris::vectorized
51 changes: 51 additions & 0 deletions be/test/vec/data_types/from_string_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,57 @@ TEST(FromStringTest, ScalaWrapperFieldVsDataType) {
}
}

// ipv4 and ipv6 type
{
typedef std::pair<FieldType, string> FieldType_RandStr;
std::vector<FieldType_RandStr> ip_scala_field_types = {
FieldType_RandStr(FieldType::OLAP_FIELD_TYPE_IPV4, "127.0.0.1"),
FieldType_RandStr(FieldType::OLAP_FIELD_TYPE_IPV6, "2405:9800:9800:66::2")};
for (auto pair : ip_scala_field_types) {
auto type = pair.first;
DataTypePtr data_type_ptr = DataTypeFactory::instance().create_data_type(type, 0, 0);
std::cout << "this type is " << data_type_ptr->get_name() << ": "
<< fmt::format("{}", type) << std::endl;

std::unique_ptr<WrapperField> min_wf(WrapperField::create_by_type(type));
std::unique_ptr<WrapperField> max_wf(WrapperField::create_by_type(type));
std::unique_ptr<WrapperField> rand_wf(WrapperField::create_by_type(type));

min_wf->set_to_min();
max_wf->set_to_max();
static_cast<void>(rand_wf->from_string(pair.second, 0, 0));

string min_s = min_wf->to_string();
string max_s = max_wf->to_string();
string rand_ip = rand_wf->to_string();

ReadBuffer min_rb(min_s.data(), min_s.size());
ReadBuffer max_rb(max_s.data(), max_s.size());
ReadBuffer rand_rb(rand_ip.data(), rand_ip.size());

auto col = data_type_ptr->create_column();
Status st = data_type_ptr->from_string(min_rb, col);
EXPECT_EQ(st.ok(), true);
st = data_type_ptr->from_string(max_rb, col);
EXPECT_EQ(st.ok(), true);
st = data_type_ptr->from_string(rand_rb, col);
EXPECT_EQ(st.ok(), true);

string min_s_d = data_type_ptr->to_string(*col, 0);
string max_s_d = data_type_ptr->to_string(*col, 1);
string rand_s_d = data_type_ptr->to_string(*col, 2);
rtrim(min_s);
rtrim(max_s);
rtrim(rand_ip);
std::cout << "min(" << min_s << ") with data_type_str:" << min_s_d << std::endl;
std::cout << "max(" << max_s << ") with data_type_str:" << max_s_d << std::endl;
std::cout << "rand(" << rand_ip << ") with data_type_str:" << rand_s_d << std::endl;
EXPECT_EQ(min_s, min_s_d);
EXPECT_EQ(max_s, max_s_d);
EXPECT_EQ(rand_ip, rand_s_d);
}
}

// null data type
{
DataTypePtr data_type_ptr = DataTypeFactory::instance().create_data_type(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 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.

package org.apache.doris.nereids.trees.expressions.functions.scalar;

import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable;
import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.StringType;
import org.apache.doris.nereids.types.TinyIntType;
import org.apache.doris.nereids.types.VarcharType;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;

import java.util.List;

/**
* scalar function IsIpv4String
*/
public class IsIpv4String extends ScalarFunction
implements BinaryExpression, ExplicitlyCastableSignature, AlwaysNullable {

public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
FunctionSignature.ret(TinyIntType.INSTANCE).args(VarcharType.SYSTEM_DEFAULT),
FunctionSignature.ret(TinyIntType.INSTANCE).args(StringType.INSTANCE));

public IsIpv4String(Expression arg0) {
super("isipv4string", arg0);
}

@Override
public IsIpv4String withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() == 1,
"isipv4string accept 1 args, but got %s (%s)",
children.size(),
children);
return new IsIpv4String(children.get(0));
}

@Override
public List<FunctionSignature> getSignatures() {
return SIGNATURES;
}

@Override
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
return visitor.visitIsIpv4String(this, context);
}
}
Loading