def sql_indexes_for_field(self, model, f, style): """ Return the CREATE INDEX SQL statements for a single model field. """ from djangocg.db.backends.util import truncate_name if f.db_index and not f.unique: qn = self.connection.ops.quote_name tablespace = f.db_tablespace or model._meta.db_tablespace if tablespace: tablespace_sql = self.connection.ops.tablespace_sql(tablespace) if tablespace_sql: tablespace_sql = ' ' + tablespace_sql else: tablespace_sql = '' i_name = '%s_%s' % (model._meta.db_table, self._digest(f.column)) output = [style.SQL_KEYWORD('CREATE INDEX') + ' ' + style.SQL_TABLE(qn(truncate_name( i_name, self.connection.ops.max_name_length()))) + ' ' + style.SQL_KEYWORD('ON') + ' ' + style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + "(%s)" % style.SQL_FIELD(qn(f.column)) + "%s;" % tablespace_sql] else: output = [] return output
def get_index_sql(index_name, opclass=''): return (style.SQL_KEYWORD('CREATE INDEX') + ' ' + style.SQL_TABLE(qn(truncate_name(index_name,self.connection.ops.max_name_length()))) + ' ' + style.SQL_KEYWORD('ON') + ' ' + style.SQL_TABLE(qn(db_table)) + ' ' + "(%s%s)" % (style.SQL_FIELD(qn(f.column)), opclass) + "%s;" % tablespace_sql)
def sql_for_pending_references(self, model, style, pending_references): """ Returns any ALTER TABLE statements to add constraints after the fact. """ from djangocg.db.backends.util import truncate_name if not model._meta.managed or model._meta.proxy: return [] qn = self.connection.ops.quote_name final_output = [] opts = model._meta if model in pending_references: for rel_class, f in pending_references[model]: rel_opts = rel_class._meta r_table = rel_opts.db_table r_col = f.column table = opts.db_table col = opts.get_field(f.rel.field_name).column # For MySQL, r_name must be unique in the first 64 characters. # So we are careful with character usage here. r_name = '%s_refs_%s_%s' % ( r_col, col, self._digest(r_table, table)) final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % (qn(r_table), qn(truncate_name( r_name, self.connection.ops.max_name_length())), qn(r_col), qn(table), qn(col), self.connection.ops.deferrable_sql())) del pending_references[model] return final_output
def contribute_to_class(self, cls, name): from djangocg.db import connection from djangocg.db.backends.util import truncate_name cls._meta = self self.installed = re.sub('\.models$', '', cls.__module__) in settings.INSTALLED_APPS # First, construct the default values for these options. self.object_name = cls.__name__ self.module_name = self.object_name.lower() self.verbose_name = get_verbose_name(self.object_name) # Next, apply any overridden values from 'class Meta'. if self.meta: meta_attrs = self.meta.__dict__.copy() for name in self.meta.__dict__: # Ignore any private attributes that Django doesn't care about. # NOTE: We can't modify a dictionary's contents while looping # over it, so we loop over the *original* dictionary instead. if name.startswith('_'): del meta_attrs[name] for attr_name in DEFAULT_NAMES: if attr_name in meta_attrs: setattr(self, attr_name, meta_attrs.pop(attr_name)) elif hasattr(self.meta, attr_name): setattr(self, attr_name, getattr(self.meta, attr_name)) # unique_together can be either a tuple of tuples, or a single # tuple of two strings. Normalize it to a tuple of tuples, so that # calling code can uniformly expect that. ut = meta_attrs.pop('unique_together', self.unique_together) if ut and not isinstance(ut[0], (tuple, list)): ut = (ut,) self.unique_together = ut # verbose_name_plural is a special case because it uses a 's' # by default. if self.verbose_name_plural is None: self.verbose_name_plural = string_concat(self.verbose_name, 's') # Any leftover attributes must be invalid. if meta_attrs != {}: raise TypeError("'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys())) else: self.verbose_name_plural = string_concat(self.verbose_name, 's') del self.meta # If the db_table wasn't provided, use the app_label + module_name. if not self.db_table: self.db_table = "%s_%s" % (self.app_label, self.module_name) self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
def sql_remove_table_constraints(self, model, references_to_delete, style): from djangocg.db.backends.util import truncate_name if not model._meta.managed or model._meta.proxy: return [] output = [] qn = self.connection.ops.quote_name for rel_class, f in references_to_delete[model]: table = rel_class._meta.db_table col = f.column r_table = model._meta.db_table r_col = model._meta.get_field(f.rel.field_name).column r_name = '%s_refs_%s_%s' % ( col, r_col, self._digest(table, r_table)) output.append('%s %s %s %s;' % \ (style.SQL_KEYWORD('ALTER TABLE'), style.SQL_TABLE(qn(table)), style.SQL_KEYWORD(self.connection.ops.drop_foreignkey_sql()), style.SQL_FIELD(qn(truncate_name( r_name, self.connection.ops.max_name_length()))))) del references_to_delete[model] return output
def deferred_class_factory(model, attrs): """ Returns a class object that is a copy of "model" with the specified "attrs" being replaced with DeferredAttribute objects. The "pk_value" ties the deferred attributes to a particular instance of the model. """ class Meta: proxy = True app_label = model._meta.app_label # The app_cache wants a unique name for each model, otherwise the new class # won't be created (we get an old one back). Therefore, we generate the # name using the passed in attrs. It's OK to reuse an existing class # object if the attrs are identical. name = "%s_Deferred_%s" % (model.__name__, '_'.join(sorted(list(attrs)))) name = util.truncate_name(name, 80, 32) overrides = dict([(attr, DeferredAttribute(attr, model)) for attr in attrs]) overrides["Meta"] = Meta overrides["__module__"] = model.__module__ overrides["_deferred"] = True return type(str(name), (model,), overrides)
def sql_indexes_for_field(self, model, f, style): "Return any spatial index creation SQL for the field." from djangocg.contrib.gis.db.models.fields import GeometryField output = super(OracleCreation, self).sql_indexes_for_field(model, f, style) if isinstance(f, GeometryField): gqn = self.connection.ops.geo_quote_name qn = self.connection.ops.quote_name db_table = model._meta.db_table output.append(style.SQL_KEYWORD('INSERT INTO ') + style.SQL_TABLE('USER_SDO_GEOM_METADATA') + ' (%s, %s, %s, %s)\n ' % tuple(map(qn, ['TABLE_NAME', 'COLUMN_NAME', 'DIMINFO', 'SRID'])) + style.SQL_KEYWORD(' VALUES ') + '(\n ' + style.SQL_TABLE(gqn(db_table)) + ',\n ' + style.SQL_FIELD(gqn(f.column)) + ',\n ' + style.SQL_KEYWORD("MDSYS.SDO_DIM_ARRAY") + '(\n ' + style.SQL_KEYWORD("MDSYS.SDO_DIM_ELEMENT") + ("('LONG', %s, %s, %s),\n " % (f._extent[0], f._extent[2], f._tolerance)) + style.SQL_KEYWORD("MDSYS.SDO_DIM_ELEMENT") + ("('LAT', %s, %s, %s)\n ),\n" % (f._extent[1], f._extent[3], f._tolerance)) + ' %s\n );' % f.srid) if f.spatial_index: # Getting the index name, Oracle doesn't allow object # names > 30 characters. idx_name = truncate_name('%s_%s_id' % (db_table, f.column), 30) output.append(style.SQL_KEYWORD('CREATE INDEX ') + style.SQL_TABLE(qn(idx_name)) + style.SQL_KEYWORD(' ON ') + style.SQL_TABLE(qn(db_table)) + '(' + style.SQL_FIELD(qn(f.column)) + ') ' + style.SQL_KEYWORD('INDEXTYPE IS ') + style.SQL_TABLE('MDSYS.SPATIAL_INDEX') + ';') return output
def get_columns(self, with_aliases=False): """ Returns the list of columns to use in the select statement. If no columns have been specified, returns all columns relating to fields in the model. If 'with_aliases' is true, any column names that are duplicated (without the table names) are given unique aliases. This is needed in some cases to avoid ambiguity with nested queries. """ qn = self.quote_name_unless_alias qn2 = self.connection.ops.quote_name result = ['(%s) AS %s' % (col[0], qn2(alias)) for alias, col in six.iteritems(self.query.extra_select)] aliases = set(self.query.extra_select.keys()) if with_aliases: col_aliases = aliases.copy() else: col_aliases = set() if self.query.select: only_load = self.deferred_to_columns() for col in self.query.select: if isinstance(col, (list, tuple)): alias, column = col table = self.query.alias_map[alias].table_name if table in only_load and column not in only_load[table]: continue r = '%s.%s' % (qn(alias), qn(column)) if with_aliases: if col[1] in col_aliases: c_alias = 'Col%d' % len(col_aliases) result.append('%s AS %s' % (r, c_alias)) aliases.add(c_alias) col_aliases.add(c_alias) else: result.append('%s AS %s' % (r, qn2(col[1]))) aliases.add(r) col_aliases.add(col[1]) else: result.append(r) aliases.add(r) col_aliases.add(col[1]) else: result.append(col.as_sql(qn, self.connection)) if hasattr(col, 'alias'): aliases.add(col.alias) col_aliases.add(col.alias) elif self.query.default_cols: cols, new_aliases = self.get_default_columns(with_aliases, col_aliases) result.extend(cols) aliases.update(new_aliases) max_name_length = self.connection.ops.max_name_length() result.extend([ '%s%s' % ( aggregate.as_sql(qn, self.connection), alias is not None and ' AS %s' % qn(truncate_name(alias, max_name_length)) or '' ) for alias, aggregate in self.query.aggregate_select.items() ]) for table, col in self.query.related_select_cols: r = '%s.%s' % (qn(table), qn(col)) if with_aliases and col in col_aliases: c_alias = 'Col%d' % len(col_aliases) result.append('%s AS %s' % (r, c_alias)) aliases.add(c_alias) col_aliases.add(c_alias) else: result.append(r) aliases.add(r) col_aliases.add(col) self._select_aliases = aliases return result