Skip to content

Commit

Permalink
Fixed #30155 -- Dropped support for PostgreSQL 9.4 and PostGIS 2.1.
Browse files Browse the repository at this point in the history
  • Loading branch information
timgraham committed Feb 4, 2019
1 parent d47498c commit 39ebdf5
Show file tree
Hide file tree
Showing 13 changed files with 21 additions and 78 deletions.
9 changes: 1 addition & 8 deletions django/contrib/gis/db/backends/postgis/operations.py
Expand Up @@ -151,13 +151,6 @@ def function_names(self):
'BoundingCircle': 'ST_MinimumBoundingCircle', 'BoundingCircle': 'ST_MinimumBoundingCircle',
'NumPoints': 'ST_NPoints', 'NumPoints': 'ST_NPoints',
} }
if self.spatial_version < (2, 2, 0):
function_names.update({
'DistanceSphere': 'ST_distance_sphere',
'DistanceSpheroid': 'ST_distance_spheroid',
'LengthSpheroid': 'ST_length_spheroid',
'MemSize': 'ST_mem_size',
})
if self.spatial_version < (2, 4, 0): if self.spatial_version < (2, 4, 0):
function_names['ForcePolygonCW'] = 'ST_ForceRHR' function_names['ForcePolygonCW'] = 'ST_ForceRHR'
return function_names return function_names
Expand Down Expand Up @@ -185,7 +178,7 @@ def spatial_version(self):
raise ImproperlyConfigured( raise ImproperlyConfigured(
'Cannot determine PostGIS version for database "%s" ' 'Cannot determine PostGIS version for database "%s" '
'using command "SELECT postgis_lib_version()". ' 'using command "SELECT postgis_lib_version()". '
'GeoDjango requires at least PostGIS version 2.1. ' 'GeoDjango requires at least PostGIS version 2.2. '
'Was the database created from a spatial database ' 'Was the database created from a spatial database '
'template?' % self.connection.settings_dict['NAME'] 'template?' % self.connection.settings_dict['NAME']
) )
Expand Down
6 changes: 0 additions & 6 deletions django/contrib/postgres/indexes.py
Expand Up @@ -55,8 +55,6 @@ def deconstruct(self):
return path, args, kwargs return path, args, kwargs


def check_supported(self, schema_editor): def check_supported(self, schema_editor):
if not schema_editor.connection.features.has_brin_index_support:
raise NotSupportedError('BRIN indexes require PostgreSQL 9.5+.')
if self.autosummarize and not schema_editor.connection.features.has_brin_autosummarize: if self.autosummarize and not schema_editor.connection.features.has_brin_autosummarize:
raise NotSupportedError('BRIN option autosummarize requires PostgreSQL 10+.') raise NotSupportedError('BRIN option autosummarize requires PostgreSQL 10+.')


Expand Down Expand Up @@ -105,10 +103,6 @@ def deconstruct(self):
kwargs['gin_pending_list_limit'] = self.gin_pending_list_limit kwargs['gin_pending_list_limit'] = self.gin_pending_list_limit
return path, args, kwargs return path, args, kwargs


def check_supported(self, schema_editor):
if self.gin_pending_list_limit and not schema_editor.connection.features.has_gin_pending_list_limit:
raise NotSupportedError('GIN option gin_pending_list_limit requires PostgreSQL 9.5+.')

def get_with_params(self): def get_with_params(self):
with_params = [] with_params = []
if self.gin_pending_list_limit is not None: if self.gin_pending_list_limit is not None:
Expand Down
10 changes: 1 addition & 9 deletions django/db/backends/postgresql/features.py
Expand Up @@ -16,6 +16,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
has_select_for_update = True has_select_for_update = True
has_select_for_update_nowait = True has_select_for_update_nowait = True
has_select_for_update_of = True has_select_for_update_of = True
has_select_for_update_skip_locked = True
can_release_savepoints = True can_release_savepoints = True
supports_tablespaces = True supports_tablespaces = True
supports_transactions = True supports_transactions = True
Expand Down Expand Up @@ -55,10 +56,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supported_explain_formats = {'JSON', 'TEXT', 'XML', 'YAML'} supported_explain_formats = {'JSON', 'TEXT', 'XML', 'YAML'}
validates_explain_options = False # A query will error on invalid options. validates_explain_options = False # A query will error on invalid options.


