diff options
Diffstat (limited to 'lib/python2.7/site-packages/south/db')
-rw-r--r-- | lib/python2.7/site-packages/south/db/__init__.py | 83 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/db/firebird.py | 362 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/db/generic.py | 1164 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/db/mysql.py | 290 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/db/oracle.py | 345 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/db/postgresql_psycopg2.py | 96 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/db/sql_server/__init__.py | 0 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/db/sql_server/pyodbc.py | 444 | ||||
-rw-r--r-- | lib/python2.7/site-packages/south/db/sqlite3.py | 272 |
9 files changed, 0 insertions, 3056 deletions
diff --git a/lib/python2.7/site-packages/south/db/__init__.py b/lib/python2.7/site-packages/south/db/__init__.py deleted file mode 100644 index b9b7168..0000000 --- a/lib/python2.7/site-packages/south/db/__init__.py +++ /dev/null @@ -1,83 +0,0 @@ - -# Establish the common DatabaseOperations instance, which we call 'db'. -# Much thanks to cmkmrr for a lot of the code base here - -from django.conf import settings -import sys - -# A few aliases, because there's FQMNs now -engine_modules = { - 'django.db.backends.postgresql_psycopg2': 'postgresql_psycopg2', - 'django.db.backends.sqlite3': 'sqlite3', - 'django.db.backends.mysql': 'mysql', - 'mysql_oursql.standard': 'mysql', - 'django.db.backends.oracle': 'oracle', - 'sql_server.pyodbc': 'sql_server.pyodbc', #django-pyodbc-azure - 'django_pyodbc': 'sql_server.pyodbc', #django-pyodbc - 'sqlserver_ado': 'sql_server.pyodbc', #django-mssql - 'firebird': 'firebird', #django-firebird - 'django.contrib.gis.db.backends.postgis': 'postgresql_psycopg2', - 'django.contrib.gis.db.backends.spatialite': 'sqlite3', - 'django.contrib.gis.db.backends.mysql': 'mysql', - 'django.contrib.gis.db.backends.oracle': 'oracle', - 'doj.backends.zxjdbc.postgresql': 'postgresql_psycopg2', #django-jython - 'doj.backends.zxjdbc.mysql': 'mysql', #django-jython - 'doj.backends.zxjdbc.oracle': 'oracle', #django-jython -} - -# First, work out if we're multi-db or not, and which databases we have -try: - from django.db import DEFAULT_DB_ALIAS -except ImportError: - #### 1.1 or below #### - # We'll 'fake' multi-db; set the default alias - DEFAULT_DB_ALIAS = 'default' - # SOUTH_DATABASE_ADAPTER is an optional override if you have a different module - engine = getattr(settings, "SOUTH_DATABASE_ADAPTER", "south.db.%s" % settings.DATABASE_ENGINE) - # And then, we have one database with one engine - db_engines = {DEFAULT_DB_ALIAS: engine} -else: - #### 1.2 or above #### - # Loop over the defined databases, gathering up their engines - db_engines = dict([ - # Note we check to see if contrib.gis has overridden us. - (alias, "south.db.%s" % engine_modules[db_settings['ENGINE']]) - for alias, db_settings in settings.DATABASES.items() - if db_settings['ENGINE'] in engine_modules - ]) - # Update with any overrides - db_engines.update(getattr(settings, "SOUTH_DATABASE_ADAPTERS", {})) - # Check there's no None engines, or... - for alias, engine in db_engines.items(): - if engine is None: - # They've used a backend we don't support - sys.stderr.write( - ( - "There is no South database module for your database backend '%s'. " + \ - "Please either choose a supported database, check for " + \ - "SOUTH_DATABASE_ADAPTER[S] settings, " + \ - "or remove South from INSTALLED_APPS.\n" - ) % (settings.DATABASES[alias]['ENGINE'],) - ) - sys.exit(1) - -# Now, turn that into a dict of <alias: south db module> -dbs = {} -try: - for alias, module_name in db_engines.items(): - module = __import__(module_name, {}, {}, ['']) - dbs[alias] = module.DatabaseOperations(alias) -except ImportError: - # This error should only be triggered on 1.1 and below. - sys.stderr.write( - ( - "There is no South database module '%s' for your database. " + \ - "Please either choose a supported database, check for " + \ - "SOUTH_DATABASE_ADAPTER[S] settings, " + \ - "or remove South from INSTALLED_APPS.\n" - ) % (module_name,) - ) - sys.exit(1) - -# Finally, to make old migrations work, keep 'db' around as the default database -db = dbs[DEFAULT_DB_ALIAS] diff --git a/lib/python2.7/site-packages/south/db/firebird.py b/lib/python2.7/site-packages/south/db/firebird.py deleted file mode 100644 index a079819..0000000 --- a/lib/python2.7/site-packages/south/db/firebird.py +++ /dev/null @@ -1,362 +0,0 @@ -# firebird - -from __future__ import print_function - -import datetime - -from django.db import connection, models -from django.core.management.color import no_style -from django.db.utils import DatabaseError - -from south.db import generic -from south.utils.py3 import string_types - -class DatabaseOperations(generic.DatabaseOperations): - backend_name = 'firebird' - alter_string_set_type = 'ALTER %(column)s TYPE %(type)s' - alter_string_set_default = 'ALTER %(column)s SET DEFAULT %(default)s;' - alter_string_drop_null = '' - add_column_string = 'ALTER TABLE %s ADD %s;' - delete_column_string = 'ALTER TABLE %s DROP %s;' - rename_table_sql = '' - - # Features - allows_combined_alters = False - has_booleans = False - - def _fill_constraint_cache(self, db_name, table_name): - self._constraint_cache.setdefault(db_name, {}) - self._constraint_cache[db_name][table_name] = {} - - rows = self.execute(""" - SELECT - rc.RDB$CONSTRAINT_NAME, - rc.RDB$CONSTRAINT_TYPE, - cc.RDB$TRIGGER_NAME - FROM rdb$relation_constraints rc - JOIN rdb$check_constraints cc - ON rc.rdb$constraint_name = cc.rdb$constraint_name - WHERE rc.rdb$constraint_type = 'NOT NULL' - AND rc.rdb$relation_name = '%s' - """ % table_name) - - for constraint, kind, column in rows: - self._constraint_cache[db_name][table_name].setdefault(column, set()) - self._constraint_cache[db_name][table_name][column].add((kind, constraint)) - return - - def _alter_column_set_null(self, table_name, column_name, is_null): - sql = """ - UPDATE RDB$RELATION_FIELDS SET RDB$NULL_FLAG = %(null_flag)s - WHERE RDB$FIELD_NAME = '%(column)s' - AND RDB$RELATION_NAME = '%(table_name)s' - """ - null_flag = 'NULL' if is_null else '1' - return sql % { - 'null_flag': null_flag, - 'column': column_name.upper(), - 'table_name': table_name.upper() - } - - def _column_has_default(self, params): - sql = """ - SELECT a.RDB$DEFAULT_VALUE - FROM RDB$RELATION_FIELDS a - WHERE a.RDB$FIELD_NAME = '%(column)s' - AND a.RDB$RELATION_NAME = '%(table_name)s' - """ - value = self.execute(sql % params) - return True if value else False - - - def _alter_set_defaults(self, field, name, params, sqls): - "Subcommand of alter_column that sets default values (overrideable)" - # Historically, we used to set defaults here. - # But since South 0.8, we don't ever set defaults on alter-column -- we only - # use database-level defaults as scaffolding when adding columns. - # However, we still sometimes need to remove defaults in alter-column. - if self._column_has_default(params): - sqls.append(('ALTER COLUMN %s DROP DEFAULT' % (self.quote_name(name),), [])) - - - @generic.invalidate_table_constraints - def create_table(self, table_name, fields): - columns = [] - autoinc_sql = '' - - for field_name, field in fields: - # avoid default values in CREATE TABLE statements (#925) - field._suppress_default = True - - col = self.column_sql(table_name, field_name, field) - if not col: - continue - - columns.append(col) - if isinstance(field, models.AutoField): - field_name = field.db_column or field.column - autoinc_sql = connection.ops.autoinc_sql(table_name, field_name) - - self.execute(self.create_table_sql % { - "table": self.quote_name(table_name), - "columns": ', '.join([col for col in columns if col]), - }) - - if autoinc_sql: - self.execute(autoinc_sql[0]) - self.execute(autoinc_sql[1]) - - def rename_table(self, old_table_name, table_name): - """ - Renames table is not supported by firebird. - This involve recreate all related objects (store procedure, views, triggers, etc) - """ - pass - - @generic.invalidate_table_constraints - def delete_table(self, table_name, cascade=False): - """ - Deletes the table 'table_name'. - Firebird will also delete any triggers associated with the table. - """ - super(DatabaseOperations, self).delete_table(table_name, cascade=False) - - # Also, drop sequence if exists - sql = connection.ops.drop_sequence_sql(table_name) - if sql: - try: - self.execute(sql) - except: - pass - - def column_sql(self, table_name, field_name, field, tablespace='', with_name=True, field_prepared=False): - """ - Creates the SQL snippet for a column. Used by add_column and add_table. - """ - - # If the field hasn't already been told its attribute name, do so. - if not field_prepared: - field.set_attributes_from_name(field_name) - - # hook for the field to do any resolution prior to it's attributes being queried - if hasattr(field, 'south_init'): - field.south_init() - - # Possible hook to fiddle with the fields (e.g. defaults & TEXT on MySQL) - field = self._field_sanity(field) - - try: - sql = field.db_type(connection=self._get_connection()) - except TypeError: - sql = field.db_type() - - if sql: - # Some callers, like the sqlite stuff, just want the extended type. - if with_name: - field_output = [self.quote_name(field.column), sql] - else: - field_output = [sql] - - if field.primary_key: - field_output.append('NOT NULL PRIMARY KEY') - elif field.unique: - # Just use UNIQUE (no indexes any more, we have delete_unique) - field_output.append('UNIQUE') - - sql = ' '.join(field_output) - sqlparams = () - - # if the field is "NOT NULL" and a default value is provided, create the column with it - # this allows the addition of a NOT NULL field to a table with existing rows - if not getattr(field, '_suppress_default', False): - if field.has_default(): - default = field.get_default() - # If the default is actually None, don't add a default term - if default is not None: - # If the default is a callable, then call it! - if callable(default): - default = default() - # Now do some very cheap quoting. TODO: Redesign return values to avoid this. - if isinstance(default, string_types): - default = "'%s'" % default.replace("'", "''") - elif isinstance(default, (datetime.date, datetime.time, datetime.datetime)): - default = "'%s'" % default - elif isinstance(default, bool): - default = int(default) - # Escape any % signs in the output (bug #317) - if isinstance(default, string_types): - default = default.replace("%", "%%") - # Add it in - sql += " DEFAULT %s" - sqlparams = (default) - elif (not field.null and field.blank) or (field.get_default() == ''): - if field.empty_strings_allowed and self._get_connection().features.interprets_empty_strings_as_nulls: - sql += " DEFAULT ''" - # Error here would be nice, but doesn't seem to play fair. - #else: - # raise ValueError("Attempting to add a non null column that isn't character based without an explicit default value.") - - # Firebird need set not null after of default value keyword - if not field.primary_key and not field.null: - sql += ' NOT NULL' - - if field.rel and self.supports_foreign_keys: - self.add_deferred_sql( - self.foreign_key_sql( - table_name, - field.column, - field.rel.to._meta.db_table, - field.rel.to._meta.get_field(field.rel.field_name).column - ) - ) - - # Things like the contrib.gis module fields have this in 1.1 and below - if hasattr(field, 'post_create_sql'): - for stmt in field.post_create_sql(no_style(), table_name): - self.add_deferred_sql(stmt) - - # Avoid double index creation (#1317) - # Firebird creates an index implicity for each foreign key field - # sql_indexes_for_field tries to create an index for that field too - if not field.rel: - # In 1.2 and above, you have to ask the DatabaseCreation stuff for it. - # This also creates normal indexes in 1.1. - if hasattr(self._get_connection().creation, "sql_indexes_for_field"): - # Make a fake model to pass in, with only db_table - model = self.mock_model("FakeModelForGISCreation", table_name) - for stmt in self._get_connection().creation.sql_indexes_for_field(model, field, no_style()): - self.add_deferred_sql(stmt) - - if sql: - return sql % sqlparams - else: - return None - - - def _drop_constraints(self, table_name, name, field): - if self.has_check_constraints: - check_constraints = self._constraints_affecting_columns(table_name, [name], "CHECK") - for constraint in check_constraints: - self.execute(self.delete_check_sql % { - 'table': self.quote_name(table_name), - 'constraint': self.quote_name(constraint), - }) - - # Drop or add UNIQUE constraint - unique_constraint = list(self._constraints_affecting_columns(table_name, [name], "UNIQUE")) - if field.unique and not unique_constraint: - self.create_unique(table_name, [name]) - elif not field.unique and unique_constraint: - self.delete_unique(table_name, [name]) - - # Drop all foreign key constraints - try: - self.delete_foreign_key(table_name, name) - except ValueError: - # There weren't any - pass - - - @generic.invalidate_table_constraints - def alter_column(self, table_name, name, field, explicit_name=True, ignore_constraints=False): - """ - Alters the given column name so it will match the given field. - Note that conversion between the two by the database must be possible. - Will not automatically add _id by default; to have this behavour, pass - explicit_name=False. - - @param table_name: The name of the table to add the column to - @param name: The name of the column to alter - @param field: The new field definition to use - """ - - if self.dry_run: - if self.debug: - print(' - no dry run output for alter_column() due to dynamic DDL, sorry') - return - - - # hook for the field to do any resolution prior to it's attributes being queried - if hasattr(field, 'south_init'): - field.south_init() - - # Add _id or whatever if we need to - field.set_attributes_from_name(name) - if not explicit_name: - name = field.column - else: - field.column = name - - if not ignore_constraints: - # Drop all check constraints. Note that constraints will be added back - # with self.alter_string_set_type and self.alter_string_drop_null. - self._drop_constraints(table_name, name, field) - - # First, change the type - params = { - "column": self.quote_name(name), - "type": self._db_type_for_alter_column(field), - "table_name": table_name - } - - # SQLs is a list of (SQL, values) pairs. - sqls = [] - sqls_extra = [] - - # Only alter the column if it has a type (Geometry ones sometimes don't) - if params["type"] is not None: - sqls.append((self.alter_string_set_type % params, [])) - - # Add any field- and backend- specific modifications - self._alter_add_column_mods(field, name, params, sqls) - - # Next, nullity: modified, firebird doesn't support DROP NOT NULL - sqls_extra.append(self._alter_column_set_null(table_name, name, field.null)) - - # Next, set any default - self._alter_set_defaults(field, name, params, sqls) - - # Finally, actually change the column - if self.allows_combined_alters: - sqls, values = list(zip(*sqls)) - self.execute( - "ALTER TABLE %s %s;" % (self.quote_name(table_name), ", ".join(sqls)), - generic.flatten(values), - ) - else: - # Databases like e.g. MySQL don't like more than one alter at once. - for sql, values in sqls: - try: - self.execute("ALTER TABLE %s %s;" % (self.quote_name(table_name), sql), values) - except DatabaseError as e: - print(e) - - - # Execute extra sql, which don't need ALTER TABLE statement - for sql in sqls_extra: - self.execute(sql) - - if not ignore_constraints: - # Add back FK constraints if needed - if field.rel and self.supports_foreign_keys: - self.execute( - self.foreign_key_sql( - table_name, - field.column, - field.rel.to._meta.db_table, - field.rel.to._meta.get_field(field.rel.field_name).column - ) - ) - - @generic.copy_column_constraints - @generic.delete_column_constraints - def rename_column(self, table_name, old, new): - if old == new: - # Short-circuit out - return [] - - self.execute('ALTER TABLE %s ALTER %s TO %s;' % ( - self.quote_name(table_name), - self.quote_name(old), - self.quote_name(new), - )) diff --git a/lib/python2.7/site-packages/south/db/generic.py b/lib/python2.7/site-packages/south/db/generic.py deleted file mode 100644 index 5c19354..0000000 --- a/lib/python2.7/site-packages/south/db/generic.py +++ /dev/null @@ -1,1164 +0,0 @@ -from __future__ import print_function - -import re -import sys - -from django.core.management.color import no_style -from django.db import transaction, models -from django.db.utils import DatabaseError -from django.db.backends.util import truncate_name -from django.db.backends.creation import BaseDatabaseCreation -from django.db.models.fields import NOT_PROVIDED -from django.dispatch import dispatcher -from django.conf import settings -from django.utils.datastructures import SortedDict -try: - from django.utils.functional import cached_property -except ImportError: - class cached_property(object): - """ - Decorator that creates converts a method with a single - self argument into a property cached on the instance. - """ - def __init__(self, func): - self.func = func - - def __get__(self, instance, type): - res = instance.__dict__[self.func.__name__] = self.func(instance) - return res - -from south.logger import get_logger -from south.utils.py3 import string_types, text_type - - -def alias(attrname): - """ - Returns a function which calls 'attrname' - for function aliasing. - We can't just use foo = bar, as this breaks subclassing. - """ - def func(self, *args, **kwds): - return getattr(self, attrname)(*args, **kwds) - return func - - -def invalidate_table_constraints(func): - def _cache_clear(self, table, *args, **opts): - self._set_cache(table, value=INVALID) - return func(self, table, *args, **opts) - return _cache_clear - - -def delete_column_constraints(func): - def _column_rm(self, table, column, *args, **opts): - self._set_cache(table, column, value=[]) - return func(self, table, column, *args, **opts) - return _column_rm - - -def copy_column_constraints(func): - def _column_cp(self, table, column_old, column_new, *args, **opts): - db_name = self._get_setting('NAME') - self._set_cache(table, column_new, value=self.lookup_constraint(db_name, table, column_old)) - return func(self, table, column_old, column_new, *args, **opts) - return _column_cp - - -class INVALID(Exception): - def __repr__(self): - return 'INVALID' - - -class DryRunError(ValueError): - pass - - -class DatabaseOperations(object): - """ - Generic SQL implementation of the DatabaseOperations. - Some of this code comes from Django Evolution. - """ - - alter_string_set_type = 'ALTER COLUMN %(column)s TYPE %(type)s' - alter_string_set_null = 'ALTER COLUMN %(column)s DROP NOT NULL' - alter_string_drop_null = 'ALTER COLUMN %(column)s SET NOT NULL' - delete_check_sql = 'ALTER TABLE %(table)s DROP CONSTRAINT %(constraint)s' - add_column_string = 'ALTER TABLE %s ADD COLUMN %s;' - delete_unique_sql = "ALTER TABLE %s DROP CONSTRAINT %s" - delete_foreign_key_sql = 'ALTER TABLE %(table)s DROP CONSTRAINT %(constraint)s' - create_table_sql = 'CREATE TABLE %(table)s (%(columns)s)' - max_index_name_length = 63 - drop_index_string = 'DROP INDEX %(index_name)s' - delete_column_string = 'ALTER TABLE %s DROP COLUMN %s CASCADE;' - create_primary_key_string = "ALTER TABLE %(table)s ADD CONSTRAINT %(constraint)s PRIMARY KEY (%(columns)s)" - delete_primary_key_sql = "ALTER TABLE %(table)s DROP CONSTRAINT %(constraint)s" - add_check_constraint_fragment = "ADD CONSTRAINT %(constraint)s CHECK (%(check)s)" - rename_table_sql = "ALTER TABLE %s RENAME TO %s;" - backend_name = None - default_schema_name = "public" - - # Features - allows_combined_alters = True - supports_foreign_keys = True - has_check_constraints = True - has_booleans = True - raises_default_errors = True - - @cached_property - def has_ddl_transactions(self): - """ - Tests the database using feature detection to see if it has - transactional DDL support. - """ - self._possibly_initialise() - connection = self._get_connection() - if hasattr(connection.features, "confirm") and not connection.features._confirmed: - connection.features.confirm() - # Django 1.3's MySQLdb backend doesn't raise DatabaseError - exceptions = (DatabaseError, ) - try: - from MySQLdb import OperationalError - exceptions += (OperationalError, ) - except ImportError: - pass - # Now do the test - if getattr(connection.features, 'supports_transactions', True): - cursor = connection.cursor() - self.start_transaction() - cursor.execute('CREATE TABLE DDL_TRANSACTION_TEST (X INT)') - self.rollback_transaction() - try: - try: - cursor.execute('CREATE TABLE DDL_TRANSACTION_TEST (X INT)') - except exceptions: - return False - else: - return True - finally: - cursor.execute('DROP TABLE DDL_TRANSACTION_TEST') - else: - return False - - def __init__(self, db_alias): - self.debug = False - self.deferred_sql = [] - self.dry_run = False - self.pending_transactions = 0 - self.pending_create_signals = [] - self.db_alias = db_alias - self._constraint_cache = {} - self._initialised = False - - def lookup_constraint(self, db_name, table_name, column_name=None): - """ return a set() of constraints for db_name.table_name.column_name """ - def _lookup(): - table = self._constraint_cache[db_name][table_name] - if table is INVALID: - raise INVALID - elif column_name is None: - return list(table.items()) - else: - return table[column_name] - - try: - ret = _lookup() - return ret - except INVALID: - del self._constraint_cache[db_name][table_name] - self._fill_constraint_cache(db_name, table_name) - except KeyError: - if self._is_valid_cache(db_name, table_name): - return [] - self._fill_constraint_cache(db_name, table_name) - - return self.lookup_constraint(db_name, table_name, column_name) - - def _set_cache(self, table_name, column_name=None, value=INVALID): - db_name = self._get_setting('NAME') - try: - if column_name is not None: - self._constraint_cache[db_name][table_name][column_name] = value - else: - self._constraint_cache[db_name][table_name] = value - except (LookupError, TypeError): - pass - - def _is_valid_cache(self, db_name, table_name): - # we cache per-table so if the table is there it is valid - try: - return self._constraint_cache[db_name][table_name] is not INVALID - except KeyError: - return False - - def _is_multidb(self): - try: - from django.db import connections - connections # Prevents "unused import" warning - except ImportError: - return False - else: - return True - - def _get_connection(self): - """ - Returns a django connection for a given DB Alias - """ - if self._is_multidb(): - from django.db import connections - return connections[self.db_alias] - else: - from django.db import connection - return connection - - def _get_setting(self, setting_name): - """ - Allows code to get a setting (like, for example, STORAGE_ENGINE) - """ - setting_name = setting_name.upper() - connection = self._get_connection() - if self._is_multidb(): - # Django 1.2 and above - return connection.settings_dict[setting_name] - else: - # Django 1.1 and below - return getattr(settings, "DATABASE_%s" % setting_name) - - def _has_setting(self, setting_name): - """ - Existence-checking version of _get_setting. - """ - try: - self._get_setting(setting_name) - except (KeyError, AttributeError): - return False - else: - return True - - def _get_schema_name(self): - try: - return self._get_setting('schema') - except (KeyError, AttributeError): - return self.default_schema_name - - def _possibly_initialise(self): - if not self._initialised: - self.connection_init() - self._initialised = True - - def connection_init(self): - """ - Run before any SQL to let database-specific config be sent as a command, - e.g. which storage engine (MySQL) or transaction serialisability level. - """ - pass - - def quote_name(self, name): - """ - Uses the database backend to quote the given table/column name. - """ - return self._get_connection().ops.quote_name(name) - - def _print_sql_error(self, e, sql, params=[]): - print('FATAL ERROR - The following SQL query failed: %s' % sql, file=sys.stderr) - print('The error was: %s' % e, file=sys.stderr) - - def execute(self, sql, params=[], print_all_errors=True): - """ - Executes the given SQL statement, with optional parameters. - If the instance's debug attribute is True, prints out what it executes. - """ - - self._possibly_initialise() - - cursor = self._get_connection().cursor() - if self.debug: - print(" = %s" % sql, params) - - if self.dry_run: - return [] - - get_logger().debug(text_type('execute "%s" with params "%s"' % (sql, params))) - - try: - cursor.execute(sql, params) - except DatabaseError as e: - if print_all_errors: - self._print_sql_error(e, sql, params) - raise - - try: - return cursor.fetchall() - except: - return [] - - def execute_many(self, sql, regex=r"(?mx) ([^';]* (?:'[^']*'[^';]*)*)", comment_regex=r"(?mx) (?:^\s*$)|(?:--.*$)"): - """ - Takes a SQL file and executes it as many separate statements. - (Some backends, such as Postgres, don't work otherwise.) - """ - # Be warned: This function is full of dark magic. Make sure you really - # know regexes before trying to edit it. - # First, strip comments - sql = "\n".join([x.strip().replace("%", "%%") for x in re.split(comment_regex, sql) if x.strip()]) - # Now execute each statement - for st in re.split(regex, sql)[1:][::2]: - self.execute(st) - - def add_deferred_sql(self, sql): - """ - Add a SQL statement to the deferred list, that won't be executed until - this instance's execute_deferred_sql method is run. - """ - self.deferred_sql.append(sql) - - def execute_deferred_sql(self): - """ - Executes all deferred SQL, resetting the deferred_sql list - """ - for sql in self.deferred_sql: - self.execute(sql) - - self.deferred_sql = [] - - def clear_deferred_sql(self): - """ - Resets the deferred_sql list to empty. - """ - self.deferred_sql = [] - - def clear_run_data(self, pending_creates = None): - """ - Resets variables to how they should be before a run. Used for dry runs. - If you want, pass in an old panding_creates to reset to. - """ - self.clear_deferred_sql() - self.pending_create_signals = pending_creates or [] - - def get_pending_creates(self): - return self.pending_create_signals - - @invalidate_table_constraints - def create_table(self, table_name, fields): - """ - Creates the table 'table_name'. 'fields' is a tuple of fields, - each repsented by a 2-part tuple of field name and a - django.db.models.fields.Field object - """ - - if len(table_name) > 63: - print(" ! WARNING: You have a table name longer than 63 characters; this will not fully work on PostgreSQL or MySQL.") - - # avoid default values in CREATE TABLE statements (#925) - for field_name, field in fields: - field._suppress_default = True - - columns = [ - self.column_sql(table_name, field_name, field) - for field_name, field in fields - ] - - self.execute(self.create_table_sql % { - "table": self.quote_name(table_name), - "columns": ', '.join([col for col in columns if col]), - }) - - add_table = alias('create_table') # Alias for consistency's sake - - @invalidate_table_constraints - def rename_table(self, old_table_name, table_name): - """ - Renames the table 'old_table_name' to 'table_name'. - """ - if old_table_name == table_name: - # Short-circuit out. - return - params = (self.quote_name(old_table_name), self.quote_name(table_name)) - self.execute(self.rename_table_sql % params) - # Invalidate the not-yet-indexed table - self._set_cache(table_name, value=INVALID) - - @invalidate_table_constraints - def delete_table(self, table_name, cascade=True): - """ - Deletes the table 'table_name'. - """ - params = (self.quote_name(table_name), ) - if cascade: - self.execute('DROP TABLE %s CASCADE;' % params) - else: - self.execute('DROP TABLE %s;' % params) - - drop_table = alias('delete_table') - - @invalidate_table_constraints - def clear_table(self, table_name): - """ - Deletes all rows from 'table_name'. - """ - params = (self.quote_name(table_name), ) - self.execute('DELETE FROM %s;' % params) - - @invalidate_table_constraints - def add_column(self, table_name, name, field, keep_default=True): - """ - Adds the column 'name' to the table 'table_name'. - Uses the 'field' paramater, a django.db.models.fields.Field instance, - to generate the necessary sql - - @param table_name: The name of the table to add the column to - @param name: The name of the column to add - @param field: The field to use - """ - sql = self.column_sql(table_name, name, field) - if sql: - params = ( - self.quote_name(table_name), - sql, - ) - sql = self.add_column_string % params - self.execute(sql) - - # Now, drop the default if we need to - if field.default is not None: - field.default = NOT_PROVIDED - self.alter_column(table_name, name, field, explicit_name=False, ignore_constraints=True) - - def _db_type_for_alter_column(self, field): - """ - Returns a field's type suitable for ALTER COLUMN. - By default it just returns field.db_type(). - To be overriden by backend specific subclasses - @param field: The field to generate type for - """ - try: - return field.db_type(connection=self._get_connection()) - except TypeError: - return field.db_type() - - def _alter_add_column_mods(self, field, name, params, sqls): - """ - Subcommand of alter_column that modifies column definitions beyond - the type string -- e.g. adding constraints where they cannot be specified - as part of the type (overrideable) - """ - pass - - def _alter_set_defaults(self, field, name, params, sqls): - "Subcommand of alter_column that sets default values (overrideable)" - # Historically, we used to set defaults here. - # But since South 0.8, we don't ever set defaults on alter-column -- we only - # use database-level defaults as scaffolding when adding columns. - # However, we still sometimes need to remove defaults in alter-column. - sqls.append(('ALTER COLUMN %s DROP DEFAULT' % (self.quote_name(name),), [])) - - def _update_nulls_to_default(self, params, field): - "Subcommand of alter_column that updates nulls to default value (overrideable)" - default = field.get_db_prep_save(field.get_default(), connection=self._get_connection()) - self.execute('UPDATE %(table_name)s SET %(column)s=%%s WHERE %(column)s IS NULL' % params, [default]) - - @invalidate_table_constraints - def alter_column(self, table_name, name, field, explicit_name=True, ignore_constraints=False): - """ - Alters the given column name so it will match the given field. - Note that conversion between the two by the database must be possible. - Will not automatically add _id by default; to have this behavour, pass - explicit_name=False. - - @param table_name: The name of the table to add the column to - @param name: The name of the column to alter - @param field: The new field definition to use - """ - - if self.dry_run: - if self.debug: - print(' - no dry run output for alter_column() due to dynamic DDL, sorry') - return - - # hook for the field to do any resolution prior to it's attributes being queried - if hasattr(field, 'south_init'): - field.south_init() - - # Add _id or whatever if we need to - field.set_attributes_from_name(name) - if not explicit_name: - name = field.column - else: - field.column = name - - if not ignore_constraints: - # Drop all check constraints. Note that constraints will be added back - # with self.alter_string_set_type and self.alter_string_drop_null. - if self.has_check_constraints: - check_constraints = self._constraints_affecting_columns(table_name, [name], "CHECK") - for constraint in check_constraints: - self.execute(self.delete_check_sql % { - 'table': self.quote_name(table_name), - 'constraint': self.quote_name(constraint), - }) - - # Drop all foreign key constraints - try: - self.delete_foreign_key(table_name, name) - except ValueError: - # There weren't any - pass - - # First, change the type - params = { - "column": self.quote_name(name), - "type": self._db_type_for_alter_column(field), - "table_name": self.quote_name(table_name) - } - - # SQLs is a list of (SQL, values) pairs. - sqls = [] - - # Only alter the column if it has a type (Geometry ones sometimes don't) - if params["type"] is not None: - sqls.append((self.alter_string_set_type % params, [])) - - # Add any field- and backend- specific modifications - self._alter_add_column_mods(field, name, params, sqls) - # Next, nullity - if field.null or field.has_default(): - sqls.append((self.alter_string_set_null % params, [])) - else: - sqls.append((self.alter_string_drop_null % params, [])) - - # Do defaults - self._alter_set_defaults(field, name, params, sqls) - - # Actually change the column (step 1 -- Nullity may need to be fixed) - if self.allows_combined_alters: - sqls, values = zip(*sqls) - self.execute( - "ALTER TABLE %s %s;" % (self.quote_name(table_name), ", ".join(sqls)), - flatten(values), - ) - else: - # Databases like e.g. MySQL don't like more than one alter at once. - for sql, values in sqls: - self.execute("ALTER TABLE %s %s;" % (self.quote_name(table_name), sql), values) - - if not field.null and field.has_default(): - # Final fixes - self._update_nulls_to_default(params, field) - self.execute("ALTER TABLE %s %s;" % (self.quote_name(table_name), self.alter_string_drop_null % params), []) - - if not ignore_constraints: - # Add back FK constraints if needed - if field.rel and self.supports_foreign_keys: - self.execute( - self.foreign_key_sql( - table_name, - field.column, - field.rel.to._meta.db_table, - field.rel.to._meta.get_field(field.rel.field_name).column - ) - ) - - def _fill_constraint_cache(self, db_name, table_name): - - schema = self._get_schema_name() - ifsc_tables = ["constraint_column_usage", "key_column_usage"] - - self._constraint_cache.setdefault(db_name, {}) - self._constraint_cache[db_name][table_name] = {} - - for ifsc_table in ifsc_tables: - rows = self.execute(""" - SELECT kc.constraint_name, kc.column_name, c.constraint_type - FROM information_schema.%s AS kc - JOIN information_schema.table_constraints AS c ON - kc.table_schema = c.table_schema AND - kc.table_name = c.table_name AND - kc.constraint_name = c.constraint_name - WHERE - kc.table_schema = %%s AND - kc.table_name = %%s - """ % ifsc_table, [schema, table_name]) - for constraint, column, kind in rows: - self._constraint_cache[db_name][table_name].setdefault(column, set()) - self._constraint_cache[db_name][table_name][column].add((kind, constraint)) - return - - def _constraints_affecting_columns(self, table_name, columns, type="UNIQUE"): - """ - Gets the names of the constraints affecting the given columns. - If columns is None, returns all constraints of the type on the table. - """ - if self.dry_run: - raise DryRunError("Cannot get constraints for columns.") - - if columns is not None: - columns = set(map(lambda s: s.lower(), columns)) - - db_name = self._get_setting('NAME') - - cnames = {} - for col, constraints in self.lookup_constraint(db_name, table_name): - for kind, cname in constraints: - if kind == type: - cnames.setdefault(cname, set()) - cnames[cname].add(col.lower()) - - for cname, cols in cnames.items(): - if cols == columns or columns is None: - yield cname - - @invalidate_table_constraints - def create_unique(self, table_name, columns): - """ - Creates a UNIQUE constraint on the columns on the given table. - """ - - if not isinstance(columns, (list, tuple)): - columns = [columns] - - name = self.create_index_name(table_name, columns, suffix="_uniq") - - cols = ", ".join(map(self.quote_name, columns)) - self.execute("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE (%s)" % ( - self.quote_name(table_name), - self.quote_name(name), - cols, - )) - return name - - @invalidate_table_constraints - def delete_unique(self, table_name, columns): - """ - Deletes a UNIQUE constraint on precisely the columns on the given table. - """ - - if not isinstance(columns, (list, tuple)): - columns = [columns] - - # Dry runs mean we can't do anything. - if self.dry_run: - if self.debug: - print(' - no dry run output for delete_unique_column() due to dynamic DDL, sorry') - return - - constraints = list(self._constraints_affecting_columns(table_name, columns)) - if not constraints: - raise ValueError("Cannot find a UNIQUE constraint on table %s, columns %r" % (table_name, columns)) - for constraint in constraints: - self.execute(self.delete_unique_sql % ( - self.quote_name(table_name), - self.quote_name(constraint), - )) - - def column_sql(self, table_name, field_name, field, tablespace='', with_name=True, field_prepared=False): - """ - Creates the SQL snippet for a column. Used by add_column and add_table. - """ - - # If the field hasn't already been told its attribute name, do so. - if not field_prepared: - field.set_attributes_from_name(field_name) - - # hook for the field to do any resolution prior to it's attributes being queried - if hasattr(field, 'south_init'): - field.south_init() - - # Possible hook to fiddle with the fields (e.g. defaults & TEXT on MySQL) - field = self._field_sanity(field) - - try: - sql = field.db_type(connection=self._get_connection()) - except TypeError: - sql = field.db_type() - - if sql: - - # Some callers, like the sqlite stuff, just want the extended type. - if with_name: - field_output = [self.quote_name(field.column), sql] - else: - field_output = [sql] - - field_output.append('%sNULL' % (not field.null and 'NOT ' or '')) - if field.primary_key: - field_output.append('PRIMARY KEY') - elif field.unique: - # Just use UNIQUE (no indexes any more, we have delete_unique) - field_output.append('UNIQUE') - - tablespace = field.db_tablespace or tablespace - if tablespace and getattr(self._get_connection().features, "supports_tablespaces", False) and field.unique: - # We must specify the index tablespace inline, because we - # won't be generating a CREATE INDEX statement for this field. - field_output.append(self._get_connection().ops.tablespace_sql(tablespace, inline=True)) - - sql = ' '.join(field_output) - sqlparams = () - # if the field is "NOT NULL" and a default value is provided, create the column with it - # this allows the addition of a NOT NULL field to a table with existing rows - if not getattr(field, '_suppress_default', False): - if field.has_default(): - default = field.get_default() - # If the default is actually None, don't add a default term - if default is not None: - # If the default is a callable, then call it! - if callable(default): - default = default() - - default = field.get_db_prep_save(default, connection=self._get_connection()) - default = self._default_value_workaround(default) - # Now do some very cheap quoting. TODO: Redesign return values to avoid this. - if isinstance(default, string_types): - default = "'%s'" % default.replace("'", "''") - # Escape any % signs in the output (bug #317) - if isinstance(default, string_types): - default = default.replace("%", "%%") - # Add it in - sql += " DEFAULT %s" - sqlparams = (default) - elif (not field.null and field.blank) or (field.get_default() == ''): - if field.empty_strings_allowed and self._get_connection().features.interprets_empty_strings_as_nulls: - sql += " DEFAULT ''" - # Error here would be nice, but doesn't seem to play fair. - #else: - # raise ValueError("Attempting to add a non null column that isn't character based without an explicit default value.") - - if field.rel and self.supports_foreign_keys: - self.add_deferred_sql( - self.foreign_key_sql( - table_name, - field.column, - field.rel.to._meta.db_table, - field.rel.to._meta.get_field(field.rel.field_name).column - ) - ) - - # Things like the contrib.gis module fields have this in 1.1 and below - if hasattr(field, 'post_create_sql'): - for stmt in field.post_create_sql(no_style(), table_name): - self.add_deferred_sql(stmt) - - # In 1.2 and above, you have to ask the DatabaseCreation stuff for it. - # This also creates normal indexes in 1.1. - if hasattr(self._get_connection().creation, "sql_indexes_for_field"): - # Make a fake model to pass in, with only db_table - model = self.mock_model("FakeModelForGISCreation", table_name) - for stmt in self._get_connection().creation.sql_indexes_for_field(model, field, no_style()): - self.add_deferred_sql(stmt) - - if sql: - return sql % sqlparams - else: - return None - - def _field_sanity(self, field): - """ - Placeholder for DBMS-specific field alterations (some combos aren't valid, - e.g. DEFAULT and TEXT on MySQL) - """ - return field - - def _default_value_workaround(self, value): - """ - DBMS-specific value alterations (this really works around - missing functionality in Django backends) - """ - if isinstance(value, bool) and not self.has_booleans: - return int(value) - else: - return value - - def foreign_key_sql(self, from_table_name, from_column_name, to_table_name, to_column_name): - """ - Generates a full SQL statement to add a foreign key constraint - """ - constraint_name = '%s_refs_%s_%s' % (from_column_name, to_column_name, self._digest(from_table_name, to_table_name)) - return 'ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % ( - self.quote_name(from_table_name), - self.quote_name(self.shorten_name(constraint_name)), - self.quote_name(from_column_name), - self.quote_name(to_table_name), - self.quote_name(to_column_name), - self._get_connection().ops.deferrable_sql() # Django knows this - ) - - @invalidate_table_constraints - def delete_foreign_key(self, table_name, column): - """ - Drop a foreign key constraint - """ - if self.dry_run: - if self.debug: - print(' - no dry run output for delete_foreign_key() due to dynamic DDL, sorry') - return # We can't look at the DB to get the constraints - constraints = self._find_foreign_constraints(table_name, column) - if not constraints: - raise ValueError("Cannot find a FOREIGN KEY constraint on table %s, column %s" % (table_name, column)) - for constraint_name in constraints: - self.execute(self.delete_foreign_key_sql % { - "table": self.quote_name(table_name), - "constraint": self.quote_name(constraint_name), - }) - - drop_foreign_key = alias('delete_foreign_key') - - def _find_foreign_constraints(self, table_name, column_name=None): - constraints = self._constraints_affecting_columns( - table_name, [column_name], "FOREIGN KEY") - - primary_key_columns = self._find_primary_key_columns(table_name) - - if len(primary_key_columns) > 1: - # Composite primary keys cannot be referenced by a foreign key - return list(constraints) - else: - primary_key_columns.add(column_name) - recursive_constraints = set(self._constraints_affecting_columns( - table_name, primary_key_columns, "FOREIGN KEY")) - return list(recursive_constraints.union(constraints)) - - def _digest(self, *args): - """ - Use django.db.backends.creation.BaseDatabaseCreation._digest - to create index name in Django style. An evil hack :( - """ - if not hasattr(self, '_django_db_creation'): - self._django_db_creation = BaseDatabaseCreation(self._get_connection()) - return self._django_db_creation._digest(*args) - - def shorten_name(self, name): - return truncate_name(name, self._get_connection().ops.max_name_length()) - - def create_index_name(self, table_name, column_names, suffix=""): - """ - Generate a unique name for the index - """ - - # If there is just one column in the index, use a default algorithm from Django - if len(column_names) == 1 and not suffix: - try: - _hash = self._digest([column_names[0]]) - except TypeError: - # Django < 1.5 backward compatibility. - _hash = self._digest(column_names[0]) - return self.shorten_name( - '%s_%s' % (table_name, _hash), - ) - - # Else generate the name for the index by South - table_name = table_name.replace('"', '').replace('.', '_') - index_unique_name = '_%x' % abs(hash((table_name, ','.join(column_names)))) - - # If the index name is too long, truncate it - index_name = ('%s_%s%s%s' % (table_name, column_names[0], index_unique_name, suffix)).replace('"', '').replace('.', '_') - if len(index_name) > self.max_index_name_length: - part = ('_%s%s%s' % (column_names[0], index_unique_name, suffix)) - index_name = '%s%s' % (table_name[:(self.max_index_name_length - len(part))], part) - - return index_name - - def create_index_sql(self, table_name, column_names, unique=False, db_tablespace=''): - """ - Generates a create index statement on 'table_name' for a list of 'column_names' - """ - if not column_names: - print("No column names supplied on which to create an index") - return '' - - connection = self._get_connection() - if db_tablespace and connection.features.supports_tablespaces: - tablespace_sql = ' ' + connection.ops.tablespace_sql(db_tablespace) - else: - tablespace_sql = '' - - index_name = self.create_index_name(table_name, column_names) - return 'CREATE %sINDEX %s ON %s (%s)%s;' % ( - unique and 'UNIQUE ' or '', - self.quote_name(index_name), - self.quote_name(table_name), - ','.join([self.quote_name(field) for field in column_names]), - tablespace_sql - ) - - @invalidate_table_constraints - def create_index(self, table_name, column_names, unique=False, db_tablespace=''): - """ Executes a create index statement """ - sql = self.create_index_sql(table_name, column_names, unique, db_tablespace) - self.execute(sql) - - @invalidate_table_constraints - def delete_index(self, table_name, column_names, db_tablespace=''): - """ - Deletes an index created with create_index. - This is possible using only columns due to the deterministic - index naming function which relies on column names. - """ - if isinstance(column_names, string_types): - column_names = [column_names] - name = self.create_index_name(table_name, column_names) - sql = self.drop_index_string % { - "index_name": self.quote_name(name), - "table_name": self.quote_name(table_name), - } - self.execute(sql) - - drop_index = alias('delete_index') - - @delete_column_constraints - def delete_column(self, table_name, name): - """ - Deletes the column 'column_name' from the table 'table_name'. - """ - params = (self.quote_name(table_name), self.quote_name(name)) - self.execute(self.delete_column_string % params, []) - - drop_column = alias('delete_column') - - def rename_column(self, table_name, old, new): - """ - Renames the column 'old' from the table 'table_name' to 'new'. - """ - raise NotImplementedError("rename_column has no generic SQL syntax") - - @invalidate_table_constraints - def delete_primary_key(self, table_name): - """ - Drops the old primary key. - """ - # Dry runs mean we can't do anything. - if self.dry_run: - if self.debug: - print(' - no dry run output for delete_primary_key() due to dynamic DDL, sorry') - return - - constraints = list(self._constraints_affecting_columns(table_name, None, type="PRIMARY KEY")) - if not constraints: - raise ValueError("Cannot find a PRIMARY KEY constraint on table %s" % (table_name,)) - - for constraint in constraints: - self.execute(self.delete_primary_key_sql % { - "table": self.quote_name(table_name), - "constraint": self.quote_name(constraint), - }) - - drop_primary_key = alias('delete_primary_key') - - @invalidate_table_constraints - def create_primary_key(self, table_name, columns): - """ - Creates a new primary key on the specified columns. - """ - if not isinstance(columns, (list, tuple)): - columns = [columns] - self.execute(self.create_primary_key_string % { - "table": self.quote_name(table_name), - "constraint": self.quote_name(table_name + "_pkey"), - "columns": ", ".join(map(self.quote_name, columns)), - }) - - def _find_primary_key_columns(self, table_name): - """ - Find all columns of the primary key of the specified table - """ - db_name = self._get_setting('NAME') - - primary_key_columns = set() - for col, constraints in self.lookup_constraint(db_name, table_name): - for kind, cname in constraints: - if kind == 'PRIMARY KEY': - primary_key_columns.add(col.lower()) - - return primary_key_columns - - def start_transaction(self): - """ - Makes sure the following commands are inside a transaction. - Must be followed by a (commit|rollback)_transaction call. - """ - if self.dry_run: - self.pending_transactions += 1 - transaction.commit_unless_managed(using=self.db_alias) - transaction.enter_transaction_management(using=self.db_alias) - transaction.managed(True, using=self.db_alias) - - def commit_transaction(self): - """ - Commits the current transaction. - Must be preceded by a start_transaction call. - """ - if self.dry_run: - return - transaction.commit(using=self.db_alias) - transaction.leave_transaction_management(using=self.db_alias) - - def rollback_transaction(self): - """ - Rolls back the current transaction. - Must be preceded by a start_transaction call. - """ - if self.dry_run: - self.pending_transactions -= 1 - transaction.rollback(using=self.db_alias) - transaction.leave_transaction_management(using=self.db_alias) - - def rollback_transactions_dry_run(self): - """ - Rolls back all pending_transactions during this dry run. - """ - if not self.dry_run: - return - while self.pending_transactions > 0: - self.rollback_transaction() - if transaction.is_dirty(using=self.db_alias): - # Force an exception, if we're still in a dirty transaction. - # This means we are missing a COMMIT/ROLLBACK. - transaction.leave_transaction_management(using=self.db_alias) - - def send_create_signal(self, app_label, model_names): - self.pending_create_signals.append((app_label, model_names)) - - def send_pending_create_signals(self, verbosity=0, interactive=False): - # Group app_labels together - signals = SortedDict() - for (app_label, model_names) in self.pending_create_signals: - try: - signals[app_label].extend(model_names) - except KeyError: - signals[app_label] = list(model_names) - # Send only one signal per app. - for (app_label, model_names) in signals.items(): - self.really_send_create_signal(app_label, list(set(model_names)), - verbosity=verbosity, - interactive=interactive) - self.pending_create_signals = [] - - def really_send_create_signal(self, app_label, model_names, - verbosity=0, interactive=False): - """ - Sends a post_syncdb signal for the model specified. - - If the model is not found (perhaps it's been deleted?), - no signal is sent. - - TODO: The behavior of django.contrib.* apps seems flawed in that - they don't respect created_models. Rather, they blindly execute - over all models within the app sending the signal. This is a - patch we should push Django to make For now, this should work. - """ - - if self.debug: - print(" - Sending post_syncdb signal for %s: %s" % (app_label, model_names)) - - app = models.get_app(app_label) - if not app: - return - - created_models = [] - for model_name in model_names: - model = models.get_model(app_label, model_name) - if model: - created_models.append(model) - - if created_models: - - if hasattr(dispatcher, "send"): - # Older djangos - dispatcher.send(signal=models.signals.post_syncdb, sender=app, - app=app, created_models=created_models, - verbosity=verbosity, interactive=interactive) - else: - if self._is_multidb(): - # Django 1.2+ - models.signals.post_syncdb.send( - sender=app, - app=app, - created_models=created_models, - verbosity=verbosity, - interactive=interactive, - db=self.db_alias, - ) - else: - # Django 1.1 - 1.0 - models.signals.post_syncdb.send( - sender=app, - app=app, - created_models=created_models, - verbosity=verbosity, - interactive=interactive, - ) - - def mock_model(self, model_name, db_table, db_tablespace='', - pk_field_name='id', pk_field_type=models.AutoField, - pk_field_args=[], pk_field_kwargs={}): - """ - Generates a MockModel class that provides enough information - to be used by a foreign key/many-to-many relationship. - - Migrations should prefer to use these rather than actual models - as models could get deleted over time, but these can remain in - migration files forever. - - Depreciated. - """ - class MockOptions(object): - def __init__(self): - self.db_table = db_table - self.db_tablespace = db_tablespace or settings.DEFAULT_TABLESPACE - self.object_name = model_name - self.module_name = model_name.lower() - - if pk_field_type == models.AutoField: - pk_field_kwargs['primary_key'] = True - - self.pk = pk_field_type(*pk_field_args, **pk_field_kwargs) - self.pk.set_attributes_from_name(pk_field_name) - self.abstract = False - - def get_field_by_name(self, field_name): - # we only care about the pk field - return (self.pk, self.model, True, False) - - def get_field(self, name): - # we only care about the pk field - return self.pk - - class MockModel(object): - _meta = None - - # We need to return an actual class object here, not an instance - MockModel._meta = MockOptions() - MockModel._meta.model = MockModel - return MockModel - - def _db_positive_type_for_alter_column(self, klass, field): - """ - A helper for subclasses overriding _db_type_for_alter_column: - Remove the check constraint from the type string for PositiveInteger - and PositiveSmallInteger fields. - @param klass: The type of the child (required to allow this to be used when it is subclassed) - @param field: The field to generate type for - """ - super_result = super(klass, self)._db_type_for_alter_column(field) - if isinstance(field, (models.PositiveSmallIntegerField, models.PositiveIntegerField)): - return super_result.split(" ", 1)[0] - return super_result - - def _alter_add_positive_check(self, klass, field, name, params, sqls): - """ - A helper for subclasses overriding _alter_add_column_mods: - Add a check constraint verifying positivity to PositiveInteger and - PositiveSmallInteger fields. - """ - super(klass, self)._alter_add_column_mods(field, name, params, sqls) - if isinstance(field, (models.PositiveSmallIntegerField, models.PositiveIntegerField)): - uniq_hash = abs(hash(tuple(params.values()))) - d = dict( - constraint = "CK_%s_PSTV_%s" % (name, hex(uniq_hash)[2:]), - check = "%s >= 0" % self.quote_name(name)) - sqls.append((self.add_check_constraint_fragment % d, [])) - - -# Single-level flattening of lists -def flatten(ls): - nl = [] - for l in ls: - nl += l - return nl diff --git a/lib/python2.7/site-packages/south/db/mysql.py b/lib/python2.7/site-packages/south/db/mysql.py deleted file mode 100644 index 3e87464..0000000 --- a/lib/python2.7/site-packages/south/db/mysql.py +++ /dev/null @@ -1,290 +0,0 @@ -# MySQL-specific implementations for south -# Original author: Andrew Godwin -# Patches by: F. Gabriel Gosselin <gabrielNOSPAM@evidens.ca> - -from south.db import generic -from south.db.generic import DryRunError, INVALID -from south.logger import get_logger - - -def delete_column_constraints(func): - """ - Decorates column operation functions for MySQL. - Deletes the constraints from the database and clears local cache. - """ - def _column_rm(self, table_name, column_name, *args, **opts): - # Delete foreign key constraints - try: - self.delete_foreign_key(table_name, column_name) - except ValueError: - pass # If no foreign key on column, OK because it checks first - # Delete constraints referring to this column - try: - reverse = self._lookup_reverse_constraint(table_name, column_name) - for cname, rtable, rcolumn in reverse: - self.delete_foreign_key(rtable, rcolumn) - except DryRunError: - pass - return func(self, table_name, column_name, *args, **opts) - return _column_rm - - -def copy_column_constraints(func): - """ - Decorates column operation functions for MySQL. - Determines existing constraints and copies them to a new column - """ - def _column_cp(self, table_name, column_old, column_new, *args, **opts): - # Copy foreign key constraint - try: - constraint = self._find_foreign_constraints( - table_name, column_old)[0] - refs = self._lookup_constraint_references(table_name, constraint) - if refs is not None: - (ftable, fcolumn) = refs - if ftable and fcolumn: - fk_sql = self.foreign_key_sql( - table_name, column_new, ftable, fcolumn) - get_logger().debug("Foreign key SQL: " + fk_sql) - self.add_deferred_sql(fk_sql) - except IndexError: - pass # No constraint exists so ignore - except DryRunError: - pass - # Copy constraints referring to this column - try: - reverse = self._lookup_reverse_constraint(table_name, column_old) - for cname, rtable, rcolumn in reverse: - fk_sql = self.foreign_key_sql( - rtable, rcolumn, table_name, column_new) - self.add_deferred_sql(fk_sql) - except DryRunError: - pass - return func(self, table_name, column_old, column_new, *args, **opts) - return _column_cp - - -def invalidate_table_constraints(func): - """ - For MySQL we grab all table constraints simultaneously, so this is - effective. - It further solves the issues of invalidating referred table constraints. - """ - def _cache_clear(self, table, *args, **opts): - db_name = self._get_setting('NAME') - if db_name in self._constraint_cache: - del self._constraint_cache[db_name] - if db_name in self._reverse_cache: - del self._reverse_cache[db_name] - if db_name in self._constraint_references: - del self._constraint_references[db_name] - return func(self, table, *args, **opts) - return _cache_clear - - -class DatabaseOperations(generic.DatabaseOperations): - """ - MySQL implementation of database operations. - - MySQL has no DDL transaction support This can confuse people when they ask - how to roll back - hence the dry runs, etc., found in the migration code. - """ - - backend_name = "mysql" - alter_string_set_type = '' - alter_string_set_null = 'MODIFY %(column)s %(type)s NULL;' - alter_string_drop_null = 'MODIFY %(column)s %(type)s NOT NULL;' - drop_index_string = 'DROP INDEX %(index_name)s ON %(table_name)s' - delete_primary_key_sql = "ALTER TABLE %(table)s DROP PRIMARY KEY" - delete_foreign_key_sql = "ALTER TABLE %(table)s DROP FOREIGN KEY %(constraint)s" - delete_unique_sql = "ALTER TABLE %s DROP INDEX %s" - rename_table_sql = "RENAME TABLE %s TO %s;" - - allows_combined_alters = False - has_check_constraints = False - raises_default_errors = False - - geom_types = ['geometry', 'point', 'linestring', 'polygon'] - text_types = ['text', 'blob'] - - def __init__(self, db_alias): - self._constraint_references = {} - self._reverse_cache = {} - super(DatabaseOperations, self).__init__(db_alias) - if self._has_setting('STORAGE_ENGINE') and self._get_setting('STORAGE_ENGINE'): - self.create_table_sql = self.create_table_sql + ' ENGINE=%s' % self._get_setting('STORAGE_ENGINE') - - def _is_valid_cache(self, db_name, table_name): - cache = self._constraint_cache - # we cache the whole db so if there are any tables table_name is valid - return db_name in cache and cache[db_name].get(table_name, None) is not INVALID - - def _fill_constraint_cache(self, db_name, table_name): - # for MySQL grab all constraints for this database. It's just as cheap as a single column. - self._constraint_cache[db_name] = {} - self._constraint_cache[db_name][table_name] = {} - self._reverse_cache[db_name] = {} - self._constraint_references[db_name] = {} - - name_query = """ - SELECT kc.`constraint_name`, kc.`column_name`, kc.`table_name`, - kc.`referenced_table_name`, kc.`referenced_column_name` - FROM information_schema.key_column_usage AS kc - WHERE - kc.table_schema = %s - """ - rows = self.execute(name_query, [db_name]) - if not rows: - return - cnames = {} - for constraint, column, table, ref_table, ref_column in rows: - key = (table, constraint) - cnames.setdefault(key, set()) - cnames[key].add((column, ref_table, ref_column)) - - type_query = """ - SELECT c.constraint_name, c.table_name, c.constraint_type - FROM information_schema.table_constraints AS c - WHERE - c.table_schema = %s - """ - rows = self.execute(type_query, [db_name]) - for constraint, table, kind in rows: - key = (table, constraint) - self._constraint_cache[db_name].setdefault(table, {}) - try: - cols = cnames[key] - except KeyError: - cols = set() - for column_set in cols: - (column, ref_table, ref_column) = column_set - self._constraint_cache[db_name][table].setdefault(column, set()) - if kind == 'FOREIGN KEY': - self._constraint_cache[db_name][table][column].add((kind, - constraint)) - # Create constraint lookup, see constraint_references - self._constraint_references[db_name][(table, - constraint)] = (ref_table, ref_column) - # Create reverse table lookup, reverse_lookup - self._reverse_cache[db_name].setdefault(ref_table, {}) - self._reverse_cache[db_name][ref_table].setdefault(ref_column, - set()) - self._reverse_cache[db_name][ref_table][ref_column].add( - (constraint, table, column)) - else: - self._constraint_cache[db_name][table][column].add((kind, - constraint)) - - def connection_init(self): - """ - Run before any SQL to let database-specific config be sent as a command, - e.g. which storage engine (MySQL) or transaction serialisability level. - """ - cursor = self._get_connection().cursor() - if cursor.execute("SHOW variables WHERE Variable_Name='default_storage_engine';"): - engine_var = 'default_storage_engine' - else: - engine_var = 'storage_engine' - if self._has_setting('STORAGE_ENGINE') and self._get_setting('STORAGE_ENGINE'): - cursor.execute("SET %s=%s;" % (engine_var, self._get_setting('STORAGE_ENGINE'))) - - def start_transaction(self): - super(DatabaseOperations, self).start_transaction() - self.execute("SET FOREIGN_KEY_CHECKS=0;") - - @copy_column_constraints - @delete_column_constraints - @invalidate_table_constraints - def rename_column(self, table_name, old, new): - if old == new or self.dry_run: - return [] - - rows = [x for x in self.execute('DESCRIBE %s' % (self.quote_name(table_name),)) if x[0] == old] - - if not rows: - raise ValueError("No column '%s' in '%s'." % (old, table_name)) - - params = ( - self.quote_name(table_name), - self.quote_name(old), - self.quote_name(new), - rows[0][1], - rows[0][2] == "YES" and "NULL" or "NOT NULL", - rows[0][4] and "DEFAULT " or "", - rows[0][4] and "%s" or "", - rows[0][5] or "", - ) - - sql = 'ALTER TABLE %s CHANGE COLUMN %s %s %s %s %s %s %s;' % params - - if rows[0][4]: - self.execute(sql, (rows[0][4],)) - else: - self.execute(sql) - - @delete_column_constraints - def delete_column(self, table_name, name): - super(DatabaseOperations, self).delete_column(table_name, name) - - @invalidate_table_constraints - def rename_table(self, old_table_name, table_name): - super(DatabaseOperations, self).rename_table(old_table_name, - table_name) - - @invalidate_table_constraints - def delete_table(self, table_name): - super(DatabaseOperations, self).delete_table(table_name) - - def _lookup_constraint_references(self, table_name, cname): - """ - Provided an existing table and constraint, returns tuple of (foreign - table, column) - """ - db_name = self._get_setting('NAME') - try: - return self._constraint_references[db_name][(table_name, cname)] - except KeyError: - return None - - def _lookup_reverse_constraint(self, table_name, column_name=None): - """Look for the column referenced by a foreign constraint""" - db_name = self._get_setting('NAME') - if self.dry_run: - raise DryRunError("Cannot get constraints for columns.") - - if not self._is_valid_cache(db_name, table_name): - # Piggy-back on lookup_constraint, ensures cache exists - self.lookup_constraint(db_name, table_name) - - try: - table = self._reverse_cache[db_name][table_name] - if column_name == None: - return [(y, tuple(y)) for x, y in table.items()] - else: - return tuple(table[column_name]) - except KeyError: - return [] - - def _field_sanity(self, field): - """ - This particular override stops us sending DEFAULTs for BLOB/TEXT columns. - """ - # MySQL does not support defaults for geometry columns also - type = self._db_type_for_alter_column(field).lower() - is_geom = True in [type.find(t) > -1 for t in self.geom_types] - is_text = True in [type.find(t) > -1 for t in self.text_types] - - if is_geom or is_text: - field._suppress_default = True - return field - - def _alter_set_defaults(self, field, name, params, sqls): - """ - MySQL does not support defaults on text or blob columns. - """ - type = params['type'] - # MySQL does not support defaults for geometry columns also - is_geom = True in [type.find(t) > -1 for t in self.geom_types] - is_text = True in [type.find(t) > -1 for t in self.text_types] - if not is_geom and not is_text: - super(DatabaseOperations, self)._alter_set_defaults(field, name, params, sqls) diff --git a/lib/python2.7/site-packages/south/db/oracle.py b/lib/python2.7/site-packages/south/db/oracle.py deleted file mode 100644 index 79496d0..0000000 --- a/lib/python2.7/site-packages/south/db/oracle.py +++ /dev/null @@ -1,345 +0,0 @@ -from __future__ import print_function
-
-import os.path
-import sys
-import re
-import warnings
-import cx_Oracle
-
-
-from django.db import connection, models
-from django.db.backends.util import truncate_name
-from django.core.management.color import no_style
-from django.db.models.fields import NOT_PROVIDED
-from django.db.utils import DatabaseError
-
-# In revision r16016 function get_sequence_name has been transformed into
-# method of DatabaseOperations class. To make code backward-compatible we
-# need to handle both situations.
-try:
- from django.db.backends.oracle.base import get_sequence_name\
- as original_get_sequence_name
-except ImportError:
- original_get_sequence_name = None
-
-from south.db import generic
-
-class DatabaseOperations(generic.DatabaseOperations):
- """
- Oracle implementation of database operations.
- """
- backend_name = 'oracle'
-
- alter_string_set_type = 'ALTER TABLE %(table_name)s MODIFY %(column)s %(type)s %(nullity)s;'
- alter_string_set_default = 'ALTER TABLE %(table_name)s MODIFY %(column)s DEFAULT %(default)s;'
- alter_string_update_nulls_to_default = \
- 'UPDATE %(table_name)s SET %(column)s = %(default)s WHERE %(column)s IS NULL;'
- add_column_string = 'ALTER TABLE %s ADD %s;'
- delete_column_string = 'ALTER TABLE %s DROP COLUMN %s;'
- add_constraint_string = 'ALTER TABLE %(table_name)s ADD CONSTRAINT %(constraint)s %(clause)s'
-
- allows_combined_alters = False
- has_booleans = False
-
- constraints_dict = {
- 'P': 'PRIMARY KEY',
- 'U': 'UNIQUE',
- 'C': 'CHECK',
- 'R': 'FOREIGN KEY'
- }
-
- def get_sequence_name(self, table_name):
- if original_get_sequence_name is None:
- return self._get_connection().ops._get_sequence_name(table_name)
- else:
- return original_get_sequence_name(table_name)
-
- #TODO: This will cause very obscure bugs if anyone uses a column name or string value
- # that looks like a column definition (with 'CHECK', 'DEFAULT' and/or 'NULL' in it)
- # e.g. "CHECK MATE" varchar(10) DEFAULT 'NULL'
- def adj_column_sql(self, col):
- # Syntax fixes -- Oracle is picky about clause order
- col = re.sub('(?P<constr>CHECK \(.*\))(?P<any>.*)(?P<default>DEFAULT \d+)',
- lambda mo: '%s %s%s'%(mo.group('default'), mo.group('constr'), mo.group('any')), col) #syntax fix for boolean/integer field only
- col = re.sub('(?P<not_null>(NOT )?NULL) (?P<misc>(.* )?)(?P<default>DEFAULT.+)',
- lambda mo: '%s %s %s'%(mo.group('default'),mo.group('not_null'),mo.group('misc') or ''), col) #fix order of NULL/NOT NULL and DEFAULT
- return col
-
- def check_meta(self, table_name):
- return table_name in [ m._meta.db_table for m in models.get_models() ] #caching provided by Django
-
- def normalize_name(self, name):
- """
- Get the properly shortened and uppercased identifier as returned by quote_name(), but without the actual quotes.
- """
- nn = self.quote_name(name)
- if nn[0] == '"' and nn[-1] == '"':
- nn = nn[1:-1]
- return nn
-
- @generic.invalidate_table_constraints
- def create_table(self, table_name, fields):
- qn = self.quote_name(table_name)
- columns = []
- autoinc_sql = ''
-
-
- for field_name, field in fields:
-
- field = self._field_sanity(field)
-
- # avoid default values in CREATE TABLE statements (#925)
- field._suppress_default = True
-
-
- col = self.column_sql(table_name, field_name, field)
- if not col:
- continue
- col = self.adj_column_sql(col)
-
- columns.append(col)
- if isinstance(field, models.AutoField):
- autoinc_sql = connection.ops.autoinc_sql(table_name, field_name)
-
- sql = 'CREATE TABLE %s (%s);' % (qn, ', '.join([col for col in columns]))
- self.execute(sql)
- if autoinc_sql:
- self.execute(autoinc_sql[0])
- self.execute(autoinc_sql[1])
-
- @generic.invalidate_table_constraints
- def delete_table(self, table_name, cascade=True):
- qn = self.quote_name(table_name)
-
- # Note: PURGE is not valid syntax for Oracle 9i (it was added in 10)
- if cascade:
- self.execute('DROP TABLE %s CASCADE CONSTRAINTS;' % qn)
- else:
- self.execute('DROP TABLE %s;' % qn)
-
- # If the table has an AutoField a sequence was created.
- sequence_sql = """
-DECLARE
- i INTEGER;
-BEGIN
- SELECT COUNT(*) INTO i FROM USER_CATALOG
- WHERE TABLE_NAME = '%(sq_name)s' AND TABLE_TYPE = 'SEQUENCE';
- IF i = 1 THEN
- EXECUTE IMMEDIATE 'DROP SEQUENCE "%(sq_name)s"';
- END IF;
-END;
-/""" % {'sq_name': self.get_sequence_name(table_name)}
- self.execute(sequence_sql)
-
- @generic.invalidate_table_constraints
- def alter_column(self, table_name, name, field, explicit_name=True, ignore_constraints=False):
-
- if self.dry_run:
- if self.debug:
- print(' - no dry run output for alter_column() due to dynamic DDL, sorry')
- return
-
- qn = self.quote_name(table_name)
-
- # hook for the field to do any resolution prior to it's attributes being queried
- if hasattr(field, 'south_init'):
- field.south_init()
- field = self._field_sanity(field)
-
- # Add _id or whatever if we need to
- field.set_attributes_from_name(name)
- if not explicit_name:
- name = field.column
- qn_col = self.quote_name(name)
-
- # First, change the type
- # This will actually also add any CHECK constraints needed,
- # since e.g. 'type' for a BooleanField is 'NUMBER(1) CHECK (%(qn_column)s IN (0,1))'
- params = {
- 'table_name':qn,
- 'column': qn_col,
- 'type': self._db_type_for_alter_column(field),
- 'nullity': 'NOT NULL',
- 'default': 'NULL'
- }
- if field.null:
- params['nullity'] = 'NULL'
-
- sql_templates = [
- (self.alter_string_set_type, params, []),
- (self.alter_string_set_default, params, []),
- ]
- if not field.null and field.has_default():
- # Use default for rows that had nulls. To support the case where
- # the new default does not fit the old type, we need to first change
- # the column type to the new type, but null=True; then set the default;
- # then complete the type change.
- def change_params(**kw):
- "A little helper for non-destructively changing the params"
- p = params.copy()
- p.update(kw)
- return p
- sql_templates[:0] = [
- (self.alter_string_set_type, change_params(nullity='NULL'),[]),
- (self.alter_string_update_nulls_to_default, change_params(default="%s"), [field.get_default()]),
- ]
-
- if not ignore_constraints:
- # drop CHECK constraints. Make sure this is executed before the ALTER TABLE statements
- # generated above, since those statements recreate the constraints we delete here.
- check_constraints = self._constraints_affecting_columns(table_name, [name], "CHECK")
- for constraint in check_constraints:
- self.execute(self.delete_check_sql % {
- 'table': self.quote_name(table_name),
- 'constraint': self.quote_name(constraint),
- })
- # Drop foreign constraints
- try:
- self.delete_foreign_key(qn, qn_col)
- except ValueError:
- # There weren't any
- pass
-
- for sql_template, params, args in sql_templates:
- try:
- self.execute(sql_template % params, args, print_all_errors=False)
- except DatabaseError as exc:
- description = str(exc)
- # Oracle complains if a column is already NULL/NOT NULL
- if 'ORA-01442' in description or 'ORA-01451' in description:
- # so we just drop NULL/NOT NULL part from target sql and retry
- params['nullity'] = ''
- sql = sql_template % params
- self.execute(sql)
- # Oracle also has issues if we try to change a regular column
- # to a LOB or vice versa (also REF, object, VARRAY or nested
- # table, but these don't come up much in Django apps)
- elif 'ORA-22858' in description or 'ORA-22859' in description:
- self._alter_column_lob_workaround(table_name, name, field)
- else:
- self._print_sql_error(exc, sql_template % params)
- raise
-
- if not ignore_constraints:
- # Add back FK constraints if needed
- if field.rel: #and self.supports_foreign_keys:
- self.add_deferred_sql(
- self.foreign_key_sql(
- qn[1:-1], # foreign_key_sql uses this as part of constraint name
- qn_col[1:-1], # foreign_key_sql uses this as part of constraint name
- field.rel.to._meta.db_table,
- field.rel.to._meta.get_field(field.rel.field_name).column
- )
- )
-
-
- def _alter_column_lob_workaround(self, table_name, name, field):
- """
- Oracle refuses to change a column type from/to LOB to/from a regular
- column. In Django, this shows up when the field is changed from/to
- a TextField.
- What we need to do instead is:
- - Rename the original column
- - Add the desired field as new
- - Update the table to transfer values from old to new
- - Drop old column
- """
- renamed = self._generate_temp_name(name)
- self.rename_column(table_name, name, renamed)
- self.add_column(table_name, name, field, keep_default=False)
- self.execute("UPDATE %s set %s=%s" % (
- self.quote_name(table_name),
- self.quote_name(name),
- self.quote_name(renamed),
- ))
- self.delete_column(table_name, renamed)
-
- def _generate_temp_name(self, for_name):
- suffix = hex(hash(for_name)).upper()[1:]
- return self.normalize_name(for_name + "_" + suffix)
-
- @generic.copy_column_constraints #TODO: Appears to be nulled by the delete decorator below...
- @generic.delete_column_constraints
- def rename_column(self, table_name, old, new):
- if old == new:
- # Short-circuit out
- return []
- self.execute('ALTER TABLE %s RENAME COLUMN %s TO %s;' % (
- self.quote_name(table_name),
- self.quote_name(old),
- self.quote_name(new),
- ))
-
- @generic.invalidate_table_constraints
- def add_column(self, table_name, name, field, keep_default=False):
- field = self._field_sanity(field)
- sql = self.column_sql(table_name, name, field)
- sql = self.adj_column_sql(sql)
-
- if sql:
- params = (
- self.quote_name(table_name),
- sql
- )
- sql = self.add_column_string % params
- self.execute(sql)
-
- # Now, drop the default if we need to
- if field.default is not None:
- field.default = NOT_PROVIDED
- self.alter_column(table_name, name, field, explicit_name=False, ignore_constraints=True)
-
- def delete_column(self, table_name, name):
- return super(DatabaseOperations, self).delete_column(self.quote_name(table_name), name)
-
- def lookup_constraint(self, db_name, table_name, column_name=None):
- if column_name:
- # Column names in the constraint cache come from the database,
- # make sure we use the properly shortened/uppercased version
- # for lookup.
- column_name = self.normalize_name(column_name)
- return super(DatabaseOperations, self).lookup_constraint(db_name, table_name, column_name)
-
- def _constraints_affecting_columns(self, table_name, columns, type="UNIQUE"):
- if columns:
- columns = [self.normalize_name(c) for c in columns]
- return super(DatabaseOperations, self)._constraints_affecting_columns(table_name, columns, type)
-
- def _field_sanity(self, field):
- """
- This particular override stops us sending DEFAULTs for BooleanField.
- """
- if isinstance(field, models.BooleanField) and field.has_default():
- field.default = int(field.to_python(field.get_default()))
- # On Oracle, empty strings are null
- if isinstance(field, (models.CharField, models.TextField)):
- field.null = field.empty_strings_allowed
- return field
-
-
- def _default_value_workaround(self, value):
- from datetime import date,time,datetime
- if isinstance(value, (date,time,datetime)):
- return "'%s'" % value
- else:
- return super(DatabaseOperations, self)._default_value_workaround(value)
-
- def _fill_constraint_cache(self, db_name, table_name):
- self._constraint_cache.setdefault(db_name, {})
- self._constraint_cache[db_name][table_name] = {}
-
- rows = self.execute("""
- SELECT user_cons_columns.constraint_name,
- user_cons_columns.column_name,
- user_constraints.constraint_type
- FROM user_constraints
- JOIN user_cons_columns ON
- user_constraints.table_name = user_cons_columns.table_name AND
- user_constraints.constraint_name = user_cons_columns.constraint_name
- WHERE user_constraints.table_name = '%s'
- """ % self.normalize_name(table_name))
-
- for constraint, column, kind in rows:
- self._constraint_cache[db_name][table_name].setdefault(column, set())
- self._constraint_cache[db_name][table_name][column].add((self.constraints_dict[kind], constraint))
- return
diff --git a/lib/python2.7/site-packages/south/db/postgresql_psycopg2.py b/lib/python2.7/site-packages/south/db/postgresql_psycopg2.py deleted file mode 100644 index d6c63c4..0000000 --- a/lib/python2.7/site-packages/south/db/postgresql_psycopg2.py +++ /dev/null @@ -1,96 +0,0 @@ -from __future__ import print_function - -import uuid -from django.db.backends.util import truncate_name -from south.db import generic - - -class DatabaseOperations(generic.DatabaseOperations): - - """ - PsycoPG2 implementation of database operations. - """ - - backend_name = "postgres" - - def create_index_name(self, table_name, column_names, suffix=""): - """ - Generate a unique name for the index - - Django's logic for naming field indexes is different in the - postgresql_psycopg2 backend, so we follow that for single-column - indexes. - """ - - if len(column_names) == 1: - return truncate_name( - '%s_%s%s' % (table_name, column_names[0], suffix), - self._get_connection().ops.max_name_length() - ) - return super(DatabaseOperations, self).create_index_name(table_name, column_names, suffix) - - @generic.copy_column_constraints - @generic.delete_column_constraints - def rename_column(self, table_name, old, new): - if old == new: - # Short-circuit out - return [] - self.execute('ALTER TABLE %s RENAME COLUMN %s TO %s;' % ( - self.quote_name(table_name), - self.quote_name(old), - self.quote_name(new), - )) - - @generic.invalidate_table_constraints - def rename_table(self, old_table_name, table_name): - "will rename the table and an associated ID sequence and primary key index" - # First, rename the table - generic.DatabaseOperations.rename_table(self, old_table_name, table_name) - # Then, try renaming the ID sequence - # (if you're using other AutoFields... your problem, unfortunately) - - if self.execute( - """ - SELECT 1 - FROM information_schema.sequences - WHERE sequence_name = %s - """, - [old_table_name + '_id_seq'] - ): - generic.DatabaseOperations.rename_table(self, old_table_name + "_id_seq", table_name + "_id_seq") - - # Rename primary key index, will not rename other indices on - # the table that are used by django (e.g. foreign keys). Until - # figure out how, you need to do this yourself. - - pkey_index_names = self.execute( - """ - SELECT pg_index.indexrelid::regclass - FROM pg_index, pg_attribute - WHERE - indrelid = %s::regclass AND - pg_attribute.attrelid = indrelid AND - pg_attribute.attnum = any(pg_index.indkey) - AND indisprimary - """, - [table_name] - ) - if old_table_name + "_pkey" in pkey_index_names: - generic.DatabaseOperations.rename_table(self, old_table_name + "_pkey", table_name + "_pkey") - - def rename_index(self, old_index_name, index_name): - "Rename an index individually" - generic.DatabaseOperations.rename_table(self, old_index_name, index_name) - - def _default_value_workaround(self, value): - "Support for UUIDs on psql" - if isinstance(value, uuid.UUID): - return str(value) - else: - return super(DatabaseOperations, self)._default_value_workaround(value) - - def _db_type_for_alter_column(self, field): - return self._db_positive_type_for_alter_column(DatabaseOperations, field) - - def _alter_add_column_mods(self, field, name, params, sqls): - return self._alter_add_positive_check(DatabaseOperations, field, name, params, sqls) diff --git a/lib/python2.7/site-packages/south/db/sql_server/__init__.py b/lib/python2.7/site-packages/south/db/sql_server/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/lib/python2.7/site-packages/south/db/sql_server/__init__.py +++ /dev/null diff --git a/lib/python2.7/site-packages/south/db/sql_server/pyodbc.py b/lib/python2.7/site-packages/south/db/sql_server/pyodbc.py deleted file mode 100644 index b725ec0..0000000 --- a/lib/python2.7/site-packages/south/db/sql_server/pyodbc.py +++ /dev/null @@ -1,444 +0,0 @@ -from datetime import date, datetime, time -from warnings import warn -from django.db import models -from django.db.models import fields -from south.db import generic -from south.db.generic import delete_column_constraints, invalidate_table_constraints, copy_column_constraints -from south.exceptions import ConstraintDropped -from south.utils.py3 import string_types -try: - from django.utils.encoding import smart_text # Django >= 1.5 -except ImportError: - from django.utils.encoding import smart_unicode as smart_text # Django < 1.5 -from django.core.management.color import no_style - -class DatabaseOperations(generic.DatabaseOperations): - """ - django-pyodbc (sql_server.pyodbc) implementation of database operations. - """ - - backend_name = "pyodbc" - - add_column_string = 'ALTER TABLE %s ADD %s;' - alter_string_set_type = 'ALTER COLUMN %(column)s %(type)s' - alter_string_set_null = 'ALTER COLUMN %(column)s %(type)s NULL' - alter_string_drop_null = 'ALTER COLUMN %(column)s %(type)s NOT NULL' - - allows_combined_alters = False - - drop_index_string = 'DROP INDEX %(index_name)s ON %(table_name)s' - drop_constraint_string = 'ALTER TABLE %(table_name)s DROP CONSTRAINT %(constraint_name)s' - delete_column_string = 'ALTER TABLE %s DROP COLUMN %s' - - #create_check_constraint_sql = "ALTER TABLE %(table)s " + \ - # generic.DatabaseOperations.add_check_constraint_fragment - create_foreign_key_sql = "ALTER TABLE %(table)s ADD CONSTRAINT %(constraint)s " + \ - "FOREIGN KEY (%(column)s) REFERENCES %(target)s" - create_unique_sql = "ALTER TABLE %(table)s ADD CONSTRAINT %(constraint)s UNIQUE (%(columns)s)" - - - default_schema_name = "dbo" - - has_booleans = False - - - @delete_column_constraints - def delete_column(self, table_name, name): - q_table_name, q_name = (self.quote_name(table_name), self.quote_name(name)) - - # Zap the constraints - for const in self._find_constraints_for_column(table_name,name): - params = {'table_name':q_table_name, 'constraint_name': const} - sql = self.drop_constraint_string % params - self.execute(sql, []) - - # Zap the indexes - for ind in self._find_indexes_for_column(table_name,name): - params = {'table_name':q_table_name, 'index_name': ind} - sql = self.drop_index_string % params - self.execute(sql, []) - - # Zap default if exists - drop_default = self.drop_column_default_sql(table_name, name) - if drop_default: - sql = "ALTER TABLE [%s] %s" % (table_name, drop_default) - self.execute(sql, []) - - # Finally zap the column itself - self.execute(self.delete_column_string % (q_table_name, q_name), []) - - def _find_indexes_for_column(self, table_name, name): - "Find the indexes that apply to a column, needed when deleting" - - sql = """ - SELECT si.name, si.id, sik.colid, sc.name - FROM dbo.sysindexes si WITH (NOLOCK) - INNER JOIN dbo.sysindexkeys sik WITH (NOLOCK) - ON sik.id = si.id - AND sik.indid = si.indid - INNER JOIN dbo.syscolumns sc WITH (NOLOCK) - ON si.id = sc.id - AND sik.colid = sc.colid - WHERE si.indid !=0 - AND si.id = OBJECT_ID('%s') - AND sc.name = '%s' - """ - idx = self.execute(sql % (table_name, name), []) - return [i[0] for i in idx] - - - def _find_constraints_for_column(self, table_name, name, just_names=True): - """ - Find the constraints that apply to a column, needed when deleting. Defaults not included. - This is more general than the parent _constraints_affecting_columns, as on MSSQL this - includes PK and FK constraints. - """ - - sql = """ - SELECT CC.[CONSTRAINT_NAME] - ,TC.[CONSTRAINT_TYPE] - ,CHK.[CHECK_CLAUSE] - ,RFD.TABLE_SCHEMA - ,RFD.TABLE_NAME - ,RFD.COLUMN_NAME - -- used for normalized names - ,CC.TABLE_NAME - ,CC.COLUMN_NAME - FROM [INFORMATION_SCHEMA].[TABLE_CONSTRAINTS] TC - JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CC - ON TC.CONSTRAINT_CATALOG = CC.CONSTRAINT_CATALOG - AND TC.CONSTRAINT_SCHEMA = CC.CONSTRAINT_SCHEMA - AND TC.CONSTRAINT_NAME = CC.CONSTRAINT_NAME - LEFT JOIN INFORMATION_SCHEMA.CHECK_CONSTRAINTS CHK - ON CHK.CONSTRAINT_CATALOG = CC.CONSTRAINT_CATALOG - AND CHK.CONSTRAINT_SCHEMA = CC.CONSTRAINT_SCHEMA - AND CHK.CONSTRAINT_NAME = CC.CONSTRAINT_NAME - AND 'CHECK' = TC.CONSTRAINT_TYPE - LEFT JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS REF - ON REF.CONSTRAINT_CATALOG = CC.CONSTRAINT_CATALOG - AND REF.CONSTRAINT_SCHEMA = CC.CONSTRAINT_SCHEMA - AND REF.CONSTRAINT_NAME = CC.CONSTRAINT_NAME - AND 'FOREIGN KEY' = TC.CONSTRAINT_TYPE - LEFT JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE RFD - ON RFD.CONSTRAINT_CATALOG = REF.UNIQUE_CONSTRAINT_CATALOG - AND RFD.CONSTRAINT_SCHEMA = REF.UNIQUE_CONSTRAINT_SCHEMA - AND RFD.CONSTRAINT_NAME = REF.UNIQUE_CONSTRAINT_NAME - WHERE CC.CONSTRAINT_CATALOG = CC.TABLE_CATALOG - AND CC.CONSTRAINT_SCHEMA = CC.TABLE_SCHEMA - AND CC.TABLE_CATALOG = %s - AND CC.TABLE_SCHEMA = %s - AND CC.TABLE_NAME = %s - AND CC.COLUMN_NAME = %s - """ - db_name = self._get_setting('name') - schema_name = self._get_schema_name() - table = self.execute(sql, [db_name, schema_name, table_name, name]) - - if just_names: - return [r[0] for r in table] - - all = {} - for r in table: - cons_name, type = r[:2] - if type=='PRIMARY KEY' or type=='UNIQUE': - cons = all.setdefault(cons_name, (type,[])) - sql = ''' - SELECT COLUMN_NAME - FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE RFD - WHERE RFD.CONSTRAINT_CATALOG = %s - AND RFD.CONSTRAINT_SCHEMA = %s - AND RFD.TABLE_NAME = %s - AND RFD.CONSTRAINT_NAME = %s - ''' - columns = self.execute(sql, [db_name, schema_name, table_name, cons_name]) - cons[1].extend(col for col, in columns) - elif type=='CHECK': - cons = (type, r[2]) - elif type=='FOREIGN KEY': - if cons_name in all: - raise NotImplementedError("Multiple-column foreign keys are not supported") - else: - cons = (type, r[3:6]) - else: - raise NotImplementedError("Don't know how to handle constraints of type "+ type) - all[cons_name] = cons - return all - - @invalidate_table_constraints - def alter_column(self, table_name, name, field, explicit_name=True, ignore_constraints=False): - """ - Alters the given column name so it will match the given field. - Note that conversion between the two by the database must be possible. - Will not automatically add _id by default; to have this behavour, pass - explicit_name=False. - - @param table_name: The name of the table to add the column to - @param name: The name of the column to alter - @param field: The new field definition to use - """ - self._fix_field_definition(field) - - if not ignore_constraints: - qn = self.quote_name - sch = qn(self._get_schema_name()) - tab = qn(table_name) - table = ".".join([sch, tab]) - try: - self.delete_foreign_key(table_name, name) - except ValueError: - # no FK constraint on this field. That's OK. - pass - constraints = self._find_constraints_for_column(table_name, name, False) - for constraint in constraints.keys(): - params = dict(table_name = table, - constraint_name = qn(constraint)) - sql = self.drop_constraint_string % params - self.execute(sql, []) - - ret_val = super(DatabaseOperations, self).alter_column(table_name, name, field, explicit_name, ignore_constraints=True) - - if not ignore_constraints: - for cname, (ctype,args) in constraints.items(): - params = dict(table = table, - constraint = qn(cname)) - if ctype=='UNIQUE': - params['columns'] = ", ".join(map(qn,args)) - sql = self.create_unique_sql % params - elif ctype=='PRIMARY KEY': - params['columns'] = ", ".join(map(qn,args)) - sql = self.create_primary_key_string % params - elif ctype=='FOREIGN KEY': - continue - # Foreign keys taken care of below - #target = "%s.%s(%s)" % tuple(map(qn,args)) - #params.update(column = qn(name), target = target) - #sql = self.create_foreign_key_sql % params - elif ctype=='CHECK': - warn(ConstraintDropped("CHECK "+ args, table_name, name)) - continue - #TODO: Some check constraints should be restored; but not before the generic - # backend restores them. - #params['check'] = args - #sql = self.create_check_constraint_sql % params - else: - raise NotImplementedError("Don't know how to handle constraints of type "+ type) - self.execute(sql, []) - # Create foreign key if necessary - if field.rel and self.supports_foreign_keys: - self.execute( - self.foreign_key_sql( - table_name, - field.column, - field.rel.to._meta.db_table, - field.rel.to._meta.get_field(field.rel.field_name).column - ) - ) - model = self.mock_model("FakeModelForIndexCreation", table_name) - for stmt in self._get_connection().creation.sql_indexes_for_field(model, field, no_style()): - self.execute(stmt) - - - return ret_val - - def _alter_set_defaults(self, field, name, params, sqls): - "Subcommand of alter_column that sets default values (overrideable)" - # Historically, we used to set defaults here. - # But since South 0.8, we don't ever set defaults on alter-column -- we only - # use database-level defaults as scaffolding when adding columns. - # However, we still sometimes need to remove defaults in alter-column. - table_name = self.quote_name(params['table_name']) - drop_default = self.drop_column_default_sql(table_name, name) - if drop_default: - sqls.append((drop_default, [])) - - def _value_to_unquoted_literal(self, field, value): - # Start with the field's own translation - conn = self._get_connection() - value = field.get_db_prep_save(value, connection=conn) - # This is still a Python object -- nobody expects to need a literal. - if isinstance(value, string_types): - return smart_text(value) - elif isinstance(value, (date,time,datetime)): - return value.isoformat() - else: - #TODO: Anybody else needs special translations? - return str(value) - def _default_value_workaround(self, value): - if isinstance(value, (date,time,datetime)): - return value.isoformat() - else: - return super(DatabaseOperations, self)._default_value_workaround(value) - - def _quote_string(self, s): - return "'" + s.replace("'","''") + "'" - - - def drop_column_default_sql(self, table_name, name, q_name=None): - "MSSQL specific drop default, which is a pain" - - sql = """ - SELECT object_name(cdefault) - FROM syscolumns - WHERE id = object_id('%s') - AND name = '%s' - """ - cons = self.execute(sql % (table_name, name), []) - if cons and cons[0] and cons[0][0]: - return "DROP CONSTRAINT %s" % cons[0][0] - return None - - def _fix_field_definition(self, field): - if isinstance(field, (fields.BooleanField, fields.NullBooleanField)): - if field.default == True: - field.default = 1 - if field.default == False: - field.default = 0 - - # This is copied from South's generic add_column, with two modifications: - # 1) The sql-server-specific call to _fix_field_definition - # 2) Removing a default, when needed, by calling drop_default and not the more general alter_column - @invalidate_table_constraints - def add_column(self, table_name, name, field, keep_default=False): - """ - Adds the column 'name' to the table 'table_name'. - Uses the 'field' paramater, a django.db.models.fields.Field instance, - to generate the necessary sql - - @param table_name: The name of the table to add the column to - @param name: The name of the column to add - @param field: The field to use - """ - self._fix_field_definition(field) - sql = self.column_sql(table_name, name, field) - if sql: - params = ( - self.quote_name(table_name), - sql, - ) - sql = self.add_column_string % params - self.execute(sql) - - # Now, drop the default if we need to - if not keep_default and field.default is not None: - field.default = fields.NOT_PROVIDED - #self.alter_column(table_name, name, field, explicit_name=False, ignore_constraints=True) - self.drop_default(table_name, name, field) - - @invalidate_table_constraints - def drop_default(self, table_name, name, field): - fragment = self.drop_column_default_sql(table_name, name) - if fragment: - table_name = self.quote_name(table_name) - sql = " ".join(["ALTER TABLE", table_name, fragment]) - self.execute(sql) - - - @invalidate_table_constraints - def create_table(self, table_name, field_defs): - # Tweak stuff as needed - for _, f in field_defs: - self._fix_field_definition(f) - - # Run - super(DatabaseOperations, self).create_table(table_name, field_defs) - - def _find_referencing_fks(self, table_name): - "MSSQL does not support cascading FKs when dropping tables, we need to implement." - - # FK -- Foreign Keys - # UCTU -- Unique Constraints Table Usage - # FKTU -- Foreign Key Table Usage - # (last two are both really CONSTRAINT_TABLE_USAGE, different join conditions) - sql = """ - SELECT FKTU.TABLE_SCHEMA as REFING_TABLE_SCHEMA, - FKTU.TABLE_NAME as REFING_TABLE_NAME, - FK.[CONSTRAINT_NAME] as FK_NAME - FROM [INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS] FK - JOIN [INFORMATION_SCHEMA].[CONSTRAINT_TABLE_USAGE] UCTU - ON FK.UNIQUE_CONSTRAINT_CATALOG = UCTU.CONSTRAINT_CATALOG and - FK.UNIQUE_CONSTRAINT_NAME = UCTU.CONSTRAINT_NAME and - FK.UNIQUE_CONSTRAINT_SCHEMA = UCTU.CONSTRAINT_SCHEMA - JOIN [INFORMATION_SCHEMA].[CONSTRAINT_TABLE_USAGE] FKTU - ON FK.CONSTRAINT_CATALOG = FKTU.CONSTRAINT_CATALOG and - FK.CONSTRAINT_NAME = FKTU.CONSTRAINT_NAME and - FK.CONSTRAINT_SCHEMA = FKTU.CONSTRAINT_SCHEMA - WHERE FK.CONSTRAINT_CATALOG = %s - AND UCTU.TABLE_SCHEMA = %s -- REFD_TABLE_SCHEMA - AND UCTU.TABLE_NAME = %s -- REFD_TABLE_NAME - """ - db_name = self._get_setting('name') - schema_name = self._get_schema_name() - return self.execute(sql, [db_name, schema_name, table_name]) - - @invalidate_table_constraints - def delete_table(self, table_name, cascade=True): - """ - Deletes the table 'table_name'. - """ - if cascade: - refing = self._find_referencing_fks(table_name) - for schmea, table, constraint in refing: - table = ".".join(map (self.quote_name, [schmea, table])) - params = dict(table_name = table, - constraint_name = self.quote_name(constraint)) - sql = self.drop_constraint_string % params - self.execute(sql, []) - cascade = False - super(DatabaseOperations, self).delete_table(table_name, cascade) - - @copy_column_constraints - @delete_column_constraints - def rename_column(self, table_name, old, new): - """ - Renames the column of 'table_name' from 'old' to 'new'. - WARNING - This isn't transactional on MSSQL! - """ - if old == new: - # No Operation - return - # Examples on the MS site show the table name not being quoted... - params = (table_name, self.quote_name(old), self.quote_name(new)) - self.execute("EXEC sp_rename '%s.%s', %s, 'COLUMN'" % params) - - @invalidate_table_constraints - def rename_table(self, old_table_name, table_name): - """ - Renames the table 'old_table_name' to 'table_name'. - WARNING - This isn't transactional on MSSQL! - """ - if old_table_name == table_name: - # No Operation - return - params = (self.quote_name(old_table_name), self.quote_name(table_name)) - self.execute('EXEC sp_rename %s, %s' % params) - - def _db_type_for_alter_column(self, field): - return self._db_positive_type_for_alter_column(DatabaseOperations, field) - - def _alter_add_column_mods(self, field, name, params, sqls): - return self._alter_add_positive_check(DatabaseOperations, field, name, params, sqls) - - @invalidate_table_constraints - def delete_foreign_key(self, table_name, column): - super(DatabaseOperations, self).delete_foreign_key(table_name, column) - # A FK also implies a non-unique index - find_index_sql = """ - SELECT i.name -- s.name, t.name, c.name - FROM sys.tables t - INNER JOIN sys.schemas s ON t.schema_id = s.schema_id - INNER JOIN sys.indexes i ON i.object_id = t.object_id - INNER JOIN sys.index_columns ic ON ic.object_id = t.object_id - AND ic.index_id = i.index_id - INNER JOIN sys.columns c ON c.object_id = t.object_id - AND ic.column_id = c.column_id - WHERE i.is_unique=0 AND i.is_primary_key=0 AND i.is_unique_constraint=0 - AND s.name = %s - AND t.name = %s - AND c.name = %s - """ - schema = self._get_schema_name() - indexes = self.execute(find_index_sql, [schema, table_name, column]) - qn = self.quote_name - for index in (i[0] for i in indexes if i[0]): # "if i[0]" added because an empty name may return - self.execute("DROP INDEX %s on %s.%s" % (qn(index), qn(schema), qn(table_name) )) - diff --git a/lib/python2.7/site-packages/south/db/sqlite3.py b/lib/python2.7/site-packages/south/db/sqlite3.py deleted file mode 100644 index c4014d3..0000000 --- a/lib/python2.7/site-packages/south/db/sqlite3.py +++ /dev/null @@ -1,272 +0,0 @@ -from south.db import generic
-
-
-class DatabaseOperations(generic.DatabaseOperations):
-
- """
- SQLite3 implementation of database operations.
- """
-
- backend_name = "sqlite3"
-
- # SQLite ignores several constraints. I wish I could.
- supports_foreign_keys = False
- has_check_constraints = False
- has_booleans = False
-
- def add_column(self, table_name, name, field, *args, **kwds):
- """
- Adds a column.
- """
- # If it's not nullable, and has no default, raise an error (SQLite is picky)
- if (not field.null and
- (not field.has_default() or field.get_default() is None) and
- not field.empty_strings_allowed):
- raise ValueError("You cannot add a null=False column without a default value.")
- # Initialise the field.
- field.set_attributes_from_name(name)
- # We add columns by remaking the table; even though SQLite supports
- # adding columns, it doesn't support adding PRIMARY KEY or UNIQUE cols.
- # We define fields with no default; a default will be used, though, to fill up the remade table
- field_default = None
- if not getattr(field, '_suppress_default', False):
- default = field.get_default()
- if default is not None:
- field_default = "'%s'" % field.get_db_prep_save(default, connection=self._get_connection())
- field._suppress_default = True
- self._remake_table(table_name, added={
- field.column: (self._column_sql_for_create(table_name, name, field, False), field_default)
- })
-
- def _get_full_table_description(self, connection, cursor, table_name):
- cursor.execute('PRAGMA table_info(%s)' % connection.ops.quote_name(table_name))
- # cid, name, type, notnull, dflt_value, pk
- return [{'name': field[1],
- 'type': field[2],
- 'null_ok': not field[3],
- 'dflt_value': field[4],
- 'pk': field[5] # undocumented
- } for field in cursor.fetchall()]
-
- @generic.invalidate_table_constraints
- def _remake_table(self, table_name, added={}, renames={}, deleted=[], altered={}, primary_key_override=None, uniques_deleted=[]):
- """
- Given a table and three sets of changes (renames, deletes, alters),
- recreates it with the modified schema.
- """
- # Dry runs get skipped completely
- if self.dry_run:
- return
- # Temporary table's name
- temp_name = "_south_new_" + table_name
- # Work out the (possibly new) definitions of each column
- definitions = {}
- cursor = self._get_connection().cursor()
- # Get the index descriptions
- indexes = self._get_connection().introspection.get_indexes(cursor, table_name)
- standalone_indexes = self._get_standalone_indexes(table_name)
- # Work out new column defs.
- for column_info in self._get_full_table_description(self._get_connection(), cursor, table_name):
- name = column_info['name']
- if name in deleted:
- continue
- # Get the type, ignoring PRIMARY KEY (we need to be consistent)
- type = column_info['type'].replace("PRIMARY KEY", "")
- # Add on primary key, not null or unique if needed.
- if (primary_key_override and primary_key_override == name) or \
- (not primary_key_override and name in indexes and
- indexes[name]['primary_key']):
- type += " PRIMARY KEY"
- elif not column_info['null_ok']:
- type += " NOT NULL"
- if (name in indexes and indexes[name]['unique'] and
- name not in uniques_deleted):
- type += " UNIQUE"
- if column_info['dflt_value'] is not None:
- type += " DEFAULT " + column_info['dflt_value']
- # Deal with a rename
- if name in renames:
- name = renames[name]
- # Add to the defs
- definitions[name] = type
- # Add on altered columns
- for name, type in altered.items():
- if (primary_key_override and primary_key_override == name) or \
- (not primary_key_override and name in indexes and
- indexes[name]['primary_key']):
- type += " PRIMARY KEY"
- if (name in indexes and indexes[name]['unique'] and
- name not in uniques_deleted):
- type += " UNIQUE"
- definitions[name] = type
- # Add on the new columns
- for name, (type,_) in added.items():
- if (primary_key_override and primary_key_override == name):
- type += " PRIMARY KEY"
- definitions[name] = type
- # Alright, Make the table
- self.execute("CREATE TABLE %s (%s)" % (
- self.quote_name(temp_name),
- ", ".join(["%s %s" % (self.quote_name(cname), ctype) for cname, ctype in definitions.items()]),
- ))
- # Copy over the data
- self._copy_data(table_name, temp_name, renames, added)
- # Delete the old table, move our new one over it
- self.delete_table(table_name)
- self.rename_table(temp_name, table_name)
- # Recreate multi-valued indexes
- # We can't do that before since it's impossible to rename indexes
- # and index name scope is global
- self._make_standalone_indexes(table_name, standalone_indexes, renames=renames, deleted=deleted, uniques_deleted=uniques_deleted)
- self.deferred_sql = [] # prevent double indexing
-
- def _copy_data(self, src, dst, field_renames={}, added={}):
- "Used to copy data into a new table"
- # Make a list of all the fields to select
- cursor = self._get_connection().cursor()
- src_fields = [column_info[0] for column_info in self._get_connection().introspection.get_table_description(cursor, src)]
- dst_fields = [column_info[0] for column_info in self._get_connection().introspection.get_table_description(cursor, dst)]
- src_fields_new = []
- dst_fields_new = []
- for field in src_fields:
- if field in field_renames:
- dst_fields_new.append(self.quote_name(field_renames[field]))
- elif field in dst_fields:
- dst_fields_new.append(self.quote_name(field))
- else:
- continue
- src_fields_new.append(self.quote_name(field))
- for field, (_,default) in added.items():
- if default is not None:
- field = self.quote_name(field)
- src_fields_new.append("%s as %s" % (default, field))
- dst_fields_new.append(field)
- # Copy over the data
- self.execute("INSERT INTO %s (%s) SELECT %s FROM %s;" % (
- self.quote_name(dst),
- ', '.join(dst_fields_new),
- ', '.join(src_fields_new),
- self.quote_name(src),
- ))
-
- def _create_unique(self, table_name, columns):
- self._create_index(table_name, columns, True)
-
- def _create_index(self, table_name, columns, unique=False, index_name=None):
- if index_name is None:
- index_name = '%s_%s' % (table_name, '__'.join(columns))
- self.execute("CREATE %sINDEX %s ON %s(%s);" % (
- unique and "UNIQUE " or "",
- self.quote_name(index_name),
- self.quote_name(table_name),
- ', '.join(self.quote_name(c) for c in columns),
- ))
-
- def _get_standalone_indexes(self, table_name):
- indexes = []
- cursor = self._get_connection().cursor()
- cursor.execute('PRAGMA index_list(%s)' % self.quote_name(table_name))
- # seq, name, unique
- for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]:
- cursor.execute('PRAGMA index_info(%s)' % self.quote_name(index))
- info = cursor.fetchall()
- if len(info) == 1 and unique:
- # This index is already specified in the CREATE TABLE columns
- # specification
- continue
- columns = []
- for field in info:
- columns.append(field[2])
- indexes.append((index, columns, unique))
- return indexes
-
- def _make_standalone_indexes(self, table_name, indexes, deleted=[], renames={}, uniques_deleted=[]):
- for index_name, index, unique in indexes:
- columns = []
-
- for name in index:
- # Handle deletion
- if name in deleted:
- columns = []
- break
-
- # Handle renames
- if name in renames:
- name = renames[name]
- columns.append(name)
-
- if columns and (set(columns) != set(uniques_deleted) or not unique):
- self._create_index(table_name, columns, unique, index_name)
-
- def _column_sql_for_create(self, table_name, name, field, explicit_name=True):
- "Given a field and its name, returns the full type for the CREATE TABLE (without unique/pk)"
- field.set_attributes_from_name(name)
- if not explicit_name:
- name = field.db_column
- else:
- field.column = name
- sql = self.column_sql(table_name, name, field, with_name=False, field_prepared=True)
- # Remove keywords we don't want (this should be type only, not constraint)
- if sql:
- sql = sql.replace("PRIMARY KEY", "")
- return sql
-
- def alter_column(self, table_name, name, field, explicit_name=True, ignore_constraints=False):
- """
- Changes a column's SQL definition.
-
- Note that this sqlite3 implementation ignores the ignore_constraints argument.
- The argument is accepted for API compatibility with the generic
- DatabaseOperations.alter_column() method.
- """
- # Change nulls to default if needed
- if not field.null and field.has_default():
- params = {
- "column": self.quote_name(name),
- "table_name": self.quote_name(table_name)
- }
- self._update_nulls_to_default(params, field)
- # Remake the table correctly
- field._suppress_default = True
- self._remake_table(table_name, altered={
- name: self._column_sql_for_create(table_name, name, field, explicit_name),
- })
-
- def delete_column(self, table_name, column_name):
- """
- Deletes a column.
- """
- self._remake_table(table_name, deleted=[column_name])
-
- def rename_column(self, table_name, old, new):
- """
- Renames a column from one name to another.
- """
- self._remake_table(table_name, renames={old: new})
-
- def create_unique(self, table_name, columns):
- """
- Create an unique index on columns
- """
- self._create_unique(table_name, columns)
-
- def delete_unique(self, table_name, columns):
- """
- Delete an unique index
- """
- self._remake_table(table_name, uniques_deleted=columns)
-
- def create_primary_key(self, table_name, columns):
- if not isinstance(columns, (list, tuple)):
- columns = [columns]
- assert len(columns) == 1, "SQLite backend does not support multi-column primary keys"
- self._remake_table(table_name, primary_key_override=columns[0])
-
- # Not implemented this yet.
- def delete_primary_key(self, table_name):
- # By passing True in, we make sure we wipe all existing PKs.
- self._remake_table(table_name, primary_key_override=True)
-
- # No cascades on deletes
- def delete_table(self, table_name, cascade=True):
- generic.DatabaseOperations.delete_table(self, table_name, False)
|