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):