Exemple #1
0
 def add_inline_fk_sql(self, ctx, field):
     ctx = (ctx.literal(' REFERENCES ').sql(
         Entity(field.rel_model._meta.table_name)).literal(' ').sql(
             EnclosedNodeList((Entity(field.rel_field.column_name), ))))
     if field.on_delete is not None:
         ctx = ctx.literal(' ON DELETE %s' % field.on_delete)
     if field.on_update is not None:
         ctx = ctx.literal(' ON UPDATE %s' % field.on_update)
     return ctx
Exemple #2
0
    def apply_default(self, table, column_name, field):
        default = field.default
        if callable_(default):
            default = default()

        return (self.make_context().literal('UPDATE ').sql(
            Entity(table)).literal(' SET ').sql(
                Expression(Entity(column_name),
                           OP.EQ,
                           field.db_value(default),
                           flat=True)))
Exemple #3
0
 def alter_column_type(self, table, column, field, cast=None):
     if cast is not None:
         raise ValueError('alter_column_type() does not support cast with '
                          'MySQL.')
     ctx = self.make_context()
     return (self._alter_table(ctx, table).literal(' MODIFY ').sql(
         Entity(column)).literal(' ').sql(field.ddl(ctx)))
Exemple #4
0
    def _fts_cmd_sql(cls, cmd, **extra_params):
        tbl = cls._meta.entity
        columns = [tbl]
        values = [cmd]
        for key, value in extra_params.items():
            columns.append(Entity(key))
            values.append(value)

        return NodeList(
            (SQL('INSERT INTO'), cls._meta.entity, EnclosedNodeList(columns),
             SQL('VALUES'), EnclosedNodeList(values)))
Exemple #5
0
 def add_foreign_key_constraint(self,
                                table,
                                column_name,
                                rel,
                                rel_column,
                                on_delete=None,
                                on_update=None):
     constraint = 'fk_%s_%s_refs_%s' % (table, column_name, rel)
     ctx = (self.make_context().literal('ALTER TABLE ').sql(
         Entity(table)).literal(' ADD CONSTRAINT ').sql(
             Entity(_truncate_constraint_name(constraint))).
            literal(' FOREIGN KEY ').sql(
                EnclosedNodeList(
                    (Entity(column_name), ))).literal(' REFERENCES ').sql(
                        Entity(rel)).literal(' (').sql(
                            Entity(rel_column)).literal(')'))
     if on_delete is not None:
         ctx = ctx.literal(' ON DELETE %s' % on_delete)
     if on_update is not None:
         ctx = ctx.literal(' ON UPDATE %s' % on_update)
     return ctx
Exemple #6
0
    def drop_column(self, table, column_name, cascade=True):
        ctx = self.make_context()
        (self._alter_table(ctx, table).literal(' DROP COLUMN ').sql(
            Entity(column_name)))

        if cascade:
            ctx.literal(' CASCADE')

        fk_columns = [
            foreign_key.column
            for foreign_key in self.database.get_foreign_keys(table)
        ]
        if column_name in fk_columns and self.explicit_delete_foreign_key:
            return [self.drop_foreign_key_constraint(table, column_name), ctx]

        return ctx
Exemple #7
0
 def sql(self, column_name=None, is_null=None):
     if is_null is None:
         is_null = self.is_null
     if column_name is None:
         column_name = self.name
     parts = [Entity(column_name), SQL(self.definition)]
     if self.is_unique:
         parts.append(SQL('UNIQUE'))
     if is_null:
         parts.append(SQL('NULL'))
     else:
         parts.append(SQL('NOT NULL'))
     if self.is_pk:
         parts.append(SQL('PRIMARY KEY'))
     if self.extra:
         parts.append(SQL(self.extra))
     return NodeList(parts)
Exemple #8
0
    def rename_column(self, table, old_name, new_name):
        fk_objects = dict(
            (fk.column, fk) for fk in self.database.get_foreign_keys(table))
        is_foreign_key = old_name in fk_objects

        column = self._get_column_definition(table, old_name)
        rename_ctx = (self._alter_table(
            self.make_context(),
            table).literal(' CHANGE ').sql(Entity(old_name)).literal(' ').sql(
                column.sql(column_name=new_name)))
        if is_foreign_key:
            fk_metadata = fk_objects[old_name]
            return [
                self.drop_foreign_key_constraint(table, old_name),
                rename_ctx,
                self.add_foreign_key_constraint(table, new_name,
                                                fk_metadata.dest_table,
                                                fk_metadata.dest_column),
            ]
        else:
            return rename_ctx
