Refactored quote_name() to DatabaseOperations.quote_name(). Refs #5106

git-svn-id: http://code.djangoproject.com/svn/django/trunk@5967 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2007-08-20 01:03:33 +00:00
parent d4f218bd91
commit 221f99ed58
23 changed files with 224 additions and 187 deletions

View File

@ -1,6 +1,6 @@
from django.core import validators from django.core import validators
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.db import backend, connection, models from django.db import connection, models
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -203,6 +203,7 @@ class User(models.Model):
# AND gp."group_id" = ug."group_id" # AND gp."group_id" = ug."group_id"
# AND ct."id" = p."content_type_id" # AND ct."id" = p."content_type_id"
# AND ug."user_id" = %s, [self.id]) # AND ug."user_id" = %s, [self.id])
qn = connection.ops.quote_name
sql = """ sql = """
SELECT ct.%s, p.%s SELECT ct.%s, p.%s
FROM %s p, %s gp, %s ug, %s ct FROM %s p, %s gp, %s ug, %s ct
@ -210,13 +211,13 @@ class User(models.Model):
AND gp.%s = ug.%s AND gp.%s = ug.%s
AND ct.%s = p.%s AND ct.%s = p.%s
AND ug.%s = %%s""" % ( AND ug.%s = %%s""" % (
backend.quote_name('app_label'), backend.quote_name('codename'), qn('app_label'), qn('codename'),
backend.quote_name('auth_permission'), backend.quote_name('auth_group_permissions'), qn('auth_permission'), qn('auth_group_permissions'),
backend.quote_name('auth_user_groups'), backend.quote_name('django_content_type'), qn('auth_user_groups'), qn('django_content_type'),
backend.quote_name('id'), backend.quote_name('permission_id'), qn('id'), qn('permission_id'),
backend.quote_name('group_id'), backend.quote_name('group_id'), qn('group_id'), qn('group_id'),
backend.quote_name('id'), backend.quote_name('content_type_id'), qn('id'), qn('content_type_id'),
backend.quote_name('user_id'),) qn('user_id'),)
cursor.execute(sql, [self.id]) cursor.execute(sql, [self.id])
self._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()]) self._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
return self._group_perm_cache return self._group_perm_cache

View File

@ -4,7 +4,7 @@ Classes allowing "generic" relations through ContentType and object-id fields.
from django import oldforms from django import oldforms
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db import backend from django.db import connection
from django.db.models import signals from django.db.models import signals
from django.db.models.fields.related import RelatedField, Field, ManyToManyRel from django.db.models.fields.related import RelatedField, Field, ManyToManyRel
from django.db.models.loading import get_model from django.db.models.loading import get_model
@ -163,13 +163,15 @@ class ReverseGenericRelatedObjectsDescriptor(object):
superclass = rel_model._default_manager.__class__ superclass = rel_model._default_manager.__class__
RelatedManager = create_generic_related_manager(superclass) RelatedManager = create_generic_related_manager(superclass)
qn = connection.ops.quote_name
manager = RelatedManager( manager = RelatedManager(
model = rel_model, model = rel_model,
instance = instance, instance = instance,
symmetrical = (self.field.rel.symmetrical and instance.__class__ == rel_model), symmetrical = (self.field.rel.symmetrical and instance.__class__ == rel_model),
join_table = backend.quote_name(self.field.m2m_db_table()), join_table = qn(self.field.m2m_db_table()),
source_col_name = backend.quote_name(self.field.m2m_column_name()), source_col_name = qn(self.field.m2m_column_name()),
target_col_name = backend.quote_name(self.field.m2m_reverse_name()), target_col_name = qn(self.field.m2m_reverse_name()),
content_type = ContentType.objects.get_for_model(self.field.model), content_type = ContentType.objects.get_for_model(self.field.model),
content_type_field_name = self.field.content_type_field_name, content_type_field_name = self.field.content_type_field_name,
object_id_field_name = self.field.object_id_field_name object_id_field_name = self.field.object_id_field_name

View File

@ -8,7 +8,7 @@ class Command(LabelCommand):
requires_model_validation = False requires_model_validation = False
def handle_label(self, tablename, **options): def handle_label(self, tablename, **options):
from django.db import backend, connection, transaction, models from django.db import connection, transaction, models
fields = ( fields = (
# "key" is a reserved word in MySQL, so use "cache_key" instead. # "key" is a reserved word in MySQL, so use "cache_key" instead.
models.CharField(name='cache_key', max_length=255, unique=True, primary_key=True), models.CharField(name='cache_key', max_length=255, unique=True, primary_key=True),
@ -17,8 +17,9 @@ class Command(LabelCommand):
) )
table_output = [] table_output = []
index_output = [] index_output = []
qn = connection.ops.quote_name
for f in fields: for f in fields:
field_output = [backend.quote_name(f.name), f.db_type()] field_output = [qn(f.name), f.db_type()]
field_output.append("%sNULL" % (not f.null and "NOT " or "")) field_output.append("%sNULL" % (not f.null and "NOT " or ""))
if f.unique: if f.unique:
field_output.append("UNIQUE") field_output.append("UNIQUE")
@ -27,10 +28,10 @@ class Command(LabelCommand):
if f.db_index: if f.db_index:
unique = f.unique and "UNIQUE " or "" unique = f.unique and "UNIQUE " or ""
index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \ index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \
(unique, tablename, f.name, backend.quote_name(tablename), (unique, tablename, f.name, qn(tablename),
backend.quote_name(f.name))) qn(f.name)))
table_output.append(" ".join(field_output)) table_output.append(" ".join(field_output))
full_statement = ["CREATE TABLE %s (" % backend.quote_name(tablename)] full_statement = ["CREATE TABLE %s (" % qn(tablename)]
for i, line in enumerate(table_output): for i, line in enumerate(table_output):
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
full_statement.append(');') full_statement.append(');')

View File

