Skip to content

Commit

Permalink
Merged boulder-oracle-sprint branch (r3965:5512) back into trunk. All
Browse files Browse the repository at this point in the history
expected tests pass for all databases.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@5519 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
malcolmt committed Jun 23, 2007
1 parent 553a200 commit ac64e91
Show file tree
Hide file tree
Showing 28 changed files with 1,239 additions and 172 deletions.
2 changes: 1 addition & 1 deletion django/contrib/admin/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class LogEntryManager(models.Manager):
def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
e = self.model(None, None, user_id, content_type_id, object_id, object_repr[:200], action_flag, change_message)
e = self.model(None, None, user_id, content_type_id, str(object_id), object_repr[:200], action_flag, change_message)
e.save()

class LogEntry(models.Model):
Expand Down
112 changes: 87 additions & 25 deletions django/core/management.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,16 @@ def _is_valid_dir_name(s):

def _get_installed_models(table_list):
"Gets a set of all models that are installed, given a list of existing tables"
from django.db import models
from django.db import backend, models
all_models = []
for app in models.get_apps():
for model in models.get_models(app):
all_models.append(model)
return set([m for m in all_models if m._meta.db_table in table_list])
if backend.uses_case_insensitive_names:
converter = str.upper
else:
converter = lambda x: x
return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])

def _get_table_list():
"Gets a list of all db tables that are physically installed."
Expand Down Expand Up @@ -100,6 +104,7 @@ def _get_sequence_list():
def get_sql_create(app):
"Returns a list of the CREATE TABLE SQL statements for the given app."
from django.db import get_creation_module, models

data_types = get_creation_module().DATA_TYPES

if not data_types:
Expand Down Expand Up @@ -171,15 +176,20 @@ def _get_sql_model_create(model, known_models=set()):
rel_field = f
data_type = f.get_internal_type()
col_type = data_types[data_type]
tablespace = f.db_tablespace or opts.db_tablespace
if col_type is not None:
# Make the definition (e.g. 'foo VARCHAR(30)') for this field.
field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
style.SQL_COLTYPE(col_type % rel_field.__dict__)]
field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
if f.unique:
if f.unique and (not f.primary_key or backend.allows_unique_and_pk):
field_output.append(style.SQL_KEYWORD('UNIQUE'))
if f.primary_key:
field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys:
# We must specify the index tablespace inline, because we
# won't be generating a CREATE INDEX statement for this field.
field_output.append(backend.get_tablespace_sql(tablespace, inline=True))
if f.rel:
if f.rel.to in known_models:
field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
Expand All @@ -203,16 +213,27 @@ def _get_sql_model_create(model, known_models=set()):
full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(backend.quote_name(opts.db_table)) + ' (']
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(');')
full_statement.append(')')
if opts.db_tablespace and backend.supports_tablespaces:
full_statement.append(backend.get_tablespace_sql(opts.db_tablespace))
full_statement.append(';')
final_output.append('\n'.join(full_statement))

if opts.has_auto_field and hasattr(backend, 'get_autoinc_sql'):
# Add any extra SQL needed to support auto-incrementing primary keys
autoinc_sql = backend.get_autoinc_sql(opts.db_table)
if autoinc_sql:
for stmt in autoinc_sql:
final_output.append(stmt)

return final_output, pending_references

def _get_sql_for_pending_references(model, pending_references):
"""
Get any ALTER TABLE statements to add constraints after the fact.
"""
from django.db import backend, get_creation_module
from django.db.backends.util import truncate_name
data_types = get_creation_module().DATA_TYPES

final_output = []
Expand All @@ -229,7 +250,7 @@ def _get_sql_for_pending_references(model, pending_references):
# So we are careful with character usage here.
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;' % \
(backend.quote_name(r_table), r_name,
(backend.quote_name(r_table), truncate_name(r_name, backend.get_max_name_length()),
backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col),
backend.get_deferrable_sql()))
del pending_references[model]
Expand All @@ -245,12 +266,18 @@ def _get_many_to_many_sql_for_model(model):
final_output = []
for f in opts.many_to_many:
if not isinstance(f.rel, generic.GenericRel):
tablespace = f.db_tablespace or opts.db_tablespace
if tablespace and backend.supports_tablespaces and backend.autoindexes_primary_keys:
tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace, inline=True)
else:
tablespace_sql = ''
table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
table_output.append(' %s %s %s,' % \
table_output.append(' %s %s %s%s,' % \
(style.SQL_FIELD(backend.quote_name('id')),
style.SQL_COLTYPE(data_types['AutoField']),
style.SQL_KEYWORD('NOT NULL PRIMARY KEY')))
style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
tablespace_sql))
table_output.append(' %s %s %s %s (%s)%s,' % \
(style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
style.SQL_COLTYPE(data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__),
Expand All @@ -265,17 +292,30 @@ def _get_many_to_many_sql_for_model(model):
style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)),
backend.get_deferrable_sql()))
table_output.append(' %s (%s, %s)' % \
table_output.append(' %s (%s, %s)%s' % \
(style.SQL_KEYWORD('UNIQUE'),
style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name()))))
table_output.append(');')
style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
tablespace_sql))
table_output.append(')')
if opts.db_tablespace and backend.supports_tablespaces:
# f.db_tablespace is only for indices, so ignore its value here.
table_output.append(backend.get_tablespace_sql(opts.db_tablespace))
table_output.append(';')
final_output.append('\n'.join(table_output))

