summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2009-05-10 09:22:06 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2009-05-10 09:22:06 +0000
commitb97178f7ec311da7c885a122a2ccc1036bacf0d3 (patch)
tree4ee3f4409bec165fe2de50b6e580f9c5610f137b
parent5663258de13975e28406233328a9e51c8bc1b768 (diff)
downloaddjango-b97178f7ec311da7c885a122a2ccc1036bacf0d3.tar.gz
Fixed #10842 -- Corrected parsing of version numbers for PostgreSQL 8.4beta series. Thanks to hgdeoro for the report and fix.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@10730 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/db/backends/postgresql/base.py2
-rw-r--r--django/db/backends/postgresql/operations.py17
-rw-r--r--django/db/backends/postgresql/version.py26
-rw-r--r--django/db/backends/postgresql_psycopg2/base.py4
-rw-r--r--tests/regressiontests/backends/tests.py24
5 files changed, 49 insertions, 24 deletions
diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py
index afb7432c84..f0a117f570 100644
--- a/django/db/backends/postgresql/base.py
+++ b/django/db/backends/postgresql/base.py
@@ -121,7 +121,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
cursor.execute("SET TIME ZONE %s", [settings_dict['TIME_ZONE']])
if not hasattr(self, '_version'):
self.__class__._version = get_version(cursor)
- if self._version < (8, 0):
+ if self._version[0:2] < [8, 0]:
# No savepoint support for earlier version of PostgreSQL.
self.features.uses_savepoints = False
cursor.execute("SET client_encoding to 'UNICODE'")
diff --git a/django/db/backends/postgresql/operations.py b/django/db/backends/postgresql/operations.py
index 35824609b2..7b3a6c4413 100644
--- a/django/db/backends/postgresql/operations.py
+++ b/django/db/backends/postgresql/operations.py
@@ -2,8 +2,6 @@ import re
from django.db.backends import BaseDatabaseOperations
-server_version_re = re.compile(r'PostgreSQL (\d{1,2})\.(\d{1,2})\.?(\d{1,2})?')
-
# This DatabaseOperations class lives in here instead of base.py because it's
# used by both the 'postgresql' and 'postgresql_psycopg2' backends.
@@ -14,13 +12,9 @@ class DatabaseOperations(BaseDatabaseOperations):
def _get_postgres_version(self):
if self._postgres_version is None:
from django.db import connection
+ from django.db.backends.postgresql.version import get_version
cursor = connection.cursor()
- cursor.execute("SELECT version()")
- version_string = cursor.fetchone()[0]
- m = server_version_re.match(version_string)
- if not m:
- raise Exception('Unable to determine PostgreSQL version from version() function string: %r' % version_string)
- self._postgres_version = [int(val) for val in m.groups() if val]
+ self._postgres_version = get_version(cursor)
return self._postgres_version
postgres_version = property(_get_postgres_version)
@@ -72,7 +66,7 @@ class DatabaseOperations(BaseDatabaseOperations):
def sql_flush(self, style, tables, sequences):
if tables:
- if self.postgres_version[0] >= 8 and self.postgres_version[1] >= 1:
+ if self.postgres_version[0:2] >= [8,1]:
# Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to*
# in order to be able to truncate tables referenced by a foreign
# key in any other table. The result is a single SQL TRUNCATE
@@ -157,5 +151,6 @@ class DatabaseOperations(BaseDatabaseOperations):
NotImplementedError if this is the database in use.
"""
if aggregate.sql_function == 'STDDEV_POP' or aggregate.sql_function == 'VAR_POP':
- if self.postgres_version[0] == 8 and self.postgres_version[1] == 2 and self.postgres_version[2] <= 4:
- raise NotImplementedError('PostgreSQL 8.2 to 8.2.4 is known to have a faulty implementation of %s. Please upgrade your version of PostgreSQL.' % aggregate.sql_function)
+ if self.postgres_version[0:2] == [8,2]:
+ if self.postgres_version[2] is None or self.postgres_version[2] <= 4:
+ raise NotImplementedError('PostgreSQL 8.2 to 8.2.4 is known to have a faulty implementation of %s. Please upgrade your version of PostgreSQL.' % aggregate.sql_function)
diff --git a/django/db/backends/postgresql/version.py b/django/db/backends/postgresql/version.py
index ed2ad9e441..8fd773e59b 100644
--- a/django/db/backends/postgresql/version.py
+++ b/django/db/backends/postgresql/version.py
@@ -4,20 +4,28 @@ Extracts the version of the PostgreSQL server.
import re
-# This reg-exp is intentionally fairly flexible here. Require only the major
-# and minor version numbers, but need to be able to handle standard stuff like:
+# This reg-exp is intentionally fairly flexible here.
+# Needs to be able to handle stuff like:
# PostgreSQL 8.3.6
# EnterpriseDB 8.3
# PostgreSQL 8.3 beta4
-VERSION_RE = re.compile(r'\S+ (\d+)\.(\d+)')
+# PostgreSQL 8.4beta1
+VERSION_RE = re.compile(r'\S+ (\d+)\.(\d+)\.?(\d+)?')
+
+def _parse_version(text):
+ "Internal parsing method. Factored out for testing purposes."
+ major, major2, minor = VERSION_RE.search(text).groups()
+ try:
+ return int(major), int(major2), int(minor)
+ except (ValueError, TypeError):
+ return int(major), int(major2), None
def get_version(cursor):
"""
- Returns a tuple representing the major and minor version number of the
- server. For example, (7, 4) or (8, 3).
+ Returns a tuple representing the major, minor and revision number of the
+ server. For example, (7, 4, 1) or (8, 3, 4). The revision number will be
+ None in the case of initial releases (e.g., 'PostgreSQL 8.3') or in the
+ case of beta and prereleases ('PostgreSQL 8.4beta1').
"""
cursor.execute("SELECT version()")
- version = cursor.fetchone()[0]
- major, minor = VERSION_RE.search(version).groups()
- return int(major), int(minor)
-
+ return _parse_version(cursor.fetchone()[0])
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
index e1a5d830e2..600e864d23 100644
--- a/django/db/backends/postgresql_psycopg2/base.py
+++ b/django/db/backends/postgresql_psycopg2/base.py
@@ -105,11 +105,11 @@ class DatabaseWrapper(BaseDatabaseWrapper):
cursor.execute("SET TIME ZONE %s", [settings_dict['TIME_ZONE']])
if not hasattr(self, '_version'):
self.__class__._version = get_version(cursor)
- if self._version < (8, 0):
+ if self._version[0:2] < [8, 0]:
# No savepoint support for earlier version of PostgreSQL.
self.features.uses_savepoints = False
if self.features.uses_autocommit:
- if self._version < (8, 2):
+ if self._version[0:2] < [8, 2]:
# FIXME: Needs extra code to do reliable model insert
# handling, so we forbid it for now.
from django.core.exceptions import ImproperlyConfigured
diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
index 15bfe1f579..81dcfde30d 100644
--- a/tests/regressiontests/backends/tests.py
+++ b/tests/regressiontests/backends/tests.py
@@ -21,7 +21,29 @@ class Callproc(unittest.TestCase):
def connection_created_test(sender, **kwargs):
print 'connection_created signal'
-__test__ = {'API_TESTS': ''}
+__test__ = {'API_TESTS': """
+# Check Postgres version parsing
+>>> from django.db.backends.postgresql import version as pg_version
+
+>>> pg_version._parse_version("PostgreSQL 8.3.1 on i386-apple-darwin9.2.2, compiled by GCC i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5478)")
+(8, 3, 1)
+
+>>> pg_version._parse_version("PostgreSQL 8.3.6")
+(8, 3, 6)
+
+>>> pg_version._parse_version("PostgreSQL 8.3")
+(8, 3, None)
+
+>>> pg_version._parse_version("EnterpriseDB 8.3")
+(8, 3, None)
+
+>>> pg_version._parse_version("PostgreSQL 8.3 beta4")
+(8, 3, None)
+
+>>> pg_version._parse_version("PostgreSQL 8.4beta1")
+(8, 4, None)
+
+"""}
# Unfortunately with sqlite3 the in-memory test database cannot be
# closed, and so it cannot be re-opened during testing, and so we