@ -116,6 +116,7 @@ def sql_delete(app, style):
table_name_converter = lambda x: x table_name_converter = lambda x: x
output = [] output = []
qn = connection.ops.quote_name
# Output DROP TABLE statements for standard application tables. # Output DROP TABLE statements for standard application tables.
to_delete = set() to_delete = set()
@ -136,7 +137,7 @@ def sql_delete(app, style):
if cursor and table_name_converter(model._meta.db_table) in table_names: if cursor and table_name_converter(model._meta.db_table) in table_names:
# Drop the table now # Drop the table now
output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'), output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
style.SQL_TABLE(backend.quote_name(model._meta.db_table)))) style.SQL_TABLE(qn(model._meta.db_table))))
if backend.supports_constraints and model in references_to_delete: if backend.supports_constraints and model in references_to_delete:
for rel_class, f in references_to_delete[model]: for rel_class, f in references_to_delete[model]:
table = rel_class._meta.db_table table = rel_class._meta.db_table
@ -146,7 +147,7 @@ def sql_delete(app, style):
r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table)))) r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
output.append('%s %s %s %s;' % \ output.append('%s %s %s %s;' % \
(style.SQL_KEYWORD('ALTER TABLE'), (style.SQL_KEYWORD('ALTER TABLE'),
style.SQL_TABLE(backend.quote_name(table)), style.SQL_TABLE(qn(table)),
style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()), style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length())))) style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
del references_to_delete[model] del references_to_delete[model]
@ -159,7 +160,7 @@ def sql_delete(app, style):
for f in opts.many_to_many: for f in opts.many_to_many:
if cursor and table_name_converter(f.m2m_db_table()) in table_names: if cursor and table_name_converter(f.m2m_db_table()) in table_names:
output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'), output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
style.SQL_TABLE(backend.quote_name(f.m2m_db_table())))) style.SQL_TABLE(qn(f.m2m_db_table()))))
if hasattr(backend, 'get_drop_sequence'): if hasattr(backend, 'get_drop_sequence'):
output.append(backend.get_drop_sequence("%s_%s" % (model._meta.db_table, f.column))) output.append(backend.get_drop_sequence("%s_%s" % (model._meta.db_table, f.column)))
@ -219,6 +220,7 @@ def sql_model_create(model, style, known_models=set()):
final_output = [] final_output = []
table_output = [] table_output = []
pending_references = {} pending_references = {}
qn = connection.ops.quote_name
for f in opts.fields: for f in opts.fields:
col_type = f.db_type() col_type = f.db_type()
tablespace = f.db_tablespace or opts.db_tablespace tablespace = f.db_tablespace or opts.db_tablespace
@ -227,7 +229,7 @@ def sql_model_create(model, style, known_models=set()):
# database columns in this table. # database columns in this table.
continue continue
# Make the definition (e.g. 'foo VARCHAR(30)') for this field. # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
field_output = [style.SQL_FIELD(backend.quote_name(f.column)), field_output = [style.SQL_FIELD(qn(f.column)),
style.SQL_COLTYPE(col_type)] style.SQL_COLTYPE(col_type)]
field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or ''))) field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
if f.unique and (not f.primary_key or backend.allows_unique_and_pk): if f.unique and (not f.primary_key or backend.allows_unique_and_pk):
@ -241,8 +243,8 @@ def sql_model_create(model, style, known_models=set()):
if f.rel: if f.rel:
if f.rel.to in known_models: if f.rel.to in known_models:
field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \ field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \ style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' + style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
connection.ops.deferrable_sql() connection.ops.deferrable_sql()
) )
else: else:
@ -251,14 +253,14 @@ def sql_model_create(model, style, known_models=set()):
pr = pending_references.setdefault(f.rel.to, []).append((model, f)) pr = pending_references.setdefault(f.rel.to, []).append((model, f))
table_output.append(' '.join(field_output)) table_output.append(' '.join(field_output))
if opts.order_with_respect_to: if opts.order_with_respect_to:
table_output.append(style.SQL_FIELD(backend.quote_name('_order')) + ' ' + \ table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \ style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
style.SQL_KEYWORD('NULL')) style.SQL_KEYWORD('NULL'))
for field_constraints in opts.unique_together: for field_constraints in opts.unique_together:
table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
", ".join([backend.quote_name(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints])) ", ".join([qn(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(backend.quote_name(opts.db_table)) + ' ('] full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
for i, line in enumerate(table_output): # Combine and add commas. for i, line in enumerate(table_output): # Combine and add commas.
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
full_statement.append(')') full_statement.append(')')
@ -283,6 +285,7 @@ def sql_for_pending_references(model, style, pending_references):
from django.db import backend, connection from django.db import backend, connection
from django.db.backends.util import truncate_name from django.db.backends.util import truncate_name
qn = connection.ops.quote_name
final_output = [] final_output = []
if backend.supports_constraints: if backend.supports_constraints:
opts = model._meta opts = model._meta
@ -297,8 +300,8 @@ def sql_for_pending_references(model, style, pending_references):
# So we are careful with character usage here. # So we are careful with character usage here.
r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table)))) r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \ final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
(backend.quote_name(r_table), truncate_name(r_name, connection.ops.max_name_length()), (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col), qn(r_col), qn(table), qn(col),
connection.ops.deferrable_sql())) connection.ops.deferrable_sql()))
del pending_references[model] del pending_references[model]
return final_output return final_output
@ -309,6 +312,7 @@ def many_to_many_sql_for_model(model, style):
opts = model._meta opts = model._meta
final_output = [] final_output = []
qn = connection.ops.quote_name
for f in opts.many_to_many: for f in opts.many_to_many:
if not isinstance(f.rel, generic.GenericRel): if not isinstance(f.rel, generic.GenericRel):
tablespace = f.db_tablespace or opts.db_tablespace tablespace = f.db_tablespace or opts.db_tablespace
@ -317,30 +321,30 @@ def many_to_many_sql_for_model(model, style):
else: else:
tablespace_sql = '' tablespace_sql = ''
table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' ('] style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
table_output.append(' %s %s %s%s,' % \ table_output.append(' %s %s %s%s,' % \
(style.SQL_FIELD(backend.quote_name('id')), (style.SQL_FIELD(qn('id')),
style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()), style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
style.SQL_KEYWORD('NOT NULL PRIMARY KEY'), style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
tablespace_sql)) tablespace_sql))
table_output.append(' %s %s %s %s (%s)%s,' % \ table_output.append(' %s %s %s %s (%s)%s,' % \
(style.SQL_FIELD(backend.quote_name(f.m2m_column_name())), (style.SQL_FIELD(qn(f.m2m_column_name())),
style.SQL_COLTYPE(models.ForeignKey(model).db_type()), style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
style.SQL_KEYWORD('NOT NULL REFERENCES'), style.SQL_KEYWORD('NOT NULL REFERENCES'),
style.SQL_TABLE(backend.quote_name(opts.db_table)), style.SQL_TABLE(qn(opts.db_table)),
style.SQL_FIELD(backend.quote_name(opts.pk.column)), style.SQL_FIELD(qn(opts.pk.column)),
connection.ops.deferrable_sql())) connection.ops.deferrable_sql()))
table_output.append(' %s %s %s %s (%s)%s,' % \ table_output.append(' %s %s %s %s (%s)%s,' % \
(style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())), (style.SQL_FIELD(qn(f.m2m_reverse_name())),
style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()), style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
style.SQL_KEYWORD('NOT NULL REFERENCES'), style.SQL_KEYWORD('NOT NULL REFERENCES'),
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)), style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)), style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
connection.ops.deferrable_sql())) connection.ops.deferrable_sql()))
table_output.append(' %s (%s, %s)%s' % \ table_output.append(' %s (%s, %s)%s' % \
(style.SQL_KEYWORD('UNIQUE'), (style.SQL_KEYWORD('UNIQUE'),
style.SQL_FIELD(backend.quote_name(f.m2m_column_name())), style.SQL_FIELD(qn(f.m2m_column_name())),
style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())), style.SQL_FIELD(qn(f.m2m_reverse_name())),
tablespace_sql)) tablespace_sql))
table_output.append(')') table_output.append(')')
if opts.db_tablespace and backend.supports_tablespaces: if opts.db_tablespace and backend.supports_tablespaces:
@ -350,7 +354,7 @@ def many_to_many_sql_for_model(model, style):
final_output.append('\n'.join(table_output)) final_output.append('\n'.join(table_output))
# Add any extra SQL needed to support auto-incrementing PKs # Add any extra SQL needed to support auto-incrementing PKs
autoinc_sql = backend.get_autoinc_sql(f.m2m_db_table()) autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table())
if autoinc_sql: if autoinc_sql:
for stmt in autoinc_sql: for stmt in autoinc_sql:
final_output.append(stmt) final_output.append(stmt)
@ -389,6 +393,7 @@ def sql_indexes_for_model(model, style):
from django.db import backend, connection from django.db import backend, connection
output = [] output = []
qn = connection.ops.quote_name
for f in model._meta.fields: for f in model._meta.fields:
if f.db_index and not ((f.primary_key or f.unique) and backend.autoindexes_primary_keys): if f.db_index and not ((f.primary_key or f.unique) and backend.autoindexes_primary_keys):
unique = f.unique and 'UNIQUE ' or '' unique = f.unique and 'UNIQUE ' or ''
@ -399,10 +404,10 @@ def sql_indexes_for_model(model, style):
tablespace_sql = '' tablespace_sql = ''
output.append( output.append(
style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \ style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \ style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
style.SQL_KEYWORD('ON') + ' ' + \ style.SQL_KEYWORD('ON') + ' ' + \
style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \ style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
"(%s)" % style.SQL_FIELD(backend.quote_name(f.column)) + \ "(%s)" % style.SQL_FIELD(qn(f.column)) + \
"%s;" % tablespace_sql "%s;" % tablespace_sql
) )
return output return output

View File

@ -134,6 +134,13 @@ class BaseDatabaseOperations(object):
""" """
return 'DEFAULT' return 'DEFAULT'
def quote_name(self, name):
"""
Returns a quoted version of the given table, index or column name. Does
not quote the given name if it's already been quoted.
"""
raise NotImplementedError()
def random_function_sql(self): def random_function_sql(self):
""" """
Returns a SQL expression that returns a random value. Returns a SQL expression that returns a random value.

View File

