|
28 | 28 | #include "core/block/block.h" |
29 | 29 | #include "core/block/column_with_type_and_name.h" |
30 | 30 | #include "core/column/column.h" |
| 31 | +#include "core/column/column_array.h" |
31 | 32 | #include "core/column/column_execute_util.h" |
32 | 33 | #include "core/column/column_nullable.h" |
| 34 | +#include "core/data_type/data_type_array.h" |
33 | 35 | #include "core/data_type/data_type_nullable.h" |
34 | 36 | #include "core/data_type/data_type_number.h" |
35 | 37 | #include "core/data_type/data_type_string.h" |
@@ -917,6 +919,167 @@ struct StDistance { |
917 | 919 | } |
918 | 920 | }; |
919 | 921 |
|
| 922 | +struct StNumGeometries { |
| 923 | + static constexpr auto NAME = "st_numgeometries"; |
| 924 | + static const size_t NUM_ARGS = 1; |
| 925 | + using Type = DataTypeInt64; |
| 926 | + |
| 927 | + static Status execute(Block& block, const ColumnNumbers& arguments, size_t result) { |
| 928 | + DCHECK_EQ(arguments.size(), 1); |
| 929 | + |
| 930 | + auto col = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const(); |
| 931 | + const auto size = col->size(); |
| 932 | + |
| 933 | + auto res = ColumnInt64::create(); |
| 934 | + res->reserve(size); |
| 935 | + |
| 936 | + auto null_map = ColumnUInt8::create(size, 0); |
| 937 | + auto& null_map_data = null_map->get_data(); |
| 938 | + |
| 939 | + for (int row = 0; row < size; ++row) { |
| 940 | + auto value = col->get_data_at(row); |
| 941 | + auto shape = GeoShape::from_encoded(value.data, value.size); |
| 942 | + if (!shape) { |
| 943 | + null_map_data[row] = 1; |
| 944 | + res->insert_default(); |
| 945 | + continue; |
| 946 | + } |
| 947 | + |
| 948 | + res->insert_value(shape->num_geometries()); |
| 949 | + } |
| 950 | + |
| 951 | + block.replace_by_position(result, |
| 952 | + ColumnNullable::create(std::move(res), std::move(null_map))); |
| 953 | + return Status::OK(); |
| 954 | + } |
| 955 | +}; |
| 956 | + |
| 957 | +struct StGeometries { |
| 958 | + static constexpr auto NAME = "st_geometries"; |
| 959 | + static const size_t NUM_ARGS = 1; |
| 960 | + |
| 961 | + static Status execute(Block& block, const ColumnNumbers& arguments, size_t result) { |
| 962 | + DCHECK_EQ(arguments.size(), 1); |
| 963 | + |
| 964 | + auto col = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const(); |
| 965 | + const auto size = col->size(); |
| 966 | + |
| 967 | + auto nested_data = ColumnString::create(); |
| 968 | + auto offsets_col = ColumnArray::ColumnOffsets::create(); |
| 969 | + auto& offsets = offsets_col->get_data(); |
| 970 | + offsets.reserve(size); |
| 971 | + |
| 972 | + auto null_map = ColumnUInt8::create(size, 0); |
| 973 | + auto& null_map_data = null_map->get_data(); |
| 974 | + |
| 975 | + size_t current_offset = 0; |
| 976 | + std::string buf; |
| 977 | + |
| 978 | + for (size_t row = 0; row < size; ++row) { |
| 979 | + auto shape_value = col->get_data_at(row); |
| 980 | + auto shape = GeoShape::from_encoded(shape_value.data, shape_value.size); |
| 981 | + |
| 982 | + if (!shape) { |
| 983 | + null_map_data[row] = 1; |
| 984 | + offsets.push_back(current_offset); |
| 985 | + continue; |
| 986 | + } |
| 987 | + |
| 988 | + if (shape->type() == GEO_SHAPE_MULTI_POLYGON) { |
| 989 | + auto* multi_polygon = static_cast<GeoMultiPolygon*>(shape.get()); |
| 990 | + const auto& polygons = multi_polygon->polygons(); |
| 991 | + |
| 992 | + if (polygons.empty()) { |
| 993 | + null_map_data[row] = 1; |
| 994 | + offsets.push_back(current_offset); |
| 995 | + continue; |
| 996 | + } |
| 997 | + |
| 998 | + for (const auto& polygon : polygons) { |
| 999 | + DCHECK(polygon != nullptr); |
| 1000 | + buf.clear(); |
| 1001 | + polygon->encode_to(&buf); |
| 1002 | + nested_data->insert_data(buf.data(), buf.size()); |
| 1003 | + ++current_offset; |
| 1004 | + } |
| 1005 | + } else { |
| 1006 | + nested_data->insert_data(shape_value.data, shape_value.size); |
| 1007 | + ++current_offset; |
| 1008 | + } |
| 1009 | + |
| 1010 | + offsets.push_back(current_offset); |
| 1011 | + } |
| 1012 | + |
| 1013 | + auto nested_null_map = ColumnUInt8::create(nested_data->size(), 0); |
| 1014 | + auto nested_nullable = |
| 1015 | + ColumnNullable::create(std::move(nested_data), std::move(nested_null_map)); |
| 1016 | + auto array_col = ColumnArray::create(std::move(nested_nullable), std::move(offsets_col)); |
| 1017 | + |
| 1018 | + block.replace_by_position( |
| 1019 | + result, ColumnNullable::create(std::move(array_col), std::move(null_map))); |
| 1020 | + |
| 1021 | + return Status::OK(); |
| 1022 | + } |
| 1023 | +}; |
| 1024 | + |
| 1025 | +class FunctionStGeometries final : public IFunction { |
| 1026 | +public: |
| 1027 | + static constexpr auto name = StGeometries::NAME; |
| 1028 | + |
| 1029 | + static FunctionPtr create() { return std::make_shared<FunctionStGeometries>(); } |
| 1030 | + |
| 1031 | + String get_name() const override { return name; } |
| 1032 | + |
| 1033 | + size_t get_number_of_arguments() const override { return StGeometries::NUM_ARGS; } |
| 1034 | + |
| 1035 | + bool is_variadic() const override { return false; } |
| 1036 | + |
| 1037 | + DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { |
| 1038 | + return make_nullable( |
| 1039 | + std::make_shared<DataTypeArray>(make_nullable(std::make_shared<DataTypeString>()))); |
| 1040 | + } |
| 1041 | + |
| 1042 | + Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, |
| 1043 | + uint32_t result, size_t input_rows_count) const override { |
| 1044 | + return StGeometries::execute(block, arguments, result); |
| 1045 | + } |
| 1046 | +}; |
| 1047 | + |
| 1048 | +struct StNumPoints { |
| 1049 | + static constexpr auto NAME = "st_numpoints"; |
| 1050 | + static const size_t NUM_ARGS = 1; |
| 1051 | + using Type = DataTypeInt64; |
| 1052 | + |
| 1053 | + static Status execute(Block& block, const ColumnNumbers& arguments, size_t result) { |
| 1054 | + DCHECK_EQ(arguments.size(), 1); |
| 1055 | + |
| 1056 | + auto col = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const(); |
| 1057 | + const auto size = col->size(); |
| 1058 | + |
| 1059 | + auto res = ColumnInt64::create(); |
| 1060 | + res->reserve(size); |
| 1061 | + |
| 1062 | + auto null_map = ColumnUInt8::create(size, 0); |
| 1063 | + auto& null_map_data = null_map->get_data(); |
| 1064 | + |
| 1065 | + for (int row = 0; row < size; ++row) { |
| 1066 | + auto value = col->get_data_at(row); |
| 1067 | + auto shape = GeoShape::from_encoded(value.data, value.size); |
| 1068 | + if (!shape) { |
| 1069 | + null_map_data[row] = 1; |
| 1070 | + res->insert_default(); |
| 1071 | + continue; |
| 1072 | + } |
| 1073 | + |
| 1074 | + res->insert_value(shape->num_points()); |
| 1075 | + } |
| 1076 | + |
| 1077 | + block.replace_by_position(result, |
| 1078 | + ColumnNullable::create(std::move(res), std::move(null_map))); |
| 1079 | + return Status::OK(); |
| 1080 | + } |
| 1081 | +}; |
| 1082 | + |
920 | 1083 | void register_function_geo(SimpleFunctionFactory& factory) { |
921 | 1084 | factory.register_function<GeoFunction<StPoint>>(); |
922 | 1085 | factory.register_function<GeoFunction<StAsText<StAsWktName>>>(); |
@@ -947,6 +1110,9 @@ void register_function_geo(SimpleFunctionFactory& factory) { |
947 | 1110 | factory.register_function<GeoFunction<StLength>>(); |
948 | 1111 | factory.register_function<GeoFunction<StGeometryType>>(); |
949 | 1112 | factory.register_function<GeoFunction<StDistance>>(); |
| 1113 | + factory.register_function<GeoFunction<StNumGeometries>>(); |
| 1114 | + factory.register_function<GeoFunction<StNumPoints>>(); |
| 1115 | + factory.register_function<FunctionStGeometries>(); |
950 | 1116 | } |
951 | 1117 |
|
952 | 1118 | } // namespace doris |
0 commit comments