Fix Oracle's default handling and schema-prepared-statement issue

This commit is contained in:
Andrew Godwin 2013-08-23 12:07:55 +01:00
parent ac45f9c9c5
commit 9cc6cfc405
4 changed files with 62 additions and 9 deletions

View File

@ -654,6 +654,12 @@ class BaseDatabaseFeatures(object):
# supported by the Python driver # supported by the Python driver
supports_paramstyle_pyformat = True supports_paramstyle_pyformat = True
# Does the backend require literal defaults, rather than parameterised ones?
requires_literal_defaults = False
# Does the backend require a connection reset after each material schema change?
connection_persists_old_columns = False
def __init__(self, connection): def __init__(self, connection):
self.connection = connection self.connection = connection

View File

@ -94,6 +94,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_combined_alters = False supports_combined_alters = False
max_index_name_length = 30 max_index_name_length = 30
nulls_order_largest = True nulls_order_largest = True
requires_literal_defaults = True
connection_persists_old_columns = True
class DatabaseOperations(BaseDatabaseOperations): class DatabaseOperations(BaseDatabaseOperations):

View File

@ -1,4 +1,6 @@
import copy import copy
import datetime
from django.utils import six
from django.db.backends.schema import BaseDatabaseSchemaEditor from django.db.backends.schema import BaseDatabaseSchemaEditor
from django.db.utils import DatabaseError from django.db.utils import DatabaseError
@ -89,3 +91,13 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
""" """
suffix = hex(hash(for_name)).upper()[1:] suffix = hex(hash(for_name)).upper()[1:]
return self.normalize_name(for_name + "_" + suffix) return self.normalize_name(for_name + "_" + suffix)
def prepare_default(self, value):
if isinstance(value, (datetime.date, datetime.time, datetime.datetime)):
return "'%s'" % value
elif isinstance(value, six.string_types):
return repr(value)
elif isinstance(value, bool):
return "1" if value else "0"
else:
return str(value)

View File

@ -116,8 +116,14 @@ class BaseDatabaseSchemaEditor(object):
# If we were told to include a default value, do so # If we were told to include a default value, do so
default_value = self.effective_default(field) default_value = self.effective_default(field)
if include_default and default_value is not None: if include_default and default_value is not None:
sql += " DEFAULT %s" if self.connection.features.requires_literal_defaults:
params += [default_value] # Some databases can't take defaults as a parameter (oracle)
# If this is the case, the individual schema backend should
# implement prepare_default
sql += " DEFAULT %s" % self.prepare_default(default_value)
else:
sql += " DEFAULT %s"
params += [default_value]
# Oracle treats the empty string ('') as null, so coerce the null # Oracle treats the empty string ('') as null, so coerce the null
# option whenever '' is a possible value. # option whenever '' is a possible value.
if (field.empty_strings_allowed and not field.primary_key and if (field.empty_strings_allowed and not field.primary_key and
@ -135,6 +141,12 @@ class BaseDatabaseSchemaEditor(object):
# Return the sql # Return the sql
return sql, params return sql, params
def prepare_default(self, value):
"""
Only used for backends which have requires_literal_defaults feature
"""
raise NotImplementedError()
def effective_default(self, field): def effective_default(self, field):
""" """
Returns a field's effective database default value Returns a field's effective database default value
@ -385,6 +397,9 @@ class BaseDatabaseSchemaEditor(object):
"to_column": self.quote_name(to_column), "to_column": self.quote_name(to_column),
} }
) )
# Reset connection if required
if self.connection.features.connection_persists_old_columns:
self.connection.close()
def remove_field(self, model, field): def remove_field(self, model, field):
""" """
@ -405,6 +420,9 @@ class BaseDatabaseSchemaEditor(object):
"column": self.quote_name(field.column), "column": self.quote_name(field.column),
} }
self.execute(sql) self.execute(sql)
# Reset connection if required
if self.connection.features.connection_persists_old_columns:
self.connection.close()
def alter_field(self, model, old_field, new_field, strict=False): def alter_field(self, model, old_field, new_field, strict=False):
""" """
@ -523,13 +541,25 @@ class BaseDatabaseSchemaEditor(object):
[], [],
)) ))
else: else:
actions.append(( if self.connection.features.requires_literal_defaults:
self.sql_alter_column_default % { # Some databases can't take defaults as a parameter (oracle)
"column": self.quote_name(new_field.column), # If this is the case, the individual schema backend should
"default": "%s", # implement prepare_default
}, actions.append((
[new_default], self.sql_alter_column_default % {
)) "column": self.quote_name(new_field.column),
"default": self.prepare_default(new_default),
},
[],
))
else:
actions.append((
self.sql_alter_column_default % {
"column": self.quote_name(new_field.column),
"default": "%s",
},
[new_default],
))
# Nullability change? # Nullability change?
if old_field.null != new_field.null: if old_field.null != new_field.null:
if new_field.null: if new_field.null:
@ -628,6 +658,9 @@ class BaseDatabaseSchemaEditor(object):
"check": new_db_params['check'], "check": new_db_params['check'],
} }
) )
# Reset connection if required
if self.connection.features.connection_persists_old_columns:
self.connection.close()
def _alter_many_to_many(self, model, old_field, new_field, strict): def _alter_many_to_many(self, model, old_field, new_field, strict):
""" """