@ -67,11 +67,16 @@ class DatabaseOperations(BaseDatabaseOperations):
cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name)) cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name))
return cursor.fetchone()[0] return cursor.fetchone()[0]
def quote_name(self, name):
if name.startswith('[') and name.endswith(']'):
return name # Quoting once is enough.
return '[%s]' % name
def random_function_sql(self): def random_function_sql(self):
return 'RAND()' return 'RAND()'
def tablespace_sql(self, tablespace, inline=False): def tablespace_sql(self, tablespace, inline=False):
return "ON %s" % quote_name(tablespace) return "ON %s" % self.quote_name(tablespace)
class DatabaseWrapper(BaseDatabaseWrapper): class DatabaseWrapper(BaseDatabaseWrapper):
ops = DatabaseOperations() ops = DatabaseOperations()
@ -97,11 +102,6 @@ supports_constraints = True
supports_tablespaces = True supports_tablespaces = True
uses_case_insensitive_names = False uses_case_insensitive_names = False
def quote_name(name):
if name.startswith('[') and name.endswith(']'):
return name # Quoting once is enough.
return '[%s]' % name
dictfetchone = util.dictfetchone dictfetchone = util.dictfetchone
dictfetchmany = util.dictfetchmany dictfetchmany = util.dictfetchmany
dictfetchall = util.dictfetchall dictfetchall = util.dictfetchall

View File

@ -39,7 +39,6 @@ class DatabaseWrapper(object):
supports_constraints = False supports_constraints = False
supports_tablespaces = False supports_tablespaces = False
quote_name = complain
dictfetchone = complain dictfetchone = complain
dictfetchmany = complain dictfetchmany = complain
dictfetchall = complain dictfetchall = complain

View File

@ -84,6 +84,11 @@ class DatabaseOperations(BaseDatabaseOperations):
sql += "%s," % offset sql += "%s," % offset
return sql + str(limit) return sql + str(limit)
def quote_name(self, name):
if name.startswith("`") and name.endswith("`"):
return name # Quoting once is enough.
return "`%s`" % name
def random_function_sql(self): def random_function_sql(self):
return 'RAND()' return 'RAND()'
@ -94,7 +99,7 @@ class DatabaseOperations(BaseDatabaseOperations):
if tables: if tables:
sql = ['SET FOREIGN_KEY_CHECKS = 0;'] sql = ['SET FOREIGN_KEY_CHECKS = 0;']
for table in tables: for table in tables:
sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(quote_name(table)))) sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.quote_name(table))))
sql.append('SET FOREIGN_KEY_CHECKS = 1;') sql.append('SET FOREIGN_KEY_CHECKS = 1;')
# 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
@ -102,7 +107,7 @@ class DatabaseOperations(BaseDatabaseOperations):
sql.extend(["%s %s %s %s %s;" % \ sql.extend(["%s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'), (style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('TABLE'), style.SQL_KEYWORD('TABLE'),
style.SQL_TABLE(quote_name(sequence['table'])), style.SQL_TABLE(self.quote_name(sequence['table'])),
style.SQL_KEYWORD('AUTO_INCREMENT'), style.SQL_KEYWORD('AUTO_INCREMENT'),
style.SQL_FIELD('= 1'), style.SQL_FIELD('= 1'),
) for sequence in sequences]) ) for sequence in sequences])
@ -179,11 +184,6 @@ supports_constraints = True
supports_tablespaces = False supports_tablespaces = False
uses_case_insensitive_names = False uses_case_insensitive_names = False
def quote_name(name):
if name.startswith("`") and name.endswith("`"):
return name # Quoting once is enough.
return "`%s`" % name
dictfetchone = util.dictfetchone dictfetchone = util.dictfetchone
dictfetchmany = util.dictfetchmany dictfetchmany = util.dictfetchmany
dictfetchall = util.dictfetchall dictfetchall = util.dictfetchall

View File

@ -1,8 +1,9 @@
from django.db.backends.mysql.base import quote_name from django.db.backends.mysql.base import DatabaseOperations
from MySQLdb import ProgrammingError, OperationalError from MySQLdb import ProgrammingError, OperationalError
from MySQLdb.constants import FIELD_TYPE from MySQLdb.constants import FIELD_TYPE
import re import re
quote_name = DatabaseOperations().quote_name
foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
def get_table_list(cursor): def get_table_list(cursor):

View File

@ -94,6 +94,11 @@ class DatabaseOperations(BaseDatabaseOperations):
sql += "%s," % offset sql += "%s," % offset
return sql + str(limit) return sql + str(limit)
def quote_name(self, name):
if name.startswith("`") and name.endswith("`"):
return name # Quoting once is enough.
return "`%s`" % name
def random_function_sql(self): def random_function_sql(self):
return 'RAND()' return 'RAND()'
@ -104,7 +109,7 @@ class DatabaseOperations(BaseDatabaseOperations):
if tables: if tables:
sql = ['SET FOREIGN_KEY_CHECKS = 0;'] sql = ['SET FOREIGN_KEY_CHECKS = 0;']
for table in tables: for table in tables:
sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(quote_name(table)))) sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.quote_name(table))))
sql.append('SET FOREIGN_KEY_CHECKS = 1;') sql.append('SET FOREIGN_KEY_CHECKS = 1;')
# 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
@ -112,7 +117,7 @@ class DatabaseOperations(BaseDatabaseOperations):
sql.extend(["%s %s %s %s %s;" % \ sql.extend(["%s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'), (style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('TABLE'), style.SQL_KEYWORD('TABLE'),
style.SQL_TABLE(quote_name(sequence['table'])), style.SQL_TABLE(self.quote_name(sequence['table'])),
style.SQL_KEYWORD('AUTO_INCREMENT'), style.SQL_KEYWORD('AUTO_INCREMENT'),
style.SQL_FIELD('= 1'), style.SQL_FIELD('= 1'),
) for sequence in sequences]) ) for sequence in sequences])
@ -198,11 +203,6 @@ supports_constraints = True
supports_tablespaces = False supports_tablespaces = False
uses_case_insensitive_names = False uses_case_insensitive_names = False
def quote_name(name):
if name.startswith("`") and name.endswith("`"):
return name # Quoting once is enough.
return "`%s`" % name
dictfetchone = util.dictfetchone dictfetchone = util.dictfetchone
dictfetchmany = util.dictfetchmany dictfetchmany = util.dictfetchmany
dictfetchall = util.dictfetchall dictfetchall = util.dictfetchall

View File

@ -1,8 +1,9 @@
from django.db.backends.mysql_old.base import quote_name from django.db.backends.mysql_old.base import DatabaseOperations
from MySQLdb import ProgrammingError, OperationalError from MySQLdb import ProgrammingError, OperationalError
from MySQLdb.constants import FIELD_TYPE from MySQLdb.constants import FIELD_TYPE
import re import re
quote_name = DatabaseOperations().quote_name
foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
def get_table_list(cursor): def get_table_list(cursor):

View File

