summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2021-11-27 11:30:58 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-11-30 20:06:29 +0100
commit64c3f049ea3bcb1c82f35ae09f1dd5349a826a5c (patch)
treef3e109d0bea16be80020fa9da671c9ac3f8626b1
parentae4077e13ea2e4c460c3f21b9aab93a696590851 (diff)
Fixed #33047 -- Fixed CheckConstraint crash with GIS lookups on PostGIS and MySQL GIS backends.
Thanks Daniel Swain for the report and Arsalan Ghassemi for the initial patch. Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
-rw-r--r--django/contrib/gis/db/backends/mysql/schema.py5
-rw-r--r--django/contrib/gis/db/backends/oracle/features.py11
-rw-r--r--django/contrib/gis/db/backends/oracle/schema.py5
-rw-r--r--django/contrib/gis/db/backends/postgis/adapter.py8
-rw-r--r--tests/gis_tests/gis_migrations/test_operations.py18
5 files changed, 43 insertions, 4 deletions
diff --git a/django/contrib/gis/db/backends/mysql/schema.py b/django/contrib/gis/db/backends/mysql/schema.py
index 01c66c8083..da033ce5d6 100644
--- a/django/contrib/gis/db/backends/mysql/schema.py
+++ b/django/contrib/gis/db/backends/mysql/schema.py
@@ -22,6 +22,11 @@ class MySQLGISSchemaEditor(DatabaseSchemaEditor):
return True
return super().skip_default(field)
+ def quote_value(self, value):
+ if isinstance(value, self.connection.ops.Adapter):
+ return super().quote_value(str(value))
+ return super().quote_value(value)
+
def column_sql(self, model, field, include_default=False):
column_sql = super().column_sql(model, field, include_default)
# MySQL doesn't support spatial indexes on NULL columns
diff --git a/django/contrib/gis/db/backends/oracle/features.py b/django/contrib/gis/db/backends/oracle/features.py
index c458eb33c6..2ba951de42 100644
--- a/django/contrib/gis/db/backends/oracle/features.py
+++ b/django/contrib/gis/db/backends/oracle/features.py
@@ -2,6 +2,7 @@ from django.contrib.gis.db.backends.base.features import BaseSpatialFeatures
from django.db.backends.oracle.features import (
DatabaseFeatures as OracleDatabaseFeatures,
)
+from django.utils.functional import cached_property
class DatabaseFeatures(BaseSpatialFeatures, OracleDatabaseFeatures):
@@ -12,3 +13,13 @@ class DatabaseFeatures(BaseSpatialFeatures, OracleDatabaseFeatures):
supports_dwithin_distance_expr = False
supports_tolerance_parameter = True
unsupported_geojson_options = {'bbox', 'crs', 'precision'}
+
+ @cached_property
+ def django_test_skips(self):
+ skips = super().django_test_skips
+ skips.update({
+ "Oracle doesn't support spatial operators in constraints.": {
+ 'gis_tests.gis_migrations.test_operations.OperationTests.test_add_check_constraint',
+ },
+ })
+ return skips
diff --git a/django/contrib/gis/db/backends/oracle/schema.py b/django/contrib/gis/db/backends/oracle/schema.py
index 7bccee7a60..b281abc81b 100644
--- a/django/contrib/gis/db/backends/oracle/schema.py
+++ b/django/contrib/gis/db/backends/oracle/schema.py
@@ -31,6 +31,11 @@ class OracleGISSchemaEditor(DatabaseSchemaEditor):
def geo_quote_name(self, name):
return self.connection.ops.geo_quote_name(name)
+ def quote_value(self, value):
+ if isinstance(value, self.connection.ops.Adapter):
+ return super().quote_value(str(value))
+ return super().quote_value(value)
+
def column_sql(self, model, field, include_default=False):
column_sql = super().column_sql(model, field, include_default)
if isinstance(field, GeometryField):
diff --git a/django/contrib/gis/db/backends/postgis/adapter.py b/django/contrib/gis/db/backends/postgis/adapter.py
index 6611442cae..d6cb6ca47d 100644
--- a/django/contrib/gis/db/backends/postgis/adapter.py
+++ b/django/contrib/gis/db/backends/postgis/adapter.py
@@ -60,10 +60,10 @@ class PostGISAdapter:
"""
if self.is_geometry:
# Psycopg will figure out whether to use E'\\000' or '\000'.
- return '%s(%s)' % (
- 'ST_GeogFromWKB' if self.geography else 'ST_GeomFromEWKB',
- self._adapter.getquoted().decode()
+ return b'%s(%s)' % (
+ b'ST_GeogFromWKB' if self.geography else b'ST_GeomFromEWKB',
+ self._adapter.getquoted()
)
else:
# For rasters, add explicit type cast to WKB string.
- return "'%s'::raster" % self.ewkb
+ return b"'%s'::raster" % self.ewkb.encode()
diff --git a/tests/gis_tests/gis_migrations/test_operations.py b/tests/gis_tests/gis_migrations/test_operations.py
index 6c7adcf359..b7823dd983 100644
--- a/tests/gis_tests/gis_migrations/test_operations.py
+++ b/tests/gis_tests/gis_migrations/test_operations.py
@@ -235,6 +235,24 @@ class OperationTests(OperationTestCase):
)
self.assertFalse(Neighborhood.objects.first().geom.hasz)
+ @skipUnlessDBFeature('supports_column_check_constraints', 'can_introspect_check_constraints')
+ def test_add_check_constraint(self):
+ Neighborhood = self.current_state.apps.get_model('gis', 'Neighborhood')
+ poly = Polygon(((0, 0), (0, 1), (1, 1), (1, 0), (0, 0)))
+ constraint = models.CheckConstraint(
+ check=models.Q(geom=poly),
+ name='geom_within_constraint',
+ )
+ Neighborhood._meta.constraints = [constraint]
+ with connection.schema_editor() as editor:
+ editor.add_constraint(Neighborhood, constraint)
+ with connection.cursor() as cursor:
+ constraints = connection.introspection.get_constraints(
+ cursor,
+ Neighborhood._meta.db_table,
+ )
+ self.assertIn('geom_within_constraint', constraints)
+
@skipIfDBFeature('supports_raster')
class NoRasterSupportTests(OperationTestCase):