@cached_property
def is_postgresql_9_5(self):
return self.connection.pg_version >= 90500

@cached_property @cached_property
def is_postgresql_9_6(self): def is_postgresql_9_6(self):
return self.connection.pg_version >= 90600 return self.connection.pg_version >= 90600
Expand All @@ -67,11 +64,6 @@ def is_postgresql_9_6(self):
def is_postgresql_10(self): def is_postgresql_10(self):
return self.connection.pg_version >= 100000 return self.connection.pg_version >= 100000


has_select_for_update_skip_locked = property(operator.attrgetter('is_postgresql_9_5'))
has_brin_index_support = property(operator.attrgetter('is_postgresql_9_5'))
has_jsonb_agg = property(operator.attrgetter('is_postgresql_9_5'))
has_brin_autosummarize = property(operator.attrgetter('is_postgresql_10')) has_brin_autosummarize = property(operator.attrgetter('is_postgresql_10'))
has_gin_pending_list_limit = property(operator.attrgetter('is_postgresql_9_5'))
supports_ignore_conflicts = property(operator.attrgetter('is_postgresql_9_5'))
has_phraseto_tsquery = property(operator.attrgetter('is_postgresql_9_6')) has_phraseto_tsquery = property(operator.attrgetter('is_postgresql_9_6'))
supports_table_partitions = property(operator.attrgetter('is_postgresql_10')) supports_table_partitions = property(operator.attrgetter('is_postgresql_10'))
3 changes: 1 addition & 2 deletions docs/ref/contrib/gis/install/geolibs.txt
Expand Up @@ -12,7 +12,7 @@ Program Description Required
`PROJ.4`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 5.2, 5.1, 5.0, 4.x `PROJ.4`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 5.2, 5.1, 5.0, 4.x
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 2.3, 2.2, 2.1, 2.0, 1.11 :doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 2.3, 2.2, 2.1, 2.0, 1.11
:doc:`GeoIP <../geoip2>` IP-based geolocation library No 2 :doc:`GeoIP <../geoip2>` IP-based geolocation library No 2
`PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 2.5, 2.4, 2.3, 2.2, 2.1 `PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 2.5, 2.4, 2.3, 2.2
`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 4.3 `SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 4.3
======================== ==================================== ================================ =================================== ======================== ==================================== ================================ ===================================


Expand All @@ -30,7 +30,6 @@ totally fine with GeoDjango. Your mileage may vary.
GDAL 2.1.0 2016-04 GDAL 2.1.0 2016-04
GDAL 2.2.0 2017-05 GDAL 2.2.0 2017-05
GDAL 2.3.0 2018-05 GDAL 2.3.0 2018-05
PostGIS 2.1.0 2013-08-17
PostGIS 2.2.0 2015-10-17 PostGIS 2.2.0 2015-10-17
PostGIS 2.3.0 2016-09-26 PostGIS 2.3.0 2016-09-26
PostGIS 2.4.0 2017-09-30 PostGIS 2.4.0 2017-09-30
Expand Down
2 changes: 1 addition & 1 deletion docs/ref/contrib/gis/install/index.txt
Expand Up @@ -58,7 +58,7 @@ supported versions, and any notes for each of the supported database backends:
================== ============================== ================== ========================================= ================== ============================== ================== =========================================
Database Library Requirements Supported Versions Notes Database Library Requirements Supported Versions Notes
================== ============================== ================== ========================================= ================== ============================== ================== =========================================
PostgreSQL GEOS, GDAL, PROJ.4, PostGIS 9.4+ Requires PostGIS. PostgreSQL GEOS, GDAL, PROJ.4, PostGIS 9.5+ Requires PostGIS.
MySQL GEOS, GDAL 5.6+ Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`. MySQL GEOS, GDAL 5.6+ Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`.
Oracle GEOS, GDAL 12.1+ XE not supported. Oracle GEOS, GDAL 12.1+ XE not supported.
SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.8.3+ Requires SpatiaLite 4.3+ SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.8.3+ Requires SpatiaLite 4.3+
Expand Down
2 changes: 1 addition & 1 deletion docs/ref/contrib/postgres/aggregates.txt
Expand Up @@ -90,7 +90,7 @@ General-purpose aggregation functions