@ -35,7 +35,7 @@ class DatabaseOperations(BaseDatabaseOperations):
WHEN (new.id IS NULL) WHEN (new.id IS NULL)
BEGIN BEGIN
SELECT %s.nextval INTO :new.id FROM dual; SELECT %s.nextval INTO :new.id FROM dual;
END;/""" % (tr_name, quote_name(table), sq_name) END;/""" % (tr_name, self.quote_name(table), sq_name)
return sequence_sql, trigger_sql return sequence_sql, trigger_sql
def date_extract_sql(self, lookup_type, field_name): def date_extract_sql(self, lookup_type, field_name):
@ -70,6 +70,15 @@ class DatabaseOperations(BaseDatabaseOperations):
def max_name_length(self): def max_name_length(self):
return 30 return 30
def quote_name(self, name):
# SQL92 requires delimited (quoted) names to be case-sensitive. When
# not quoted, Oracle has case-insensitive behavior for identifiers, but
# always defaults to uppercase.
# We simplify things by making Oracle identifiers always uppercase.
if not name.startswith('"') and not name.endswith('"'):
name = '"%s"' % util.truncate_name(name.upper(), DatabaseOperations().max_name_length())
return name.upper()
def random_function_sql(self): def random_function_sql(self):
return "DBMS_RANDOM.RANDOM" return "DBMS_RANDOM.RANDOM"
@ -82,14 +91,14 @@ class DatabaseOperations(BaseDatabaseOperations):
sql = ['%s %s %s;' % \ sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'), (style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'), style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table)) style.SQL_FIELD(self.quote_name(table))
) for table in tables] ) for table in tables]
# Since we've just deleted all the rows, running our sequence # Since we've just deleted all the rows, running our sequence
# ALTER code will reset the sequence to 0. # ALTER code will reset the sequence to 0.
for sequence_info in sequences: for sequence_info in sequences:
table_name = sequence_info['table'] table_name = sequence_info['table']
seq_name = get_sequence_name(table_name) seq_name = get_sequence_name(table_name)
query = _get_sequence_reset_sql() % {'sequence':seq_name, 'table':quote_name(table_name)} query = _get_sequence_reset_sql() % {'sequence': seq_name, 'table': self.quote_name(table_name)}
sql.append(query) sql.append(query)
return sql return sql
else: else:
@ -116,7 +125,7 @@ class DatabaseOperations(BaseDatabaseOperations):
return '' return ''
def tablespace_sql(self, tablespace, inline=False): def tablespace_sql(self, tablespace, inline=False):
return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), quote_name(tablespace)) return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), self.quote_name(tablespace))
class DatabaseWrapper(BaseDatabaseWrapper): class DatabaseWrapper(BaseDatabaseWrapper):
ops = DatabaseOperations() ops = DatabaseOperations()
@ -215,15 +224,6 @@ def to_unicode(s):
return force_unicode(s) return force_unicode(s)
return s return s
def quote_name(name):
# SQL92 requires delimited (quoted) names to be case-sensitive. When
# not quoted, Oracle has case-insensitive behavior for identifiers, but
# always defaults to uppercase.
# We simplify things by making Oracle identifiers always uppercase.
if not name.startswith('"') and not name.endswith('"'):
name = '"%s"' % util.truncate_name(name.upper(), DatabaseOperations().max_name_length())
return name.upper()
dictfetchone = util.dictfetchone dictfetchone = util.dictfetchone
dictfetchmany = util.dictfetchmany dictfetchmany = util.dictfetchmany
dictfetchall = util.dictfetchall dictfetchall = util.dictfetchall
@ -235,7 +235,7 @@ def get_field_cast_sql(db_type):
return "%s%s" return "%s%s"
def get_drop_sequence(table): def get_drop_sequence(table):
return "DROP SEQUENCE %s;" % quote_name(get_sequence_name(table)) return "DROP SEQUENCE %s;" % DatabaseOperations().quote_name(get_sequence_name(table))
def _get_sequence_reset_sql(): def _get_sequence_reset_sql():
# TODO: colorize this SQL code with style.SQL_KEYWORD(), etc. # TODO: colorize this SQL code with style.SQL_KEYWORD(), etc.
@ -328,9 +328,10 @@ def get_query_set_class(DefaultQuerySet):
handle_legacy_orderlist, orderfield2column handle_legacy_orderlist, orderfield2column
opts = self.model._meta opts = self.model._meta
qn = connection.ops.quote_name
# Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields] select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields]
tables = [quote_only_if_word(t) for t in self._tables] tables = [quote_only_if_word(t) for t in self._tables]
joins = SortedDict() joins = SortedDict()
where = self._where[:] where = self._where[:]
@ -348,10 +349,10 @@ def get_query_set_class(DefaultQuerySet):
# Add any additional SELECTs. # Add any additional SELECTs.
if self._select: if self._select:
select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()]) select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in self._select.items()])
# Start composing the body of the SQL statement. # Start composing the body of the SQL statement.
sql = [" FROM", backend.quote_name(opts.db_table)] sql = [" FROM", qn(opts.db_table)]
# Compose the join dictionary into SQL describing the joins. # Compose the join dictionary into SQL describing the joins.
if joins: if joins:
@ -384,15 +385,15 @@ def get_query_set_class(DefaultQuerySet):
order = "ASC" order = "ASC"
if "." in col_name: if "." in col_name:
table_prefix, col_name = col_name.split('.', 1) table_prefix, col_name = col_name.split('.', 1)
table_prefix = backend.quote_name(table_prefix) + '.' table_prefix = qn(table_prefix) + '.'
else: else:
# Use the database table as a column prefix if it wasn't given, # Use the database table as a column prefix if it wasn't given,
# and if the requested column isn't a custom SELECT. # and if the requested column isn't a custom SELECT.
if "." not in col_name and col_name not in (self._select or ()): if "." not in col_name and col_name not in (self._select or ()):
table_prefix = backend.quote_name(opts.db_table) + '.' table_prefix = qn(opts.db_table) + '.'
else: else:
table_prefix = '' table_prefix = ''
order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order)) order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order))
if order_by: if order_by:
sql.append("ORDER BY " + ", ".join(order_by)) sql.append("ORDER BY " + ", ".join(order_by))
@ -417,8 +418,7 @@ def get_query_set_class(DefaultQuerySet):
#Oracle's row_number() function always requires an order-by clause. #Oracle's row_number() function always requires an order-by clause.
#So we need to define a default order-by, since none was provided. #So we need to define a default order-by, since none was provided.
order_by_clause = " OVER (ORDER BY %s.%s)" % \ order_by_clause = " OVER (ORDER BY %s.%s)" % \
(backend.quote_name(opts.db_table), (qn(opts.db_table), qn(opts.fields[0].db_column or opts.fields[0].column))
backend.quote_name(opts.fields[0].db_column or opts.fields[0].column))
# limit_and_offset_clause # limit_and_offset_clause
if self._limit is None: if self._limit is None:
assert self._offset is None, "'offset' is not allowed without 'limit'" assert self._offset is None, "'offset' is not allowed without 'limit'"

View File

@ -1,8 +1,8 @@
from django.db.backends.oracle.base import quote_name from django.db.backends.oracle.base import DatabaseOperations
import re import re
import cx_Oracle import cx_Oracle
quote_name = DatabaseOperations().quote_name
foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
def get_table_list(cursor): def get_table_list(cursor):

View File

@ -73,6 +73,11 @@ class DatabaseOperations(BaseDatabaseOperations):
cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name)) cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
return cursor.fetchone()[0] return cursor.fetchone()[0]
def quote_name(self, name):
if name.startswith('"') and name.endswith('"'):
return name # Quoting once is enough.
return '"%s"' % name
def sql_flush(self, style, tables, sequences): def sql_flush(self, style, tables, sequences):
if tables: if tables:
if postgres_version[0] >= 8 and postgres_version[1] >= 1: if postgres_version[0] >= 8 and postgres_version[1] >= 1:
@ -82,7 +87,7 @@ class DatabaseOperations(BaseDatabaseOperations):
# statement. # statement.
sql = ['%s %s;' % \ sql = ['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'), (style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(', '.join([quote_name(table) for table in tables])) style.SQL_FIELD(', '.join([self.quote_name(table) for table in tables]))
)] )]
else: else:
# Older versions of Postgres can't do TRUNCATE in a single call, so # Older versions of Postgres can't do TRUNCATE in a single call, so
@ -90,7 +95,7 @@ class DatabaseOperations(BaseDatabaseOperations):
sql = ['%s %s %s;' % \ sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'), (style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'), style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table)) style.SQL_FIELD(self.quote_name(table))
) for table in tables] ) for table in tables]
# 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
@ -103,7 +108,7 @@ class DatabaseOperations(BaseDatabaseOperations):
sql.append("%s %s %s %s %s %s;" % \ sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'), (style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'), style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_%s_seq' % (table_name, column_name))), style.SQL_FIELD(self.quote_name('%s_%s_seq' % (table_name, column_name))),
style.SQL_KEYWORD('RESTART'), style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'), style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1') style.SQL_FIELD('1')
@ -114,7 +119,7 @@ class DatabaseOperations(BaseDatabaseOperations):
sql.append("%s %s %s %s %s %s;" % \ sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'), (style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'), style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_id_seq' % table_name)), style.SQL_FIELD(self.quote_name('%s_id_seq' % table_name)),
style.SQL_KEYWORD('RESTART'), style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'), style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1') style.SQL_FIELD('1')
@ -127,6 +132,7 @@ class DatabaseOperations(BaseDatabaseOperations):
def sequence_reset_sql(self, style, model_list): def sequence_reset_sql(self, style, model_list):
from django.db import models from django.db import models
output = [] output = []
qn = self.quote_name
for model in model_list: for model in model_list:
# Use `coalesce` to set the sequence for each model to the max pk value if there are records, # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
# or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true # or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true
@ -135,19 +141,19 @@ class DatabaseOperations(BaseDatabaseOperations):
if isinstance(f, models.AutoField): if isinstance(f, models.AutoField):
output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
(style.SQL_KEYWORD('SELECT'), (style.SQL_KEYWORD('SELECT'),
style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))), style.SQL_FIELD(qn('%s_%s_seq' % (model._meta.db_table, f.column))),
style.SQL_FIELD(quote_name(f.column)), style.SQL_FIELD(qn(f.column)),
style.SQL_FIELD(quote_name(f.column)), style.SQL_FIELD(qn(f.column)),
style.SQL_KEYWORD('IS NOT'), style.SQL_KEYWORD('IS NOT'),
style.SQL_KEYWORD('FROM'), style.SQL_KEYWORD('FROM'),
style.SQL_TABLE(quote_name(model._meta.db_table)))) style.SQL_TABLE(qn(model._meta.db_table))))
break # Only one AutoField is allowed per model, so don't bother continuing. break # Only one AutoField is allowed per model, so don't bother continuing.
for f in model._meta.many_to_many: for f in model._meta.many_to_many:
output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
(style.SQL_KEYWORD('SELECT'), (style.SQL_KEYWORD('SELECT'),
style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())), style.SQL_FIELD(qn('%s_id_seq' % f.m2m_db_table())),
style.SQL_FIELD(quote_name('id')), style.SQL_FIELD(qn('id')),
style.SQL_FIELD(quote_name('id')), style.SQL_FIELD(qn('id')),
style.SQL_KEYWORD('IS NOT'), style.SQL_KEYWORD('IS NOT'),
style.SQL_KEYWORD('FROM'), style.SQL_KEYWORD('FROM'),
style.SQL_TABLE(f.m2m_db_table()))) style.SQL_TABLE(f.m2m_db_table())))
@ -194,11 +200,6 @@ supports_constraints = True
supports_tablespaces = False supports_tablespaces = False
uses_case_insensitive_names = False uses_case_insensitive_names = False
def quote_name(name):
if name.startswith('"') and name.endswith('"'):
return name # Quoting once is enough.
return '"%s"' % name
def dictfetchone(cursor): def dictfetchone(cursor):
"Returns a row from the cursor as a dict" "Returns a row from the cursor as a dict"
return cursor.dictfetchone() return cursor.dictfetchone()