# Add any extra SQL needed to support auto-incrementing PKs
autoinc_sql = backend.get_autoinc_sql(f.m2m_db_table())
if autoinc_sql:
for stmt in autoinc_sql:
final_output.append(stmt)

return final_output

def get_sql_delete(app):
"Returns a list of the DROP TABLE SQL statements for the given app."
from django.db import backend, connection, models, get_introspection_module
from django.db.backends.util import truncate_name
introspection = get_introspection_module()

# This should work even if a connection isn't available
Expand All @@ -289,6 +329,10 @@ def get_sql_delete(app):
table_names = introspection.get_table_list(cursor)
else:
table_names = []
if backend.uses_case_insensitive_names:
table_name_converter = str.upper
else:
table_name_converter = lambda x: x

output = []

Expand All @@ -298,7 +342,7 @@ def get_sql_delete(app):
references_to_delete = {}
app_models = models.get_models(app)
for model in app_models:
if cursor and model._meta.db_table in table_names:
if cursor and table_name_converter(model._meta.db_table) in table_names:
# The table exists, so it needs to be dropped
opts = model._meta
for f in opts.fields:
Expand All @@ -308,7 +352,7 @@ def get_sql_delete(app):
to_delete.add(model)

for model in app_models:
if cursor and model._meta.db_table in table_names:
if cursor and table_name_converter(model._meta.db_table) in table_names:
# Drop the table now
output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
style.SQL_TABLE(backend.quote_name(model._meta.db_table))))
Expand All @@ -318,20 +362,26 @@ def get_sql_delete(app):
col = f.column
r_table = model._meta.db_table
r_col = model._meta.get_field(f.rel.field_name).column
r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
output.append('%s %s %s %s;' % \
(style.SQL_KEYWORD('ALTER TABLE'),
style.SQL_TABLE(backend.quote_name(table)),
style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()),
style.SQL_FIELD(backend.quote_name('%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))))))
style.SQL_FIELD(truncate_name(r_name, backend.get_max_name_length()))))
del references_to_delete[model]
if model._meta.has_auto_field and hasattr(backend, 'get_drop_sequence'):
output.append(backend.get_drop_sequence(model._meta.db_table))

# Output DROP TABLE statements for many-to-many tables.
for model in app_models:
opts = model._meta
for f in opts.many_to_many:
if cursor and 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'),
style.SQL_TABLE(backend.quote_name(f.m2m_db_table()))))
if hasattr(backend, 'get_drop_sequence'):
output.append(backend.get_drop_sequence("%s_%s" % (model._meta.db_table, f.column)))


app_label = app_models[0]._meta.app_label

Expand Down Expand Up @@ -430,14 +480,20 @@ def get_sql_indexes_for_model(model):
output = []

for f in model._meta.fields:
if f.db_index:
if f.db_index and not ((f.primary_key or f.unique) and backend.autoindexes_primary_keys):
unique = f.unique and 'UNIQUE ' or ''
tablespace = f.db_tablespace or model._meta.db_tablespace
if tablespace and backend.supports_tablespaces:
tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace)
else:
tablespace_sql = ''
output.append(
style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
style.SQL_KEYWORD('ON') + ' ' + \
style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
"(%s);" % style.SQL_FIELD(backend.quote_name(f.column))
"(%s)" % style.SQL_FIELD(backend.quote_name(f.column)) + \
"%s;" % tablespace_sql
)
return output

Expand All @@ -461,7 +517,7 @@ def _emit_post_sync_signal(created_models, verbosity, interactive):

def syncdb(verbosity=1, interactive=True):
"Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
from django.db import connection, transaction, models, get_creation_module
from django.db import backend, connection, transaction, models, get_creation_module
from django.conf import settings

