App Engine Python SDK version 1.7.4 (2)
[gae.git] / python / lib / django_1_4 / django / db / backends / creation.py
blob0cd055866a3fea6ee03c03511a4125dfe5c6c9ad
1 import sys
2 import time
4 from django.conf import settings
5 from django.db.utils import load_backend
7 # The prefix to put on the default database name when creating
8 # the test database.
9 TEST_DATABASE_PREFIX = 'test_'
12 class BaseDatabaseCreation(object):
13 """
14 This class encapsulates all backend-specific differences that pertain to
15 database *creation*, such as the column types to use for particular Django
16 Fields, the SQL used to create and destroy tables, and the creation and
17 destruction of test databases.
18 """
19 data_types = {}
21 def __init__(self, connection):
22 self.connection = connection
24 def _digest(self, *args):
25 """
26 Generates a 32-bit digest of a set of arguments that can be used to
27 shorten identifying names.
28 """
29 return '%x' % (abs(hash(args)) % 4294967296L) # 2**32
31 def sql_create_model(self, model, style, known_models=set()):
32 """
33 Returns the SQL required to create a single model, as a tuple of:
34 (list_of_sql, pending_references_dict)
35 """
36 opts = model._meta
37 if not opts.managed or opts.proxy:
38 return [], {}
39 final_output = []
40 table_output = []
41 pending_references = {}
42 qn = self.connection.ops.quote_name
43 for f in opts.local_fields:
44 col_type = f.db_type(connection=self.connection)
45 tablespace = f.db_tablespace or opts.db_tablespace
46 if col_type is None:
47 # Skip ManyToManyFields, because they're not represented as
48 # database columns in this table.
49 continue
50 # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
51 field_output = [style.SQL_FIELD(qn(f.column)),
52 style.SQL_COLTYPE(col_type)]
53 if not f.null:
54 field_output.append(style.SQL_KEYWORD('NOT NULL'))
55 if f.primary_key:
56 field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
57 elif f.unique:
58 field_output.append(style.SQL_KEYWORD('UNIQUE'))
59 if tablespace and f.unique:
60 # We must specify the index tablespace inline, because we
61 # won't be generating a CREATE INDEX statement for this field.
62 tablespace_sql = self.connection.ops.tablespace_sql(
63 tablespace, inline=True)
64 if tablespace_sql:
65 field_output.append(tablespace_sql)
66 if f.rel:
67 ref_output, pending = self.sql_for_inline_foreign_key_references(
68 f, known_models, style)
69 if pending:
70 pending_references.setdefault(f.rel.to, []).append(
71 (model, f))
72 else:
73 field_output.extend(ref_output)
74 table_output.append(' '.join(field_output))
75 for field_constraints in opts.unique_together:
76 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' %
77 ", ".join(
78 [style.SQL_FIELD(qn(opts.get_field(f).column))
79 for f in field_constraints]))
81 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' +
82 style.SQL_TABLE(qn(opts.db_table)) + ' (']
83 for i, line in enumerate(table_output): # Combine and add commas.
84 full_statement.append(
85 ' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
86 full_statement.append(')')
87 if opts.db_tablespace:
88 tablespace_sql = self.connection.ops.tablespace_sql(
89 opts.db_tablespace)
90 if tablespace_sql:
91 full_statement.append(tablespace_sql)
92 full_statement.append(';')
93 final_output.append('\n'.join(full_statement))
95 if opts.has_auto_field:
96 # Add any extra SQL needed to support auto-incrementing primary
97 # keys.
98 auto_column = opts.auto_field.db_column or opts.auto_field.name
99 autoinc_sql = self.connection.ops.autoinc_sql(opts.db_table,
100 auto_column)
101 if autoinc_sql:
102 for stmt in autoinc_sql:
103 final_output.append(stmt)
105 return final_output, pending_references
107 def sql_for_inline_foreign_key_references(self, field, known_models, style):
109 Return the SQL snippet defining the foreign key reference for a field.
111 qn = self.connection.ops.quote_name
112 if field.rel.to in known_models:
113 output = [style.SQL_KEYWORD('REFERENCES') + ' ' +
114 style.SQL_TABLE(qn(field.rel.to._meta.db_table)) + ' (' +
115 style.SQL_FIELD(qn(field.rel.to._meta.get_field(
116 field.rel.field_name).column)) + ')' +
117 self.connection.ops.deferrable_sql()
119 pending = False
120 else:
121 # We haven't yet created the table to which this field
122 # is related, so save it for later.
123 output = []
124 pending = True
126 return output, pending
128 def sql_for_pending_references(self, model, style, pending_references):
130 Returns any ALTER TABLE statements to add constraints after the fact.
132 from django.db.backends.util import truncate_name
134 if not model._meta.managed or model._meta.proxy:
135 return []
136 qn = self.connection.ops.quote_name
137 final_output = []
138 opts = model._meta
139 if model in pending_references:
140 for rel_class, f in pending_references[model]:
141 rel_opts = rel_class._meta
142 r_table = rel_opts.db_table
143 r_col = f.column
144 table = opts.db_table
145 col = opts.get_field(f.rel.field_name).column
146 # For MySQL, r_name must be unique in the first 64 characters.
147 # So we are careful with character usage here.
148 r_name = '%s_refs_%s_%s' % (
149 r_col, col, self._digest(r_table, table))
150 final_output.append(style.SQL_KEYWORD('ALTER TABLE') +
151 ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %
152 (qn(r_table), qn(truncate_name(
153 r_name, self.connection.ops.max_name_length())),
154 qn(r_col), qn(table), qn(col),
155 self.connection.ops.deferrable_sql()))
156 del pending_references[model]
157 return final_output
159 def sql_indexes_for_model(self, model, style):
161 Returns the CREATE INDEX SQL statements for a single model.
163 if not model._meta.managed or model._meta.proxy:
164 return []
165 output = []
166 for f in model._meta.local_fields:
167 output.extend(self.sql_indexes_for_field(model, f, style))
168 return output
170 def sql_indexes_for_field(self, model, f, style):
172 Return the CREATE INDEX SQL statements for a single model field.
174 from django.db.backends.util import truncate_name
176 if f.db_index and not f.unique:
177 qn = self.connection.ops.quote_name
178 tablespace = f.db_tablespace or model._meta.db_tablespace
179 if tablespace:
180 tablespace_sql = self.connection.ops.tablespace_sql(tablespace)
181 if tablespace_sql:
182 tablespace_sql = ' ' + tablespace_sql
183 else:
184 tablespace_sql = ''
185 i_name = '%s_%s' % (model._meta.db_table, self._digest(f.column))
186 output = [style.SQL_KEYWORD('CREATE INDEX') + ' ' +
187 style.SQL_TABLE(qn(truncate_name(
188 i_name, self.connection.ops.max_name_length()))) + ' ' +
189 style.SQL_KEYWORD('ON') + ' ' +
190 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' +
191 "(%s)" % style.SQL_FIELD(qn(f.column)) +
192 "%s;" % tablespace_sql]
193 else:
194 output = []
195 return output
197 def sql_destroy_model(self, model, references_to_delete, style):
199 Return the DROP TABLE and restraint dropping statements for a single
200 model.
202 if not model._meta.managed or model._meta.proxy:
203 return []
204 # Drop the table now
205 qn = self.connection.ops.quote_name
206 output = ['%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
207 style.SQL_TABLE(qn(model._meta.db_table)))]
208 if model in references_to_delete:
209 output.extend(self.sql_remove_table_constraints(
210 model, references_to_delete, style))
211 if model._meta.has_auto_field:
212 ds = self.connection.ops.drop_sequence_sql(model._meta.db_table)
213 if ds:
214 output.append(ds)
215 return output
217 def sql_remove_table_constraints(self, model, references_to_delete, style):
218 from django.db.backends.util import truncate_name
219 if not model._meta.managed or model._meta.proxy:
220 return []
221 output = []
222 qn = self.connection.ops.quote_name
223 for rel_class, f in references_to_delete[model]:
224 table = rel_class._meta.db_table
225 col = f.column
226 r_table = model._meta.db_table
227 r_col = model._meta.get_field(f.rel.field_name).column
228 r_name = '%s_refs_%s_%s' % (
229 col, r_col, self._digest(table, r_table))
230 output.append('%s %s %s %s;' % \
231 (style.SQL_KEYWORD('ALTER TABLE'),
232 style.SQL_TABLE(qn(table)),
233 style.SQL_KEYWORD(self.connection.ops.drop_foreignkey_sql()),
234 style.SQL_FIELD(qn(truncate_name(
235 r_name, self.connection.ops.max_name_length())))))
236 del references_to_delete[model]
237 return output
239 def create_test_db(self, verbosity=1, autoclobber=False):
241 Creates a test database, prompting the user for confirmation if the
242 database already exists. Returns the name of the test database created.
244 # Don't import django.core.management if it isn't needed.
245 from django.core.management import call_command
247 test_database_name = self._get_test_db_name()
249 if verbosity >= 1:
250 test_db_repr = ''
251 if verbosity >= 2:
252 test_db_repr = " ('%s')" % test_database_name
253 print "Creating test database for alias '%s'%s..." % (
254 self.connection.alias, test_db_repr)
256 self._create_test_db(verbosity, autoclobber)
258 self.connection.close()
259 self.connection.settings_dict["NAME"] = test_database_name
261 # Confirm the feature set of the test database
262 self.connection.features.confirm()
264 # Report syncdb messages at one level lower than that requested.
265 # This ensures we don't get flooded with messages during testing
266 # (unless you really ask to be flooded)
267 call_command('syncdb',
268 verbosity=max(verbosity - 1, 0),
269 interactive=False,
270 database=self.connection.alias,
271 load_initial_data=False)
273 # We need to then do a flush to ensure that any data installed by
274 # custom SQL has been removed. The only test data should come from
275 # test fixtures, or autogenerated from post_syncdb triggers.
276 # This has the side effect of loading initial data (which was
277 # intentionally skipped in the syncdb).
278 call_command('flush',
279 verbosity=max(verbosity - 1, 0),
280 interactive=False,
281 database=self.connection.alias)
283 from django.core.cache import get_cache
284 from django.core.cache.backends.db import BaseDatabaseCache
285 for cache_alias in settings.CACHES:
286 cache = get_cache(cache_alias)
287 if isinstance(cache, BaseDatabaseCache):
288 call_command('createcachetable', cache._table,
289 database=self.connection.alias)
291 # Get a cursor (even though we don't need one yet). This has
292 # the side effect of initializing the test database.
293 self.connection.cursor()
295 return test_database_name
297 def _get_test_db_name(self):
299 Internal implementation - returns the name of the test DB that will be
300 created. Only useful when called from create_test_db() and
301 _create_test_db() and when no external munging is done with the 'NAME'
302 or 'TEST_NAME' settings.
304 if self.connection.settings_dict['TEST_NAME']:
305 return self.connection.settings_dict['TEST_NAME']
306 return TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME']
308 def _create_test_db(self, verbosity, autoclobber):
310 Internal implementation - creates the test db tables.
312 suffix = self.sql_table_creation_suffix()
314 test_database_name = self._get_test_db_name()
316 qn = self.connection.ops.quote_name
318 # Create the test database and connect to it. We need to autocommit
319 # if the database supports it because PostgreSQL doesn't allow
320 # CREATE/DROP DATABASE statements within transactions.
321 cursor = self.connection.cursor()
322 self._prepare_for_test_db_ddl()
323 try:
324 cursor.execute(
325 "CREATE DATABASE %s %s" % (qn(test_database_name), suffix))
326 except Exception, e:
327 sys.stderr.write(
328 "Got an error creating the test database: %s\n" % e)
329 if not autoclobber:
330 confirm = raw_input(
331 "Type 'yes' if you would like to try deleting the test "
332 "database '%s', or 'no' to cancel: " % test_database_name)
333 if autoclobber or confirm == 'yes':
334 try:
335 if verbosity >= 1:
336 print ("Destroying old test database '%s'..."
337 % self.connection.alias)
338 cursor.execute(
339 "DROP DATABASE %s" % qn(test_database_name))
340 cursor.execute(
341 "CREATE DATABASE %s %s" % (qn(test_database_name),
342 suffix))
343 except Exception, e:
344 sys.stderr.write(
345 "Got an error recreating the test database: %s\n" % e)
346 sys.exit(2)
347 else:
348 print "Tests cancelled."
349 sys.exit(1)
351 return test_database_name
353 def destroy_test_db(self, old_database_name, verbosity=1):
355 Destroy a test database, prompting the user for confirmation if the
356 database already exists.
358 self.connection.close()
359 test_database_name = self.connection.settings_dict['NAME']
360 if verbosity >= 1:
361 test_db_repr = ''
362 if verbosity >= 2:
363 test_db_repr = " ('%s')" % test_database_name
364 print "Destroying test database for alias '%s'%s..." % (
365 self.connection.alias, test_db_repr)
367 # Temporarily use a new connection and a copy of the settings dict.
368 # This prevents the production database from being exposed to potential
369 # child threads while (or after) the test database is destroyed.
370 # Refs #10868 and #17786.
371 settings_dict = self.connection.settings_dict.copy()
372 settings_dict['NAME'] = old_database_name
373 backend = load_backend(settings_dict['ENGINE'])
374 new_connection = backend.DatabaseWrapper(
375 settings_dict,
376 alias='__destroy_test_db__',
377 allow_thread_sharing=False)
378 new_connection.creation._destroy_test_db(test_database_name, verbosity)
380 def _destroy_test_db(self, test_database_name, verbosity):
382 Internal implementation - remove the test db tables.
384 # Remove the test database to clean up after
385 # ourselves. Connect to the previous database (not the test database)
386 # to do so, because it's not allowed to delete a database while being
387 # connected to it.
388 cursor = self.connection.cursor()
389 self._prepare_for_test_db_ddl()
390 # Wait to avoid "database is being accessed by other users" errors.
391 time.sleep(1)
392 cursor.execute("DROP DATABASE %s"
393 % self.connection.ops.quote_name(test_database_name))
394 self.connection.close()
396 def set_autocommit(self):
398 Make sure a connection is in autocommit mode. - Deprecated, not used
399 anymore by Django code. Kept for compatibility with user code that
400 might use it.
402 pass
404 def _prepare_for_test_db_ddl(self):
406 Internal implementation - Hook for tasks that should be performed
407 before the ``CREATE DATABASE``/``DROP DATABASE`` clauses used by
408 testing code to create/ destroy test databases. Needed e.g. in
409 PostgreSQL to rollback and close any active transaction.
411 pass
413 def sql_table_creation_suffix(self):
415 SQL to append to the end of the test table creation statements.
417 return ''
419 def test_db_signature(self):
421 Returns a tuple with elements of self.connection.settings_dict (a
422 DATABASES setting value) that uniquely identify a database
423 accordingly to the RDBMS particularities.
425 settings_dict = self.connection.settings_dict
426 return (
427 settings_dict['HOST'],
428 settings_dict['PORT'],
429 settings_dict['ENGINE'],
430 settings_dict['NAME']