View File

@ -1,4 +1,6 @@
from django.db.backends.postgresql.base import quote_name from django.db.backends.postgresql.base import DatabaseOperations
quote_name = DatabaseOperations().quote_name
def get_table_list(cursor): def get_table_list(cursor):
"Returns a list of table names in the current database." "Returns a list of table names in the current database."

View File

@ -35,7 +35,13 @@ class DatabaseOperations(BaseDatabaseOperations):
cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name)) cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
return cursor.fetchone()[0] return cursor.fetchone()[0]
def quote_name(self, name):
if name.startswith('"') and name.endswith('"'):
return name # Quoting once is enough.
return '"%s"' % name
def sql_flush(self, style, tables, sequences): def sql_flush(self, style, tables, sequences):
qn = self.quote_name
if tables: if tables:
if postgres_version[0] >= 8 and postgres_version[1] >= 1: if postgres_version[0] >= 8 and postgres_version[1] >= 1:
# Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to*
@ -44,7 +50,7 @@ class DatabaseOperations(BaseDatabaseOperations):
# statement. # statement.
sql = ['%s %s;' % \ sql = ['%s %s;' % \
(style.SQL_KEYWORD('TRUNCATE'), (style.SQL_KEYWORD('TRUNCATE'),
style.SQL_FIELD(', '.join([quote_name(table) for table in tables])) style.SQL_FIELD(', '.join([qn(table) for table in tables]))
)] )]
else: else:
# Older versions of Postgres can't do TRUNCATE in a single call, so # Older versions of Postgres can't do TRUNCATE in a single call, so
@ -52,7 +58,7 @@ class DatabaseOperations(BaseDatabaseOperations):
sql = ['%s %s %s;' % \ sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'), (style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'), style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table)) style.SQL_FIELD(qn(table))
) for table in tables] ) for table in tables]
# 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
@ -65,7 +71,7 @@ class DatabaseOperations(BaseDatabaseOperations):
sql.append("%s %s %s %s %s %s;" % \ sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'), (style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'), style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_%s_seq' % (table_name, column_name))), style.SQL_FIELD(qn('%s_%s_seq' % (table_name, column_name))),
style.SQL_KEYWORD('RESTART'), style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'), style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1') style.SQL_FIELD('1')
@ -76,7 +82,7 @@ class DatabaseOperations(BaseDatabaseOperations):
sql.append("%s %s %s %s %s %s;" % \ sql.append("%s %s %s %s %s %s;" % \
(style.SQL_KEYWORD('ALTER'), (style.SQL_KEYWORD('ALTER'),
style.SQL_KEYWORD('SEQUENCE'), style.SQL_KEYWORD('SEQUENCE'),
style.SQL_FIELD(quote_name('%s_id_seq' % table_name)), style.SQL_FIELD(qn('%s_id_seq' % table_name)),
style.SQL_KEYWORD('RESTART'), style.SQL_KEYWORD('RESTART'),
style.SQL_KEYWORD('WITH'), style.SQL_KEYWORD('WITH'),
style.SQL_FIELD('1') style.SQL_FIELD('1')
@ -88,6 +94,7 @@ class DatabaseOperations(BaseDatabaseOperations):
def sequence_reset_sql(self, style, model_list): def sequence_reset_sql(self, style, model_list):
from django.db import models from django.db import models
qn = self.quote_name
output = [] output = []
for model in model_list: for model in model_list:
# Use `coalesce` to set the sequence for each model to the max pk value if there are records, # Use `coalesce` to set the sequence for each model to the max pk value if there are records,
@ -97,19 +104,19 @@ class DatabaseOperations(BaseDatabaseOperations):
if isinstance(f, models.AutoField): if isinstance(f, models.AutoField):
output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
(style.SQL_KEYWORD('SELECT'), (style.SQL_KEYWORD('SELECT'),
style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))), style.SQL_FIELD(qn('%s_%s_seq' % (model._meta.db_table, f.column))),
style.SQL_FIELD(quote_name(f.column)), style.SQL_FIELD(qn(f.column)),
style.SQL_FIELD(quote_name(f.column)), style.SQL_FIELD(qn(f.column)),
style.SQL_KEYWORD('IS NOT'), style.SQL_KEYWORD('IS NOT'),
style.SQL_KEYWORD('FROM'), style.SQL_KEYWORD('FROM'),
style.SQL_TABLE(quote_name(model._meta.db_table)))) style.SQL_TABLE(qn(model._meta.db_table))))
break # Only one AutoField is allowed per model, so don't bother continuing. break # Only one AutoField is allowed per model, so don't bother continuing.
for f in model._meta.many_to_many: for f in model._meta.many_to_many:
output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
(style.SQL_KEYWORD('SELECT'), (style.SQL_KEYWORD('SELECT'),
style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())), style.SQL_FIELD(qn('%s_id_seq' % f.m2m_db_table())),
style.SQL_FIELD(quote_name('id')), style.SQL_FIELD(qn('id')),
style.SQL_FIELD(quote_name('id')), style.SQL_FIELD(qn('id')),
style.SQL_KEYWORD('IS NOT'), style.SQL_KEYWORD('IS NOT'),
style.SQL_KEYWORD('FROM'), style.SQL_KEYWORD('FROM'),
style.SQL_TABLE(f.m2m_db_table()))) style.SQL_TABLE(f.m2m_db_table())))
@ -156,11 +163,6 @@ supports_constraints = True
supports_tablespaces = False supports_tablespaces = False
uses_case_insensitive_names = False uses_case_insensitive_names = False
def quote_name(name):
if name.startswith('"') and name.endswith('"'):
return name # Quoting once is enough.
return '"%s"' % name
dictfetchone = util.dictfetchone dictfetchone = util.dictfetchone
dictfetchmany = util.dictfetchmany dictfetchmany = util.dictfetchmany
dictfetchall = util.dictfetchall dictfetchall = util.dictfetchall

View File

@ -1,4 +1,6 @@
from django.db.backends.postgresql_psycopg2.base import quote_name from django.db.backends.postgresql_psycopg2.base import DatabaseOperations
quote_name = DatabaseOperations().quote_name
def get_table_list(cursor): def get_table_list(cursor):
"Returns a list of table names in the current database." "Returns a list of table names in the current database."

View File

