2015-01-13 04:20:40 +08:00
|
|
|
from django.contrib.gis.db.backends.base.adapter import WKTAdapter
|
2017-06-02 01:23:48 +08:00
|
|
|
from django.contrib.gis.db.backends.base.operations import (
|
|
|
|
BaseSpatialOperations,
|
|
|
|
)
|
2014-05-23 03:51:30 +08:00
|
|
|
from django.contrib.gis.db.backends.utils import SpatialOperator
|
2017-08-23 14:30:24 +08:00
|
|
|
from django.contrib.gis.db.models import aggregates
|
2017-09-05 21:54:57 +08:00
|
|
|
from django.contrib.gis.geos.geometry import GEOSGeometryBase
|
2017-08-23 14:30:24 +08:00
|
|
|
from django.contrib.gis.geos.prototypes.io import wkb_r
|
2017-07-26 15:40:19 +08:00
|
|
|
from django.contrib.gis.measure import Distance
|
2015-01-13 04:20:40 +08:00
|
|
|
from django.db.backends.mysql.operations import DatabaseOperations
|
2015-01-25 07:03:02 +08:00
|
|
|
from django.utils.functional import cached_property
|
2009-12-22 23:18:51 +08:00
|
|
|
|
2012-07-21 03:14:27 +08:00
|
|
|
|
2015-01-14 20:36:32 +08:00
|
|
|
class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
|
2009-12-22 23:18:51 +08:00
|
|
|
|
|
|
|
mysql = True
|
|
|
|
name = 'mysql'
|
2017-08-25 02:56:09 +08:00
|
|
|
geom_func_prefix = 'ST_'
|
2009-12-22 23:18:51 +08:00
|
|
|
|
|
|
|
Adapter = WKTAdapter
|
|
|
|
|
2016-01-30 06:25:15 +08:00
|
|
|
@cached_property
|
|
|
|
def select(self):
|
2017-08-23 14:30:24 +08:00
|
|
|
return self.geom_func_prefix + 'AsBinary(%s)'
|
2016-01-30 06:25:15 +08:00
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def from_text(self):
|
2016-10-24 23:12:47 +08:00
|
|
|
return self.geom_func_prefix + 'GeomFromText'
|
2016-01-30 06:25:15 +08:00
|
|
|
|
2016-05-24 21:53:50 +08:00
|
|
|
@cached_property
|
|
|
|
def gis_operators(self):
|
2017-11-18 21:22:15 +08:00
|
|
|
MBREquals = 'MBREqual' if (
|
|
|
|
self.connection.mysql_is_mariadb or self.connection.mysql_version < (5, 7, 6)
|
|
|
|
) else 'MBREquals'
|
2016-05-24 21:53:50 +08:00
|
|
|
return {
|
|
|
|
'bbcontains': SpatialOperator(func='MBRContains'), # For consistency w/PostGIS API
|
|
|
|
'bboverlaps': SpatialOperator(func='MBROverlaps'), # ...
|
|
|
|
'contained': SpatialOperator(func='MBRWithin'), # ...
|
|
|
|
'contains': SpatialOperator(func='MBRContains'),
|
|
|
|
'disjoint': SpatialOperator(func='MBRDisjoint'),
|
|
|
|
'equals': SpatialOperator(func=MBREquals),
|
|
|
|
'exact': SpatialOperator(func=MBREquals),
|
|
|
|
'intersects': SpatialOperator(func='MBRIntersects'),
|
|
|
|
'overlaps': SpatialOperator(func='MBROverlaps'),
|
|
|
|
'same_as': SpatialOperator(func=MBREquals),
|
|
|
|
'touches': SpatialOperator(func='MBRTouches'),
|
|
|
|
'within': SpatialOperator(func='MBRWithin'),
|
|
|
|
}
|
2013-05-09 23:13:13 +08:00
|
|
|
|
2015-01-25 07:03:02 +08:00
|
|
|
disallowed_aggregates = (
|
|
|
|
aggregates.Collect, aggregates.Extent, aggregates.Extent3D,
|
|
|
|
aggregates.MakeLine, aggregates.Union,
|
|
|
|
)
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def unsupported_functions(self):
|
|
|
|
unsupported = {
|
2017-11-25 01:30:53 +08:00
|
|
|
'AsGML', 'AsKML', 'AsSVG', 'Azimuth', 'BoundingCircle',
|
2018-12-28 09:31:55 +08:00
|
|
|
'ForcePolygonCW', 'LineLocatePoint', 'MakeValid', 'MemSize',
|
|
|
|
'Perimeter', 'PointOnSurface', 'Reverse', 'Scale', 'SnapToGrid',
|
|
|
|
'Transform', 'Translate',
|
2015-01-25 07:03:02 +08:00
|
|
|
}
|
2017-11-18 21:22:15 +08:00
|
|
|
if self.connection.mysql_is_mariadb:
|
|
|
|
unsupported.update({'GeoHash', 'IsValid'})
|
|
|
|
if self.connection.mysql_version < (10, 2, 4):
|
|
|
|
unsupported.add('AsGeoJSON')
|
|
|
|
elif self.connection.mysql_version < (5, 7, 5):
|
2017-04-02 01:43:53 +08:00
|
|
|
unsupported.update({'AsGeoJSON', 'GeoHash', 'IsValid'})
|
2015-01-25 07:03:02 +08:00
|
|
|
return unsupported
|
2015-01-15 18:35:35 +08:00
|
|
|
|
2009-12-22 23:18:51 +08:00
|
|
|
def geo_db_type(self, f):
|
|
|
|
return f.geom_type
|
|
|
|
|
2017-07-26 15:40:19 +08:00
|
|
|
def get_distance(self, f, value, lookup_type):
|
|
|
|
value = value[0]
|
|
|
|
if isinstance(value, Distance):
|
|
|
|
if f.geodetic(self.connection):
|
|
|
|
raise ValueError(
|
|
|
|
'Only numeric values of degree units are allowed on '
|
|
|
|
'geodetic distance queries.'
|
|
|
|
)
|
|
|
|
dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
|
|
|
|
else:
|
|
|
|
dist_param = value
|
|
|
|
return [dist_param]
|
|
|
|
|
2017-08-23 14:30:24 +08:00
|
|
|
def get_geometry_converter(self, expression):
|
|
|
|
read = wkb_r().read
|
|
|
|
srid = expression.output_field.srid
|
|
|
|
if srid == -1:
|
|
|
|
srid = None
|
2017-09-05 21:54:57 +08:00
|
|
|
geom_class = expression.output_field.geom_class
|
2017-08-23 14:30:24 +08:00
|
|
|
|
|
|
|
def converter(value, expression, connection):
|
2017-09-05 21:54:57 +08:00
|
|
|
if value is not None:
|
|
|
|
geom = GEOSGeometryBase(read(memoryview(value)), geom_class)
|
|
|
|
if srid:
|
|
|
|
geom.srid = srid
|
|
|
|
return geom
|
2017-08-23 14:30:24 +08:00
|
|
|
return converter
|