Refs #25759 -- Fixed some GIS Funcs if different database backends are used.
This commit is contained in:
parent
4bc355079c
commit
d5977e492e
|
@ -8,20 +8,21 @@ class GeoAggregate(Aggregate):
|
||||||
function = None
|
function = None
|
||||||
is_extent = False
|
is_extent = False
|
||||||
|
|
||||||
def as_sql(self, compiler, connection):
|
def as_sql(self, compiler, connection, function=None, **extra_context):
|
||||||
# this will be called again in parent, but it's needed now - before
|
# this will be called again in parent, but it's needed now - before
|
||||||
# we get the spatial_aggregate_name
|
# we get the spatial_aggregate_name
|
||||||
connection.ops.check_expression_support(self)
|
connection.ops.check_expression_support(self)
|
||||||
self.function = connection.ops.spatial_aggregate_name(self.name)
|
return super().as_sql(
|
||||||
return super().as_sql(compiler, connection)
|
compiler,
|
||||||
|
connection,
|
||||||
|
function=function or connection.ops.spatial_aggregate_name(self.name),
|
||||||
|
**extra_context
|
||||||
|
)
|
||||||
|
|
||||||
def as_oracle(self, compiler, connection):
|
def as_oracle(self, compiler, connection):
|
||||||
if not hasattr(self, 'tolerance'):
|
tolerance = self.extra.get('tolerance') or getattr(self, 'tolerance', 0.05)
|
||||||
self.tolerance = 0.05
|
template = None if self.is_extent else '%(function)s(SDOAGGRTYPE(%(expressions)s,%(tolerance)s))'
|
||||||
self.extra['tolerance'] = self.tolerance
|
return self.as_sql(compiler, connection, template=template, tolerance=tolerance)
|
||||||
if not self.is_extent:
|
|
||||||
self.template = '%(function)s(SDOAGGRTYPE(%(expressions)s,%(tolerance)s))'
|
|
||||||
return self.as_sql(compiler, connection)
|
|
||||||
|
|
||||||
def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
|
def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
|
||||||
c = super().resolve_expression(query, allow_joins, reuse, summarize, for_save)
|
c = super().resolve_expression(query, allow_joins, reuse, summarize, for_save)
|
||||||
|
|
|
@ -45,12 +45,12 @@ class GeoFuncMixin:
|
||||||
def geo_field(self):
|
def geo_field(self):
|
||||||
return GeometryField(srid=self.srid) if self.srid else None
|
return GeometryField(srid=self.srid) if self.srid else None
|
||||||
|
|
||||||
def as_sql(self, compiler, connection, **extra_context):
|
def as_sql(self, compiler, connection, function=None, **extra_context):
|
||||||
if self.function is None:
|
if not self.function and not function:
|
||||||
self.function = connection.ops.spatial_function_name(self.name)
|
function = connection.ops.spatial_function_name(self.name)
|
||||||
if any(isinstance(field, RasterField) for field in self.get_source_fields()):
|
if any(isinstance(field, RasterField) for field in self.get_source_fields()):
|
||||||
raise TypeError("Geometry functions not supported for raster fields.")
|
raise TypeError("Geometry functions not supported for raster fields.")
|
||||||
return super().as_sql(compiler, connection, **extra_context)
|
return super().as_sql(compiler, connection, function=function, **extra_context)
|
||||||
|
|
||||||
def resolve_expression(self, *args, **kwargs):
|
def resolve_expression(self, *args, **kwargs):
|
||||||
res = super().resolve_expression(*args, **kwargs)
|
res = super().resolve_expression(*args, **kwargs)
|
||||||
|
@ -125,8 +125,7 @@ class OracleToleranceMixin:
|
||||||
|
|
||||||
def as_oracle(self, compiler, connection):
|
def as_oracle(self, compiler, connection):
|
||||||
tol = self.extra.get('tolerance', self.tolerance)
|
tol = self.extra.get('tolerance', self.tolerance)
|
||||||
self.template = "%%(function)s(%%(expressions)s, %s)" % tol
|
return super().as_sql(compiler, connection, template="%%(function)s(%%(expressions)s, %s)" % tol)
|
||||||
return super().as_sql(compiler, connection)
|
|
||||||
|
|
||||||
|
|
||||||
class Area(OracleToleranceMixin, GeoFunc):
|
class Area(OracleToleranceMixin, GeoFunc):
|
||||||
|
@ -272,6 +271,7 @@ class Distance(DistanceResultMixin, OracleToleranceMixin, GeoFuncWithGeoParam):
|
||||||
super().__init__(*expressions, **extra)
|
super().__init__(*expressions, **extra)
|
||||||
|
|
||||||
def as_postgresql(self, compiler, connection):
|
def as_postgresql(self, compiler, connection):
|
||||||
|
function = None
|
||||||
geo_field = GeometryField(srid=self.srid) # Fake field to get SRID info
|
geo_field = GeometryField(srid=self.srid) # Fake field to get SRID info
|
||||||
if self.source_is_geography():
|
if self.source_is_geography():
|
||||||
# Set parameters as geography if base field is geography
|
# Set parameters as geography if base field is geography
|
||||||
|
@ -283,12 +283,12 @@ class Distance(DistanceResultMixin, OracleToleranceMixin, GeoFuncWithGeoParam):
|
||||||
# Geometry fields with geodetic (lon/lat) coordinates need special distance functions
|
# Geometry fields with geodetic (lon/lat) coordinates need special distance functions
|
||||||
if self.spheroid:
|
if self.spheroid:
|
||||||
# DistanceSpheroid is more accurate and resource intensive than DistanceSphere
|
# DistanceSpheroid is more accurate and resource intensive than DistanceSphere
|
||||||
self.function = connection.ops.spatial_function_name('DistanceSpheroid')
|
function = connection.ops.spatial_function_name('DistanceSpheroid')
|
||||||
# Replace boolean param by the real spheroid of the base field
|
# Replace boolean param by the real spheroid of the base field
|
||||||
self.source_expressions[2] = Value(geo_field._spheroid)
|
self.source_expressions[2] = Value(geo_field._spheroid)
|
||||||
else:
|
else:
|
||||||
self.function = connection.ops.spatial_function_name('DistanceSphere')
|
function = connection.ops.spatial_function_name('DistanceSphere')
|
||||||
return super().as_sql(compiler, connection)
|
return super().as_sql(compiler, connection, function=function)
|
||||||
|
|
||||||
def as_oracle(self, compiler, connection):
|
def as_oracle(self, compiler, connection):
|
||||||
if self.spheroid:
|
if self.spheroid:
|
||||||
|
@ -351,27 +351,26 @@ class Length(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
|
||||||
return super().as_sql(compiler, connection)
|
return super().as_sql(compiler, connection)
|
||||||
|
|
||||||
def as_postgresql(self, compiler, connection):
|
def as_postgresql(self, compiler, connection):
|
||||||
|
function = None
|
||||||
geo_field = GeometryField(srid=self.srid) # Fake field to get SRID info
|
geo_field = GeometryField(srid=self.srid) # Fake field to get SRID info
|
||||||
if self.source_is_geography():
|
if self.source_is_geography():
|
||||||
self.source_expressions.append(Value(self.spheroid))
|
self.source_expressions.append(Value(self.spheroid))
|
||||||
elif geo_field.geodetic(connection):
|
elif geo_field.geodetic(connection):
|
||||||
# Geometry fields with geodetic (lon/lat) coordinates need length_spheroid
|
# Geometry fields with geodetic (lon/lat) coordinates need length_spheroid
|
||||||
self.function = connection.ops.spatial_function_name('LengthSpheroid')
|
function = connection.ops.spatial_function_name('LengthSpheroid')
|
||||||
self.source_expressions.append(Value(geo_field._spheroid))
|
self.source_expressions.append(Value(geo_field._spheroid))
|
||||||
else:
|
else:
|
||||||
dim = min(f.dim for f in self.get_source_fields() if f)
|
dim = min(f.dim for f in self.get_source_fields() if f)
|
||||||
if dim > 2:
|
if dim > 2:
|
||||||
self.function = connection.ops.length3d
|
function = connection.ops.length3d
|
||||||
return super().as_sql(compiler, connection)
|
return super().as_sql(compiler, connection, function=function)
|
||||||
|
|
||||||
def as_sqlite(self, compiler, connection):
|
def as_sqlite(self, compiler, connection):
|
||||||
|
function = None
|
||||||
geo_field = GeometryField(srid=self.srid)
|
geo_field = GeometryField(srid=self.srid)
|
||||||
if geo_field.geodetic(connection):
|
if geo_field.geodetic(connection):
|
||||||
if self.spheroid:
|
function = 'GeodesicLength' if self.spheroid else 'GreatCircleLength'
|
||||||
self.function = 'GeodesicLength'
|
return super().as_sql(compiler, connection, function=function)
|
||||||
else:
|
|
||||||
self.function = 'GreatCircleLength'
|
|
||||||
return super().as_sql(compiler, connection)
|
|
||||||
|
|
||||||
|
|
||||||
class MakeValid(GeoFunc):
|
class MakeValid(GeoFunc):
|
||||||
|
@ -404,13 +403,14 @@ class Perimeter(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
|
||||||
arity = 1
|
arity = 1
|
||||||
|
|
||||||
def as_postgresql(self, compiler, connection):
|
def as_postgresql(self, compiler, connection):
|
||||||
|
function = None
|
||||||
geo_field = GeometryField(srid=self.srid) # Fake field to get SRID info
|
geo_field = GeometryField(srid=self.srid) # Fake field to get SRID info
|
||||||
if geo_field.geodetic(connection) and not self.source_is_geography():
|
if geo_field.geodetic(connection) and not self.source_is_geography():
|
||||||
raise NotImplementedError("ST_Perimeter cannot use a non-projected non-geography field.")
|
raise NotImplementedError("ST_Perimeter cannot use a non-projected non-geography field.")
|
||||||
dim = min(f.dim for f in self.get_source_fields())
|
dim = min(f.dim for f in self.get_source_fields())
|
||||||
if dim > 2:
|
if dim > 2:
|
||||||
self.function = connection.ops.perimeter3d
|
function = connection.ops.perimeter3d
|
||||||
return super().as_sql(compiler, connection)
|
return super().as_sql(compiler, connection, function=function)
|
||||||
|
|
||||||
def as_sqlite(self, compiler, connection):
|
def as_sqlite(self, compiler, connection):
|
||||||
geo_field = GeometryField(srid=self.srid) # Fake field to get SRID info
|
geo_field = GeometryField(srid=self.srid) # Fake field to get SRID info
|
||||||
|
|
Loading…
Reference in New Issue