@ -51,6 +51,11 @@ class DatabaseOperations(BaseDatabaseOperations):
def pk_default_value(self): def pk_default_value(self):
return 'NULL' return 'NULL'
def quote_name(self, name):
if name.startswith('"') and name.endswith('"'):
return name # Quoting once is enough.
return '"%s"' % name
def sql_flush(self, style, tables, sequences): def sql_flush(self, style, tables, sequences):
# NB: The generated SQL below is specific to SQLite # NB: The generated SQL below is specific to SQLite
# Note: The DELETE FROM... SQL generated below works for SQLite databases # Note: The DELETE FROM... SQL generated below works for SQLite databases
@ -58,7 +63,7 @@ class DatabaseOperations(BaseDatabaseOperations):
sql = ['%s %s %s;' % \ sql = ['%s %s %s;' % \
(style.SQL_KEYWORD('DELETE'), (style.SQL_KEYWORD('DELETE'),
style.SQL_KEYWORD('FROM'), style.SQL_KEYWORD('FROM'),
style.SQL_FIELD(quote_name(table)) style.SQL_FIELD(self.quote_name(table))
) for table in tables] ) for table in tables]
# Note: No requirement for reset of auto-incremented indices (cf. other # Note: No requirement for reset of auto-incremented indices (cf. other
# sql_flush() implementations). Just return SQL at this point # sql_flush() implementations). Just return SQL at this point
@ -115,11 +120,6 @@ supports_constraints = False
supports_tablespaces = False supports_tablespaces = False
uses_case_insensitive_names = False uses_case_insensitive_names = False
def quote_name(name):
if name.startswith('"') and name.endswith('"'):
return name # Quoting once is enough.
return '"%s"' % name
dictfetchone = util.dictfetchone dictfetchone = util.dictfetchone
dictfetchmany = util.dictfetchmany dictfetchmany = util.dictfetchmany
dictfetchall = util.dictfetchall dictfetchall = util.dictfetchall

View File

@ -1,4 +1,6 @@
from django.db.backends.sqlite3.base import quote_name from django.db.backends.sqlite3.base import DatabaseOperations
quote_name = DatabaseOperations().quote_name
def get_table_list(cursor): def get_table_list(cursor):
"Returns a list of table names in the current database." "Returns a list of table names in the current database."

View File

@ -207,6 +207,8 @@ class Model(object):
non_pks = [f for f in self._meta.fields if not f.primary_key] non_pks = [f for f in self._meta.fields if not f.primary_key]
cursor = connection.cursor() cursor = connection.cursor()
qn = connection.ops.quote_name
# First, try an UPDATE. If that doesn't update anything, do an INSERT. # First, try an UPDATE. If that doesn't update anything, do an INSERT.
pk_val = self._get_pk_val() pk_val = self._get_pk_val()
# Note: the comparison with '' is required for compatibility with # Note: the comparison with '' is required for compatibility with
@ -216,21 +218,21 @@ class Model(object):
if pk_set: if pk_set:
# Determine whether a record with the primary key already exists. # Determine whether a record with the primary key already exists.
cursor.execute("SELECT 1 FROM %s WHERE %s=%%s" % \ cursor.execute("SELECT 1 FROM %s WHERE %s=%%s" % \
(backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), (qn(self._meta.db_table), qn(self._meta.pk.column)),
self._meta.pk.get_db_prep_lookup('exact', pk_val)) self._meta.pk.get_db_prep_lookup('exact', pk_val))
# If it does already exist, do an UPDATE. # If it does already exist, do an UPDATE.
if cursor.fetchone(): if cursor.fetchone():
db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False)) for f in non_pks] db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False)) for f in non_pks]
if db_values: if db_values:
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \ cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
(backend.quote_name(self._meta.db_table), (qn(self._meta.db_table),
','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]), ','.join(['%s=%%s' % qn(f.column) for f in non_pks]),
backend.quote_name(self._meta.pk.column)), qn(self._meta.pk.column)),
db_values + self._meta.pk.get_db_prep_lookup('exact', pk_val)) db_values + self._meta.pk.get_db_prep_lookup('exact', pk_val))
else: else:
record_exists = False record_exists = False
if not pk_set or not record_exists: if not pk_set or not record_exists:
field_names = [backend.quote_name(f.column) for f in self._meta.fields if not isinstance(f, AutoField)] field_names = [qn(f.column) for f in self._meta.fields if not isinstance(f, AutoField)]
db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)] db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]
# If the PK has been manually set, respect that. # If the PK has been manually set, respect that.
if pk_set: if pk_set:
@ -238,20 +240,19 @@ class Model(object):
db_values += [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)] db_values += [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
placeholders = ['%s'] * len(field_names) placeholders = ['%s'] * len(field_names)
if self._meta.order_with_respect_to: if self._meta.order_with_respect_to:
field_names.append(backend.quote_name('_order')) field_names.append(qn('_order'))
# TODO: This assumes the database supports subqueries. # TODO: This assumes the database supports subqueries.
placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \ placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \
(backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column))) (qn(self._meta.db_table), qn(self._meta.order_with_respect_to.column)))
db_values.append(getattr(self, self._meta.order_with_respect_to.attname)) db_values.append(getattr(self, self._meta.order_with_respect_to.attname))
if db_values: if db_values:
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
(backend.quote_name(self._meta.db_table), ','.join(field_names), (qn(self._meta.db_table), ','.join(field_names),
','.join(placeholders)), db_values) ','.join(placeholders)), db_values)
else: else:
# Create a new record with defaults for everything. # Create a new record with defaults for everything.
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % cursor.execute("INSERT INTO %s (%s) VALUES (%s)" %
(backend.quote_name(self._meta.db_table), (qn(self._meta.db_table), qn(self._meta.pk.column),
backend.quote_name(self._meta.pk.column),
connection.ops.pk_default_value())) connection.ops.pk_default_value()))
if self._meta.has_auto_field and not pk_set: if self._meta.has_auto_field and not pk_set:
setattr(self, self._meta.pk.attname, connection.ops.last_insert_id(cursor, self._meta.db_table, self._meta.pk.column)) setattr(self, self._meta.pk.attname, connection.ops.last_insert_id(cursor, self._meta.db_table, self._meta.pk.column))
@ -326,10 +327,11 @@ class Model(object):
return force_unicode(dict(field.choices).get(value, value), strings_only=True) return force_unicode(dict(field.choices).get(value, value), strings_only=True)
def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs): def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
qn = connection.ops.quote_name
op = is_next and '>' or '<' op = is_next and '>' or '<'
where = '(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \ where = '(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \
(backend.quote_name(field.column), op, backend.quote_name(field.column), (qn(field.column), op, qn(field.column),
backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column), op) qn(self._meta.db_table), qn(self._meta.pk.column), op)
param = smart_str(getattr(self, field.attname)) param = smart_str(getattr(self, field.attname))
q = self.__class__._default_manager.filter(**kwargs).order_by((not is_next and '-' or '') + field.name, (not is_next and '-' or '') + self._meta.pk.name) q = self.__class__._default_manager.filter(**kwargs).order_by((not is_next and '-' or '') + field.name, (not is_next and '-' or '') + self._meta.pk.name)
q._where.append(where) q._where.append(where)
@ -340,14 +342,15 @@ class Model(object):
raise self.DoesNotExist, "%s matching query does not exist." % self.__class__._meta.object_name raise self.DoesNotExist, "%s matching query does not exist." % self.__class__._meta.object_name
def _get_next_or_previous_in_order(self, is_next): def _get_next_or_previous_in_order(self, is_next):
qn = connection.ops.quote_name
cachename = "__%s_order_cache" % is_next cachename = "__%s_order_cache" % is_next
if not hasattr(self, cachename): if not hasattr(self, cachename):
op = is_next and '>' or '<' op = is_next and '>' or '<'
order_field = self._meta.order_with_respect_to order_field = self._meta.order_with_respect_to
where = ['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \ where = ['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \
(backend.quote_name('_order'), op, backend.quote_name('_order'), (qn('_order'), op, qn('_order'),
backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), qn(self._meta.db_table), qn(self._meta.pk.column)),
'%s=%%s' % backend.quote_name(order_field.column)] '%s=%%s' % qn(order_field.column)]
params = [self._get_pk_val(), getattr(self, order_field.attname)] params = [self._get_pk_val(), getattr(self, order_field.attname)]
obj = self._default_manager.order_by('_order').extra(where=where, params=params)[:1].get() obj = self._default_manager.order_by('_order').extra(where=where, params=params)[:1].get()
setattr(self, cachename, obj) setattr(self, cachename, obj)
@ -429,24 +432,26 @@ class Model(object):
# ORDERING METHODS ######################### # ORDERING METHODS #########################
def method_set_order(ordered_obj, self, id_list): def method_set_order(ordered_obj, self, id_list):
qn = connection.ops.quote_name
cursor = connection.cursor() cursor = connection.cursor()
# Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s" # Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s"
sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \ sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \
(backend.quote_name(ordered_obj._meta.db_table), backend.quote_name('_order'), (qn(ordered_obj._meta.db_table), qn('_order'),
backend.quote_name(ordered_obj._meta.order_with_respect_to.column), qn(ordered_obj._meta.order_with_respect_to.column),
backend.quote_name(ordered_obj._meta.pk.column)) qn(ordered_obj._meta.pk.column))
rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name) rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)]) cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)])
transaction.commit_unless_managed() transaction.commit_unless_managed()
def method_get_order(ordered_obj, self): def method_get_order(ordered_obj, self):
qn = connection.ops.quote_name
cursor = connection.cursor() cursor = connection.cursor()
# Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order" # Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order"
sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \ sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \
(backend.quote_name(ordered_obj._meta.pk.column), (qn(ordered_obj._meta.pk.column),
backend.quote_name(ordered_obj._meta.db_table), qn(ordered_obj._meta.db_table),
backend.quote_name(ordered_obj._meta.order_with_respect_to.column), qn(ordered_obj._meta.order_with_respect_to.column),
backend.quote_name('_order')) qn('_order'))
rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name) rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
cursor.execute(sql, [rel_val]) cursor.execute(sql, [rel_val])
return [r[0] for r in cursor.fetchall()] return [r[0] for r in cursor.fetchall()]

