You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

creation.py 3.0KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import subprocess
  2. import sys
  3. from django.db.backends.base.creation import BaseDatabaseCreation
  4. from .client import DatabaseClient
  5. class DatabaseCreation(BaseDatabaseCreation):
  6. def sql_table_creation_suffix(self):
  7. suffix = []
  8. test_settings = self.connection.settings_dict['TEST']
  9. if test_settings['CHARSET']:
  10. suffix.append('CHARACTER SET %s' % test_settings['CHARSET'])
  11. if test_settings['COLLATION']:
  12. suffix.append('COLLATE %s' % test_settings['COLLATION'])
  13. return ' '.join(suffix)
  14. def _execute_create_test_db(self, cursor, parameters, keepdb=False):
  15. try:
  16. super()._execute_create_test_db(cursor, parameters, keepdb)
  17. except Exception as e:
  18. if len(e.args) < 1 or e.args[0] != 1007:
  19. # All errors except "database exists" (1007) cancel tests.
  20. self.log('Got an error creating the test database: %s' % e)
  21. sys.exit(2)
  22. else:
  23. raise e
  24. def _clone_test_db(self, suffix, verbosity, keepdb=False):
  25. source_database_name = self.connection.settings_dict['NAME']
  26. target_database_name = self.get_test_db_clone_settings(suffix)['NAME']
  27. test_db_params = {
  28. 'dbname': self.connection.ops.quote_name(target_database_name),
  29. 'suffix': self.sql_table_creation_suffix(),
  30. }
  31. with self._nodb_connection.cursor() as cursor:
  32. try:
  33. self._execute_create_test_db(cursor, test_db_params, keepdb)
  34. except Exception:
  35. if keepdb:
  36. # If the database should be kept, skip everything else.
  37. return
  38. try:
  39. if verbosity >= 1:
  40. self.log('Destroying old test database for alias %s...' % (
  41. self._get_database_display_str(verbosity, target_database_name),
  42. ))
  43. cursor.execute('DROP DATABASE %(dbname)s' % test_db_params)
  44. self._execute_create_test_db(cursor, test_db_params, keepdb)
  45. except Exception as e:
  46. self.log('Got an error recreating the test database: %s' % e)
  47. sys.exit(2)
  48. self._clone_db(source_database_name, target_database_name)
  49. def _clone_db(self, source_database_name, target_database_name):
  50. dump_args = DatabaseClient.settings_to_cmd_args(self.connection.settings_dict)[1:]
  51. dump_args[-1] = source_database_name
  52. dump_cmd = ['mysqldump', '--routines', '--events'] + dump_args
  53. load_cmd = DatabaseClient.settings_to_cmd_args(self.connection.settings_dict)
  54. load_cmd[-1] = target_database_name
  55. with subprocess.Popen(dump_cmd, stdout=subprocess.PIPE) as dump_proc:
  56. with subprocess.Popen(load_cmd, stdin=dump_proc.stdout, stdout=subprocess.DEVNULL):
  57. # Allow dump_proc to receive a SIGPIPE if the load process exits.
  58. dump_proc.stdout.close()