summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2017-09-06 10:26:45 -0400
committerTim Graham <timograham@gmail.com>2017-09-27 11:00:04 -0400
commit1d8cfa36089f2d1295abad03a99fc3c259bde6b5 (patch)
tree458e608105acb5fe7e9db7e2c01c833df1673795
parentea7ca5db302367d84f92a4cf0ca03ec62886a7ca (diff)
Fixed #28626 -- Dropped support for PostgreSQL 9.3.
Thanks Simon Charette for the introspection changes.
-rw-r--r--django/db/backends/postgresql/features.py9
-rw-r--r--django/db/backends/postgresql/introspection.py22
-rw-r--r--docs/ref/contrib/gis/install/index.txt2
-rw-r--r--docs/ref/contrib/postgres/fields.txt2
-rw-r--r--docs/ref/contrib/postgres/functions.txt2
-rw-r--r--docs/ref/databases.txt2
-rw-r--r--docs/releases/2.1.txt6
-rw-r--r--tests/postgres_tests/__init__.py10
-rw-r--r--tests/postgres_tests/migrations/0002_create_test_models.py2
-rw-r--r--tests/postgres_tests/models.py5
-rw-r--r--tests/postgres_tests/test_functions.py3
-rw-r--r--tests/postgres_tests/test_introspection.py2
-rw-r--r--tests/postgres_tests/test_json.py4
13 files changed, 18 insertions, 53 deletions
diff --git a/django/db/backends/postgresql/features.py b/django/db/backends/postgresql/features.py
index 0349493dae..c70966c2f6 100644
--- a/django/db/backends/postgresql/features.py
+++ b/django/db/backends/postgresql/features.py
@@ -49,10 +49,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
END;
$$ LANGUAGE plpgsql;"""
supports_over_clause = True
-
- @cached_property
- def supports_aggregate_filter_clause(self):
- return self.connection.pg_version >= 90400
+ supports_aggregate_filter_clause = True
@cached_property
def has_select_for_update_skip_locked(self):
@@ -63,10 +60,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
return self.connection.pg_version >= 90500
@cached_property
- def has_jsonb_datatype(self):
- return self.connection.pg_version >= 90400
-
- @cached_property
def has_jsonb_agg(self):
return self.connection.pg_version >= 90500
diff --git a/django/db/backends/postgresql/introspection.py b/django/db/backends/postgresql/introspection.py
index f060546a53..30f764f2f0 100644
--- a/django/db/backends/postgresql/introspection.py
+++ b/django/db/backends/postgresql/introspection.py
@@ -145,17 +145,12 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
# Loop over the key table, collecting things as constraints. The column
# array must return column names in the same order in which they were
# created.
- # The subquery containing generate_series can be replaced with
- # "WITH ORDINALITY" when support for PostgreSQL 9.3 is dropped.
cursor.execute("""
SELECT
c.conname,
array(
SELECT attname
- FROM (
- SELECT unnest(c.conkey) AS colid,
- generate_series(1, array_length(c.conkey, 1)) AS arridx
- ) AS cols
+ FROM unnest(c.conkey) WITH ORDINALITY cols(colid, arridx)
JOIN pg_attribute AS ca ON cols.colid = ca.attnum
WHERE ca.attrelid = c.conrelid
ORDER BY cols.arridx
@@ -183,17 +178,13 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
"options": options,
}
# Now get indexes
- # The row_number() function for ordering the index fields can be
- # replaced by WITH ORDINALITY in the unnest() functions when support
- # for PostgreSQL 9.3 is dropped.
cursor.execute("""
SELECT
- indexname, array_agg(attname ORDER BY rnum), indisunique, indisprimary,
- array_agg(ordering ORDER BY rnum), amname, exprdef, s2.attoptions
+ indexname, array_agg(attname ORDER BY arridx), indisunique, indisprimary,
+ array_agg(ordering ORDER BY arridx), amname, exprdef, s2.attoptions
FROM (
SELECT
- row_number() OVER () as rnum, c2.relname as indexname,
- idx.*, attr.attname, am.amname,
+ c2.relname as indexname, idx.*, attr.attname, am.amname,
CASE
WHEN idx.indexprs IS NOT NULL THEN
pg_get_indexdef(idx.indexrelid)
@@ -206,9 +197,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
END as ordering,
c2.reloptions as attoptions
FROM (
- SELECT
- *, unnest(i.indkey) as key, unnest(i.indoption) as option
- FROM pg_index i
+ SELECT *
+ FROM pg_index i, unnest(i.indkey, i.indoption) WITH ORDINALITY koi(key, option, arridx)
) idx
LEFT JOIN pg_class c ON idx.indrelid = c.oid
LEFT JOIN pg_class c2 ON idx.indexrelid = c2.oid
diff --git a/docs/ref/contrib/gis/install/index.txt b/docs/ref/contrib/gis/install/index.txt
index c547c9b268..9872f25602 100644
--- a/docs/ref/contrib/gis/install/index.txt
+++ b/docs/ref/contrib/gis/install/index.txt
@@ -58,7 +58,7 @@ supported versions, and any notes for each of the supported database backends:
================== ============================== ================== =========================================
Database Library Requirements Supported Versions Notes
================== ============================== ================== =========================================
-PostgreSQL GEOS, GDAL, PROJ.4, PostGIS 9.3+ Requires PostGIS.
+PostgreSQL GEOS, GDAL, PROJ.4, PostGIS 9.4+ Requires PostGIS.
MySQL GEOS, GDAL 5.6+ Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`.
Oracle GEOS, GDAL 12.1+ XE not supported.
SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.6.+ Requires SpatiaLite 4.0+
diff --git a/docs/ref/contrib/postgres/fields.txt b/docs/ref/contrib/postgres/fields.txt
index 0a39f000f1..38ca9200cd 100644
--- a/docs/ref/contrib/postgres/fields.txt
+++ b/docs/ref/contrib/postgres/fields.txt
@@ -509,8 +509,6 @@ using in conjunction with lookups on
of the JSON which allows indexing. The trade-off is a small additional cost
on writing to the ``jsonb`` field. ``JSONField`` uses ``jsonb``.
- **As a result, this field requires PostgreSQL ≥ 9.4**.
-
Querying ``JSONField``
----------------------
diff --git a/docs/ref/contrib/postgres/functions.txt b/docs/ref/contrib/postgres/functions.txt
index 171272c518..8d3df51864 100644
--- a/docs/ref/contrib/postgres/functions.txt
+++ b/docs/ref/contrib/postgres/functions.txt
@@ -16,8 +16,6 @@ All of these functions are available from the
Returns a version 4 UUID.
-Requires PostgreSQL 9.4 or greater.
-
The `pgcrypto extension`_ must be installed. You can use the
:class:`~django.contrib.postgres.operations.CryptoExtension` migration
operation to install it.
diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt
index e7d474a81d..1005780f19 100644
--- a/docs/ref/databases.txt
+++ b/docs/ref/databases.txt
@@ -92,7 +92,7 @@ below for information on how to set up your database correctly.
PostgreSQL notes
================
-Django supports PostgreSQL 9.3 and higher. `psycopg2`_ 2.5.4 or higher is
+Django supports PostgreSQL 9.4 and higher. `psycopg2`_ 2.5.4 or higher is
required, though the latest release is recommended.
.. _psycopg2: http://initd.org/psycopg/
diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt
index ead4d2fde3..fa4b407d9a 100644
--- a/docs/releases/2.1.txt
+++ b/docs/releases/2.1.txt
@@ -206,6 +206,12 @@ Dropped support for MySQL 5.5
The end of upstream support for MySQL 5.5 is December 2018. Django 2.1 supports
MySQL 5.6 and higher.
+Dropped support for PostgreSQL 9.3
+----------------------------------
+
+The end of upstream support for PostgreSQL 9.3 is September 2018. Django 2.1
+supports PostgreSQL 9.4 and higher.
+
Miscellaneous
-------------
diff --git a/tests/postgres_tests/__init__.py b/tests/postgres_tests/__init__.py
index ea6b96aff9..24d78c9bfe 100644
--- a/tests/postgres_tests/__init__.py
+++ b/tests/postgres_tests/__init__.py
@@ -7,16 +7,6 @@ from django.db.backends.signals import connection_created
from django.test import TestCase, modify_settings
-def skipUnlessPG94(test):
- try:
- PG_VERSION = connection.pg_version
- except AttributeError:
- PG_VERSION = 0
- if PG_VERSION < 90400:
- return unittest.skip('PostgreSQL ≥ 9.4 required')(test)
- return test
-
-
@unittest.skipUnless(connection.vendor == 'postgresql', "PostgreSQL specific tests")
class PostgreSQLTestCase(TestCase):
@classmethod
diff --git a/tests/postgres_tests/migrations/0002_create_test_models.py b/tests/postgres_tests/migrations/0002_create_test_models.py
index 1cb6fe686e..cbc984d485 100644
--- a/tests/postgres_tests/migrations/0002_create_test_models.py
+++ b/tests/postgres_tests/migrations/0002_create_test_models.py
@@ -242,7 +242,7 @@ class Migration(migrations.Migration):
('field_custom', JSONField(null=True, blank=True, encoder=DjangoJSONEncoder)),
],
options={
- 'required_db_features': {'has_jsonb_datatype'},
+ 'required_db_vendor': 'postgresql',
},
bases=(models.Model,),
),
diff --git a/tests/postgres_tests/models.py b/tests/postgres_tests/models.py
index b7094b77e1..fa390daaa8 100644
--- a/tests/postgres_tests/models.py
+++ b/tests/postgres_tests/models.py
@@ -140,13 +140,10 @@ class RangeLookupsModel(PostgreSQLModel):
date = models.DateField(blank=True, null=True)
-class JSONModel(models.Model):
+class JSONModel(PostgreSQLModel):
field = JSONField(blank=True, null=True)
field_custom = JSONField(blank=True, null=True, encoder=DjangoJSONEncoder)
- class Meta:
- required_db_features = ['has_jsonb_datatype']
-
class ArrayFieldSubclass(ArrayField):
def __init__(self, *args, **kwargs):
diff --git a/tests/postgres_tests/test_functions.py b/tests/postgres_tests/test_functions.py
index de5cb4d767..875a4b9520 100644
--- a/tests/postgres_tests/test_functions.py
+++ b/tests/postgres_tests/test_functions.py
@@ -4,7 +4,7 @@ from time import sleep
from django.contrib.postgres.functions import RandomUUID, TransactionNow
-from . import PostgreSQLTestCase, skipUnlessPG94
+from . import PostgreSQLTestCase
from .models import NowTestModel, UUIDTestModel
@@ -29,7 +29,6 @@ class TestTransactionNow(PostgreSQLTestCase):
self.assertEqual(m1.when, m2.when)
-@skipUnlessPG94
class TestRandomUUID(PostgreSQLTestCase):
def test_random_uuid(self):
diff --git a/tests/postgres_tests/test_introspection.py b/tests/postgres_tests/test_introspection.py
index b17d9fc81a..a63f08db50 100644
--- a/tests/postgres_tests/test_introspection.py
+++ b/tests/postgres_tests/test_introspection.py
@@ -1,7 +1,6 @@
from io import StringIO
from django.core.management import call_command
-from django.test import skipUnlessDBFeature
from django.test.utils import modify_settings
from . import PostgreSQLTestCase
@@ -20,7 +19,6 @@ class InspectDBTests(PostgreSQLTestCase):
for field_output in field_outputs:
self.assertIn(field_output, output)
- @skipUnlessDBFeature('has_jsonb_datatype')
def test_json_field(self):
self.assertFieldsInModel(
'postgres_tests_jsonmodel',
diff --git a/tests/postgres_tests/test_json.py b/tests/postgres_tests/test_json.py
index 2506fc36d6..cdabca04d6 100644
--- a/tests/postgres_tests/test_json.py
+++ b/tests/postgres_tests/test_json.py
@@ -5,7 +5,6 @@ from decimal import Decimal
from django.core import exceptions, serializers
from django.core.serializers.json import DjangoJSONEncoder
from django.forms import CharField, Form, widgets
-from django.test import skipUnlessDBFeature
from django.utils.html import escape
from . import PostgreSQLTestCase
@@ -18,7 +17,6 @@ except ImportError:
pass
-@skipUnlessDBFeature('has_jsonb_datatype')
class TestSaveLoad(PostgreSQLTestCase):
def test_null(self):
instance = JSONModel()
@@ -92,7 +90,6 @@ class TestSaveLoad(PostgreSQLTestCase):
self.assertEqual(loaded.field_custom, obj_after)
-@skipUnlessDBFeature('has_jsonb_datatype')
class TestQuerying(PostgreSQLTestCase):
@classmethod
def setUpTestData(cls):
@@ -262,7 +259,6 @@ class TestQuerying(PostgreSQLTestCase):
self.assertTrue(JSONModel.objects.filter(field__foo__iregex=r'^bAr$').exists())
-@skipUnlessDBFeature('has_jsonb_datatype')
class TestSerialization(PostgreSQLTestCase):
test_data = (
'[{"fields": {"field": {"a": "b", "c": null}, "field_custom": null}, '