View File

@ -1,4 +1,4 @@
from django.db import backend, transaction from django.db import backend, connection, transaction
from django.db.models import signals, get_model from django.db.models import signals, get_model
from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class
from django.db.models.related import RelatedObject from django.db.models.related import RelatedObject
@ -319,7 +319,6 @@ def create_many_related_manager(superclass):
# source_col_name: the PK colname in join_table for the source object # source_col_name: the PK colname in join_table for the source object
# target_col_name: the PK colname in join_table for the target object # target_col_name: the PK colname in join_table for the target object
# *objs - objects to add. Either object instances, or primary keys of object instances. # *objs - objects to add. Either object instances, or primary keys of object instances.
from django.db import connection
# If there aren't any objects, there is nothing to do. # If there aren't any objects, there is nothing to do.
if objs: if objs:
@ -350,7 +349,6 @@ def create_many_related_manager(superclass):
# source_col_name: the PK colname in join_table for the source object # source_col_name: the PK colname in join_table for the source object
# target_col_name: the PK colname in join_table for the target object # target_col_name: the PK colname in join_table for the target object
# *objs - objects to remove # *objs - objects to remove
from django.db import connection
# If there aren't any objects, there is nothing to do. # If there aren't any objects, there is nothing to do.
if objs: if objs:
@ -371,7 +369,6 @@ def create_many_related_manager(superclass):
def _clear_items(self, source_col_name): def _clear_items(self, source_col_name):
# source_col_name: the PK colname in join_table for the source object # source_col_name: the PK colname in join_table for the source object
from django.db import connection
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute("DELETE FROM %s WHERE %s = %%s" % \ cursor.execute("DELETE FROM %s WHERE %s = %%s" % \
(self.join_table, source_col_name), (self.join_table, source_col_name),
@ -400,7 +397,7 @@ class ManyRelatedObjectsDescriptor(object):
superclass = rel_model._default_manager.__class__ superclass = rel_model._default_manager.__class__
RelatedManager = create_many_related_manager(superclass) RelatedManager = create_many_related_manager(superclass)
qn = backend.quote_name qn = connection.ops.quote_name
manager = RelatedManager( manager = RelatedManager(
model=rel_model, model=rel_model,
core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()}, core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()},
@ -441,7 +438,7 @@ class ReverseManyRelatedObjectsDescriptor(object):
superclass = rel_model._default_manager.__class__ superclass = rel_model._default_manager.__class__
RelatedManager = create_many_related_manager(superclass) RelatedManager = create_many_related_manager(superclass)
qn = backend.quote_name qn = connection.ops.quote_name
manager = RelatedManager( manager = RelatedManager(
model=rel_model, model=rel_model,
core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()}, core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()},

View File

@ -64,23 +64,24 @@ def orderfield2column(f, opts):
return f return f
def orderlist2sql(order_list, opts, prefix=''): def orderlist2sql(order_list, opts, prefix=''):
qn = connection.ops.quote_name
if prefix.endswith('.'): if prefix.endswith('.'):
prefix = backend.quote_name(prefix[:-1]) + '.' prefix = qn(prefix[:-1]) + '.'
output = [] output = []
for f in handle_legacy_orderlist(order_list): for f in handle_legacy_orderlist(order_list):
if f.startswith('-'): if f.startswith('-'):
output.append('%s%s DESC' % (prefix, backend.quote_name(orderfield2column(f[1:], opts)))) output.append('%s%s DESC' % (prefix, qn(orderfield2column(f[1:], opts))))
elif f == '?': elif f == '?':
output.append(connection.ops.random_function_sql()) output.append(connection.ops.random_function_sql())
else: else:
output.append('%s%s ASC' % (prefix, backend.quote_name(orderfield2column(f, opts)))) output.append('%s%s ASC' % (prefix, qn(orderfield2column(f, opts))))
return ', '.join(output) return ', '.join(output)
def quote_only_if_word(word): def quote_only_if_word(word):
if re.search('\W', word): # Don't quote if there are spaces or non-word chars. if re.search('\W', word): # Don't quote if there are spaces or non-word chars.
return word return word
else: else:
return backend.quote_name(word) return connection.ops.quote_name(word)
class _QuerySet(object): class _QuerySet(object):
"Represents a lazy database lookup for a set of objects" "Represents a lazy database lookup for a set of objects"
@ -235,8 +236,8 @@ class _QuerySet(object):
cursor = connection.cursor() cursor = connection.cursor()
if self._distinct: if self._distinct:
id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table), id_col = "%s.%s" % (connection.ops.quote_name(self.model._meta.db_table),
backend.quote_name(self.model._meta.pk.column)) connection.ops.quote_name(self.model._meta.pk.column))
cursor.execute("SELECT COUNT(DISTINCT(%s))" % id_col + sql, params) cursor.execute("SELECT COUNT(DISTINCT(%s))" % id_col + sql, params)
else: else:
cursor.execute("SELECT COUNT(*)" + sql, params) cursor.execute("SELECT COUNT(*)" + sql, params)
@ -308,11 +309,12 @@ class _QuerySet(object):
assert self._limit is None and self._offset is None, \ assert self._limit is None and self._offset is None, \
"Cannot use 'limit' or 'offset' with in_bulk" "Cannot use 'limit' or 'offset' with in_bulk"
assert isinstance(id_list, (tuple, list)), "in_bulk() must be provided with a list of IDs." assert isinstance(id_list, (tuple, list)), "in_bulk() must be provided with a list of IDs."
qn = connection.ops.quote_name
id_list = list(id_list) id_list = list(id_list)
if id_list == []: if id_list == []:
return {} return {}
qs = self._clone() qs = self._clone()
qs._where.append("%s.%s IN (%s)" % (backend.quote_name(self.model._meta.db_table), backend.quote_name(self.model._meta.pk.column), ",".join(['%s'] * len(id_list)))) qs._where.append("%s.%s IN (%s)" % (qn(self.model._meta.db_table), qn(self.model._meta.pk.column), ",".join(['%s'] * len(id_list))))
qs._params.extend(id_list) qs._params.extend(id_list)
return dict([(obj._get_pk_val(), obj) for obj in qs.iterator()]) return dict([(obj._get_pk_val(), obj) for obj in qs.iterator()])
@ -481,10 +483,11 @@ class _QuerySet(object):
return self._result_cache return self._result_cache
def _get_sql_clause(self): def _get_sql_clause(self):
qn = connection.ops.quote_name
opts = self.model._meta opts = self.model._meta
# Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields] select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields]
tables = [quote_only_if_word(t) for t in self._tables] tables = [quote_only_if_word(t) for t in self._tables]
joins = SortedDict() joins = SortedDict()
where = self._where[:] where = self._where[:]
@ -505,10 +508,10 @@ class _QuerySet(object):
# Add any additional SELECTs. # Add any additional SELECTs.
if self._select: if self._select:
select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()]) select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in self._select.items()])
# Start composing the body of the SQL statement. # Start composing the body of the SQL statement.
sql = [" FROM", backend.quote_name(opts.db_table)] sql = [" FROM", qn(opts.db_table)]
# Compose the join dictionary into SQL describing the joins. # Compose the join dictionary into SQL describing the joins.
if joins: if joins:
@ -541,15 +544,15 @@ class _QuerySet(object):
order = "ASC" order = "ASC"
if "." in col_name: if "." in col_name:
table_prefix, col_name = col_name.split('.', 1) table_prefix, col_name = col_name.split('.', 1)
table_prefix = backend.quote_name(table_prefix) + '.' table_prefix = qn(table_prefix) + '.'
else: else:
# Use the database table as a column prefix if it wasn't given, # Use the database table as a column prefix if it wasn't given,
# and if the requested column isn't a custom SELECT. # and if the requested column isn't a custom SELECT.
if "." not in col_name and col_name not in (self._select or ()): if "." not in col_name and col_name not in (self._select or ()):
table_prefix = backend.quote_name(opts.db_table) + '.' table_prefix = qn(opts.db_table) + '.'
else: else:
table_prefix = '' table_prefix = ''
order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order)) order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order))
if order_by: if order_by:
sql.append("ORDER BY " + ", ".join(order_by)) sql.append("ORDER BY " + ", ".join(order_by))
@ -579,6 +582,8 @@ class ValuesQuerySet(QuerySet):
except EmptyResultSet: except EmptyResultSet:
raise StopIteration raise StopIteration
qn = connection.ops.quote_name
# self._select is a dictionary, and dictionaries' key order is # self._select is a dictionary, and dictionaries' key order is
# undefined, so we convert it to a list of tuples. # undefined, so we convert it to a list of tuples.
extra_select = self._select.items() extra_select = self._select.items()
@ -605,9 +610,9 @@ class ValuesQuerySet(QuerySet):
field_names = [f.attname for f in fields] field_names = [f.attname for f in fields]
columns = [f.column for f in fields] columns = [f.column for f in fields]
select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns] select = ['%s.%s' % (qn(self.model._meta.db_table), qn(c)) for c in columns]
if extra_select: if extra_select:
select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in extra_select]) select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in extra_select])
field_names.extend([f[0] for f in extra_select]) field_names.extend([f[0] for f in extra_select])
cursor = connection.cursor() cursor = connection.cursor()
@ -632,17 +637,19 @@ class DateQuerySet(QuerySet):
def iterator(self): def iterator(self):
from django.db.backends.util import typecast_timestamp from django.db.backends.util import typecast_timestamp
from django.db.models.fields import DateTimeField from django.db.models.fields import DateTimeField
qn = connection.ops.quote_name
self._order_by = () # Clear this because it'll mess things up otherwise. self._order_by = () # Clear this because it'll mess things up otherwise.
if self._field.null: if self._field.null:
self._where.append('%s.%s IS NOT NULL' % \ self._where.append('%s.%s IS NOT NULL' % \
(backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column))) (qn(self.model._meta.db_table), qn(self._field.column)))
try: try:
select, sql, params = self._get_sql_clause() select, sql, params = self._get_sql_clause()
except EmptyResultSet: except EmptyResultSet:
raise StopIteration raise StopIteration
table_name = backend.quote_name(self.model._meta.db_table) table_name = qn(self.model._meta.db_table)
field_name = backend.quote_name(self._field.column) field_name = qn(self._field.column)
if backend.allows_group_by_ordinal: if backend.allows_group_by_ordinal:
group_by = '1' group_by = '1'
@ -650,8 +657,8 @@ class DateQuerySet(QuerySet):
group_by = connection.ops.date_trunc_sql(self._kind, '%s.%s' % (table_name, field_name)) group_by = connection.ops.date_trunc_sql(self._kind, '%s.%s' % (table_name, field_name))
sql = 'SELECT %s %s GROUP BY %s ORDER BY 1 %s' % \ sql = 'SELECT %s %s GROUP BY %s ORDER BY 1 %s' % \
(connection.ops.date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table), (connection.ops.date_trunc_sql(self._kind, '%s.%s' % (qn(self.model._meta.db_table),
backend.quote_name(self._field.column))), sql, group_by, self._order) qn(self._field.column))), sql, group_by, self._order)
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute(sql, params) cursor.execute(sql, params)
@ -778,8 +785,8 @@ class QNot(Q):
def get_where_clause(lookup_type, table_prefix, field_name, value, db_type): def get_where_clause(lookup_type, table_prefix, field_name, value, db_type):
if table_prefix.endswith('.'): if table_prefix.endswith('.'):
table_prefix = backend.quote_name(table_prefix[:-1])+'.' table_prefix = connection.ops.quote_name(table_prefix[:-1])+'.'
field_name = backend.quote_name(field_name) field_name = connection.ops.quote_name(field_name)
if type(value) == datetime.datetime and connection.ops.datetime_cast_sql(): if type(value) == datetime.datetime and connection.ops.datetime_cast_sql():
cast_sql = connection.ops.datetime_cast_sql() cast_sql = connection.ops.datetime_cast_sql()
else: else:
@ -849,7 +856,7 @@ def fill_table_cache(opts, select, tables, where, old_prefix, cache_tables_seen,
if max_depth and cur_depth > max_depth: if max_depth and cur_depth > max_depth:
return None return None
qn = backend.quote_name qn = connection.ops.quote_name
for f in opts.fields: for f in opts.fields:
if f.rel and not f.null: if f.rel and not f.null:
db_table = f.rel.to._meta.db_table db_table = f.rel.to._meta.db_table
@ -947,7 +954,7 @@ def field_choices(field_list, related_query):
return choices return choices
def lookup_inner(path, lookup_type, value, opts, table, column): def lookup_inner(path, lookup_type, value, opts, table, column):
qn = backend.quote_name qn = connection.ops.quote_name
joins, where, params = SortedDict(), [], [] joins, where, params = SortedDict(), [], []
current_opts = opts current_opts = opts
current_table = table current_table = table
@ -1113,7 +1120,7 @@ def lookup_inner(path, lookup_type, value, opts, table, column):
def delete_objects(seen_objs): def delete_objects(seen_objs):
"Iterate through a list of seen classes, and remove any instances that are referred to" "Iterate through a list of seen classes, and remove any instances that are referred to"
qn = backend.quote_name qn = connection.ops.quote_name
ordered_classes = seen_objs.keys() ordered_classes = seen_objs.keys()
ordered_classes.reverse() ordered_classes.reverse()

View File

@ -118,13 +118,15 @@ def create_test_db(verbosity=1, autoclobber=False):
else: else:
TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
qn = connection.ops.quote_name
# Create the test database and connect to it. We need to autocommit # Create the test database and connect to it. We need to autocommit
# if the database supports it because PostgreSQL doesn't allow # if the database supports it because PostgreSQL doesn't allow
# CREATE/DROP DATABASE statements within transactions. # CREATE/DROP DATABASE statements within transactions.
cursor = connection.cursor() cursor = connection.cursor()
_set_autocommit(connection) _set_autocommit(connection)
try: try:
cursor.execute("CREATE DATABASE %s %s" % (backend.quote_name(TEST_DATABASE_NAME), suffix)) cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))
except Exception, e: except Exception, e:
sys.stderr.write("Got an error creating the test database: %s\n" % e) sys.stderr.write("Got an error creating the test database: %s\n" % e)
if not autoclobber: if not autoclobber:
@ -133,10 +135,10 @@ def create_test_db(verbosity=1, autoclobber=False):
try: try:
if verbosity >= 1: if verbosity >= 1:
print "Destroying old test database..." print "Destroying old test database..."
cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)) cursor.execute("DROP DATABASE %s" % qn(TEST_DATABASE_NAME))
if verbosity >= 1: if verbosity >= 1:
print "Creating test database..." print "Creating test database..."
cursor.execute("CREATE DATABASE %s %s" % (backend.quote_name(TEST_DATABASE_NAME), suffix)) cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))
except Exception, e: except Exception, e:
sys.stderr.write("Got an error recreating the test database: %s\n" % e) sys.stderr.write("Got an error recreating the test database: %s\n" % e)
sys.exit(2) sys.exit(2)
@ -180,5 +182,5 @@ def destroy_test_db(old_database_name, verbosity=1):
cursor = connection.cursor() cursor = connection.cursor()
_set_autocommit(connection) _set_autocommit(connection)
time.sleep(1) # To avoid "database is being accessed by other users" errors. time.sleep(1) # To avoid "database is being accessed by other users" errors.
cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)) cursor.execute("DROP DATABASE %s" % connection.ops.quote_name(TEST_DATABASE_NAME))
connection.close() connection.close()