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

yiguolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 9e6857a01cf [Enhancement] (GEO) Support MultiPolygon for Geometry 
functions (#49665)
9e6857a01cf is described below

commit 9e6857a01cf9a3c4adc5a8e0cc6b2798975e7fb8
Author: linrrarity <[email protected]>
AuthorDate: Tue Apr 15 16:21:36 2025 +0800

    [Enhancement] (GEO) Support MultiPolygon for Geometry functions (#49665)
    
    ### What problem does this PR solve?
    1. Enhances the `GeometryFromText` function to support parsing
    `MULTIPOLYGON` WKT
    2. Support `ST_CONTAINS ` , `ST_INTERSECTS`, `ST_TOUCHES` for it and
    other shapes.
    3. Fixed the behavior of `ST_Touches` between two polygons, which has
    been updated to return `true` when they touch at a single point that is
    not on a horizontal or vertical edge.
    For example, the following polygons now return true for ST_Touches:
             - `POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))`
             -  `POLYGON((5 10, 0 15, 10 15))`
    Obviously, they touches at the point `(5 10)`
---
 be/src/geo/geo_common.h                            |   7 +-
 be/src/geo/geo_types.cpp                           | 442 +++++++++++++++++++--
 be/src/geo/geo_types.h                             |  32 ++
 be/src/geo/wkt_parse_type.h                        |   2 +
 be/src/geo/wkt_yacc.y                              |  37 +-
 be/test/geo/geo_types_test.cpp                     | 435 ++++++++++++++++++++
 .../spatial_functions/test_gis_function.out        | Bin 3346 -> 6772 bytes
 .../spatial_functions/test_gis_function.groovy     | 119 +++++-
 8 files changed, 1041 insertions(+), 33 deletions(-)

diff --git a/be/src/geo/geo_common.h b/be/src/geo/geo_common.h
index b2f32e5494a..f4c78dff190 100644
--- a/be/src/geo/geo_common.h
+++ b/be/src/geo/geo_common.h
@@ -42,9 +42,10 @@ enum GeoParseStatus {
     GEO_PARSE_POLYGON_NOT_HOLE = 5,
     GEO_PARSE_POLYLINE_LACK_VERTICES = 6,
     GEO_PARSE_POLYLINE_INVALID = 7,
-    GEO_PARSE_CIRCLE_INVALID = 8,
-    GEO_PARSE_WKT_SYNTAX_ERROR = 9,
-    GEO_PARSE_WKB_SYNTAX_ERROR = 10,
+    GEO_PARSE_MULTIPOLYGON_OVERLAP = 8,
+    GEO_PARSE_CIRCLE_INVALID = 9,
+    GEO_PARSE_WKT_SYNTAX_ERROR = 10,
+    GEO_PARSE_WKB_SYNTAX_ERROR = 11,
 };
 
 std::string to_string(GeoParseStatus status);
diff --git a/be/src/geo/geo_types.cpp b/be/src/geo/geo_types.cpp
index 04e5b5ef1ac..19254be105b 100644
--- a/be/src/geo/geo_types.cpp
+++ b/be/src/geo/geo_types.cpp
@@ -62,6 +62,9 @@ GeoPolygon::~GeoPolygon() = default;
 GeoCircle::GeoCircle() = default;
 GeoCircle::~GeoCircle() = default;
 
+GeoMultiPolygon::GeoMultiPolygon() = default;
+GeoMultiPolygon::~GeoMultiPolygon() = default;
+
 void print_s2point(std::ostream& os, const S2Point& point) {
     S2LatLng coord(point);
     os << std::setprecision(15) << coord.lng().degrees() << " " << 
coord.lat().degrees();
@@ -259,6 +262,30 @@ bool is_point_in_polygon(const S2Point& point, const 
S2Polygon* polygon) {
     return (crossings % 2 == 1);
 }
 
+bool is_line_touches_line(const S2Point& Line1_Point1, const S2Point& 
Line1_Point2,
+                          const S2Point& Line2_Point1, const S2Point& 
Line2_Point2) {
+    int count = 0;
+    if (compute_distance_to_line(Line1_Point1, Line2_Point1, Line2_Point2) < 
TOLERANCE) {
+        count++;
+    }
+    if (compute_distance_to_line(Line1_Point2, Line2_Point1, Line2_Point2) < 
TOLERANCE) {
+        count++;
+    }
+    if (compute_distance_to_line(Line2_Point1, Line1_Point1, Line1_Point2) < 
TOLERANCE) {
+        count++;
+    }
+    if (compute_distance_to_line(Line2_Point2, Line1_Point1, Line1_Point2) < 
TOLERANCE) {
+        count++;
+    }
+    // Two intersections are allowed when there is only one intersection, or 
when the intersection is an endpoint
+    if (count == 1 ||
+        (count == 2 && ((Line1_Point1 == Line2_Point1 || Line1_Point1 == 
Line2_Point2) +
+                        (Line1_Point2 == Line2_Point1 || Line1_Point2 == 
Line2_Point2)) == 1)) {
+        return true;
+    }
+    return false;
+}
+
 static inline GeoParseStatus to_s2point(const GeoCoordinate& coord, S2Point* 
point) {
     return to_s2point(coord.x, coord.y, point);
 }
@@ -418,6 +445,10 @@ std::unique_ptr<GeoShape> GeoShape::from_encoded(const 
void* ptr, size_t size) {
         shape = GeoCircle::create_unique();
         break;
     }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        shape = GeoMultiPolygon::create_unique();
+        break;
+    }
     default:
         return nullptr;
     }
@@ -483,6 +514,15 @@ const std::unique_ptr<GeoCoordinateListList> 
GeoPolygon::to_coords() const {
     return coordss;
 }
 
+const std::vector<std::unique_ptr<GeoCoordinateListList>> 
GeoMultiPolygon::to_coords() const {
+    std::vector<std::unique_ptr<GeoCoordinateListList>> coordss;
+    for (const auto& polygon : _polygons) {
+        std::unique_ptr<GeoCoordinateListList> coords = polygon->to_coords();
+        coordss.push_back(std::move(coords));
+    }
+    return coordss;
+}
+
 bool GeoPoint::intersects(const GeoShape* rhs) const {
     switch (rhs->type()) {
     case GEO_SHAPE_POINT: {
@@ -498,6 +538,10 @@ bool GeoPoint::intersects(const GeoShape* rhs) const {
         const GeoPolygon* polygon = assert_cast<const GeoPolygon*>(rhs);
         return polygon->intersects(this);
     }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        return multi_polygon->intersects(this);
+    }
     case GEO_SHAPE_CIRCLE: {
         const GeoCircle* circle = assert_cast<const GeoCircle*>(rhs);
         return circle->intersects(this);
@@ -525,6 +569,10 @@ bool GeoPoint::touches(const GeoShape* rhs) const {
         const GeoPolygon* polygon = assert_cast<const GeoPolygon*>(rhs);
         return polygon->touches(this);
     }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        return multi_polygon->touches(this);
+    }
     case GEO_SHAPE_CIRCLE: {
         const GeoCircle* circle = assert_cast<const GeoCircle*>(rhs);
         return circle->touches(this);
@@ -653,6 +701,15 @@ bool GeoLine::intersects(const GeoShape* rhs) const {
         const GeoPolygon* polygon = assert_cast<const GeoPolygon*>(rhs);
         return polygon->polygon()->Intersects(*_polyline);
     }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        for (const auto& polygon : multi_polygon->polygons()) {
+            if (polygon->intersects(this)) {
+                return true;
+            }
+        }
+        return false;
+    }
     case GEO_SHAPE_CIRCLE: {
         const GeoCircle* circle = assert_cast<const GeoCircle*>(rhs);
         return circle->intersects(this);
@@ -686,29 +743,16 @@ bool GeoLine::touches(const GeoShape* rhs) const {
 
         const S2Point& p3 = other->polyline()->vertex(0);
         const S2Point& p4 = other->polyline()->vertex(1);
-        int count = 0;
-        if (compute_distance_to_line(p1, p3, p4) < TOLERANCE) {
-            count++;
-        }
-        if (compute_distance_to_line(p2, p3, p4) < TOLERANCE) {
-            count++;
-        }
-        if (compute_distance_to_line(p3, p1, p2) < TOLERANCE) {
-            count++;
-        }
-        if (compute_distance_to_line(p4, p1, p2) < TOLERANCE) {
-            count++;
-        }
-        // Two intersections are allowed when there is only one intersection, 
or when the intersection is an endpoint
-        if (count == 1 || (count == 2 && ((p1 == p3 || p1 == p4) + (p2 == p3 
|| p2 == p4)) == 1)) {
-            return true;
-        }
-        return false;
+        return is_line_touches_line(p1, p2, p3, p4);
     }
     case GEO_SHAPE_POLYGON: {
         const GeoPolygon* polygon = assert_cast<const GeoPolygon*>(rhs);
         return polygon->touches(this);
     }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        return multi_polygon->touches(this);
+    }
     case GEO_SHAPE_CIRCLE: {
         const GeoCircle* circle = assert_cast<const GeoCircle*>(rhs);
         return circle->touches(this);
@@ -833,6 +877,15 @@ bool GeoPolygon::intersects(const GeoShape* rhs) const {
         }
         return true;
     }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        for (const auto& other : multi_polygon->polygons()) {
+            if (this->intersects(other.get())) {
+                return true;
+            }
+        }
+        return false;
+    }
     case GEO_SHAPE_CIRCLE: {
         const GeoCircle* circle = assert_cast<const GeoCircle*>(rhs);
         return circle->intersects(this);
@@ -862,17 +915,23 @@ bool GeoPolygon::polygon_touch_point(const S2Polygon* 
polygon, const S2Point* po
 }
 
 bool GeoPolygon::polygon_touch_polygon(const S2Polygon* polygon1, const 
S2Polygon* polygon2) const {
+    // Dual-check to avoid the following situations
+    // POLYGON((0 0, 20 0, 20 20, 0 20, 0 0), (5 5, 15 5, 15 15, 5 15, 5 5))
+    // POLYGON((5 10, 10 5, 15 10, 10 15, 5 10))
     for (int i = 0; i < polygon1->num_loops(); ++i) {
         const S2Loop* loop = polygon1->loop(i);
         for (int j = 0; j < loop->num_vertices(); ++j) {
-            const S2Point& p = loop->vertex(j);
+            const S2Point& p1 = loop->vertex(j);
+            const S2Point& p2 = loop->vertex((j + 1) % loop->num_vertices());
             for (int k = 0; k < polygon2->num_loops(); ++k) {
                 const S2Loop* innee_loop = polygon2->loop(k);
                 for (int l = 0; l < innee_loop->num_vertices(); ++l) {
-                    const S2Point& p1 = innee_loop->vertex(l);
-                    const S2Point& p2 = innee_loop->vertex((l + 1) % 
loop->num_vertices());
-                    double distance = compute_distance_to_line(p, p1, p2);
-                    if (distance < TOLERANCE) {
+                    const S2Point& p3 = innee_loop->vertex(l);
+                    const S2Point& p4 = innee_loop->vertex((l + 1) % 
innee_loop->num_vertices());
+                    if (compute_distance_to_line(p1, p3, p4) < TOLERANCE ||
+                        compute_distance_to_line(p2, p3, p4) < TOLERANCE ||
+                        compute_distance_to_line(p3, p1, p2) < TOLERANCE ||
+                        compute_distance_to_line(p4, p1, p2) < TOLERANCE) {
                         return true;
                     }
                 }
@@ -941,11 +1000,25 @@ bool GeoPolygon::touches(const GeoShape* rhs) const {
         const GeoPolygon* other = assert_cast<const GeoPolygon*>(rhs);
         const S2Polygon* polygon1 = _polygon.get();
         const S2Polygon* polygon2 = other->polygon();
-        // when the two polygons do not have overlapping areas, then determine 
if the touch regulation is met.
-        if (!polygon1->Intersects(polygon2)) {
-            return polygon_touch_polygon(polygon1, polygon2);
+
+        // "Touches" equivalent to boundary contact  but no internal overlap
+        std::unique_ptr<S2Polygon> intersection(new S2Polygon());
+        intersection->InitToIntersection(*polygon1, *polygon2);
+        return (intersection->GetArea() < 
S1Angle::Radians(TOLERANCE).radians() &&
+                polygon_touch_polygon(polygon1, polygon2));
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        bool has_touches = false;
+        for (const auto& other : multi_polygon->polygons()) {
+            if (this->intersects(other.get())) {
+                if (!this->touches(other.get())) {
+                    return false;
+                }
+                has_touches = true;
+            }
         }
-        return false;
+        return has_touches;
     }
     case GEO_SHAPE_CIRCLE: {
         const GeoCircle* circle = assert_cast<const GeoCircle*>(rhs);
@@ -970,6 +1043,15 @@ bool GeoPolygon::contains(const GeoShape* rhs) const {
         const GeoPolygon* other = (const GeoPolygon*)rhs;
         return _polygon->Contains(*other->polygon());
     }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = (const GeoMultiPolygon*)rhs;
+        for (const auto& other : multi_polygon->polygons()) {
+            if (!this->contains(other.get())) {
+                return false;
+            }
+        }
+        return true;
+    }
     default:
         return false;
     }
@@ -987,6 +1069,290 @@ S2Loop* GeoPolygon::getLoop(int i) const {
     return const_cast<S2Loop*>(_polygon->loop(i));
 }
 
+GeoParseStatus GeoMultiPolygon::from_coords(const 
std::vector<GeoCoordinateListList>& list) {
+    _polygons.clear();
+    for (const auto& coords_list : list) {
+        std::unique_ptr<GeoPolygon> polygon = GeoPolygon::create_unique();
+        auto status = polygon->from_coords(coords_list);
+        if (status != GEO_PARSE_OK) {
+            return status;
+        }
+        _polygons.push_back(std::move(polygon));
+    }
+
+    return check_self_intersection();
+}
+
+GeoParseStatus GeoMultiPolygon::check_self_intersection() {
+    for (int i = 0; i < _polygons.size(); ++i) {
+        for (int j = i + 1; j < _polygons.size(); ++j) {
+            if (_polygons[i]->intersects(_polygons[j].get())) {
+                if (!_polygons[i]->touches(_polygons[j].get())) {
+                    return GEO_PARSE_MULTIPOLYGON_OVERLAP;
+                }
+            } else {
+                continue;
+            }
+
+            //  Polygons in a multipolygon can only share discrete points, not 
edges.
+            for (int k = 0; k < _polygons[i]->numLoops(); ++k) {
+                const S2Loop* loop1 = _polygons[i]->getLoop(k);
+                for (int l = 0; l < _polygons[j]->numLoops(); ++l) {
+                    const S2Loop* loop2 = _polygons[j]->getLoop(l);
+                    for (int m = 0; m < loop1->num_vertices(); ++m) {
+                        const S2Point& p1 = loop1->vertex(m);
+                        const S2Point& p2 = loop1->vertex((m + 1) % 
loop1->num_vertices());
+                        for (int n = 0; n < loop2->num_vertices(); ++n) {
+                            const S2Point& p3 = loop2->vertex(n);
+                            const S2Point& p4 = loop2->vertex((n + 1) % 
loop2->num_vertices());
+
+                            // 1. At least one endpoint of an edge is near 
another edge
+                            // 2. Check the edges "touches" each other in a 
valid way
+                            if ((compute_distance_to_line(p1, p3, p4) < 
TOLERANCE ||
+                                 compute_distance_to_line(p2, p3, p4) < 
TOLERANCE ||
+                                 compute_distance_to_line(p3, p1, p2) < 
TOLERANCE ||
+                                 compute_distance_to_line(p4, p1, p2) < 
TOLERANCE) &&
+                                !is_line_touches_line(p1, p2, p3, p4)) {
+                                return GEO_PARSE_MULTIPOLYGON_OVERLAP;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return GEO_PARSE_OK;
+}
+
+bool GeoMultiPolygon::intersects(const GeoShape* rhs) const {
+    switch (rhs->type()) {
+    case GEO_SHAPE_POINT: {
+        const GeoPoint* point = assert_cast<const GeoPoint*>(rhs);
+        for (const auto& polygon : this->_polygons) {
+            if (polygon->intersects(point)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        const GeoLine* line = assert_cast<const GeoLine*>(rhs);
+        for (const auto& polygon : this->_polygons) {
+            if (polygon->intersects(line)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    case GEO_SHAPE_POLYGON: {
+        const GeoPolygon* other = assert_cast<const GeoPolygon*>(rhs);
+        for (const auto& polygon : this->_polygons) {
+            if (polygon->intersects(other)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        for (const auto& other : multi_polygon->polygons()) {
+            for (const auto& polygon : this->_polygons) {
+                if (polygon->intersects(other.get())) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    case GEO_SHAPE_CIRCLE: {
+        const GeoCircle* circle = assert_cast<const GeoCircle*>(rhs);
+        return circle->intersects(this);
+    }
+    default:
+        return false;
+    }
+}
+
+bool GeoMultiPolygon::disjoint(const GeoShape* rhs) const {
+    return !intersects(rhs);
+}
+
+bool GeoMultiPolygon::touches(const GeoShape* rhs) const {
+    switch (rhs->type()) {
+    case GEO_SHAPE_POINT: {
+        const GeoPoint* point = assert_cast<const GeoPoint*>(rhs);
+        for (const auto& polygon : this->_polygons) {
+            if (polygon->touches(point)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        const GeoLine* line = assert_cast<const GeoLine*>(rhs);
+        bool has_touches = false;
+        for (const auto& polygon : this->_polygons) {
+            if (polygon->intersects(line)) {
+                if (!polygon->touches(line)) {
+                    return false;
+                }
+                has_touches = true;
+            }
+        }
+        return has_touches;
+    }
+    case GEO_SHAPE_POLYGON: {
+        const GeoPolygon* other = assert_cast<const GeoPolygon*>(rhs);
+        bool has_touches = false;
+        for (const auto& polygon : this->_polygons) {
+            if (polygon->intersects(other)) {
+                if (!polygon->touches(other)) {
+                    return false;
+                }
+                has_touches = true;
+            }
+        }
+        return has_touches;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        bool has_touches = false;
+        for (const auto& other : multi_polygon->polygons()) {
+            for (const auto& polygon : this->_polygons) {
+                if (polygon->intersects(other.get())) {
+                    if (!polygon->touches(other.get())) {
+                        return false;
+                    }
+                    has_touches = true;
+                }
+            }
+        }
+        return has_touches;
+    }
+    case GEO_SHAPE_CIRCLE: {
+        const GeoCircle* circle = assert_cast<const GeoCircle*>(rhs);
+        return circle->touches(this);
+    }
+    default:
+        return false;
+    }
+}
+
+bool GeoMultiPolygon::contains(const GeoShape* rhs) const {
+    switch (rhs->type()) {
+    case GEO_SHAPE_POINT: {
+        const GeoPoint* point = assert_cast<const GeoPoint*>(rhs);
+        for (const auto& polygon : this->_polygons) {
+            if (polygon->contains(point)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        const GeoLine* line = assert_cast<const GeoLine*>(rhs);
+        for (const auto& polygon : this->_polygons) {
+            if (polygon->contains(line)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    case GEO_SHAPE_POLYGON: {
+        const GeoPolygon* other = assert_cast<const GeoPolygon*>(rhs);
+        for (const auto& polygon : this->_polygons) {
+            if (polygon->contains(other)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        //All polygons in rhs need to be contained
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        for (const auto& other : multi_polygon->polygons()) {
+            for (const auto& polygon : this->_polygons) {
+                if (polygon->contains(other.get())) {
+                    continue;
+                }
+                return false;
+            }
+        }
+        return true;
+    }
+    default:
+        return false;
+    }
+}
+
+std::string GeoMultiPolygon::as_wkt() const {
+    std::stringstream ss;
+    ss << "MULTIPOLYGON (";
+    for (size_t i = 0; i < _polygons.size(); ++i) {
+        if (i != 0) {
+            ss << ", ";
+        }
+        ss << "(";
+        const S2Polygon* polygon = _polygons[i]->polygon();
+        for (int j = 0; j < polygon->num_loops(); ++j) {
+            if (j != 0) {
+                ss << ", ";
+            }
+            ss << "(";
+            const S2Loop* loop = polygon->loop(j);
+            for (int k = 0; k < loop->num_vertices(); ++k) {
+                if (k != 0) {
+                    ss << ", ";
+                }
+                print_s2point(ss, loop->vertex(k));
+            }
+            ss << ", ";
+            print_s2point(ss, loop->vertex(0));
+            ss << ")";
+        }
+        ss << ")";
+    }
+    ss << ")";
+    return ss.str();
+}
+
+double GeoMultiPolygon::getArea() const {
+    double area = 0;
+    for (const auto& polygon : _polygons) {
+        area += polygon->getArea();
+    }
+    return area;
+}
+
+void GeoMultiPolygon::encode(std::string* buf) {
+    Encoder encoder;
+    encoder.Ensure(sizeof(size_t));
+    encoder.put_varint32(_polygons.size());
+    for (const auto& polygon : _polygons) {
+        polygon->polygon()->Encode(&encoder);
+    }
+    buf->append(encoder.base(), encoder.length());
+}
+
+bool GeoMultiPolygon::decode(const void* data, size_t size) {
+    Decoder decoder(data, size);
+    uint32_t num_polygons;
+    if (!decoder.get_varint32(&num_polygons)) {
+        return false;
+    }
+
+    _polygons.clear();
+    for (uint32_t i = 0; i < num_polygons; ++i) {
+        std::unique_ptr<GeoPolygon> polygon = GeoPolygon::create_unique();
+        polygon->_polygon.reset(new S2Polygon());
+        if (!(polygon->_polygon->Decode(&decoder)) && 
polygon->_polygon->IsValid()) {
+            return false;
+        }
+        _polygons.push_back(std::move(polygon));
+    }
+    return true;
+}
+
 GeoParseStatus GeoCircle::init(double lng, double lat, double radius_meter) {
     S2Point center;
     auto status = to_s2point(lng, lat, &center);
@@ -1043,6 +1409,15 @@ bool GeoCircle::intersects(const GeoShape* rhs) const {
         }
         return false;
     }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        for (const auto& polygon : multi_polygon->polygons()) {
+            if (this->intersects(polygon.get())) {
+                return true;
+            }
+        }
+        return false;
+    }
     case GEO_SHAPE_CIRCLE: {
         const GeoCircle* circle = assert_cast<const GeoCircle*>(rhs);
         S1ChordAngle radius_angle = _cap->radius();
@@ -1106,6 +1481,19 @@ bool GeoCircle::touches(const GeoShape* rhs) const {
 
         return false;
     }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = assert_cast<const 
GeoMultiPolygon*>(rhs);
+        bool has_touches = false;
+        for (const auto& polygon : multi_polygon->polygons()) {
+            if (this->intersects(polygon.get())) {
+                if (!this->touches(polygon.get())) {
+                    return false;
+                }
+                has_touches = true;
+            }
+        }
+        return has_touches;
+    }
     case GEO_SHAPE_CIRCLE: {
         const GeoCircle* circle = assert_cast<const GeoCircle*>(rhs);
         S1ChordAngle radius_angle = _cap->radius();
diff --git a/be/src/geo/geo_types.h b/be/src/geo/geo_types.h
index 0d08c9a80ef..1f44fa3deb5 100644
--- a/be/src/geo/geo_types.h
+++ b/be/src/geo/geo_types.h
@@ -21,6 +21,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "common/factory_creator.h"
 #include "geo/geo_common.h"
@@ -152,6 +153,7 @@ private:
 
 class GeoPolygon : public GeoShape {
     ENABLE_FACTORY_CREATOR(GeoPolygon);
+    friend class GeoMultiPolygon;
 
 public:
     GeoPolygon();
@@ -185,6 +187,36 @@ private:
     std::unique_ptr<S2Polygon> _polygon;
 };
 
+class GeoMultiPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoMultiPolygon);
+
+public:
+    GeoMultiPolygon();
+    ~GeoMultiPolygon() override;
+
+    GeoParseStatus check_self_intersection();
+    GeoParseStatus from_coords(const std::vector<GeoCoordinateListList>& list);
+    const std::vector<std::unique_ptr<GeoCoordinateListList>> to_coords() 
const;
+
+    GeoShapeType type() const override { return GEO_SHAPE_MULTI_POLYGON; }
+    const std::vector<std::unique_ptr<GeoPolygon>>& polygons() const { return 
_polygons; }
+
+    bool intersects(const GeoShape* rhs) const override;
+    bool disjoint(const GeoShape* rhs) const override;
+    bool touches(const GeoShape* rhs) const override;
+    bool contains(const GeoShape* rhs) const override;
+    std::string as_wkt() const override;
+
+    double getArea() const;
+
+protected:
+    void encode(std::string* buf) override;
+    bool decode(const void* data, size_t size) override;
+
+private:
+    std::vector<std::unique_ptr<GeoPolygon>> _polygons;
+};
+
 class GeoCircle : public GeoShape {
     ENABLE_FACTORY_CREATOR(GeoCircle);
 
diff --git a/be/src/geo/wkt_parse_type.h b/be/src/geo/wkt_parse_type.h
index 8d4204049a2..a871ce10217 100644
--- a/be/src/geo/wkt_parse_type.h
+++ b/be/src/geo/wkt_parse_type.h
@@ -38,6 +38,8 @@ struct GeoCoordinateListList {
             delete item;
         }
     }
+    GeoCoordinateListList() = default;
+    GeoCoordinateListList(GeoCoordinateListList&& other) : 
list(std::move(other.list)) {}
     void add(GeoCoordinateList* coordinates) { list.push_back(coordinates); }
     std::vector<GeoCoordinateList*> list;
 };
diff --git a/be/src/geo/wkt_yacc.y b/be/src/geo/wkt_yacc.y
index 1af26e82eee..02f59ea7068 100644
--- a/be/src/geo/wkt_yacc.y
+++ b/be/src/geo/wkt_yacc.y
@@ -33,6 +33,7 @@ void wkt_error(WktParseContext* ctx, const char* msg) {
     doris::GeoCoordinate coordinate_value;
     doris::GeoCoordinateList* coordinate_list_value;
     doris::GeoCoordinateListList* coordinate_list_list_value;
+    std::vector<doris::GeoCoordinateListList>* multi_polygon_value;
     doris::GeoShape* shape_value;
 }
 
@@ -67,16 +68,19 @@ void wkt_error(WktParseContext* ctx, const char* msg) {
 %token <double_value> NUMERIC
 
 %type <None> shape
-%type <shape_value> point linestring polygon
+%type <shape_value> point linestring polygon multi_polygon
 %type <coordinate_value> coordinate
 %type <coordinate_list_value> coordinate_list
 %type <coordinate_list_list_value> coordinate_list_list
+%type <multi_polygon_value> multi_polygon_list
 
 %destructor { delete $$; } coordinate_list
 %destructor { delete $$; } coordinate_list_list
 %destructor { delete $$; } point
 %destructor { delete $$; } linestring
 %destructor { delete $$; } polygon
+%destructor { delete $$; } multi_polygon
+%destructor { delete $$; } multi_polygon_list
 
 %%
 
@@ -87,6 +91,8 @@ shape:
     { ctx->shape = $1; }
     | polygon
     { ctx->shape = $1; }
+    | multi_polygon
+    { ctx->shape = $1; }
     ;
 
 point:
@@ -129,6 +135,35 @@ polygon:
     }
     ;
 
+multi_polygon:
+    KW_MULTI_POLYGON '(' multi_polygon_list ')'
+    {
+        // to avoid memory leak
+        std::unique_ptr<std::vector<doris::GeoCoordinateListList>> list($3);
+        std::unique_ptr<doris::GeoMultiPolygon> multi_polygon = 
doris::GeoMultiPolygon::create_unique();
+        ctx->parse_status = multi_polygon->from_coords(*$3);
+        if (ctx->parse_status != doris::GEO_PARSE_OK) {
+            YYABORT;
+        }
+        $$ = multi_polygon.release();
+    }
+    ;
+
+multi_polygon_list:
+    multi_polygon_list ',' '(' coordinate_list_list ')'
+    {
+        $1->push_back(std::move(*$4));
+        delete $4;
+        $$ = $1; 
+    }
+    | '(' coordinate_list_list ')'
+    {
+        $$ = new std::vector<doris::GeoCoordinateListList>();
+        $$->push_back(std::move(*$2));
+        delete $2;
+    }
+    ;
+
 coordinate_list_list:
     coordinate_list_list ',' '(' coordinate_list ')'
     {
diff --git a/be/test/geo/geo_types_test.cpp b/be/test/geo/geo_types_test.cpp
index 5f8dc105651..55504c5799a 100644
--- a/be/test/geo/geo_types_test.cpp
+++ b/be/test/geo/geo_types_test.cpp
@@ -100,13 +100,17 @@ TEST_F(GeoTypesTest, point_intersects) {
 
     const char* wkt_linestring = "LINESTRING(-20 0, 20 0)";
     const char* wkt_polygon = "POLYGON((0 0,10 0,10 10,0 10,0 0))";
+    const char* wkt_multi_polygon = "MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 
0)))";
 
     std::unique_ptr<GeoShape> line(
             GeoShape::from_wkt(wkt_linestring, strlen(wkt_linestring), 
&status));
     std::unique_ptr<GeoShape> polygon(
             GeoShape::from_wkt(wkt_polygon, strlen(wkt_polygon), &status));
+    std::unique_ptr<GeoShape> multi_polygon(
+            GeoShape::from_wkt(wkt_multi_polygon, strlen(wkt_multi_polygon), 
&status));
     ASSERT_NE(nullptr, line.get());
     ASSERT_NE(nullptr, polygon.get());
+    ASSERT_NE(nullptr, multi_polygon.get());
 
     {
         // point on the line (center)
@@ -132,24 +136,28 @@ TEST_F(GeoTypesTest, point_intersects) {
         GeoPoint point;
         point.from_coord(5, 5);
         EXPECT_TRUE(point.intersects(polygon.get()));
+        EXPECT_TRUE(point.intersects(multi_polygon.get()));
     }
     {
         // point on polygon boundary edges (not vertices)
         GeoPoint point;
         point.from_coord(5, 0);
         EXPECT_TRUE(point.intersects(polygon.get()));
+        EXPECT_TRUE(point.intersects(multi_polygon.get()));
     }
     {
         // point at polygon vertices
         GeoPoint point;
         point.from_coord(0, 0);
         EXPECT_TRUE(point.intersects(polygon.get()));
+        EXPECT_TRUE(point.intersects(multi_polygon.get()));
     }
     {
         // point outside the polygon
         GeoPoint point;
         point.from_coord(20, 20);
         EXPECT_FALSE(point.intersects(polygon.get()));
+        EXPECT_FALSE(point.intersects(multi_polygon.get()));
     }
 
     std::string buf;
@@ -172,15 +180,20 @@ TEST_F(GeoTypesTest, linestring_intersects) {
     const char* base_line = "LINESTRING(-10 0, 10 0)";
     const char* vertical_line = "LINESTRING(0 -10, 0 10)";
     const char* polygon = "POLYGON((-5 -5,5 -5,5 5,-5 5,-5 -5))";
+    const char* multi_polygon =
+            "MULTIPOLYGON(((30 30,35 30,35 35,30 35,30 30)), ((-5 -5,5 -5,5 
5,-5 5,-5 -5)))";
 
     std::unique_ptr<GeoShape> base_line_shape(
             GeoShape::from_wkt(base_line, strlen(base_line), &status));
     std::unique_ptr<GeoShape> vertical_line_shape(
             GeoShape::from_wkt(vertical_line, strlen(vertical_line), &status));
     std::unique_ptr<GeoShape> polygon_shape(GeoShape::from_wkt(polygon, 
strlen(polygon), &status));
+    std::unique_ptr<GeoShape> multi_polygon_shape(
+            GeoShape::from_wkt(multi_polygon, strlen(multi_polygon), &status));
     ASSERT_NE(nullptr, base_line_shape.get());
     ASSERT_NE(nullptr, vertical_line_shape.get());
     ASSERT_NE(nullptr, polygon_shape.get());
+    ASSERT_NE(nullptr, multi_polygon_shape.get());
 
     // ======================
     // LineString vs Point
@@ -252,6 +265,7 @@ TEST_F(GeoTypesTest, linestring_intersects) {
         std::unique_ptr<GeoShape> inner_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_TRUE(polygon_shape->intersects(inner_line.get()));
+        EXPECT_TRUE(multi_polygon_shape->intersects(inner_line.get()));
     }
     {
         // crossing the border
@@ -259,6 +273,7 @@ TEST_F(GeoTypesTest, linestring_intersects) {
         std::unique_ptr<GeoShape> cross_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_TRUE(polygon_shape->intersects(cross_line.get()));
+        EXPECT_TRUE(multi_polygon_shape->intersects(cross_line.get()));
     }
     {
         // along the borderline
@@ -266,6 +281,7 @@ TEST_F(GeoTypesTest, linestring_intersects) {
         std::unique_ptr<GeoShape> edge_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_TRUE(polygon_shape->intersects(edge_line.get()));
+        EXPECT_TRUE(multi_polygon_shape->intersects(edge_line.get()));
     }
     {
         // only one point
@@ -273,6 +289,7 @@ TEST_F(GeoTypesTest, linestring_intersects) {
         std::unique_ptr<GeoShape> edge_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_TRUE(polygon_shape->intersects(edge_line.get()));
+        EXPECT_TRUE(multi_polygon_shape->intersects(edge_line.get()));
     }
     {
         // fully external
@@ -280,6 +297,7 @@ TEST_F(GeoTypesTest, linestring_intersects) {
         std::unique_ptr<GeoShape> outer_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_FALSE(polygon_shape->intersects(outer_line.get()));
+        EXPECT_FALSE(multi_polygon_shape->intersects(outer_line.get()));
     }
 
     std::string buf;
@@ -303,6 +321,8 @@ TEST_F(GeoTypesTest, polygon_intersects) {
     const char* test_line = "LINESTRING(-5 5,15 5)";
     const char* overlap_polygon = "POLYGON((5 5,15 5,15 15,5 15,5 5))";
     const char* base_polygon2 = "POLYGON((-5 -5,5 -5,5 5,-5 5,-5 -5))";
+    const char* multi_polygons =
+            "MULTIPOLYGON(((35 35,40 35,40 40,35 40,35 35)), ((0 0,10 0,10 
10,0 10,0 0)))";
 
     std::unique_ptr<GeoShape> polygon(
             GeoShape::from_wkt(base_polygon, strlen(base_polygon), &status));
@@ -311,10 +331,13 @@ TEST_F(GeoTypesTest, polygon_intersects) {
     std::unique_ptr<GeoShape> line(GeoShape::from_wkt(test_line, 
strlen(test_line), &status));
     std::unique_ptr<GeoShape> other_polygon(
             GeoShape::from_wkt(overlap_polygon, strlen(overlap_polygon), 
&status));
+    std::unique_ptr<GeoShape> multi_polygon(
+            GeoShape::from_wkt(multi_polygons, strlen(multi_polygons), 
&status));
     ASSERT_NE(nullptr, polygon.get());
     ASSERT_NE(nullptr, polygon2.get());
     ASSERT_NE(nullptr, line.get());
     ASSERT_NE(nullptr, other_polygon.get());
+    ASSERT_NE(nullptr, multi_polygon.get());
 
     // ======================
     // Polygon vs Point
@@ -443,21 +466,25 @@ TEST_F(GeoTypesTest, polygon_intersects) {
         const char* wkt = "POLYGON((2 2,8 2,8 8,2 8,2 2))";
         std::unique_ptr<GeoShape> small_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
         EXPECT_TRUE(polygon->intersects(small_polygon.get()));
+        EXPECT_TRUE(multi_polygon->intersects(small_polygon.get()));
     }
     {
         const char* wkt = "POLYGON((5 5,15 5,15 15,5 15,5 5))";
         std::unique_ptr<GeoShape> overlap_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
         EXPECT_TRUE(polygon->intersects(overlap_polygon.get()));
+        EXPECT_TRUE(multi_polygon->intersects(overlap_polygon.get()));
     }
     {
         const char* wkt = "POLYGON((10 0,20 0,20 10,10 10,10 0))";
         std::unique_ptr<GeoShape> touch_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
         EXPECT_TRUE(polygon->intersects(touch_polygon.get()));
+        EXPECT_TRUE(multi_polygon->intersects(touch_polygon.get()));
     }
     {
         const char* wkt = "POLYGON((20 20,30 20,30 30,20 30,20 20))";
         std::unique_ptr<GeoShape> separate_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
         EXPECT_FALSE(polygon->intersects(separate_polygon.get()));
+        EXPECT_FALSE(multi_polygon->intersects(separate_polygon.get()));
     }
 
     std::string buf;
@@ -474,6 +501,160 @@ TEST_F(GeoTypesTest, polygon_intersects) {
     }
 }
 
+TEST_F(GeoTypesTest, multipolygon_intersects) {
+    GeoParseStatus status;
+
+    const char* base_multipolygon =
+            "MULTIPOLYGON ("
+            "((0 0, 10 0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),"
+            "((15 0, 25 0, 25 10, 15 10, 15 0)),"
+            "((30 30, 40 30, 35 35, 30 30))"
+            ")";
+
+    const char* test_line = "LINESTRING(-5 5, 35 5)";
+    const char* overlap_polygon = "POLYGON((8 8, 18 8, 18 18, 8 18, 8 8))";
+    const char* external_polygon = "POLYGON((50 50, 60 50, 60 60, 50 60, 50 
50))";
+
+    std::unique_ptr<GeoShape> multipolygon(
+            GeoShape::from_wkt(base_multipolygon, strlen(base_multipolygon), 
&status));
+    std::unique_ptr<GeoShape> line(GeoShape::from_wkt(test_line, 
strlen(test_line), &status));
+    std::unique_ptr<GeoShape> poly_overlap(
+            GeoShape::from_wkt(overlap_polygon, strlen(overlap_polygon), 
&status));
+    std::unique_ptr<GeoShape> poly_external(
+            GeoShape::from_wkt(external_polygon, strlen(external_polygon), 
&status));
+
+    ASSERT_NE(nullptr, multipolygon.get());
+    ASSERT_NE(nullptr, line.get());
+    ASSERT_NE(nullptr, poly_overlap.get());
+    ASSERT_NE(nullptr, poly_external.get());
+
+    // ======================
+    // MultiPolygon vs Point
+    // ======================
+    {
+        GeoPoint point;
+        point.from_coord(5, 5);
+        EXPECT_FALSE(multipolygon->intersects(&point));
+    }
+    {
+        GeoPoint point;
+        point.from_coord(1.5, 1.8);
+        EXPECT_TRUE(multipolygon->intersects(&point));
+    }
+    {
+        GeoPoint point;
+        point.from_coord(20, 5);
+        EXPECT_TRUE(multipolygon->intersects(&point));
+    }
+    {
+        GeoPoint point;
+        point.from_coord(12, 0);
+        EXPECT_FALSE(multipolygon->intersects(&point));
+    }
+    {
+        GeoPoint point;
+        point.from_coord(40, 30);
+        EXPECT_TRUE(multipolygon->intersects(&point));
+    }
+
+    // ======================
+    // MultiPolygon vs LineString
+    // ======================
+    {
+        const char* wkt = "LINESTRING(4 4, 7 7)";
+        std::unique_ptr<GeoShape> in_hole_line(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(multipolygon->intersects(in_hole_line.get()));
+    }
+    {
+        const char* wkt = "LINESTRING(-5 5, 35 5)";
+        std::unique_ptr<GeoShape> cross_line(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->intersects(cross_line.get()));
+    }
+    {
+        const char* wkt = "LINESTRING(3 3, 7 3)";
+        std::unique_ptr<GeoShape> inner_line(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->intersects(inner_line.get()));
+    }
+    {
+        const char* wkt = "LINESTRING(30 30, 35 35)";
+        std::unique_ptr<GeoShape> triangle_line(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->intersects(triangle_line.get()));
+    }
+    {
+        const char* wkt = "LINESTRING(50 50, 60 60)";
+        std::unique_ptr<GeoShape> outer_line(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(multipolygon->intersects(outer_line.get()));
+    }
+
+    // ======================
+    // MultiPolygon vs Polygon
+    // ======================
+    {
+        const char* wkt = "POLYGON((4 4, 7 4, 7 7, 4 7, 4 4))";
+        std::unique_ptr<GeoShape> in_hole_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(multipolygon->intersects(in_hole_polygon.get()));
+    }
+    {
+        const char* wkt = "POLYGON((20 0, 30 0, 30 10, 20 10, 20 0))";
+        std::unique_ptr<GeoShape> overlap_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->intersects(overlap_polygon.get()));
+    }
+    {
+        const char* wkt = "POLYGON((50 50, 60 50, 60 60, 50 60, 50 50))";
+        std::unique_ptr<GeoShape> external_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(multipolygon->intersects(external_polygon.get()));
+    }
+    {
+        const char* wkt = "POLYGON((10 0, 20 0, 20 5, 10 5, 10 0))";
+        std::unique_ptr<GeoShape> cross_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->intersects(cross_polygon.get()));
+    }
+    {
+        const char* wkt = "POLYGON((10 0, 15 0, 15 10, 10 10, 10 0))";
+        std::unique_ptr<GeoShape> touch_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->intersects(touch_polygon.get()));
+    }
+
+    // ======================
+    // MultiPolygon vs MultiPolygon
+    // ======================
+    {
+        const char* wkt = "MULTIPOLYGON (((4 4, 5 4, 5 5, 4 5, 4 4)), ((6 6, 7 
6, 7 7, 6 7, 6 6)))";
+        std::unique_ptr<GeoShape> in_hole_multi(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(multipolygon->intersects(in_hole_multi.get()));
+    }
+    {
+        const char* wkt =
+                "MULTIPOLYGON (((8 8, 18 8, 18 18, 8 18, 8 8)), ((30 30, 40 
30, 35 35, 30 30)))";
+        std::unique_ptr<GeoShape> overlap_multi(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->intersects(overlap_multi.get()));
+    }
+    {
+        const char* wkt =
+                "MULTIPOLYGON (((-10 -10, 0 -10, 0 0, -10 0, -10 -10)), ((50 
50, 60 50, 60 60, 50 "
+                "60, 50 50)))";
+        std::unique_ptr<GeoShape> separate_multi(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->intersects(separate_multi.get()));
+    }
+
+    std::string buf;
+    multipolygon->encode_to(&buf);
+    {
+        std::unique_ptr<GeoShape> decoded(GeoShape::from_encoded(buf.data(), 
buf.size()));
+        ASSERT_NE(nullptr, decoded.get());
+        EXPECT_EQ(GEO_SHAPE_MULTI_POLYGON, decoded->type());
+
+        GeoPoint point;
+        point.from_coord(20, 5);
+        EXPECT_TRUE(decoded->intersects(&point));
+    }
+    {
+        buf.resize(buf.size() - 2);
+        std::unique_ptr<GeoShape> decoded(GeoShape::from_encoded(buf.data(), 
buf.size()));
+        EXPECT_EQ(nullptr, decoded.get());
+    }
+}
+
 TEST_F(GeoTypesTest, circle_intersect) {
     GeoParseStatus status;
 
@@ -553,13 +734,17 @@ TEST_F(GeoTypesTest, point_touches) {
 
     const char* wkt_linestring = "LINESTRING(-20 0, 20 0)";
     const char* wkt_polygon = "POLYGON((0 0,10 0,10 10,0 10,0 0))";
+    const char* wkt_multi_polygon = "MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 
0)))";
 
     std::unique_ptr<GeoShape> line(
             GeoShape::from_wkt(wkt_linestring, strlen(wkt_linestring), 
&status));
     std::unique_ptr<GeoShape> polygon(
             GeoShape::from_wkt(wkt_polygon, strlen(wkt_polygon), &status));
+    std::unique_ptr<GeoShape> multi_polygon(
+            GeoShape::from_wkt(wkt_multi_polygon, strlen(wkt_multi_polygon), 
&status));
     ASSERT_NE(nullptr, line.get());
     ASSERT_NE(nullptr, polygon.get());
+    ASSERT_NE(nullptr, multi_polygon.get());
 
     {
         // point touches the line at the center
@@ -585,24 +770,28 @@ TEST_F(GeoTypesTest, point_touches) {
         GeoPoint point;
         point.from_coord(5, 5);
         EXPECT_FALSE(point.touches(polygon.get()));
+        EXPECT_FALSE(point.touches(multi_polygon.get()));
     }
     {
         // point touches the polygon boundary edge (not vertex)
         GeoPoint point;
         point.from_coord(5, 0);
         EXPECT_TRUE(point.touches(polygon.get()));
+        EXPECT_TRUE(point.touches(multi_polygon.get()));
     }
     {
         // point touches the polygon vertex
         GeoPoint point;
         point.from_coord(0, 0);
         EXPECT_TRUE(point.touches(polygon.get()));
+        EXPECT_TRUE(point.touches(multi_polygon.get()));
     }
     {
         // point does not touch the polygon
         GeoPoint point;
         point.from_coord(20, 20);
         EXPECT_FALSE(point.touches(polygon.get()));
+        EXPECT_FALSE(point.touches(multi_polygon.get()));
     }
 
     std::string buf;
@@ -625,15 +814,19 @@ TEST_F(GeoTypesTest, linestring_touches) {
     const char* base_line = "LINESTRING(-10 0, 10 0)";
     const char* vertical_line = "LINESTRING(0 -10, 0 10)";
     const char* polygon = "POLYGON((-5 -5,5 -5,5 5,-5 5,-5 -5))";
+    const char* multi_polygon = "MULTIPOLYGON(((-5 -5,5 -5,5 5,-5 5,-5 -5)))";
 
     std::unique_ptr<GeoShape> base_line_shape(
             GeoShape::from_wkt(base_line, strlen(base_line), &status));
     std::unique_ptr<GeoShape> vertical_line_shape(
             GeoShape::from_wkt(vertical_line, strlen(vertical_line), &status));
     std::unique_ptr<GeoShape> polygon_shape(GeoShape::from_wkt(polygon, 
strlen(polygon), &status));
+    std::unique_ptr<GeoShape> multi_polygon_shape(
+            GeoShape::from_wkt(multi_polygon, strlen(multi_polygon), &status));
     ASSERT_NE(nullptr, base_line_shape.get());
     ASSERT_NE(nullptr, vertical_line_shape.get());
     ASSERT_NE(nullptr, polygon_shape.get());
+    ASSERT_NE(nullptr, multi_polygon_shape.get());
 
     // ======================
     // LineString vs Point
@@ -712,6 +905,7 @@ TEST_F(GeoTypesTest, linestring_touches) {
         std::unique_ptr<GeoShape> inner_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_FALSE(polygon_shape->touches(inner_line.get()));
+        EXPECT_FALSE(multi_polygon_shape->touches(inner_line.get()));
     }
     {
         // crossing the border
@@ -719,6 +913,7 @@ TEST_F(GeoTypesTest, linestring_touches) {
         std::unique_ptr<GeoShape> cross_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_FALSE(polygon_shape->touches(cross_line.get()));
+        EXPECT_FALSE(multi_polygon_shape->touches(cross_line.get()));
     }
     {
         // along the borderline
@@ -726,6 +921,7 @@ TEST_F(GeoTypesTest, linestring_touches) {
         std::unique_ptr<GeoShape> edge_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_TRUE(polygon_shape->touches(edge_line.get()));
+        EXPECT_TRUE(multi_polygon_shape->touches(edge_line.get()));
     }
     {
         // along the borderline
@@ -733,6 +929,7 @@ TEST_F(GeoTypesTest, linestring_touches) {
         std::unique_ptr<GeoShape> edge_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_FALSE(polygon_shape->touches(edge_line.get()));
+        EXPECT_FALSE(multi_polygon_shape->touches(edge_line.get()));
     }
     {
         // along the borderline
@@ -740,6 +937,7 @@ TEST_F(GeoTypesTest, linestring_touches) {
         std::unique_ptr<GeoShape> edge_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_FALSE(polygon_shape->touches(edge_line.get()));
+        EXPECT_FALSE(multi_polygon_shape->touches(edge_line.get()));
     }
     {
         // along the borderline
@@ -747,6 +945,7 @@ TEST_F(GeoTypesTest, linestring_touches) {
         std::unique_ptr<GeoShape> edge_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_TRUE(polygon_shape->touches(edge_line.get()));
+        EXPECT_TRUE(multi_polygon_shape->touches(edge_line.get()));
     }
     {
         // fully external
@@ -754,6 +953,7 @@ TEST_F(GeoTypesTest, linestring_touches) {
         std::unique_ptr<GeoShape> outer_line(
                 GeoShape::from_wkt(wkt_string, strlen(wkt_string), &status));
         EXPECT_FALSE(polygon_shape->touches(outer_line.get()));
+        EXPECT_FALSE(multi_polygon_shape->touches(outer_line.get()));
     }
 
     std::string buf;
@@ -776,15 +976,20 @@ TEST_F(GeoTypesTest, polygon_touches) {
     const char* base_polygon = "POLYGON((0 0,10 0,10 10,0 10,0 0))";
     const char* test_line = "LINESTRING(-5 5,15 5)";
     const char* overlap_polygon = "POLYGON((5 5,15 5,15 15,5 15,5 5))";
+    const char* test_multi_polugon =
+            "MULTIPOLYGON(((30 30,35 30,35 35,30 35,30 30)), ((0 0,10 0,10 
10,0 10,0 0)))";
 
     std::unique_ptr<GeoShape> polygon(
             GeoShape::from_wkt(base_polygon, strlen(base_polygon), &status));
     std::unique_ptr<GeoShape> line(GeoShape::from_wkt(test_line, 
strlen(test_line), &status));
     std::unique_ptr<GeoShape> other_polygon(
             GeoShape::from_wkt(overlap_polygon, strlen(overlap_polygon), 
&status));
+    std::unique_ptr<GeoShape> multi_polygon(
+            GeoShape::from_wkt(test_multi_polugon, strlen(test_multi_polugon), 
&status));
     ASSERT_NE(nullptr, polygon.get());
     ASSERT_NE(nullptr, line.get());
     ASSERT_NE(nullptr, other_polygon.get());
+    ASSERT_NE(nullptr, multi_polygon.get());
 
     // ======================
     // Polygon vs Point
@@ -893,6 +1098,40 @@ TEST_F(GeoTypesTest, polygon_touches) {
         EXPECT_FALSE(polygon->touches(separate_polygon.get()));
     }
 
+    // ========================
+    // Polygon vs MultiPolygon
+    // ========================
+    {
+        const char* wkt = "MULTIPOLYGON(((2 2,8 2,8 8,2 8,2 2)))";
+        std::unique_ptr<GeoShape> small_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(polygon->touches(small_polygon.get()));
+    }
+    {
+        const char* wkt = "MULTIPOLYGON(((5 5,15 5,15 15,5 15,5 5)))";
+        std::unique_ptr<GeoShape> overlap_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(polygon->touches(overlap_polygon.get()));
+    }
+    {
+        const char* wkt = "MULTIPOLYGON(((10 0,20 0,20 10,10 10,10 0)))";
+        std::unique_ptr<GeoShape> touch_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(polygon->touches(touch_polygon.get()));
+    }
+    {
+        const char* wkt = "MULTIPOLYGON(((10.1 0,20 0,20 10,10.1 10,10.1 0)))";
+        std::unique_ptr<GeoShape> touch_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(polygon->touches(touch_polygon.get()));
+    }
+    {
+        const char* wkt = "MULTIPOLYGON(((9.99 0,20 0,20 10,9.99 10,9.99 0)))";
+        std::unique_ptr<GeoShape> touch_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(polygon->touches(touch_polygon.get()));
+    }
+    {
+        const char* wkt = "MULTIPOLYGON(((20 20,30 20,30 30,20 30,20 20)))";
+        std::unique_ptr<GeoShape> separate_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(polygon->touches(separate_polygon.get()));
+    }
+
     std::string buf;
     polygon->encode_to(&buf);
     {
@@ -907,6 +1146,155 @@ TEST_F(GeoTypesTest, polygon_touches) {
     }
 }
 
+TEST_F(GeoTypesTest, multipolygon_touches) {
+    GeoParseStatus status;
+
+    const char* base_multipolygon =
+            "MULTIPOLYGON ("
+            "((0 0, 10 0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),"
+            "((15 0, 25 0, 25 10, 15 10, 15 0)),"
+            "((30 30, 40 30, 35 35, 30 30))"
+            ")";
+    const char* test_line = "LINESTRING(10 5, 20 5)";
+    const char* overlap_polygon = "POLYGON((8 8, 18 8, 18 18, 8 18, 8 8))";
+    const char* test_multi_polygon =
+            "MULTIPOLYGON (((-5 -5, 0 -5, 0 0, -5 0, -5 -5)), ((40 40, 50 40, 
50 50, 40 50, 40 "
+            "40)))";
+
+    std::unique_ptr<GeoShape> multipolygon(
+            GeoShape::from_wkt(base_multipolygon, strlen(base_multipolygon), 
&status));
+    std::unique_ptr<GeoShape> line(GeoShape::from_wkt(test_line, 
strlen(test_line), &status));
+    std::unique_ptr<GeoShape> other_polygon(
+            GeoShape::from_wkt(overlap_polygon, strlen(overlap_polygon), 
&status));
+    std::unique_ptr<GeoShape> other_multipolygon(
+            GeoShape::from_wkt(test_multi_polygon, strlen(test_multi_polygon), 
&status));
+    ASSERT_NE(nullptr, multipolygon.get());
+    ASSERT_NE(nullptr, line.get());
+    ASSERT_NE(nullptr, other_polygon.get());
+    ASSERT_NE(nullptr, other_multipolygon.get());
+
+    // ======================
+    // MultiPolygon vs Point
+    // ======================
+    {
+        GeoPoint point;
+        point.from_coord(0, 0);
+        EXPECT_TRUE(multipolygon->touches(&point));
+    }
+    {
+        GeoPoint point;
+        point.from_coord(10, 5);
+        EXPECT_TRUE(multipolygon->touches(&point));
+    }
+    {
+        GeoPoint point;
+        point.from_coord(30, 30);
+        EXPECT_TRUE(multipolygon->touches(&point));
+    }
+    {
+        GeoPoint point;
+        point.from_coord(50, 50);
+        EXPECT_FALSE(multipolygon->touches(&point));
+    }
+
+    // ===========================
+    // MultiPolygon vs LineString
+    // ===========================
+    {
+        const char* wkt = "LINESTRING(3 5, 8 5)";
+        std::unique_ptr<GeoShape> in_hole_line(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->touches(in_hole_line.get()));
+    }
+    {
+        const char* wkt = "LINESTRING(10 5, 20 5)";
+        std::unique_ptr<GeoShape> cross_line(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(multipolygon->touches(cross_line.get()));
+    }
+    {
+        const char* wkt = "LINESTRING(30 30, 35 35)";
+        std::unique_ptr<GeoShape> edge_line(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->touches(edge_line.get()));
+    }
+    {
+        const char* wkt = "LINESTRING(10 10, 15 0)";
+        std::unique_ptr<GeoShape> cross_line(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->touches(cross_line.get()));
+    }
+
+    // ========================
+    // MultiPolygon vs Polygon
+    // ========================
+    {
+        const char* wkt = "POLYGON((3 3, 8 3, 8 8, 3 8, 3 3))";
+        std::unique_ptr<GeoShape> in_hole_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->touches(in_hole_polygon.get()));
+    }
+    {
+        const char* wkt = "POLYGON((3 3, 10 3, 10 8, 3 8, 3 3))";
+        std::unique_ptr<GeoShape> cross_hole_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(multipolygon->touches(cross_hole_polygon.get()));
+    }
+    {
+        const char* wkt = "POLYGON((25 0, 35 0, 35 10, 25 10, 25 0))";
+        std::unique_ptr<GeoShape> touch_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->touches(touch_polygon.get()));
+    }
+    {
+        const char* wkt = "POLYGON((8 8, 18 8, 18 18, 8 18, 8 8))";
+        std::unique_ptr<GeoShape> overlap_poly(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(multipolygon->touches(overlap_poly.get()));
+    }
+    {
+        const char* wkt = "POLYGON((10 0, 15 0, 15 10, 10 10, 10 0))";
+        std::unique_ptr<GeoShape> touch_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->touches(touch_polygon.get()));
+    }
+    {
+        const char* wkt = "POLYGON((20 20, 30 20, 30 30, 20 30, 20 20))";
+        std::unique_ptr<GeoShape> separate_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->touches(separate_polygon.get()));
+    }
+    {
+        const char* wkt = "POLYGON((10 0, 20 0, 20 5, 10 5, 10 0))";
+        std::unique_ptr<GeoShape> cross_polygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(multipolygon->touches(cross_polygon.get()));
+    }
+
+    // =============================
+    // MultiPolygon vs MultiPolygon
+    // =============================
+    {
+        const char* wkt =
+                "MULTIPOLYGON (((-5 -5, 0 -5, 0 0, -5 0, -5 -5)), ((40 30, 50 
30, 50 50, 40 50, 40 "
+                "30)))";
+        std::unique_ptr<GeoShape> touch_multi(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_TRUE(multipolygon->touches(touch_multi.get()));
+    }
+    {
+        const char* wkt =
+                "MULTIPOLYGON (((8 8, 18 8, 18 18, 8 18, 8 8)), ((30 30, 40 
30, 35 25, 30 30)))";
+        std::unique_ptr<GeoShape> overlap_multi(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_FALSE(multipolygon->touches(overlap_multi.get()));
+    }
+
+    std::string buf;
+    multipolygon->encode_to(&buf);
+    {
+        std::unique_ptr<GeoShape> decoded(GeoShape::from_encoded(buf.data(), 
buf.size()));
+        ASSERT_NE(nullptr, decoded.get());
+        EXPECT_EQ(GEO_SHAPE_MULTI_POLYGON, decoded->type());
+
+        GeoPoint point;
+        point.from_coord(10, 5);
+        EXPECT_TRUE(decoded->touches(&point));
+    }
+    {
+        buf.resize(buf.size() - 2);
+        std::unique_ptr<GeoShape> decoded(GeoShape::from_encoded(buf.data(), 
buf.size()));
+        EXPECT_EQ(nullptr, decoded.get());
+    }
+}
+
 TEST_F(GeoTypesTest, circle_touches) {
     GeoParseStatus status;
 
@@ -1098,6 +1486,53 @@ TEST_F(GeoTypesTest, polygon_hole_contains) {
     }
 }
 
+TEST_F(GeoTypesTest, multipolygon_parse_fail) {
+    {
+        const char* wkt = "MULTIPOLYGON (((10 10, 50 10, 50 50, 10 50), (10 10 
01)))";
+        GeoParseStatus status;
+        std::unique_ptr<GeoShape> multipolygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_EQ(GEO_PARSE_WKT_SYNTAX_ERROR, status);
+        EXPECT_EQ(nullptr, multipolygon.get());
+    }
+    {
+        const char* wkt = "MULTIPOLYGON (((10 10, 50 10, 50 50, 10 50)))";
+        GeoParseStatus status;
+        std::unique_ptr<GeoShape> multipolygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_EQ(GEO_PARSE_LOOP_NOT_CLOSED, status);
+        EXPECT_EQ(nullptr, multipolygon.get());
+    }
+    {
+        const char* wkt = "MULTIPOLYGON (((10 10, 50 10, 10 10)))";
+        GeoParseStatus status;
+        std::unique_ptr<GeoShape> multipolygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_EQ(GEO_PARSE_LOOP_LACK_VERTICES, status);
+        EXPECT_EQ(nullptr, multipolygon.get());
+    }
+    {
+        const char* wkt =
+                "MULTIPOLYGON (((0 0, 0 10, 10 10, 10 0, 0 0)), ((5 5, 5 15, 
15 15, 15 5, 5 5)))";
+        GeoParseStatus status;
+        std::unique_ptr<GeoShape> multipolygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_EQ(GEO_PARSE_MULTIPOLYGON_OVERLAP, status);
+        EXPECT_EQ(nullptr, multipolygon.get());
+    }
+    {
+        const char* wkt =
+                "MULTIPOLYGON(((5 5, 5 8, 8 8, 8 5, 5 5)), ((8 6, 10 6, 10 10, 
8 10, 8 6)))";
+        GeoParseStatus status;
+        std::unique_ptr<GeoShape> multipolygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_EQ(GEO_PARSE_MULTIPOLYGON_OVERLAP, status);
+        EXPECT_EQ(nullptr, multipolygon.get());
+    }
+    {
+        const char* wkt = "MULTIPOLYGON((()))";
+        GeoParseStatus status;
+        std::unique_ptr<GeoShape> multipolygon(GeoShape::from_wkt(wkt, 
strlen(wkt), &status));
+        EXPECT_EQ(GEO_PARSE_WKT_SYNTAX_ERROR, status);
+        EXPECT_EQ(nullptr, multipolygon.get());
+    }
+}
+
 TEST_F(GeoTypesTest, circle) {
     GeoCircle circle;
     auto res = circle.init(110.123, 64, 1000);
diff --git 
a/regression-test/data/nereids_p0/sql_functions/spatial_functions/test_gis_function.out
 
b/regression-test/data/nereids_p0/sql_functions/spatial_functions/test_gis_function.out
index cf0146b0493..f1169aa3486 100644
Binary files 
a/regression-test/data/nereids_p0/sql_functions/spatial_functions/test_gis_function.out
 and 
b/regression-test/data/nereids_p0/sql_functions/spatial_functions/test_gis_function.out
 differ
diff --git 
a/regression-test/suites/nereids_p0/sql_functions/spatial_functions/test_gis_function.groovy
 
b/regression-test/suites/nereids_p0/sql_functions/spatial_functions/test_gis_function.groovy
index 4ff443ad4fa..d2c8d1006b8 100644
--- 
a/regression-test/suites/nereids_p0/sql_functions/spatial_functions/test_gis_function.groovy
+++ 
b/regression-test/suites/nereids_p0/sql_functions/spatial_functions/test_gis_function.groovy
@@ -26,6 +26,10 @@ suite("test_gis_function") {
 
     qt_sql "SELECT ST_Contains(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 10, 
0 0))\"), ST_Point(5, 5));"
     qt_sql "SELECT ST_Contains(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 10, 
0 0))\"), ST_Point(50, 50));"
+    qt_sql "SELECT ST_Contains(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 
0, 0 0))'), ST_GeomFromText('POINT(2 10)'));"
+    qt_sql "SELECT ST_Contains(ST_GeomFromText(\"POLYGON((0 0, 0 10, 10 10, 10 
0, 0 0))\"),ST_GeomFromText(\"MULTIPOLYGON(((2 2, 4 2, 4 4, 2 4, 2 2)), ((6 6, 
8 6, 8 8, 6 8, 6 6)))\"));"
+    qt_sql "SELECT ST_Contains(ST_GeomFromText(\"POLYGON((0 0, 0 10, 10 10, 10 
0, 0 0))\"),ST_GeomFromText(\"MULTIPOLYGON(((2 2, 2 8, 8 8, 8 2, 2 2)), ((10 
10, 10 15, 15 15, 15 10, 10 10)))\"));"
+
 
     qt_sql "SELECT ST_Intersects(ST_Point(0, 0), ST_Point(0, 0));"
     qt_sql "SELECT ST_Intersects(ST_Point(0, 0), ST_Point(5, 5));"
@@ -58,6 +62,35 @@ suite("test_gis_function") {
     qt_sql "SELECT ST_Intersects(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 
10, 0 0))\"), ST_Polygon(\"POLYGON ((11 0, 11 10, 21 10, 21 0, 11 0))\"));"
     qt_sql "SELECT ST_Intersects(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 
10, 0 0))\"), ST_Polygon(\"POLYGON ((10 10, 20 10, 20 20, 10 20, 10 10))\"));"
 
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText(\"MULTIPOLYGON(((0 0, 0 
5, 5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))\"), ST_Point(0, 0));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText(\"MULTIPOLYGON(((0 0, 0 
5, 5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))\"), ST_Point(8, 8));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_Point(5.000001, 0));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 
0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POINT(5 3)'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 
0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POINT(5 5)'));"
+
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText(\"MULTIPOLYGON(((0 0, 0 
5, 5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))\"), 
ST_LineFromText(\"LINESTRING (4 4, 7 7)\"));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_LineFromText('LINESTRING (5.000001 0, 5.999999 10)'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 
0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('LINESTRING(3 3, 8 
8)'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 
0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('LINESTRING(4 3, 4 
7)'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 
0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('LINESTRING(3.000001 
3.000001, 7.999999 7.999999)'));"
+
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((12 12, 12 15, 15 15, 15 12, 12 12))'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((3 3, 3 8, 8 8, 8 3, 3 3))'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((5.000001 0, 5.999999 0, 5.999999 9.999999, 
5.000001 9.999999, 5.000001 0))'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 
0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POLYGON((3.00001 
3.00001, 7.99999 3.00001, 7.99999 7.99999, 3.00001 7.99999, 3.00001 
3.00001))'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 
0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POLYGON((4 4, 6 4, 
6 6, 4 6, 4 4))'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 
0, 10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POLYGON((4 3, 7 3, 
7 8, 4 8, 4 3))'));"
+
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('MULTIPOLYGON(((5 5, 5 8, 8 8, 8 5, 5 5)), ((8 8, 8 12, 12 
12, 12 8, 8 8)))'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('MULTIPOLYGON(((2 2, 3 2, 3 3, 2 3, 2 2)), ((11 11, 11 12, 
12 12, 12 11, 11 11)))'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('MULTIPOLYGON(((-2 -2, -3 -2, -3 -3, -2 -3, -2 -2)), ((11 
11, 11 12, 12 12, 12 11, 11 11)))'));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('MULTIPOLYGON(((5.000001 0, 6 0, 6 5.999999, 5.000001 
5.999999, 5.000001 0)), ((0 5.000001, 5 5.000001, 5 6, 5.999999 6, 5.999999 10, 
0 10, 0 5.000001)))'));"
+
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_CIRCLE(2, 6, 1));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_CIRCLE(2, 6, 
0.999999));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_CIRCLE(10, 10, 1));"
+    qt_sql "SELECT ST_Intersects(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_CIRCLE(5, 6, 
0.999999));"
+
     qt_sql "SELECT ST_Intersects(ST_Circle(1, 1, 1), ST_Point(2, 1));" 
     qt_sql "SELECT ST_Intersects(ST_Circle(1, 1, 1), ST_Point(1, 1));"
     qt_sql "SELECT ST_Intersects(ST_Circle(1, 1, 1), ST_Point(3, 1));"  