Exemple #9
0
    def _create_virtual_table(self, safe=True, **options):
        options = self.model.clean_options(
            merge_dict(self.model._meta.options, options))

        # Structure:
        # CREATE VIRTUAL TABLE <model>
        # USING <extension_module>
        # ([prefix_arguments, ...] fields, ... [arguments, ...], [options...])
        ctx = self._create_context()
        ctx.literal('CREATE VIRTUAL TABLE ')
        if safe:
            ctx.literal('IF NOT EXISTS ')
        (ctx.sql(self.model).literal(' USING '))

        ext_module = self.model._meta.extension_module
        if isinstance(ext_module, Node):
            return ctx.sql(ext_module)

        ctx.sql(SQL(ext_module)).literal(' ')
        arguments = []
        meta = self.model._meta

        if meta.prefix_arguments:
            arguments.extend([SQL(a) for a in meta.prefix_arguments])

        # Constraints, data-types, foreign and primary keys are all omitted.
        for field in meta.sorted_fields:
            if isinstance(field, (RowIDField)) or field._hidden:
                continue
            field_def = [Entity(field.column_name)]
            if field.unindexed:
                field_def.append(SQL('UNINDEXED'))
            arguments.append(NodeList(field_def))

        if meta.arguments:
            arguments.extend([SQL(a) for a in meta.arguments])

        if options:
            arguments.extend(self._create_table_option_sql(options))
        return ctx.sql(EnclosedNodeList(arguments))
Exemple #10
0
    def clean_options(cls, options):
        content = options.get('content')
        prefix = options.get('prefix')
        tokenize = options.get('tokenize')

        if isinstance(content, basestring) and content == '':
            # Special-case content-less full-text search tables.
            options['content'] = "''"
        elif isinstance(content, Field):
            # Special-case to ensure fields are fully-qualified.
            options['content'] = Entity(content.model._meta.table_name,
                                        content.column_name)

        if prefix:
            if isinstance(prefix, (list, tuple)):
                prefix = ','.join([str(i) for i in prefix])
            options['prefix'] = "'%s'" % prefix.strip("' ")

        if tokenize and cls._meta.extension_module.lower() == 'fts5':
            # Tokenizers need to be in quoted string for FTS5, but not for FTS3
            # or FTS4.
            options['tokenize'] = '"%s"' % tokenize

        return options
Exemple #11
0
 def _alter_column(self, ctx, table, column):
     return (self._alter_table(ctx, table).literal(' MODIFY ').sql(
         Entity(column)))
Exemple #12
0
 def _alter_column_type(column_name, column_def):
     node_list = field.ddl(ctx)
     sql, _ = ctx.sql(Entity(column)).sql(node_list).query()
     return sql
