PageRenderTime 75ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/DjamboServerWithProcessing/django/django/contrib/gis/db/backends/oracle/operations.py

https://gitlab.com/benji-bou/urotechchallenge-Serenity
Python | 273 lines | 221 code | 31 blank | 21 comment | 15 complexity | 808dcac5752a46b7d9b53eb8ce2b8959 MD5 | raw file
  1. """
  2. This module contains the spatial lookup types, and the `get_geo_where_clause`
  3. routine for Oracle Spatial.
  4. Please note that WKT support is broken on the XE version, and thus
  5. this backend will not work on such platforms. Specifically, XE lacks
  6. support for an internal JVM, and Java libraries are required to use
  7. the WKT constructors.
  8. """
  9. import re
  10. from django.contrib.gis.db.backends.base.operations import \
  11. BaseSpatialOperations
  12. from django.contrib.gis.db.backends.oracle.adapter import OracleSpatialAdapter
  13. from django.contrib.gis.db.backends.utils import SpatialOperator
  14. from django.contrib.gis.db.models import aggregates
  15. from django.contrib.gis.geometry.backend import Geometry
  16. from django.contrib.gis.measure import Distance
  17. from django.db.backends.oracle.base import Database
  18. from django.db.backends.oracle.operations import DatabaseOperations
  19. from django.utils import six
  20. DEFAULT_TOLERANCE = '0.05'
  21. class SDOOperator(SpatialOperator):
  22. sql_template = "%(func)s(%(lhs)s, %(rhs)s) = 'TRUE'"
  23. class SDODistance(SpatialOperator):
  24. sql_template = "SDO_GEOM.SDO_DISTANCE(%%(lhs)s, %%(rhs)s, %s) %%(op)s %%(value)s" % DEFAULT_TOLERANCE
  25. class SDODWithin(SpatialOperator):
  26. sql_template = "SDO_WITHIN_DISTANCE(%(lhs)s, %(rhs)s, %%s) = 'TRUE'"
  27. class SDODisjoint(SpatialOperator):
  28. sql_template = "SDO_GEOM.RELATE(%%(lhs)s, 'DISJOINT', %%(rhs)s, %s) = 'DISJOINT'" % DEFAULT_TOLERANCE
  29. class SDORelate(SpatialOperator):
  30. sql_template = "SDO_RELATE(%(lhs)s, %(rhs)s, 'mask=%(mask)s') = 'TRUE'"
  31. def check_relate_argument(self, arg):
  32. masks = 'TOUCH|OVERLAPBDYDISJOINT|OVERLAPBDYINTERSECT|EQUAL|INSIDE|COVEREDBY|CONTAINS|COVERS|ANYINTERACT|ON'
  33. mask_regex = re.compile(r'^(%s)(\+(%s))*$' % (masks, masks), re.I)
  34. if not isinstance(arg, six.string_types) or not mask_regex.match(arg):
  35. raise ValueError('Invalid SDO_RELATE mask: "%s"' % arg)
  36. def as_sql(self, connection, lookup, template_params, sql_params):
  37. template_params['mask'] = sql_params.pop()
  38. return super(SDORelate, self).as_sql(connection, lookup, template_params, sql_params)
  39. class OracleOperations(BaseSpatialOperations, DatabaseOperations):
  40. name = 'oracle'
  41. oracle = True
  42. disallowed_aggregates = (aggregates.Collect, aggregates.Extent3D, aggregates.MakeLine)
  43. Adapter = OracleSpatialAdapter
  44. area = 'SDO_GEOM.SDO_AREA'
  45. gml = 'SDO_UTIL.TO_GMLGEOMETRY'
  46. centroid = 'SDO_GEOM.SDO_CENTROID'
  47. difference = 'SDO_GEOM.SDO_DIFFERENCE'
  48. distance = 'SDO_GEOM.SDO_DISTANCE'
  49. extent = 'SDO_AGGR_MBR'
  50. intersection = 'SDO_GEOM.SDO_INTERSECTION'
  51. length = 'SDO_GEOM.SDO_LENGTH'
  52. num_points = 'SDO_UTIL.GETNUMVERTICES'
  53. perimeter = length
  54. point_on_surface = 'SDO_GEOM.SDO_POINTONSURFACE'
  55. reverse = 'SDO_UTIL.REVERSE_LINESTRING'
  56. sym_difference = 'SDO_GEOM.SDO_XOR'
  57. transform = 'SDO_CS.TRANSFORM'
  58. union = 'SDO_GEOM.SDO_UNION'
  59. unionagg = 'SDO_AGGR_UNION'
  60. from_text = 'SDO_GEOMETRY'
  61. function_names = {
  62. 'Area': 'SDO_GEOM.SDO_AREA',
  63. 'Centroid': 'SDO_GEOM.SDO_CENTROID',
  64. 'Difference': 'SDO_GEOM.SDO_DIFFERENCE',
  65. 'Distance': 'SDO_GEOM.SDO_DISTANCE',
  66. 'Intersection': 'SDO_GEOM.SDO_INTERSECTION',
  67. 'Length': 'SDO_GEOM.SDO_LENGTH',
  68. 'NumGeometries': 'SDO_UTIL.GETNUMELEM',
  69. 'NumPoints': 'SDO_UTIL.GETNUMVERTICES',
  70. 'Perimeter': 'SDO_GEOM.SDO_LENGTH',
  71. 'PointOnSurface': 'SDO_GEOM.SDO_POINTONSURFACE',
  72. 'Reverse': 'SDO_UTIL.REVERSE_LINESTRING',
  73. 'SymDifference': 'SDO_GEOM.SDO_XOR',
  74. 'Transform': 'SDO_CS.TRANSFORM',
  75. 'Union': 'SDO_GEOM.SDO_UNION',
  76. }
  77. # We want to get SDO Geometries as WKT because it is much easier to
  78. # instantiate GEOS proxies from WKT than SDO_GEOMETRY(...) strings.
  79. # However, this adversely affects performance (i.e., Java is called
  80. # to convert to WKT on every query). If someone wishes to write a
  81. # SDO_GEOMETRY(...) parser in Python, let me know =)
  82. select = 'SDO_UTIL.TO_WKTGEOMETRY(%s)'
  83. gis_operators = {
  84. 'contains': SDOOperator(func='SDO_CONTAINS'),
  85. 'coveredby': SDOOperator(func='SDO_COVEREDBY'),
  86. 'covers': SDOOperator(func='SDO_COVERS'),
  87. 'disjoint': SDODisjoint(),
  88. 'intersects': SDOOperator(func='SDO_OVERLAPBDYINTERSECT'), # TODO: Is this really the same as ST_Intersects()?
  89. 'equals': SDOOperator(func='SDO_EQUAL'),
  90. 'exact': SDOOperator(func='SDO_EQUAL'),
  91. 'overlaps': SDOOperator(func='SDO_OVERLAPS'),
  92. 'same_as': SDOOperator(func='SDO_EQUAL'),
  93. 'relate': SDORelate(), # Oracle uses a different syntax, e.g., 'mask=inside+touch'
  94. 'touches': SDOOperator(func='SDO_TOUCH'),
  95. 'within': SDOOperator(func='SDO_INSIDE'),
  96. 'distance_gt': SDODistance(op='>'),
  97. 'distance_gte': SDODistance(op='>='),
  98. 'distance_lt': SDODistance(op='<'),
  99. 'distance_lte': SDODistance(op='<='),
  100. 'dwithin': SDODWithin(),
  101. }
  102. truncate_params = {'relate': None}
  103. unsupported_functions = {
  104. 'AsGeoJSON', 'AsGML', 'AsKML', 'AsSVG',
  105. 'BoundingCircle', 'Envelope',
  106. 'ForceRHR', 'GeoHash', 'IsValid', 'MakeValid', 'MemSize', 'Scale',
  107. 'SnapToGrid', 'Translate',
  108. }
  109. def geo_quote_name(self, name):
  110. return super(OracleOperations, self).geo_quote_name(name).upper()
  111. def get_db_converters(self, expression):
  112. converters = super(OracleOperations, self).get_db_converters(expression)
  113. internal_type = expression.output_field.get_internal_type()
  114. geometry_fields = (
  115. 'PointField', 'GeometryField', 'LineStringField',
  116. 'PolygonField', 'MultiPointField', 'MultiLineStringField',
  117. 'MultiPolygonField', 'GeometryCollectionField', 'GeomField',
  118. 'GMLField',
  119. )
  120. if internal_type in geometry_fields:
  121. converters.append(self.convert_textfield_value)
  122. if hasattr(expression.output_field, 'geom_type'):
  123. converters.append(self.convert_geometry)
  124. return converters
  125. def convert_geometry(self, value, expression, connection, context):
  126. if value:
  127. value = Geometry(value)
  128. if 'transformed_srid' in context:
  129. value.srid = context['transformed_srid']
  130. return value
  131. def convert_extent(self, clob, srid):
  132. if clob:
  133. # Generally, Oracle returns a polygon for the extent -- however,
  134. # it can return a single point if there's only one Point in the
  135. # table.
  136. ext_geom = Geometry(clob.read(), srid)
  137. gtype = str(ext_geom.geom_type)
  138. if gtype == 'Polygon':
  139. # Construct the 4-tuple from the coordinates in the polygon.
  140. shell = ext_geom.shell
  141. ll, ur = shell[0][:2], shell[2][:2]
  142. elif gtype == 'Point':
  143. ll = ext_geom.coords[:2]
  144. ur = ll
  145. else:
  146. raise Exception('Unexpected geometry type returned for extent: %s' % gtype)
  147. xmin, ymin = ll
  148. xmax, ymax = ur
  149. return (xmin, ymin, xmax, ymax)
  150. else:
  151. return None
  152. def convert_geom(self, value, geo_field):
  153. if value:
  154. if isinstance(value, Database.LOB):
  155. value = value.read()
  156. return Geometry(value, geo_field.srid)
  157. else:
  158. return None
  159. def geo_db_type(self, f):
  160. """
  161. Returns the geometry database type for Oracle. Unlike other spatial
  162. backends, no stored procedure is necessary and it's the same for all
  163. geometry types.
  164. """
  165. return 'MDSYS.SDO_GEOMETRY'
  166. def get_distance(self, f, value, lookup_type, **kwargs):
  167. """
  168. Returns the distance parameters given the value and the lookup type.
  169. On Oracle, geometry columns with a geodetic coordinate system behave
  170. implicitly like a geography column, and thus meters will be used as
  171. the distance parameter on them.
  172. """
  173. if not value:
  174. return []
  175. value = value[0]
  176. if isinstance(value, Distance):
  177. if f.geodetic(self.connection):
  178. dist_param = value.m
  179. else:
  180. dist_param = getattr(value, Distance.unit_attname(f.units_name(self.connection)))
  181. else:
  182. dist_param = value
  183. # dwithin lookups on Oracle require a special string parameter
  184. # that starts with "distance=".
  185. if lookup_type == 'dwithin':
  186. dist_param = 'distance=%s' % dist_param
  187. return [dist_param]
  188. def get_geom_placeholder(self, f, value, compiler):
  189. """
  190. Provides a proper substitution value for Geometries that are not in the
  191. SRID of the field. Specifically, this routine will substitute in the
  192. SDO_CS.TRANSFORM() function call.
  193. """
  194. if value is None:
  195. return 'NULL'
  196. def transform_value(val, srid):
  197. return val.srid != srid
  198. if hasattr(value, 'as_sql'):
  199. if transform_value(value, f.srid):
  200. placeholder = '%s(%%s, %s)' % (self.transform, f.srid)
  201. else:
  202. placeholder = '%s'
  203. # No geometry value used for F expression, substitute in
  204. # the column name instead.
  205. sql, _ = compiler.compile(value)
  206. return placeholder % sql
  207. else:
  208. if transform_value(value, f.srid):
  209. return '%s(SDO_GEOMETRY(%%s, %s), %s)' % (self.transform, value.srid, f.srid)
  210. else:
  211. return 'SDO_GEOMETRY(%%s, %s)' % f.srid
  212. def spatial_aggregate_name(self, agg_name):
  213. """
  214. Returns the spatial aggregate SQL name.
  215. """
  216. agg_name = 'unionagg' if agg_name.lower() == 'union' else agg_name.lower()
  217. return getattr(self, agg_name)
  218. # Routines for getting the OGC-compliant models.
  219. def geometry_columns(self):
  220. from django.contrib.gis.db.backends.oracle.models import OracleGeometryColumns
  221. return OracleGeometryColumns
  222. def spatial_ref_sys(self):
  223. from django.contrib.gis.db.backends.oracle.models import OracleSpatialRefSys
  224. return OracleSpatialRefSys
  225. def modify_insert_params(self, placeholder, params):
  226. """Drop out insert parameters for NULL placeholder. Needed for Oracle Spatial
  227. backend due to #10888.
  228. """
  229. if placeholder == 'NULL':
  230. return []
  231. return super(OracleOperations, self).modify_insert_params(placeholder, params)