@@ -98,8 +131,48 @@ suite("test_gis_function") {
 
     qt_sql "SELECT ST_Touches(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 
0))\"), ST_Polygon(\"POLYGON ((5 0, 15 0, 15 10, 5 10, 5 0))\"));"
     qt_sql "SELECT ST_Touches(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 
0))\"), ST_Polygon(\"POLYGON ((10 0, 10 10, 20 10, 20 0, 10 0))\"));"
-    qt_sql "SELECT ST_Touches(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 
0))\"), ST_Polygon(\"POLYGON ((11 0, 11 10, 21 10, 21 0, 11 0))\"));"
-    qt_sql "SELECT ST_Touches(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 
0))\"), ST_Polygon(\"POLYGON ((10 10, 20 10, 20 20, 10 20, 10 10))\"));"
+    qt_sql "SELECT ST_Touches(ST_Polygon('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 
0))'), ST_Polygon('POLYGON ((11 0, 11 10, 21 10, 21 0, 11 0))'));"
+    qt_sql "SELECT ST_Touches(ST_Polygon('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 
0))'), ST_Polygon('POLYGON ((10 10, 20 10, 20 20, 10 20, 10 10))'));"
+    qt_sql "SELECT ST_Touches(ST_GeomFromText('POLYGON((0 0, 0 10, 10 10, 10 
0, 0 0))'),ST_GeomFromText('POLYGON((2 10, 5 15, 8 10, 10 15, 5 20, 0 15, 2 
10))'));"
+
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_Point(0, 3));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_Point(5, 5));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_Point(5, 6));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_Point(3, 3));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_Point(5.00001, 0));"
+
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_LineFromText('LINESTRING 
(5 5, 7 7)'));"                           
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('LINESTRING (5 5, 5 10)'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('LINESTRING (0 3, 5 3)'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('LINESTRING (5.5 0, 5.5 10)'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('LINESTRING (5.000001 0, 5.999999 10)'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('LINESTRING(3 3, 8 
8)'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('LINESTRING(4 4, 4 
7)'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('LINESTRING(3.000001 
3.000001, 7.999999 7.999999)'));"
+
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((5 5, 5 8, 8 8, 8 5, 5 5))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)))'), ST_GeometryFromText('POLYGON((5 5, 5 8, 8 8, 8 5, 5 5))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((12 12, 12 15, 15 15, 15 12, 12 12))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((0 0, 0 4, 4 4, 4 0, 0 0))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((0 0, 0 -4, -4 -4, -4 0, 0 0))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((5.000001 0, 6 0, 6 5.999999, 5.000001 5.999999, 
5.000001 0))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POLYGON((3.00001 
3.00001, 7.99999 3.00001, 7.99999 7.99999, 3.00001 7.99999, 3.00001 
3.00001))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POLYGON((4 4, 6 4, 
6 6, 4 6, 4 4))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POLYGON((3 4, 8 4, 
8 7, 3 7, 3 4))'));"
+    
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0)), ((15 0, 25 0, 25 10, 15 10, 15 0)), ((30 30, 35 35, 40 30, 
30 30)))'),ST_GeometryFromText('MULTIPOLYGON (((10 0, 20 0, 20 10, 10 10, 10 
0)))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('MULTIPOLYGON(((3 4, 
8 4, 8 7, 3 7, 3 4)), ((-8 -8, -8 -12, -12 -12, -12 -8, -8 -8)))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), 
ST_GeometryFromText('MULTIPOLYGON(((10.00001 0, 14.99999 0, 14.99999 10, 
10.00001 10, 10.00001 0)), ((-8 -8, -8 -12, -12 -12, -12 -8, -8 -8)))'));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('MULTIPOLYGON(((3 3, 
8 3, 8 8, 3 8, 3 3)), ((8 8, 8 12, 12 12, 12 8, 8 8)))'));"
+
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_Circle(10, 15, 5));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_Circle(10, 15, 5.00001));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_Circle(3, 5, 2));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_Circle(4.5, 5, 1.5));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_Circle(20, 20, 1));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_Circle(5.5, 5.5, 0.5));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_Circle(1, 1, 0.5));"
+    qt_sql "SELECT ST_Touches(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_Circle(8, 8, 2));"
 
     qt_sql "SELECT ST_Touches(ST_Circle(1, 1, 1), ST_Point(2, 1));"
     qt_sql "SELECT ST_Touches(ST_Circle(1, 1, 1), ST_Point(1, 2));"