.. class:: JSONBAgg(expressions, filter=None, **extra) .. class:: JSONBAgg(expressions, filter=None, **extra)


Returns the input values as a ``JSON`` array. Requires PostgreSQL ≥ 9.5. Returns the input values as a ``JSON`` array.


``StringAgg`` ``StringAgg``
------------- -------------
Expand Down
2 changes: 1 addition & 1 deletion docs/ref/contrib/postgres/indexes.txt
Expand Up @@ -61,7 +61,7 @@ available from the ``django.contrib.postgres.indexes`` module.


Provide an integer number of bytes to the gin_pending_list_limit_ parameter Provide an integer number of bytes to the gin_pending_list_limit_ parameter
to tune the maximum size of the GIN pending list which is used when to tune the maximum size of the GIN pending list which is used when
``fastupdate`` is enabled. This parameter requires PostgreSQL ≥ 9.5. ``fastupdate`` is enabled.


.. _GIN Fast Update Technique: https://www.postgresql.org/docs/current/static/gin-implementation.html#GIN-FAST-UPDATE .. _GIN Fast Update Technique: https://www.postgresql.org/docs/current/static/gin-implementation.html#GIN-FAST-UPDATE
.. _gin_pending_list_limit: https://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-GIN-PENDING-LIST-LIMIT .. _gin_pending_list_limit: https://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-GIN-PENDING-LIST-LIMIT
Expand Down
2 changes: 1 addition & 1 deletion docs/ref/databases.txt
Expand Up @@ -92,7 +92,7 @@ below for information on how to set up your database correctly.
PostgreSQL notes PostgreSQL notes
================ ================


Django supports PostgreSQL 9.4 and higher. `psycopg2`_ 2.5.4 or higher is Django supports PostgreSQL 9.5 and higher. `psycopg2`_ 2.5.4 or higher is
required, though the latest release is recommended. required, though the latest release is recommended.


.. _psycopg2: http://initd.org/psycopg/ .. _psycopg2: http://initd.org/psycopg/
Expand Down
10 changes: 5 additions & 5 deletions docs/ref/models/querysets.txt
Expand Up @@ -2073,11 +2073,11 @@ The ``batch_size`` parameter controls how many objects are created in a single
query. The default is to create all objects in one batch, except for SQLite query. The default is to create all objects in one batch, except for SQLite
where the default is such that at most 999 variables per query are used. where the default is such that at most 999 variables per query are used.


On databases that support it (all except PostgreSQL < 9.5 and Oracle), setting On databases that support it (all but Oracle), setting the ``ignore_conflicts``
the ``ignore_conflicts`` parameter to ``True`` tells the database to ignore parameter to ``True`` tells the database to ignore failure to insert any rows
failure to insert any rows that fail constraints such as duplicate unique that fail constraints such as duplicate unique values. Enabling this parameter
values. Enabling this parameter disables setting the primary key on each model disables setting the primary key on each model instance (if the database
instance (if the database normally supports it). normally supports it).


.. versionchanged:: 2.2 .. versionchanged:: 2.2


