diff --git a/django/contrib/gis/db/backends/mysql/operations.py b/django/contrib/gis/db/backends/mysql/operations.py index 8af78d8703..f838a79da6 100644 --- a/django/contrib/gis/db/backends/mysql/operations.py +++ b/django/contrib/gis/db/backends/mysql/operations.py @@ -45,6 +45,7 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations): "bboverlaps": SpatialOperator(func="MBROverlaps"), # ... "contained": SpatialOperator(func="MBRWithin"), # ... "contains": SpatialOperator(func="ST_Contains"), + "coveredby": SpatialOperator(func="MBRCoveredBy"), "crosses": SpatialOperator(func="ST_Crosses"), "disjoint": SpatialOperator(func="ST_Disjoint"), "equals": SpatialOperator(func="ST_Equals"), @@ -57,9 +58,10 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations): } if self.connection.mysql_is_mariadb: operators["relate"] = SpatialOperator(func="ST_Relate") + if self.connection.mysql_version < (12, 0, 1): + del operators["coveredby"] else: operators["covers"] = SpatialOperator(func="MBRCovers") - operators["coveredby"] = SpatialOperator(func="MBRCoveredBy") return operators @cached_property @@ -71,7 +73,10 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations): models.Union, ] is_mariadb = self.connection.mysql_is_mariadb - if is_mariadb or self.connection.mysql_version < (8, 0, 24): + if is_mariadb: + if self.connection.mysql_version < (12, 0, 1): + disallowed_aggregates.insert(0, models.Collect) + elif self.connection.mysql_version < (8, 0, 24): disallowed_aggregates.insert(0, models.Collect) return tuple(disallowed_aggregates) @@ -106,7 +111,8 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations): } if self.connection.mysql_is_mariadb: unsupported.remove("PointOnSurface") - unsupported.update({"GeoHash", "IsValid"}) + if self.connection.mysql_version < (12, 0, 1): + unsupported.update({"GeoHash", "IsValid"}) return unsupported def geo_db_type(self, f): diff --git a/docs/ref/contrib/gis/db-api.txt b/docs/ref/contrib/gis/db-api.txt index ee365b9320..5ce009e9bb 100644 --- a/docs/ref/contrib/gis/db-api.txt +++ b/docs/ref/contrib/gis/db-api.txt @@ -339,42 +339,42 @@ divided into the three categories described in the :ref:`raster lookup details `: native support ``N``, bilateral native support ``B``, and geometry conversion support ``C``. -================================= ========= ======== ========== ============ ========== ======== -Lookup Type PostGIS Oracle MariaDB MySQL [#]_ SpatiaLite PGRaster -================================= ========= ======== ========== ============ ========== ======== -:lookup:`bbcontains` X X X X N -:lookup:`bboverlaps` X X X X N -:lookup:`contained` X X X X N -:lookup:`contains ` X X X X X B -:lookup:`contains_properly` X B -:lookup:`coveredby` X X X X B -:lookup:`covers` X X X X B -:lookup:`crosses` X X X X C -:lookup:`disjoint` X X X X X B -:lookup:`distance_gt` X X X X X N -:lookup:`distance_gte` X X X X X N -:lookup:`distance_lt` X X X X X N -:lookup:`distance_lte` X X X X X N -:lookup:`dwithin` X X X B -:lookup:`equals` X X X X X C -:lookup:`exact ` X X X X X B -:lookup:`intersects` X X X X X B +================================= ========= ======== ============ ============ ========== ======== +Lookup Type PostGIS Oracle MariaDB MySQL [#]_ SpatiaLite PGRaster +================================= ========= ======== ============ ============ ========== ======== +:lookup:`bbcontains` X X X X N +:lookup:`bboverlaps` X X X X N +:lookup:`contained` X X X X N +:lookup:`contains ` X X X X X B +:lookup:`contains_properly` X B +:lookup:`coveredby` X X X (≥ 12.0.1) X X B +:lookup:`covers` X X X X B +:lookup:`crosses` X X X X C +:lookup:`disjoint` X X X X X B +:lookup:`distance_gt` X X X X X N +:lookup:`distance_gte` X X X X X N +:lookup:`distance_lt` X X X X X N +:lookup:`distance_lte` X X X X X N +:lookup:`dwithin` X X X B +:lookup:`equals` X X X X X C +:lookup:`exact ` X X X X X B +:lookup:`intersects` X X X X X B :lookup:`isempty` X -:lookup:`isvalid` X X X X -:lookup:`overlaps` X X X X X B -:lookup:`relate` X X X X C -:lookup:`same_as` X X X X X B -:lookup:`touches` X X X X X B -:lookup:`within` X X X X X B -:lookup:`left` X C -:lookup:`right` X C -:lookup:`overlaps_left` X B -:lookup:`overlaps_right` X B -:lookup:`overlaps_above` X C -:lookup:`overlaps_below` X C -:lookup:`strictly_above` X C -:lookup:`strictly_below` X C -================================= ========= ======== ========== ============ ========== ======== +:lookup:`isvalid` X X X (≥ 12.0.1) X X +:lookup:`overlaps` X X X X X B +:lookup:`relate` X X X X C +:lookup:`same_as` X X X X X B +:lookup:`touches` X X X X X B +:lookup:`within` X X X X X B +:lookup:`left` X C +:lookup:`right` X C +:lookup:`overlaps_left` X B +:lookup:`overlaps_right` X B +:lookup:`overlaps_above` X C +:lookup:`overlaps_below` X C +:lookup:`strictly_above` X C +:lookup:`strictly_below` X C +================================= ========= ======== ============ ============ ========== ======== .. _database-functions-compatibility: @@ -406,11 +406,11 @@ Function PostGIS Oracle MariaDB MySQL :class:`ForcePolygonCW` X X :class:`FromWKB` X X X X X :class:`FromWKT` X X X X X -:class:`GeoHash` X X X (LWGEOM/RTTOPO) +:class:`GeoHash` X X (≥ 12.0.1) X X (LWGEOM/RTTOPO) :class:`GeometryDistance` X :class:`Intersection` X X X X X :class:`IsEmpty` X -:class:`IsValid` X X X X +:class:`IsValid` X X X (≥ 12.0.1) X X :class:`Length` X X X X X :class:`LineLocatePoint` X X :class:`MakeValid` X X (LWGEOM/RTTOPO) @@ -433,20 +433,19 @@ Aggregate Functions ------------------- The following table provides a summary of what GIS-specific aggregate functions -are available on each spatial backend. Please note that MariaDB does not -support any of these aggregates, and is thus excluded from the table. +are available on each spatial backend. .. currentmodule:: django.contrib.gis.db.models -======================= ======= ====== ============ ========== -Aggregate PostGIS Oracle MySQL SpatiaLite -======================= ======= ====== ============ ========== -:class:`Collect` X X (≥ 8.0.24) X -:class:`Extent` X X X +======================= ======= ====== ============ ============ ========== +Aggregate PostGIS Oracle MariaDB MySQL SpatiaLite +======================= ======= ====== ============ ============ ========== +:class:`Collect` X X (≥ 12.0.1) X (≥ 8.0.24) X +:class:`Extent` X X X :class:`Extent3D` X -:class:`MakeLine` X X -:class:`Union` X X X -======================= ======= ====== ============ ========== +:class:`MakeLine` X X +:class:`Union` X X X +======================= ======= ====== ============ ============ ========== .. rubric:: Footnotes .. [#fnwkt] *See* Open Geospatial Consortium, Inc., `OpenGIS Simple Feature Specification For SQL `_, Document 99-049 (May 5, 1999), at Ch. 3.2.5, p. 3-11 (SQL Textual Representation of Geometry). diff --git a/docs/ref/contrib/gis/functions.txt b/docs/ref/contrib/gis/functions.txt index 3133e89b59..f9939c5e63 100644 --- a/docs/ref/contrib/gis/functions.txt +++ b/docs/ref/contrib/gis/functions.txt @@ -589,7 +589,7 @@ Example: .. class:: GeoHash(expression, precision=None, **extra) -*Availability*: `MySQL +*Availability*: MariaDB, `MySQL `__, `PostGIS `__, SpatiaLite (LWGEOM/RTTOPO) @@ -602,6 +602,10 @@ result. __ https://en.wikipedia.org/wiki/Geohash +.. versionchanged:: 6.0 + + MariaDB 12.0.1+ support was added. + Miscellaneous ============= @@ -620,13 +624,17 @@ geometry. Returns ``True`` if its value is empty and ``False`` otherwise. .. class:: IsValid(expr) -*Availability*: `MySQL +*Availability*: MariaDB, `MySQL `__, `PostGIS `__, Oracle, SpatiaLite Accepts a geographic field or expression and tests if the value is well formed. Returns ``True`` if its value is a valid geometry and ``False`` otherwise. +.. versionchanged:: 6.0 + + MariaDB 12.0.1+ support was added. + ``MemSize`` ----------- diff --git a/docs/ref/contrib/gis/geoquerysets.txt b/docs/ref/contrib/gis/geoquerysets.txt index 5881eb0a85..0231ce6af8 100644 --- a/docs/ref/contrib/gis/geoquerysets.txt +++ b/docs/ref/contrib/gis/geoquerysets.txt @@ -183,7 +183,7 @@ PostGIS ``ST_ContainsProperly(poly, geom)`` ------------- *Availability*: `PostGIS `__, -Oracle, MySQL, PGRaster (Bilateral), SpatiaLite +Oracle, MariaDB, MySQL, PGRaster (Bilateral), SpatiaLite Tests if no point in the geometry field is outside the lookup geometry. [#fncovers]_ @@ -197,6 +197,7 @@ Backend SQL Equivalent ========== ============================= PostGIS ``ST_CoveredBy(poly, geom)`` Oracle ``SDO_COVEREDBY(poly, geom)`` +MariaDB ``MBRCoveredBy(poly, geom)`` MySQL ``MBRCoveredBy(poly, geom)`` SpatiaLite ``CoveredBy(poly, geom)`` ========== ============================= @@ -205,6 +206,10 @@ SpatiaLite ``CoveredBy(poly, geom)`` MySQL support was added. +.. versionchanged:: 6.0 + + MariaDB 12.0.1+ support was added. + .. fieldlookup:: covers ``covers`` @@ -374,8 +379,8 @@ Example:: ``isvalid`` ----------- -*Availability*: MySQL, `PostGIS `__, -Oracle, SpatiaLite +*Availability*: MariaDB, MySQL, +`PostGIS `__, Oracle, SpatiaLite Tests if the geometry is valid. @@ -383,12 +388,16 @@ Example:: Zipcode.objects.filter(poly__isvalid=True) -========================== ================================================================ -Backend SQL Equivalent -========================== ================================================================ -MySQL, PostGIS, SpatiaLite ``ST_IsValid(poly)`` -Oracle ``SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(poly, 0.05) = 'TRUE'`` -========================== ================================================================ +=================================== ================================================================ +Backend SQL Equivalent +=================================== ================================================================ +MariaDB, MySQL, PostGIS, SpatiaLite ``ST_IsValid(poly)`` +Oracle ``SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(poly, 0.05) = 'TRUE'`` +=================================== ================================================================ + +.. versionchanged:: 6.0 + + MariaDB 12.0.1+ support was added. .. fieldlookup:: overlaps @@ -880,8 +889,8 @@ Example: .. class:: Collect(geo_field, filter=None) -*Availability*: `PostGIS `__, MySQL, -SpatiaLite +*Availability*: `PostGIS `__, +MariaDB, MySQL, SpatiaLite Returns a ``GEOMETRYCOLLECTION`` or a ``MULTI`` geometry object from the geometry column. This is analogous to a simplified version of the :class:`Union` @@ -889,6 +898,10 @@ aggregate, except it can be several orders of magnitude faster than performing a union because it rolls up geometries into a collection or multi object, not caring about dissolving boundaries. +.. versionchanged:: 6.0 + + MariaDB 12.0.1+ support was added. + ``Extent`` ~~~~~~~~~~ diff --git a/docs/releases/6.0.txt b/docs/releases/6.0.txt index 304343256f..e653884163 100644 --- a/docs/releases/6.0.txt +++ b/docs/releases/6.0.txt @@ -76,6 +76,12 @@ Minor features * The new :attr:`.BaseGeometryWidget.base_layer` attribute allows specifying a JavaScript map base layer, enabling customization of map tile providers. +* :lookup:`coveredby` and :lookup:`isvalid` lookups, + :class:`~django.contrib.gis.db.models.Collect` aggregation, and + :class:`~django.contrib.gis.db.models.functions.GeoHash` and + :class:`~django.contrib.gis.db.models.functions.IsValid` database functions + are now supported on MariaDB 12.0.1+. + :mod:`django.contrib.messages` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/gis_tests/relatedapp/tests.py b/tests/gis_tests/relatedapp/tests.py index 303d357705..2db635b0c0 100644 --- a/tests/gis_tests/relatedapp/tests.py +++ b/tests/gis_tests/relatedapp/tests.py @@ -346,9 +346,12 @@ class RelatedGeoModelTest(TestCase): ) ) city = qs.get(name="Aurora") - self.assertIsInstance(city.parcel_centroid, Point) - self.assertAlmostEqual(city.parcel_centroid[0], 3.2128, 4) - self.assertAlmostEqual(city.parcel_centroid[1], 1.5, 4) + if connection.ops.mariadb: + self.assertIsNone(city.parcel_centroid) + else: + self.assertIsInstance(city.parcel_centroid, Point) + self.assertAlmostEqual(city.parcel_centroid[0], 3.2128, 4) + self.assertAlmostEqual(city.parcel_centroid[1], 1.5, 4) @skipUnlessDBFeature("supports_make_line_aggr") def test_make_line_filter(self):