@@ -143,6 +216,35 @@ suite("test_gis_function") {
     qt_sql "SELECT ST_Disjoint(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 10, 
0 0))\"), ST_Polygon(\"POLYGON ((11 0, 11 10, 21 10, 21 0, 11 0))\"));"
     qt_sql "SELECT ST_Disjoint(ST_Polygon(\"POLYGON ((0 0, 10 0, 10 10, 0 10, 
0 0))\"), ST_Polygon(\"POLYGON ((10 10, 20 10, 20 20, 10 20, 10 10))\"));"
 
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText(\"MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))\"), ST_Point(0, 0));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText(\"MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))\"), ST_Point(8, 8));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_Point(5.000001, 0));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POINT(5 3)'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POINT(5 5)'));"
+
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText(\"MULTIPOLYGON(((0 0, 0 5, 
5 5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))\"), 
ST_LineFromText(\"LINESTRING (4 4, 7 7)\"));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_LineFromText('LINESTRING 
(5.000001 0, 5.999999 10)'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('LINESTRING(3 3, 8 
8)'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('LINESTRING(4 3, 4 
7)'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('LINESTRING(3.000001 
3.000001, 7.999999 7.999999)'));"
+
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((12 12, 12 15, 15 15, 15 12, 12 12))'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((3 3, 3 8, 8 8, 8 3, 3 3))'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('POLYGON((5.000001 0, 5.999999 0, 5.999999 9.999999, 
5.000001 9.999999, 5.000001 0))'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POLYGON((3.00001 
3.00001, 7.99999 3.00001, 7.99999 7.99999, 3.00001 7.99999, 3.00001 
3.00001))'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POLYGON((4 4, 6 4, 
6 6, 4 6, 4 4))'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON (((0 0, 10 0, 
10 10, 0 10, 0 0), (3 3, 8 3, 8 8, 3 8, 3 3)),((15 0, 25 0, 25 10, 15 10, 15 
0)),((30 30, 40 30, 35 35, 30 30)))'), ST_GeometryFromText('POLYGON((4 3, 7 3, 
7 8, 4 8, 4 3))'));"
+
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('MULTIPOLYGON(((5 5, 5 8, 8 8, 8 5, 5 5)), ((8 8, 8 12, 12 
12, 12 8, 8 8)))'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('MULTIPOLYGON(((2 2, 3 2, 3 3, 2 3, 2 2)), ((11 11, 11 12, 
12 12, 12 11, 11 11)))'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('MULTIPOLYGON(((-2 -2, -3 -2, -3 -3, -2 -3, -2 -2)), ((11 
11, 11 12, 12 12, 12 11, 11 11)))'));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), 
ST_GeometryFromText('MULTIPOLYGON(((5.000001 0, 6 0, 6 5.999999, 5.000001 
5.999999, 5.000001 0)), ((0 5.000001, 5 5.000001, 5 6, 5.999999 6, 5.999999 10, 
0 10, 0 5.000001)))'));"
+
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_CIRCLE(2, 6, 1));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_CIRCLE(2, 6, 0.999999));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_CIRCLE(10, 10, 1));"
+    qt_sql "SELECT ST_Disjoint(ST_GeometryFromText('MULTIPOLYGON(((0 0, 0 5, 5 
5, 5 0, 0 0)), ((6 6, 6 10, 10 10, 10 6, 6 6)))'), ST_CIRCLE(5, 6, 0.999999));"
+
     qt_sql "SELECT ST_Disjoint(ST_Circle(1, 1, 1), ST_Point(2, 1));" 
     qt_sql "SELECT ST_Disjoint(ST_Circle(1, 1, 1), ST_Point(1, 1));"
     qt_sql "SELECT ST_Disjoint(ST_Circle(1, 1, 1), ST_Point(3, 1));"  