disable_termcolors()
Expand All @@ -484,6 +540,10 @@ def syncdb(verbosity=1, interactive=True):
# Get a list of all existing database tables,
# so we know what needs to be added.
table_list = _get_table_list()
if backend.uses_case_insensitive_names:
table_name_converter = str.upper
else:
table_name_converter = lambda x: x

# Get a list of already installed *models* so that references work right.
seen_models = _get_installed_models(table_list)
Expand All @@ -498,7 +558,7 @@ def syncdb(verbosity=1, interactive=True):
# Create the model's database table, if it doesn't already exist.
if verbosity >= 2:
print "Processing %s.%s model" % (app_name, model._meta.object_name)
if model._meta.db_table in table_list:
if table_name_converter(model._meta.db_table) in table_list:
continue
sql, references = _get_sql_model_create(model, seen_models)
seen_models.add(model)
Expand All @@ -510,7 +570,7 @@ def syncdb(verbosity=1, interactive=True):
print "Creating table %s" % model._meta.db_table
for statement in sql:
cursor.execute(statement)
table_list.append(model._meta.db_table)
table_list.append(table_name_converter(model._meta.db_table))

# Create the m2m tables. This must be done after all tables have been created
# to ensure that all referred tables will exist.
Expand Down Expand Up @@ -829,7 +889,7 @@ def inspectdb():
except NotImplementedError:
indexes = {}
for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)):
att_name = row[0]
att_name = row[0].lower()
comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
extra_params = {} # Holds Field parameters such as 'db_column'.

Expand Down Expand Up @@ -1322,7 +1382,7 @@ def load_data(fixture_labels, verbosity=1):
# Keep a count of the installed objects and fixtures
count = [0,0]
models = set()

humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'

# Get a cursor (even though we don't need one yet). This has
Expand Down Expand Up @@ -1400,18 +1460,18 @@ def load_data(fixture_labels, verbosity=1):
if verbosity > 1:
print "No %s fixture '%s' in %s." % \
(format, fixture_name, humanize(fixture_dir))

if count[0] > 0:
sequence_sql = backend.get_sql_sequence_reset(style, models)
if sequence_sql:
if verbosity > 1:
print "Resetting sequences"
for line in sequence_sql:
cursor.execute(line)

transaction.commit()
transaction.leave_transaction_management()

if count[0] == 0:
if verbosity > 0:
print "No fixtures found."
Expand Down Expand Up @@ -1626,7 +1686,9 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
if not mod_list:
parser.print_usage_and_exit()
if action not in NO_SQL_TRANSACTION:
print style.SQL_KEYWORD("BEGIN;")
from django.db import backend
if backend.get_start_transaction_sql():
print style.SQL_KEYWORD(backend.get_start_transaction_sql())
for mod in mod_list:
if action == 'reset':
output = action_mapping[action](mod, options.interactive)
Expand Down
22 changes: 22 additions & 0 deletions django/db/backends/ado_mssql/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,14 @@ def close(self):
self.connection.close()
self.connection = None

allows_group_by_ordinal = True
allows_unique_and_pk = True
autoindexes_primary_keys = True
needs_datetime_string_cast = True
needs_upper_for_iops = False
supports_constraints = True
supports_tablespaces = True
uses_case_insensitive_names = False

def quote_name(name):
if name.startswith('[') and name.endswith(']'):
Expand Down Expand Up @@ -117,6 +124,9 @@ def get_date_trunc_sql(lookup_type, field_name):
if lookup_type=='day':
return "Convert(datetime, Convert(varchar(12), %s))" % field_name

def get_datetime_cast_sql():
return None

def get_limit_offset_sql(limit, offset=None):
# TODO: This is a guess. Make sure this is correct.
sql = "LIMIT %s" % limit
Expand All @@ -139,6 +149,18 @@ def get_drop_foreignkey_sql():
def get_pk_default_value():
return "DEFAULT"

def get_max_name_length():
return None

def get_start_transaction_sql():
return "BEGIN;"

def get_tablespace_sql(tablespace, inline=False):
return "ON %s" % quote_name(tablespace)

def get_autoinc_sql(table):
return None

def get_sql_flush(style, tables, sequences):
"""Return a list of SQL statements required to remove all data from
all tables in the database (without actually removing the tables
Expand Down
1 change: 1 addition & 0 deletions django/db/backends/dummy/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def close(self):
pass # close()

supports_constraints = False
supports_tablespaces = False
quote_name = complain
dictfetchone = complain
dictfetchmany = complain
Expand Down
Loading

0 comments on commit ac64e91

Please sign in to comment.