Expand Down
8 changes: 8 additions & 0 deletions docs/releases/3.0.txt
Expand Up @@ -225,8 +225,16 @@ backends.
:mod:`django.contrib.gis` :mod:`django.contrib.gis`
------------------------- -------------------------


* Supported for PostGIS 2.1 is removed.

* Support for SpatiaLite 4.1 and 4.2 is removed. * Support for SpatiaLite 4.1 and 4.2 is removed.


Dropped support for PostgreSQL 9.4
----------------------------------

Upstream support for PostgreSQL 9.4 ends in December 2019. Django 3.0 supports
PostgreSQL 9.5 and higher.

Miscellaneous Miscellaneous
------------- -------------


Expand Down
18 changes: 0 additions & 18 deletions tests/gis_tests/tests.py
Expand Up @@ -81,21 +81,3 @@ def test_no_version_number(self):
ops = FakePostGISOperations() ops = FakePostGISOperations()
with self.assertRaises(ImproperlyConfigured): with self.assertRaises(ImproperlyConfigured):
ops.spatial_version ops.spatial_version

def test_version_dependent_funcs(self):
"""
Resolve names of functions renamed and deprecated in PostGIS 2.2.0
depending on PostGIS version.
Remove when dropping support for PostGIS 2.1.
"""
ops = FakePostGISOperations('2.2.0')
self.assertEqual(ops.spatial_function_name('DistanceSphere'), 'ST_DistanceSphere')
self.assertEqual(ops.spatial_function_name('DistanceSpheroid'), 'ST_DistanceSpheroid')
self.assertEqual(ops.spatial_function_name('LengthSpheroid'), 'ST_LengthSpheroid')
self.assertEqual(ops.spatial_function_name('MemSize'), 'ST_MemSize')

ops = FakePostGISOperations('2.1.0')
self.assertEqual(ops.spatial_function_name('DistanceSphere'), 'ST_distance_sphere')
self.assertEqual(ops.spatial_function_name('DistanceSpheroid'), 'ST_distance_spheroid')
self.assertEqual(ops.spatial_function_name('LengthSpheroid'), 'ST_length_spheroid')
self.assertEqual(ops.spatial_function_name('MemSize'), 'ST_mem_size')
3 changes: 0 additions & 3 deletions tests/postgres_tests/test_aggregates.py
@@ -1,7 +1,6 @@
import json import json


from django.db.models.expressions import F, Value from django.db.models.expressions import F, Value
from django.test.testcases import skipUnlessDBFeature
from django.test.utils import Approximate from django.test.utils import Approximate


from . import PostgreSQLTestCase from . import PostgreSQLTestCase
Expand Down Expand Up @@ -184,12 +183,10 @@ def test_orderable_agg_alternative_fields(self):
) )
self.assertEqual(values, {'arrayagg': [0, 1, 0, 2]}) self.assertEqual(values, {'arrayagg': [0, 1, 0, 2]})


@skipUnlessDBFeature('has_jsonb_agg')
def test_json_agg(self): def test_json_agg(self):
values = AggregateTestModel.objects.aggregate(jsonagg=JSONBAgg('char_field')) values = AggregateTestModel.objects.aggregate(jsonagg=JSONBAgg('char_field'))
self.assertEqual(values, {'jsonagg': ['Foo1', 'Foo2', 'Foo4', 'Foo3']}) self.assertEqual(values, {'jsonagg': ['Foo1', 'Foo2', 'Foo4', 'Foo3']})


@skipUnlessDBFeature('has_jsonb_agg')
def test_json_agg_empty(self): def test_json_agg_empty(self):
values = AggregateTestModel.objects.none().aggregate(jsonagg=JSONBAgg('integer_field')) values = AggregateTestModel.objects.none().aggregate(jsonagg=JSONBAgg('integer_field'))
self.assertEqual(values, json.loads('{"jsonagg": []}')) self.assertEqual(values, json.loads('{"jsonagg": []}'))
Expand Down
24 changes: 1 addition & 23 deletions tests/postgres_tests/test_indexes.py
Expand Up @@ -205,7 +205,6 @@ def test_partial_gin_index_with_tablespace(self):
editor.remove_index(CharFieldModel, index) editor.remove_index(CharFieldModel, index)
self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table)) self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table))