@@ -176,6 +278,19 @@ suite("test_gis_function") {
     qt_sql "SELECT ST_AsText(ST_PolyFromText(\"POLYGON ((0 0, 10 0, 10 10, 0 
10, 0 0))\"));"
     qt_sql "SELECT ST_AsText(ST_PolygonFromText(\"POLYGON ((0 0, 10 0, 10 10, 
0 10, 0 0))\"));"
 
+    qt_sql "SELECT ST_AsText(ST_GeometryFromText(\"MULTIPOLYGON (((0.0 0.0, 
0.0 4.9, 5.3 5.3, 5.2 0.0, 0.0 0.0)), ((20.1 20.3, 20.4 30.6, 30.6 30.4, 30.0 
20.2, 20.1 20.3)), ((50.2 50.3, 50.1 60.7, 60.7 60.9, 60.5 50.5, 50.2 50.3)), 
((70.3 70.1, 70.5 80.5, 80.3 80.2, 80.0 70.0, 70.3 70.1)))\"));"
+    qt_sql "SELECT ST_AsText(ST_GeometryFromText('MULTIPOLYGON(((5 5, 5 8, 8 
8, 8 5, 5 5)), ((8 8, 8 12, 12 12, 12 8, 8 8)))'));"
+    qt_sql "SELECT ST_AsText(ST_GeometryFromText('MULTIPOLYGON(((5 5, 5 8, 8 
8, 8 5, 5 5)), ((8 6, 10 6, 10 10, 8 10, 8 6)))'));"
+    qt_sql "SELECT ST_AsText(ST_GeometryFromText(\"MULTIPOLYGON (((0 0, 0 10, 
10 10, 10 0, 0 0)), ((5 5, 5 15, 15 15, 15 5, 5 5)))\"));"
+    qt_sql "SELECT ST_AsText(ST_GeomFromText('MULTIPOLYGON (((-10 -10, -10 10, 
10 10, 10 -10, -10 -10)), ((20 20, 20 30, 30 30, 30 20, 20 20), (25 25, 25 27, 
27 27, 27 25, 25 25)))'));"
+    qt_sql "SELECT ST_AsText(ST_GeometryFromText('MULTIPOLYGON(((0 0, 10 0, 10 
10, 0 10, 0 0)), ((2 10, 5 15, 8 10, 10 15, 5 20, 0 15, 2 10)))'));"
+    qt_sql "SELECT ST_AsText(ST_GeomFromText('MULTIPOLYGON (((0 0, 20 0, 20 
20, 0 20, 0 0), (5 5, 15 5, 15 15, 5 15, 5 5)), ((5 10, 10 5, 15 10, 10 15, 5 
10)))'));"
+    qt_sql "SELECT ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0, 0 10, 10 10, 
10 0, 0 0), (3 3, 7 3, 7 7, 3 7, 3 3)), ((3 3, 3 7, 7 7, 7 3, 3 3)))'));"
+    qt_sql "SELECT ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0, 4 1, 2 4, 0 
0)), ((2 4, 5 6, 3 8, 2 4)))'));"
+    qt_sql "SELECT ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0, 1e-8 0, 1e-8 
1e-8, 0 1e-8, 0 0)))'));"
+    qt_sql "SELECT ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0, 1e-6 0, 1e-6 
1e-6, 0 1e-6, 0 0)), ((1e-5 0, 1 0, 1 1e-5, 1e-5 1e-5, 1e-5 0)))'));"
+    qt_sql "SELECT ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0, 1e-6 0, 1e-6 
1e-6, 0 1e-6, 0 0), (1e-8 1e-8, 1e-7 1e-8, 1e-7 1e-7, 1e-8 1e-7, 1e-8 
1e-8)))'));"
+
     qt_sql "SELECT ST_X(ST_Point(1, 2));"
     qt_sql "SELECT ST_X(ST_Point(24.7, 56.7));"
     qt_sql "SELECT ST_Y(ST_Point(2, 1));"


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to