You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2022/04/11 06:03:45 UTC

[incubator-doris] 04/09: [feature](function)(vectorized) Support all geolocation functions on vectorized engine (#8846)

This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch dev-1.0.1
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git

commit d003cc7524520b4c1d4532683f6d07998737d946
Author: Gabriel <ga...@gmail.com>
AuthorDate: Mon Apr 11 09:36:53 2022 +0800

    [feature](function)(vectorized) Support all geolocation functions on vectorized engine (#8846)
---
 be/src/geo/geo_functions.cpp                       |  18 --
 be/src/geo/geo_functions.h                         |  20 ++
 be/src/vec/functions/functions_geo.cpp             | 318 +++++++++++++++++++++
 be/src/vec/functions/functions_geo.h               |  21 ++
 be/test/vec/function/function_geo_test.cpp         | 197 +++++++++++++
 .../vectorized-execution-engine.md                 |   9 +-
 .../vectorized-execution-engine.md                 |   9 +-
 gensrc/script/doris_builtins_functions.py          |  19 +-
 8 files changed, 574 insertions(+), 37 deletions(-)

diff --git a/be/src/geo/geo_functions.cpp b/be/src/geo/geo_functions.cpp
index 4baf9245cc..33ea5ca0c0 100644
--- a/be/src/geo/geo_functions.cpp
+++ b/be/src/geo/geo_functions.cpp
@@ -106,14 +106,6 @@ StringVal GeoFunctions::st_as_wkt(doris_udf::FunctionContext* ctx,
     return result;
 }
 
-struct StConstructState {
-    StConstructState() : is_null(false) {}
-    ~StConstructState() {}
-
-    bool is_null;
-    std::string encoded_buf;
-};
-
 void GeoFunctions::st_from_wkt_close(FunctionContext* ctx,
                                      FunctionContext::FunctionStateScope scope) {
     if (scope != FunctionContext::FRAGMENT_LOCAL) {
@@ -229,16 +221,6 @@ doris_udf::StringVal GeoFunctions::st_circle(FunctionContext* ctx, const DoubleV
     }
 }
 
-struct StContainsState {
-    StContainsState() : is_null(false), shapes{nullptr, nullptr} {}
-    ~StContainsState() {
-        delete shapes[0];
-        delete shapes[1];
-    }
-    bool is_null;
-    GeoShape* shapes[2];
-};
-
 void GeoFunctions::st_contains_prepare(doris_udf::FunctionContext* ctx,
                                        doris_udf::FunctionContext::FunctionStateScope scope) {
     if (scope != FunctionContext::FRAGMENT_LOCAL) {
diff --git a/be/src/geo/geo_functions.h b/be/src/geo/geo_functions.h
index ef1e896e2f..90f7d6bccb 100644
--- a/be/src/geo/geo_functions.h
+++ b/be/src/geo/geo_functions.h
@@ -18,6 +18,7 @@
 #pragma once
 
 #include "geo/geo_common.h"
+#include "geo/geo_types.h"
 #include "udf/udf.h"
 
 namespace doris {
@@ -107,4 +108,23 @@ public:
                                   doris_udf::FunctionContext::FunctionStateScope);
 };
 
+struct StConstructState {
+    StConstructState() : is_null(false) {}
+    ~StConstructState() {}
+
+    bool is_null;
+    std::string encoded_buf;
+};
+
+
+struct StContainsState {
+    StContainsState() : is_null(false), shapes{nullptr, nullptr} {}
+    ~StContainsState() {
+        delete shapes[0];
+        delete shapes[1];
+    }
+    bool is_null;
+    GeoShape* shapes[2];
+};
+
 } // namespace doris
diff --git a/be/src/vec/functions/functions_geo.cpp b/be/src/vec/functions/functions_geo.cpp
index 3b8adfc878..ba4c370506 100644
--- a/be/src/vec/functions/functions_geo.cpp
+++ b/be/src/vec/functions/functions_geo.cpp
@@ -18,12 +18,15 @@
 #include "vec/functions/functions_geo.h"
 
 #include "geo/geo_types.h"
+#include "geo/geo_functions.h"
 #include "gutil/strings/substitute.h"
+#include "vec/columns/column_const.h"
 #include "vec/functions/simple_function_factory.h"
 
 namespace doris::vectorized {
 
 struct StPoint {
+    static constexpr auto NEED_CONTEXT = false;
     static constexpr auto NAME = "st_point";
     static const size_t NUM_ARGS = 2;
     static Status execute(Block& block, const ColumnNumbers& arguments, size_t result) {
@@ -66,6 +69,7 @@ struct StAsWktName {
 
 template<typename FunctionName>
 struct StAsText {
+    static constexpr auto NEED_CONTEXT = false;
     static constexpr auto NAME = FunctionName::NAME;
     static const size_t NUM_ARGS = 1;
     static Status execute(Block& block, const ColumnNumbers& arguments,size_t result) {
@@ -99,6 +103,7 @@ struct StAsText {
 };
 
 struct StX {
+    static constexpr auto NEED_CONTEXT = false;
     static constexpr auto NAME = "st_x";
     static const size_t NUM_ARGS = 1;
     static Status execute(Block& block, const ColumnNumbers& arguments,size_t result) {
@@ -132,6 +137,7 @@ struct StX {
 };
 
 struct StY {
+    static constexpr auto NEED_CONTEXT = false;
     static constexpr auto NAME = "st_y";
     static const size_t NUM_ARGS = 1;
     static Status execute(Block& block, const ColumnNumbers& arguments,size_t result) {
@@ -165,6 +171,7 @@ struct StY {
 };
 
 struct StDistanceSphere {
+    static constexpr auto NEED_CONTEXT = false;
     static constexpr auto NAME = "st_distance_sphere";
     static const size_t NUM_ARGS = 4;
     static Status execute(Block& block, const ColumnNumbers& arguments, size_t result) {
@@ -199,6 +206,308 @@ struct StDistanceSphere {
     }
 };
 
+struct StCircle {
+    static constexpr auto NEED_CONTEXT = true;
+    static constexpr auto NAME = "st_circle";
+    static const size_t NUM_ARGS = 3;
+    static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
+                          size_t result) {
+        DCHECK_EQ(arguments.size(), 3);
+        auto return_type = remove_nullable(block.get_data_type(result));
+        auto center_lng = block.get_by_position(arguments[0])
+                                  .column->convert_to_full_column_if_const();
+        auto center_lat = block.get_by_position(arguments[1])
+                                  .column->convert_to_full_column_if_const();
+        auto radius = block.get_by_position(arguments[2])
+                              .column->convert_to_full_column_if_const();
+
+        const auto size = center_lng->size();
+
+        MutableColumnPtr res = nullptr;
+        auto null_type = std::reinterpret_pointer_cast<const DataTypeNullable>(return_type);
+        res = ColumnNullable::create(return_type->create_column(), ColumnUInt8::create());
+
+        StConstructState* state =
+                (StConstructState*) context->get_function_state(FunctionContext::FRAGMENT_LOCAL);
+        if (state == nullptr) {
+            GeoCircle circle;
+            std::string buf;
+            for (int row = 0; row < size; ++row) {
+                auto lng_value = center_lng->get_float64(row);
+                auto lat_value = center_lat->get_float64(row);
+                auto radius_value = radius->get_float64(row);
+
+                auto value = circle.init(lng_value, lat_value, radius_value);
+                if (value != GEO_PARSE_OK) {
+                    res->insert_data(nullptr, 0);
+                    continue;
+                }
+                buf.clear();
+                circle.encode_to(&buf);
+                res->insert_data(buf.data(), buf.size());
+            }
+            block.replace_by_position(result, std::move(res));
+        } else {
+            if (state->is_null) {
+                res->insert_data(nullptr, 0);
+                block.replace_by_position(result, ColumnConst::create(std::move(res), size));
+            } else {
+                res->insert_data(state->encoded_buf.data(), state->encoded_buf.size());
+                block.replace_by_position(result, ColumnConst::create(std::move(res), size));
+            }
+        }
+        return Status::OK();
+    }
+
+    static Status prepare(FunctionContext* context, FunctionContext::FunctionStateScope scope) {
+        if (scope != FunctionContext::FRAGMENT_LOCAL) {
+            return Status::OK();
+        }
+
+        if (!context->is_arg_constant(0) || !context->is_arg_constant(1)
+            || !context->is_arg_constant(2)) {
+            return Status::OK();
+        }
+
+        auto state = new StConstructState();
+        DoubleVal* lng = reinterpret_cast<DoubleVal*>(context->get_constant_arg(0));
+        DoubleVal* lat = reinterpret_cast<DoubleVal*>(context->get_constant_arg(1));
+        DoubleVal* radius = reinterpret_cast<DoubleVal*>(context->get_constant_arg(2));
+        if (lng->is_null || lat->is_null || radius->is_null) {
+            state->is_null = true;
+        } else {
+            std::unique_ptr<GeoCircle> circle(new GeoCircle());
+
+            auto res = circle->init(lng->val, lat->val, radius->val);
+            if (res != GEO_PARSE_OK) {
+                state->is_null = true;
+            } else {
+                circle->encode_to(&state->encoded_buf);
+            }
+        }
+        context->set_function_state(scope, state);
+
+        return Status::OK();
+    }
+
+    static Status close(FunctionContext* context, FunctionContext::FunctionStateScope scope) {
+        if (scope != FunctionContext::FRAGMENT_LOCAL) {
+            return Status::OK();
+        }
+        StConstructState* state = reinterpret_cast<StConstructState*>(
+                context->get_function_state(scope));
+        delete state;
+        return Status::OK();
+    }
+};
+
+struct StContains {
+    static constexpr auto NEED_CONTEXT = true;
+    static constexpr auto NAME = "st_contains";
+    static const size_t NUM_ARGS = 2;
+    static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
+                          size_t result) {
+        DCHECK_EQ(arguments.size(), 2);
+        auto return_type = remove_nullable(block.get_data_type(result));
+        auto shape1 = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
+        auto shape2 = block.get_by_position(arguments[1]).column->convert_to_full_column_if_const();
+
+        const auto size = shape1->size();
+        auto null_type = std::reinterpret_pointer_cast<const DataTypeNullable>(return_type);
+        auto res = ColumnNullable::create(return_type->create_column(), ColumnUInt8::create());
+
+        StContainsState* state = (StContainsState*) context->get_function_state(FunctionContext::FRAGMENT_LOCAL);
+        if (state != nullptr && state->is_null) {
+            res->insert_data(nullptr, 0);
+            block.replace_by_position(result, ColumnConst::create(std::move(res), size));
+            return Status::OK();
+        }
+
+        StContainsState local_state;
+        int i;
+        GeoShape* shapes[2] = {nullptr, nullptr};
+        for (int row = 0; row < size; ++row) {
+            auto lhs_value = shape1->get_data_at(row);
+            auto rhs_value = shape2->get_data_at(row);
+            StringRef* strs[2] = {&lhs_value, &rhs_value};
+            for (i = 0; i < 2; ++i) {
+                if (state != nullptr && state->shapes[i] != nullptr) {
+                    shapes[i] = state->shapes[i];
+                } else {
+                    shapes[i] = local_state.shapes[i] = GeoShape::from_encoded(strs[i]->data, strs[i]->size);
+                    if (shapes[i] == nullptr) {
+                        res->insert_data(nullptr, 0);
+                        break;
+                    }
+                }
+            }
+
+            if (i == 2) {
+                auto contains_value = shapes[0]->contains(shapes[1]);
+                res->insert_data(const_cast<const char*>((char*)&contains_value), 0);
+            }
+        }
+        block.replace_by_position(result, std::move(res));
+        return Status::OK();
+    }
+
+    static Status prepare(FunctionContext* context, FunctionContext::FunctionStateScope scope) {
+        if (scope != FunctionContext::FRAGMENT_LOCAL) {
+            return Status::OK();
+        }
+
+        if (!context->is_arg_constant(0) && !context->is_arg_constant(1)) {
+            return Status::OK();
+        }
+
+        auto contains_ctx = new StContainsState();
+        for (int i = 0; !contains_ctx->is_null && i < 2; ++i) {
+            if (context->is_arg_constant(i)) {
+                StringVal* str = reinterpret_cast<StringVal*>(context->get_constant_arg(i));
+                if (str->is_null) {
+                    contains_ctx->is_null = true;
+                } else {
+                    contains_ctx->shapes[i] = GeoShape::from_encoded(str->ptr, str->len);
+                    if (contains_ctx->shapes[i] == nullptr) {
+                        contains_ctx->is_null = true;
+                    }
+                }
+            }
+        }
+
+        context->set_function_state(scope, contains_ctx);
+        return Status::OK();
+    }
+
+    static Status close(FunctionContext* context, FunctionContext::FunctionStateScope scope) {
+        if (scope != FunctionContext::FRAGMENT_LOCAL) {
+            return Status::OK();
+        }
+        StContainsState* state = reinterpret_cast<StContainsState*>(
+                context->get_function_state(scope));
+        delete state;
+        return Status::OK();
+    }
+};
+
+struct StGeometryFromText{
+    static constexpr auto NAME = "st_geometryfromtext";
+    static constexpr GeoShapeType shape_type = GEO_SHAPE_ANY;
+};
+
+struct StGeomFromText{
+    static constexpr auto NAME = "st_geomfromtext";
+    static constexpr GeoShapeType shape_type = GEO_SHAPE_ANY;
+};
+
+struct StLineFromText{
+    static constexpr auto NAME = "st_linefromtext";
+    static constexpr GeoShapeType shape_type = GEO_SHAPE_LINE_STRING;
+};
+
+struct StLineStringFromText{
+    static constexpr auto NAME = "st_linestringfromtext";
+    static constexpr GeoShapeType shape_type = GEO_SHAPE_LINE_STRING;
+};
+
+struct StPolygon{
+    static constexpr auto NAME = "st_polygon";
+    static constexpr GeoShapeType shape_type = GEO_SHAPE_POLYGON;
+};
+
+struct StPolyFromText{
+    static constexpr auto NAME = "st_polyfromtext";
+    static constexpr GeoShapeType shape_type = GEO_SHAPE_POLYGON;
+};
+
+struct StPolygonFromText{
+    static constexpr auto NAME = "st_polygonfromtext";
+    static constexpr GeoShapeType shape_type = GEO_SHAPE_POLYGON;
+};
+
+template<typename Impl>
+struct StGeoFromText {
+    static constexpr auto NEED_CONTEXT = true;
+    static constexpr auto NAME = Impl::NAME;
+    static const size_t NUM_ARGS = 1;
+    static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
+                          size_t result) {
+        DCHECK_EQ(arguments.size(), 1);
+        auto return_type = remove_nullable(block.get_data_type(result));
+        auto geo = block.get_by_position(arguments[0]).column->convert_to_full_column_if_const();
+
+        const auto size = geo->size();
+        auto null_type = std::reinterpret_pointer_cast<const DataTypeNullable>(return_type);
+        auto res = ColumnNullable::create(return_type->create_column(), ColumnUInt8::create());
+
+        StConstructState* state = (StConstructState*) context->get_function_state(FunctionContext::FRAGMENT_LOCAL);
+        if (state == nullptr) {
+            GeoParseStatus status;
+            std::string buf;
+            for (int row = 0; row < size; ++row) {
+                auto value = geo->get_data_at(row);
+                std::unique_ptr<GeoShape> shape(GeoShape::from_wkt(value.data, value.size, &status));
+                if (shape == nullptr || status != GEO_PARSE_OK ||
+                    (Impl::shape_type != GEO_SHAPE_ANY && shape->type() != Impl::shape_type)) {
+                    res->insert_data(nullptr, 0);
+                    continue;
+                }
+                buf.clear();
+                shape->encode_to(&buf);
+                res->insert_data(buf.data(), buf.size());
+            }
+            block.replace_by_position(result, std::move(res));
+        } else {
+            if (state->is_null) {
+                res->insert_data(nullptr, 0);
+                block.replace_by_position(result, ColumnConst::create(std::move(res), size));
+            } else {
+                res->insert_data(state->encoded_buf.data(), state->encoded_buf.size());
+                block.replace_by_position(result, ColumnConst::create(std::move(res), size));
+            }
+        }
+        return Status::OK();
+    }
+
+    static Status prepare(FunctionContext* context, FunctionContext::FunctionStateScope scope) {
+        if (scope != FunctionContext::FRAGMENT_LOCAL) {
+            return Status::OK();
+        }
+
+        if (!context->is_arg_constant(0)) {
+            return Status::OK();
+        }
+
+        auto state = new StConstructState();
+        auto str_value = reinterpret_cast<StringVal*>(context->get_constant_arg(0));
+        if (str_value->is_null) {
+            state->is_null = true;
+        } else {
+            GeoParseStatus status;
+            std::unique_ptr<GeoShape> shape(GeoShape::from_wkt(const_cast<const char*>(
+                (char*)str_value->ptr), str_value->len, &status));
+            if (shape == nullptr ||
+                (Impl::shape_type != GEO_SHAPE_ANY && shape->type() != Impl::shape_type)) {
+                state->is_null = true;
+            } else {
+                shape->encode_to(&state->encoded_buf);
+            }
+        }
+
+        context->set_function_state(scope, state);
+        return Status::OK();
+    }
+
+    static Status close(FunctionContext* context, FunctionContext::FunctionStateScope scope) {
+        if (scope == FunctionContext::FRAGMENT_LOCAL) {
+            StConstructState* state = reinterpret_cast<StConstructState*>(
+                    context->get_function_state(scope));
+            delete state;
+        }
+        return Status::OK();
+    }
+};
+
 void register_geo_functions(SimpleFunctionFactory& factory) {
     factory.register_function<GeoFunction<StPoint>>();
     factory.register_function<GeoFunction<StAsText<StAsWktName>>>();
@@ -206,6 +515,15 @@ void register_geo_functions(SimpleFunctionFactory& factory) {
     factory.register_function<GeoFunction<StX, DataTypeFloat64>>();
     factory.register_function<GeoFunction<StY, DataTypeFloat64>>();
     factory.register_function<GeoFunction<StDistanceSphere, DataTypeFloat64>>();
+    factory.register_function<GeoFunction<StContains, DataTypeUInt8>>();
+    factory.register_function<GeoFunction<StCircle>>();
+    factory.register_function<GeoFunction<StGeoFromText<StGeometryFromText>>>();
+    factory.register_function<GeoFunction<StGeoFromText<StGeomFromText>>>();
+    factory.register_function<GeoFunction<StGeoFromText<StLineFromText>>>();
+    factory.register_function<GeoFunction<StGeoFromText<StLineStringFromText>>>();
+    factory.register_function<GeoFunction<StGeoFromText<StPolygon>>>();
+    factory.register_function<GeoFunction<StGeoFromText<StPolygonFromText>>>();
+    factory.register_function<GeoFunction<StGeoFromText<StPolyFromText>>>();
 }
 
 } // namespace doris::vectorized
diff --git a/be/src/vec/functions/functions_geo.h b/be/src/vec/functions/functions_geo.h
index 4533adb6bc..d18b808c3f 100644
--- a/be/src/vec/functions/functions_geo.h
+++ b/be/src/vec/functions/functions_geo.h
@@ -43,6 +43,27 @@ public:
     Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
                         size_t result, size_t input_rows_count) override {
         return Impl::execute(block, arguments, result);
+        if constexpr (Impl::NEED_CONTEXT) {
+            return Impl::execute(context, block, arguments, result);
+        } else {
+            return Impl::execute(block, arguments, result);
+        }
+    }
+
+    Status prepare(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
+        if constexpr (Impl::NEED_CONTEXT) {
+            return Impl::prepare(context, scope);
+        } else {
+            return Status::OK();
+        }
+    }
+
+    Status close(FunctionContext* context, FunctionContext::FunctionStateScope scope) override {
+        if constexpr (Impl::NEED_CONTEXT) {
+            return Impl::close(context, scope);
+        } else {
+            return Status::OK();
+        }
     }
 };
 
diff --git a/be/test/vec/function/function_geo_test.cpp b/be/test/vec/function/function_geo_test.cpp
index 15925f0b96..f514233459 100644
--- a/be/test/vec/function/function_geo_test.cpp
+++ b/be/test/vec/function/function_geo_test.cpp
@@ -142,6 +142,203 @@ TEST(function_geo_test, function_geo_st_distance_sphere) {
     }
 }
 
+TEST(function_geo_test, function_geo_st_contains) {
+    std::string func_name = "st_contains";
+    {
+        InputTypeSet input_types = {TypeIndex::String, TypeIndex::String};
+
+        std::string buf1;
+        std::string buf2;
+        std::string buf3;
+        GeoParseStatus status;
+
+        std::string shape1 = std::string("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))");
+        std::unique_ptr<GeoShape> shape(
+                GeoShape::from_wkt(shape1.data(), shape1.size(), &status));
+        ASSERT_TRUE(status == GEO_PARSE_OK);
+        ASSERT_TRUE(shape != nullptr);
+        shape->encode_to(&buf1);
+
+        GeoPoint point1;
+        status = point1.from_coord(5, 5);
+        ASSERT_TRUE(status == GEO_PARSE_OK);
+        point1.encode_to(&buf2);
+
+        GeoPoint point2;
+        status = point2.from_coord(50, 50);
+        ASSERT_TRUE(status == GEO_PARSE_OK);
+        point2.encode_to(&buf3);
+
+        DataSet data_set = {
+                {{buf1, buf2}, (uint8_t) 1},
+                {{buf1, buf3}, (uint8_t) 0},
+                {{buf1, Null()}, Null()},
+                {{Null(), buf3}, Null()}};
+
+        check_function<DataTypeUInt8 , true>(func_name, input_types, data_set);
+    }
+}
+
+TEST(function_geo_test, function_geo_st_circle) {
+    std::string func_name = "st_circle";
+    {
+        InputTypeSet input_types = {TypeIndex::Float64, TypeIndex::Float64, TypeIndex::Float64};
+
+        GeoCircle circle;
+        std::string buf;
+        auto value = circle.init(111, 64, 10000);
+        ASSERT_TRUE(value == GEO_PARSE_OK);
+        circle.encode_to(&buf);
+        DataSet data_set = {
+                {{(double) 111, (double) 64, (double) 10000}, buf},
+                {{Null(), (double) 64, (double) 10000}, Null()},
+                {{(double) 111, Null(), (double) 10000}, Null()},
+                {{(double) 111, (double) 64, Null()}, Null()}};
+
+        check_function<DataTypeString , true>(func_name, input_types, data_set);
+    }
+}
+
+TEST(function_geo_test, function_geo_st_geometryfromtext) {
+    std::string func_name = "st_geometryfromtext";
+    {
+        InputTypeSet input_types = {TypeIndex::String};
+
+        GeoParseStatus status;
+        std::string buf;
+        std::string input = "LINESTRING (1 1, 2 2)";
+        std::unique_ptr<GeoShape> shape(GeoShape::from_wkt(input.data(), input.size(), &status));
+        ASSERT_TRUE(shape != nullptr);
+        ASSERT_TRUE(status == GEO_PARSE_OK);
+        shape->encode_to(&buf);
+        DataSet data_set = {
+                {{std::string("LINESTRING (1 1, 2 2)")}, buf},
+                {{Null()}, Null()}};
+
+        check_function<DataTypeString , true>(func_name, input_types, data_set);
+    }
+}
+
+TEST(function_geo_test, function_geo_st_geomfromtext) {
+    std::string func_name = "st_geomfromtext";
+    {
+        InputTypeSet input_types = {TypeIndex::String};
+
+        GeoParseStatus status;
+        std::string buf;
+        std::string input = "LINESTRING (1 1, 2 2)";
+        std::unique_ptr<GeoShape> shape(GeoShape::from_wkt(input.data(), input.size(), &status));
+        ASSERT_TRUE(shape != nullptr);
+        ASSERT_TRUE(status == GEO_PARSE_OK);
+        shape->encode_to(&buf);
+        DataSet data_set = {
+            {{std::string("LINESTRING (1 1, 2 2)")}, buf},
+            {{Null()}, Null()}};
+
+        check_function<DataTypeString , true>(func_name, input_types, data_set);
+    }
+}
+
+TEST(function_geo_test, function_geo_st_linefromtext) {
+    std::string func_name = "st_linefromtext";
+    {
+        InputTypeSet input_types = {TypeIndex::String};
+
+        GeoParseStatus status;
+        std::string buf;
+        std::string input = "LINESTRING (1 1, 2 2)";
+        std::unique_ptr<GeoShape> shape(GeoShape::from_wkt(input.data(), input.size(), &status));
+        ASSERT_TRUE(shape != nullptr);
+        ASSERT_TRUE(status == GEO_PARSE_OK);
+        shape->encode_to(&buf);
+        DataSet data_set = {
+            {{std::string("LINESTRING (1 1, 2 2)")}, buf},
+            {{Null()}, Null()}};
+
+        check_function<DataTypeString , true>(func_name, input_types, data_set);
+    }
+}
+
+TEST(function_geo_test, function_geo_st_linestringfromtext) {
+    std::string func_name = "st_linestringfromtext";
+    {
+        InputTypeSet input_types = {TypeIndex::String};
+
+        GeoParseStatus status;
+        std::string buf;
+        std::string input = "LINESTRING (1 1, 2 2)";
+        std::unique_ptr<GeoShape> shape(GeoShape::from_wkt(input.data(), input.size(), &status));
+        ASSERT_TRUE(shape != nullptr);
+        ASSERT_TRUE(status == GEO_PARSE_OK);
+        shape->encode_to(&buf);
+        DataSet data_set = {
+                {{std::string("LINESTRING (1 1, 2 2)")}, buf},
+                {{Null()}, Null()}};
+
+        check_function<DataTypeString , true>(func_name, input_types, data_set);
+    }
+}
+
+TEST(function_geo_test, function_geo_st_polygon) {
+    std::string func_name = "st_polygon";
+    {
+        InputTypeSet input_types = {TypeIndex::String};
+
+        GeoParseStatus status;
+        std::string buf;
+        std::string input = "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))";
+        std::unique_ptr<GeoShape> shape(GeoShape::from_wkt(input.data(), input.size(), &status));
+        ASSERT_TRUE(shape != nullptr);
+        ASSERT_TRUE(status == GEO_PARSE_OK);
+        shape->encode_to(&buf);
+        DataSet data_set = {
+                {{std::string("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")}, buf},
+                {{Null()}, Null()}};
+
+        check_function<DataTypeString , true>(func_name, input_types, data_set);
+    }
+}
+
+TEST(function_geo_test, function_geo_st_polygonfromtext) {
+    std::string func_name = "st_polygonfromtext";
+    {
+        InputTypeSet input_types = {TypeIndex::String};
+
+        GeoParseStatus status;
+        std::string buf;
+        std::string input = "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))";
+        std::unique_ptr<GeoShape> shape(GeoShape::from_wkt(input.data(), input.size(), &status));
+        ASSERT_TRUE(shape != nullptr);
+        ASSERT_TRUE(status == GEO_PARSE_OK);
+        shape->encode_to(&buf);
+        DataSet data_set = {
+                {{std::string("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")}, buf},
+                {{Null()}, Null()}};
+
+        check_function<DataTypeString , true>(func_name, input_types, data_set);
+    }
+}
+
+TEST(function_geo_test, function_geo_st_polyfromtext) {
+    std::string func_name = "st_polyfromtext";
+    {
+        InputTypeSet input_types = {TypeIndex::String};
+
+        GeoParseStatus status;
+        std::string buf;
+        std::string input = "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))";
+        std::unique_ptr<GeoShape> shape(GeoShape::from_wkt(input.data(), input.size(), &status));
+        ASSERT_TRUE(shape != nullptr);
+        ASSERT_TRUE(status == GEO_PARSE_OK);
+        shape->encode_to(&buf);
+        DataSet data_set = {
+                {{std::string("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")}, buf},
+                {{Null()}, Null()}};
+
+        check_function<DataTypeString , true>(func_name, input_types, data_set);
+    }
+}
+
 } // namespace doris::vectorized
 
 int main(int argc, char** argv) {
diff --git a/docs/en/administrator-guide/vectorized-execution-engine.md b/docs/en/administrator-guide/vectorized-execution-engine.md
index 37d9bcafa8..6f5a07c40b 100644
--- a/docs/en/administrator-guide/vectorized-execution-engine.md
+++ b/docs/en/administrator-guide/vectorized-execution-engine.md
@@ -116,8 +116,7 @@ In most scenarios, users only need to turn on the session variable by default to
 
 #### Type B
 
-1. The `geolocation function` is not supported, including all functions starting with `ST_` in the function. For details, please refer to the section on SQL functions in the official documentation.
-2. The `UDF` and `UDAF` of the original row storage execution engine are not supported.
-3. The maximum length of `string/text` type is 1MB instead of the default 2GB. That is, when the vectorization engine is turned on, it is impossible to query or import strings larger than 1MB. However, if you turn off the vectorization engine, you can still query and import normally.
-4. The export method of `select ... into outfile` is not supported.
-5. Extrenal broker appearance is not supported.
+1. The `UDF` and `UDAF` of the original row storage execution engine are not supported.
+2. The maximum length of `string/text` type is 1MB instead of the default 2GB. That is, when the vectorization engine is turned on, it is impossible to query or import strings larger than 1MB. However, if you turn off the vectorization engine, you can still query and import normally.
+3. The export method of `select ... into outfile` is not supported.
+4. Extrenal broker appearance is not supported.
diff --git a/docs/zh-CN/administrator-guide/vectorized-execution-engine.md b/docs/zh-CN/administrator-guide/vectorized-execution-engine.md
index f97be1f540..4bcd1fa999 100644
--- a/docs/zh-CN/administrator-guide/vectorized-execution-engine.md
+++ b/docs/zh-CN/administrator-guide/vectorized-execution-engine.md
@@ -113,8 +113,7 @@ set batch_size = 4096;
 4. bitmap/hll 类型在向量化执行引擎中:输入均为NULL,则输出的结果为NULL而不是0。
 
 #### b类
-1. 不支持`地理位置函数` ,包含了函数中所有以`ST_`开头的函数。具体请参考官方文档SQL函数的部分。
-2. 不支持原有行存执行引擎的`UDF`与`UDAF`。
-3. `string/text`类型最大长度支持为1MB,而不是默认的2GB。即当开启向量化引擎后,将无法查询或导入大于1MB的字符串。但如果关闭向量化引擎,则依然可以正常查询和导入。
-4. 不支持 `select ... into outfile` 的导出方式。 
-5. 不支持extrenal broker外表。
+1. 不支持原有行存执行引擎的`UDF`与`UDAF`。
+2. `string/text`类型最大长度支持为1MB,而不是默认的2GB。即当开启向量化引擎后,将无法查询或导入大于1MB的字符串。但如果关闭向量化引擎,则依然可以正常查询和导入。
+3. 不支持 `select ... into outfile` 的导出方式。 
+4. 不支持extrenal broker外表。
diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py
index 2de4da6c14..9d1b602def 100755
--- a/gensrc/script/doris_builtins_functions.py
+++ b/gensrc/script/doris_builtins_functions.py
@@ -1326,7 +1326,8 @@ visible_functions = [
 
     # geo functions
     [['ST_Point'], 'VARCHAR', ['DOUBLE', 'DOUBLE'],
-        '_ZN5doris12GeoFunctions8st_pointEPN9doris_udf15FunctionContextERKNS1_9DoubleValES6_', '', '', 'vec', 'ALWAYS_NULLABLE'],
+        '_ZN5doris12GeoFunctions8st_pointEPN9doris_udf15FunctionContextERKNS1_9DoubleValES6_',
+        '', '', 'vec', 'ALWAYS_NULLABLE'],
     [['ST_X'], 'DOUBLE', ['VARCHAR'],
         '_ZN5doris12GeoFunctions4st_xEPN9doris_udf15FunctionContextERKNS1_9StringValE',
         '', '', 'vec', 'ALWAYS_NULLABLE'],
@@ -1354,46 +1355,46 @@ visible_functions = [
         '_ZN5doris12GeoFunctions11st_from_wktEPN9doris_udf15FunctionContextERKNS1_9StringValE',
         '_ZN5doris12GeoFunctions19st_from_wkt_prepareEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
         '_ZN5doris12GeoFunctions17st_from_wkt_closeEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
-        '', 'ALWAYS_NULLABLE'],
+        'vec', 'ALWAYS_NULLABLE'],
     [['ST_GeometryFromText', 'ST_GeomFromText'], 'VARCHAR', ['STRING'],
         '_ZN5doris12GeoFunctions11st_from_wktEPN9doris_udf15FunctionContextERKNS1_9StringValE',
         '_ZN5doris12GeoFunctions19st_from_wkt_prepareEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
         '_ZN5doris12GeoFunctions17st_from_wkt_closeEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
-        '', 'ALWAYS_NULLABLE'],
+        'vec', 'ALWAYS_NULLABLE'],
 
     [['ST_LineFromText', 'ST_LineStringFromText'], 'VARCHAR', ['VARCHAR'],
         '_ZN5doris12GeoFunctions7st_lineEPN9doris_udf15FunctionContextERKNS1_9StringValE',
         '_ZN5doris12GeoFunctions15st_line_prepareEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
         '_ZN5doris12GeoFunctions17st_from_wkt_closeEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
-        '', 'ALWAYS_NULLABLE'],
+        'vec', 'ALWAYS_NULLABLE'],
     [['ST_LineFromText', 'ST_LineStringFromText'], 'VARCHAR', ['STRING'],
         '_ZN5doris12GeoFunctions7st_lineEPN9doris_udf15FunctionContextERKNS1_9StringValE',
         '_ZN5doris12GeoFunctions15st_line_prepareEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
         '_ZN5doris12GeoFunctions17st_from_wkt_closeEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
-        '', 'ALWAYS_NULLABLE'],
+        'vec', 'ALWAYS_NULLABLE'],
 
     [['ST_Polygon', 'ST_PolyFromText', 'ST_PolygonFromText'], 'VARCHAR', ['VARCHAR'],
         '_ZN5doris12GeoFunctions10st_polygonEPN9doris_udf15FunctionContextERKNS1_9StringValE',
         '_ZN5doris12GeoFunctions18st_polygon_prepareEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
         '_ZN5doris12GeoFunctions17st_from_wkt_closeEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
-        '', 'ALWAYS_NULLABLE'],
+        'vec', 'ALWAYS_NULLABLE'],
     [['ST_Polygon', 'ST_PolyFromText', 'ST_PolygonFromText'], 'VARCHAR', ['STRING'],
         '_ZN5doris12GeoFunctions10st_polygonEPN9doris_udf15FunctionContextERKNS1_9StringValE',
         '_ZN5doris12GeoFunctions18st_polygon_prepareEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
         '_ZN5doris12GeoFunctions17st_from_wkt_closeEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
-        '', 'ALWAYS_NULLABLE'],
+        'vec', 'ALWAYS_NULLABLE'],
 
     [['ST_Circle'], 'VARCHAR', ['DOUBLE', 'DOUBLE', 'DOUBLE'],
         '_ZN5doris12GeoFunctions9st_circleEPN9doris_udf15FunctionContextERKNS1_9DoubleValES6_S6_',
         '_ZN5doris12GeoFunctions17st_circle_prepareEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
         '_ZN5doris12GeoFunctions17st_from_wkt_closeEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
-        '', ''],
+        'vec', 'ALWAYS_NULLABLE'],
 
     [['ST_Contains'], 'BOOLEAN', ['VARCHAR', 'VARCHAR'],
         '_ZN5doris12GeoFunctions11st_containsEPN9doris_udf15FunctionContextERKNS1_9StringValES6_',
         '_ZN5doris12GeoFunctions19st_contains_prepareEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
         '_ZN5doris12GeoFunctions17st_contains_closeEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE',
-        '', 'ALWAYS_NULLABLE'],
+        'vec', 'ALWAYS_NULLABLE'],
     # grouping sets functions
     [['grouping_id'], 'BIGINT', ['BIGINT'],
         '_ZN5doris21GroupingSetsFunctions11grouping_idEPN9doris_udf15FunctionContextERKNS1_9BigIntValE',


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org