@skipUnlessDBFeature('has_gin_pending_list_limit')
def test_gin_parameters(self): def test_gin_parameters(self):
index_name = 'integer_array_gin_params' index_name = 'integer_array_gin_params'
index = GinIndex(fields=['field'], name=index_name, fastupdate=True, gin_pending_list_limit=64) index = GinIndex(fields=['field'], name=index_name, fastupdate=True, gin_pending_list_limit=64)
Expand All @@ -218,17 +217,6 @@ def test_gin_parameters(self):
editor.remove_index(IntegerArrayModel, index) editor.remove_index(IntegerArrayModel, index)
self.assertNotIn(index_name, self.get_constraints(IntegerArrayModel._meta.db_table)) self.assertNotIn(index_name, self.get_constraints(IntegerArrayModel._meta.db_table))


@mock.patch('django.db.backends.postgresql.features.DatabaseFeatures.has_gin_pending_list_limit', False)
def test_gin_parameters_exception(self):
index_name = 'gin_options_exception'
index = GinIndex(fields=['field'], name=index_name, gin_pending_list_limit=64)
msg = 'GIN option gin_pending_list_limit requires PostgreSQL 9.5+.'
with self.assertRaisesMessage(NotSupportedError, msg):
with connection.schema_editor() as editor:
editor.add_index(IntegerArrayModel, index)
self.assertNotIn(index_name, self.get_constraints(IntegerArrayModel._meta.db_table))

@skipUnlessDBFeature('has_brin_index_support')
def test_brin_index(self): def test_brin_index(self):
index_name = 'char_field_model_field_brin' index_name = 'char_field_model_field_brin'
index = BrinIndex(fields=['field'], name=index_name, pages_per_range=4) index = BrinIndex(fields=['field'], name=index_name, pages_per_range=4)
Expand All @@ -241,7 +229,7 @@ def test_brin_index(self):
editor.remove_index(CharFieldModel, index) editor.remove_index(CharFieldModel, index)
self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table)) self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table))


@skipUnlessDBFeature('has_brin_index_support', 'has_brin_autosummarize') @skipUnlessDBFeature('has_brin_autosummarize')
def test_brin_parameters(self): def test_brin_parameters(self):
index_name = 'char_field_brin_params' index_name = 'char_field_brin_params'
index = BrinIndex(fields=['field'], name=index_name, autosummarize=True) index = BrinIndex(fields=['field'], name=index_name, autosummarize=True)
Expand All @@ -254,16 +242,6 @@ def test_brin_parameters(self):
editor.remove_index(CharFieldModel, index) editor.remove_index(CharFieldModel, index)
self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table)) self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table))


def test_brin_index_not_supported(self):
index_name = 'brin_index_exception'
index = BrinIndex(fields=['field'], name=index_name)
with self.assertRaisesMessage(NotSupportedError, 'BRIN indexes require PostgreSQL 9.5+.'):
with mock.patch('django.db.backends.postgresql.features.DatabaseFeatures.has_brin_index_support', False):
with connection.schema_editor() as editor:
editor.add_index(CharFieldModel, index)
self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table))

@skipUnlessDBFeature('has_brin_index_support')
def test_brin_autosummarize_not_supported(self): def test_brin_autosummarize_not_supported(self):
index_name = 'brin_options_exception' index_name = 'brin_options_exception'
index = BrinIndex(fields=['field'], name=index_name, autosummarize=True) index = BrinIndex(fields=['field'], name=index_name, autosummarize=True)
Expand Down

0 comments on commit 39ebdf5

Please sign in to comment.