Exemple #13
0
    def _update_column(self, table, column_to_update, fn):
        columns = set(column.name.lower()
                      for column in self.database.get_columns(table))
        if column_to_update.lower() not in columns:
            raise ValueError('Column "%s" does not exist on "%s"' %
                             (column_to_update, table))

        # Get the SQL used to create the given table.
        table, create_table = self._get_create_table(table)

        # Get the indexes and SQL to re-create indexes.
        indexes = self.database.get_indexes(table)

        # Find any foreign keys we may need to remove.
        self.database.get_foreign_keys(table)

        # Make sure the create_table does not contain any newlines or tabs,
        # allowing the regex to work correctly.
        create_table = re.sub(r'\s+', ' ', create_table)

        # Parse out the `CREATE TABLE` and column list portions of the query.
        raw_create, raw_columns = self.column_re.search(create_table).groups()

        # Clean up the individual column definitions.
        split_columns = self.column_split_re.findall(raw_columns)
        column_defs = [col.strip() for col in split_columns]

        new_column_defs = []
        new_column_names = []
        original_column_names = []
        constraint_terms = ('foreign ', 'primary ', 'constraint ')

        for column_def in column_defs:
            column_name, = self.column_name_re.match(column_def).groups()

            if column_name == column_to_update:
                new_column_def = fn(column_name, column_def)
                if new_column_def:
                    new_column_defs.append(new_column_def)
                    original_column_names.append(column_name)
                    column_name, = self.column_name_re.match(
                        new_column_def).groups()
                    new_column_names.append(column_name)
            else:
                new_column_defs.append(column_def)

                # Avoid treating constraints as columns.
                if not column_def.lower().startswith(constraint_terms):
                    new_column_names.append(column_name)
                    original_column_names.append(column_name)

        # Create a mapping of original columns to new columns.
        original_to_new = dict(zip(original_column_names, new_column_names))
        new_column = original_to_new.get(column_to_update)

        fk_filter_fn = lambda column_def: column_def
        if not new_column:
            # Remove any foreign keys associated with this column.
            fk_filter_fn = lambda column_def: None
        elif new_column != column_to_update:
            # Update any foreign keys for this column.
            fk_filter_fn = lambda column_def: self.fk_re.sub(
                'FOREIGN KEY ("%s") ' % new_column, column_def)

        cleaned_columns = []
        for column_def in new_column_defs:
            match = self.fk_re.match(column_def)
            if match is not None and match.groups()[0] == column_to_update:
                column_def = fk_filter_fn(column_def)
            if column_def:
                cleaned_columns.append(column_def)

        # Update the name of the new CREATE TABLE query.
        temp_table = table + '__tmp__'
        rgx = re.compile('("?)%s("?)' % table, re.I)
        create = rgx.sub('\\1%s\\2' % temp_table, raw_create)

        # Create the new table.
        columns = ', '.join(cleaned_columns)
        queries = [
            NodeList([SQL('DROP TABLE IF EXISTS'),
                      Entity(temp_table)]),
            SQL('%s (%s)' % (create.strip(), columns))
        ]

        # Populate new table.
        populate_table = NodeList(
            (SQL('INSERT INTO'), Entity(temp_table),
             EnclosedNodeList([Entity(col)
                               for col in new_column_names]), SQL('SELECT'),
             CommaNodeList([Entity(col) for col in original_column_names]),
             SQL('FROM'), Entity(table)))
        drop_original = NodeList([SQL('DROP TABLE'), Entity(table)])

        # Drop existing table and rename temp table.
        queries += [
            populate_table, drop_original,
            self.rename_table(temp_table, table)
        ]

        # Re-create user-defined indexes. User-defined indexes will have a
        # non-empty SQL attribute.
        for index in filter(lambda idx: idx.sql, indexes):
            if column_to_update not in index.columns:
                queries.append(SQL(index.sql))
            elif new_column:
                sql = self._fix_index(index.sql, column_to_update, new_column)
                if sql is not None:
                    queries.append(SQL(sql))

        return queries
Exemple #14
0
 def drop_index(self, table, index_name):
     return (self.make_context().literal('DROP INDEX ').sql(
         Entity(index_name)).literal(' ON ').sql(Entity(table)))
Exemple #15
0
 def _alter_column(self, ctx, table, column):
     return (self._alter_table(ctx, table).literal(' ALTER COLUMN ').sql(
         Entity(column)))
Exemple #16
0
 def add_constraint(self, table, name, constraint):
     return (self._alter_table(
         self.make_context(), table).literal(' ADD CONSTRAINT ').sql(
             Entity(name)).literal(' ').sql(constraint))
Exemple #17
0
 def drop_foreign_key_constraint(self, table, column_name):
     fk_constraint = self.get_foreign_key_constraint(table, column_name)
     return (self._alter_table(self.make_context(),
                               table).literal(' DROP FOREIGN KEY ').sql(
                                   Entity(fk_constraint)))
Exemple #18
0
 def drop_constraint(self, table, name):
     return (self._alter_table(self.make_context(),
                               table).literal(' DROP CONSTRAINT ').sql(
                                   Entity(name)))
Exemple #19
0
 def _alter_table(self, ctx, table):
     return ctx.literal('ALTER TABLE ').sql(Entity(table))
Exemple #20
0
 def rename_table(self, old_name, new_name):
     return (self._alter_table(self.make_context(),
                               old_name).literal(' RENAME TO ').sql(
                                   Entity(new_name)))
Exemple #21
0
 def rename_column(self, table, old_name, new_name):
     return (self._alter_table(self.make_context(),
                               table).literal(' RENAME COLUMN ').sql(
                                   Entity(old_name)).literal(' TO ').sql(
                                       Entity(new_name)))
Exemple #22
0
 def rename_table(self, old_name, new_name):
     return (self.make_context().literal('RENAME TABLE ').sql(
         Entity(old_name)).literal(' TO ').sql(Entity(new_name)))
Exemple #23
0
 def add_unique(self, table, *column_names):
     constraint_name = 'uniq_%s' % '_'.join(column_names)
     constraint = NodeList(
         (SQL('UNIQUE'),
          EnclosedNodeList([Entity(column) for column in column_names])))
     return self.add_constraint(table, constraint_name, constraint)