Ticket #6148: generic-db_schema-r11871.diff
File generic-db_schema-r11871.diff, 71.4 KB (added by , 15 years ago) |
---|
-
django/conf/project_template/settings.py
15 15 DATABASE_PASSWORD = '' # Not used with sqlite3. 16 16 DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. 17 17 DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. 18 DATABASE_SCHEMA = '' # Set to empty string for default. 18 19 19 20 # Local time zone for this installation. Choices can be found here: 20 21 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -
django/conf/global_settings.py
130 130 DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. 131 131 DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. 132 132 DATABASE_OPTIONS = {} # Set to empty dictionary for default. 133 DATABASE_SCHEMA = '' # Set to empty string for default. 133 134 134 135 # The email backend to use. For possible shortcuts see django.core.mail. 135 136 # The default is to use the SMTP backend. -
django/db/models/sql/query.py
585 585 might not have all the pieces in place at that time. 586 586 """ 587 587 if not self.tables: 588 self.join((None, self.model._meta. db_table, None, None))588 self.join((None, self.model._meta.qualified_name, None, None)) 589 589 if (not self.select and self.default_cols and not 590 590 self.included_inherited_models): 591 591 self.setup_inherited_models() … … 685 685 Callback used by deferred_to_columns(). The "target" parameter should 686 686 be a set instance. 687 687 """ 688 table = model._meta. db_table688 table = model._meta.qualified_name 689 689 if table not in target: 690 690 target[table] = set() 691 691 for field in fields: … … 802 802 alias = start_alias 803 803 else: 804 804 link_field = opts.get_ancestor_link(model) 805 alias = self.join((start_alias, model._meta.db_table, 805 alias = self.join((start_alias, 806 model._meta.qualified_name, 806 807 link_field.column, model._meta.pk.column)) 807 808 seen[model] = alias 808 809 else: … … 1210 1211 alias = self.tables[0] 1211 1212 self.ref_alias(alias) 1212 1213 else: 1213 alias = self.join((None, self.model._meta.db_table, None, None)) 1214 alias = self.join((None, self.model._meta.qualified_name, 1215 None, None)) 1214 1216 return alias 1215 1217 1216 1218 def count_active_tables(self): … … 1323 1325 seen[model] = root_alias 1324 1326 else: 1325 1327 link_field = opts.get_ancestor_link(model) 1326 seen[model] = self.join((root_alias, model._meta.db_table, 1328 seen[model] = self.join((root_alias, 1329 model._meta.qualified_name, 1327 1330 link_field.column, model._meta.pk.column)) 1328 1331 self.included_inherited_models = seen 1329 1332 … … 1381 1384 # what "used" specifies). 1382 1385 avoid = avoid_set.copy() 1383 1386 dupe_set = orig_dupe_set.copy() 1384 table = f.rel.to._meta. db_table1387 table = f.rel.to._meta.qualified_name 1385 1388 if nullable or f.null: 1386 1389 promote = True 1387 1390 else: … … 1405 1408 ()) 1406 1409 dupe_set.add((opts, lhs_col)) 1407 1410 int_opts = int_model._meta 1408 alias = self.join((alias, int_opts. db_table, lhs_col,1409 int_opts.pk.column), exclusions=used,1411 alias = self.join((alias, int_opts.qualified_name, 1412 lhs_col, int_opts.pk.column), exclusions=used, 1410 1413 promote=promote) 1411 1414 alias_chain.append(alias) 1412 1415 for (dupe_opts, dupe_col) in dupe_set: … … 1760 1763 (id(opts), lhs_col), ())) 1761 1764 dupe_set.add((opts, lhs_col)) 1762 1765 opts = int_model._meta 1763 alias = self.join((alias, opts.db_table, lhs_col, 1764 opts.pk.column), exclusions=exclusions) 1766 alias = self.join((alias, opts.qualified_name, 1767 lhs_col, opts.pk.column), 1768 exclusions=exclusions) 1765 1769 joins.append(alias) 1766 1770 exclusions.add(alias) 1767 1771 for (dupe_opts, dupe_col) in dupe_set: … … 1786 1790 (table1, from_col1, to_col1, table2, from_col2, 1787 1791 to_col2, opts, target) = cached_data 1788 1792 else: 1789 table1 = field.m2m_ db_table()1793 table1 = field.m2m_qualified_name() 1790 1794 from_col1 = opts.pk.column 1791 1795 to_col1 = field.m2m_column_name() 1792 1796 opts = field.rel.to._meta 1793 table2 = opts. db_table1797 table2 = opts.qualified_name 1794 1798 from_col2 = field.m2m_reverse_name() 1795 1799 to_col2 = opts.pk.column 1796 1800 target = opts.pk … … 1817 1821 else: 1818 1822 opts = field.rel.to._meta 1819 1823 target = field.rel.get_related_field() 1820 table = opts. db_table1824 table = opts.qualified_name 1821 1825 from_col = field.column 1822 1826 to_col = target.column 1823 1827 orig_opts._join_cache[name] = (table, from_col, to_col, … … 1839 1843 (table1, from_col1, to_col1, table2, from_col2, 1840 1844 to_col2, opts, target) = cached_data 1841 1845 else: 1842 table1 = field.m2m_ db_table()1846 table1 = field.m2m_qualified_name() 1843 1847 from_col1 = opts.pk.column 1844 1848 to_col1 = field.m2m_reverse_name() 1845 1849 opts = orig_field.opts 1846 table2 = opts. db_table1850 table2 = opts.qualified_name 1847 1851 from_col2 = field.m2m_column_name() 1848 1852 to_col2 = opts.pk.column 1849 1853 target = opts.pk … … 1866 1870 local_field = opts.get_field_by_name( 1867 1871 field.rel.field_name)[0] 1868 1872 opts = orig_field.opts 1869 table = opts. db_table1873 table = opts.qualified_name 1870 1874 from_col = local_field.column 1871 1875 to_col = field.column 1872 1876 target = opts.pk … … 2105 2109 self.group_by = [] 2106 2110 if self.connection.features.allows_group_by_pk: 2107 2111 if len(self.select) == len(self.model._meta.fields): 2108 self.group_by.append((self.model._meta. db_table,2112 self.group_by.append((self.model._meta.qualified_name, 2109 2113 self.model._meta.pk.column)) 2110 2114 return 2111 2115 … … 2127 2131 else: 2128 2132 opts = self.model._meta 2129 2133 if not self.select: 2130 count = self.aggregates_module.Count((self.join((None, opts.db_table, None, None)), opts.pk.column), 2134 count = self.aggregates_module.Count((self.join((None, 2135 opts.qualified_name, None, None)), opts.pk.column), 2131 2136 is_summary=True, distinct=True) 2132 2137 else: 2133 2138 # Because of SQL portability issues, multi-column, distinct -
django/db/models/sql/subqueries.py
54 54 'in', 55 55 pk_list[offset : offset+GET_ITERATOR_CHUNK_SIZE]), 56 56 AND) 57 self.do_query(related.field.m2m_ db_table(), where)57 self.do_query(related.field.m2m_qualified_name(), where) 58 58 59 59 for f in cls._meta.many_to_many: 60 60 w1 = self.where_class() … … 70 70 AND) 71 71 if w1: 72 72 where.add(w1, AND) 73 self.do_query(f.m2m_ db_table(), where)73 self.do_query(f.m2m_qualified_name(), where) 74 74 75 75 def delete_batch(self, pk_list): 76 76 """ … … 85 85 field = self.model._meta.pk 86 86 where.add((Constraint(None, field.column, field), 'in', 87 87 pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]), AND) 88 self.do_query(self.model._meta. db_table, where)88 self.do_query(self.model._meta.qualified_name, where) 89 89 90 90 class UpdateQuery(Query): 91 91 """ … … 304 304 # going to be column names (so we can avoid the extra overhead). 305 305 qn = self.connection.ops.quote_name 306 306 opts = self.model._meta 307 result = ['INSERT INTO %s' % qn(opts.db_table)]307 result = ['INSERT INTO %s' % opts.qualified_name] 308 308 result.append('(%s)' % ', '.join([qn(c) for c in self.columns])) 309 309 result.append('VALUES (%s)' % ', '.join(self.values)) 310 310 params = self.params 311 311 if self.return_id and self.connection.features.can_return_id_from_insert: 312 col = "%s.%s" % ( qn(opts.db_table), qn(opts.pk.column))312 col = "%s.%s" % (opts.qualified_name, qn(opts.pk.column)) 313 313 r_fmt, r_params = self.connection.ops.return_insert_id() 314 314 result.append(r_fmt % col) 315 315 params = params + r_params … … 323 323 if self.connection.features.can_return_id_from_insert: 324 324 return self.connection.ops.fetch_returned_insert_id(cursor) 325 325 return self.connection.ops.last_insert_id(cursor, 326 self.model._meta.db_table, self.model._meta.pk.column) 326 self.model._meta.db_schema, self.model._meta.db_table, 327 self.model._meta.pk.column) 327 328 328 329 def insert_values(self, insert_values, raw_values=False): 329 330 """ -
django/db/models/base.py
611 611 # into a pure queryset operation. 612 612 where = ['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \ 613 613 (qn('_order'), op, qn('_order'), 614 qn(self._meta.db_table), qn(self._meta.pk.column))]614 self._meta.qualified_name, qn(self._meta.pk.column))] 615 615 params = [self.pk] 616 616 obj = self._default_manager.filter(**{order_field.name: getattr(self, order_field.attname)}).extra(where=where, params=params).order_by(order)[:1].get() 617 617 setattr(self, cachename, obj) -
django/db/models/options.py
21 21 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering', 22 22 'unique_together', 'permissions', 'get_latest_by', 23 23 'order_with_respect_to', 'app_label', 'db_tablespace', 24 'abstract', 'managed', 'proxy', 'auto_created' )24 'abstract', 'managed', 'proxy', 'auto_created', 'db_schema') 25 25 26 26 class Options(object): 27 27 def __init__(self, meta, app_label=None): … … 30 30 self.module_name, self.verbose_name = None, None 31 31 self.verbose_name_plural = None 32 32 self.db_table = '' 33 self.db_schema = settings.DATABASE_SCHEMA 34 self.qualified_name = '' 33 35 self.ordering = [] 34 36 self.unique_together = [] 35 37 self.permissions = [] … … 104 106 self.db_table = "%s_%s" % (self.app_label, self.module_name) 105 107 self.db_table = truncate_name(self.db_table, connection.ops.max_name_length()) 106 108 109 # Construct qualified table name. 110 self.qualified_name = connection.ops.prep_db_table(self.db_schema, 111 self.db_table) 112 if self.qualified_name == connection.ops.quote_name(self.db_table): 113 # If unchanged, the backend doesn't support schemas. 114 self.db_schema = '' 107 115 108 116 def _prepare(self, model): 109 117 if self.order_with_respect_to: … … 177 185 self.pk = target._meta.pk 178 186 self.proxy_for_model = target 179 187 self.db_table = target._meta.db_table 188 self.db_schema = target._meta.db_schema 180 189 181 190 def __repr__(self): 182 191 return '<Options for %s>' % self.object_name -
django/db/models/fields/related.py
559 559 core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()}, 560 560 instance=instance, 561 561 symmetrical=False, 562 source_field_name=self.related.field.m2m_reverse_field_name(), 563 target_field_name=self.related.field.m2m_field_name() 562 join_table=self.related.field.m2m_qualified_name(), 563 source_field_name=qn(self.related.field.m2m_reverse_field_name()), 564 target_field_name=qn(self.related.field.m2m_field_name()) 564 565 ) 565 566 566 567 return manager … … 609 610 core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()}, 610 611 instance=instance, 611 612 symmetrical=(self.field.rel.symmetrical and isinstance(instance, rel_model)), 613 join_table=self.field.m2m_qualified_name(), 612 614 source_field_name=self.field.m2m_field_name(), 613 615 target_field_name=self.field.m2m_reverse_field_name() 614 616 ) … … 753 755 if isinstance(self.rel.to, basestring): 754 756 target = self.rel.to 755 757 else: 756 target = self.rel.to._meta. db_table758 target = self.rel.to._meta.qualified_name 757 759 cls._meta.duplicate_targets[self.column] = (target, "o2m") 758 760 759 761 def contribute_to_related_class(self, cls, related): … … 866 868 through=kwargs.pop('through', None)) 867 869 868 870 self.db_table = kwargs.pop('db_table', None) 871 self.db_schema = kwargs.pop('db_schema', '') 869 872 if kwargs['rel'].through is not None: 870 873 assert self.db_table is None, "Cannot specify a db_table if an intermediary model is used." 871 874 … … 887 890 return util.truncate_name('%s_%s' % (opts.db_table, self.name), 888 891 connection.ops.max_name_length()) 889 892 893 def _get_m2m_db_schema(self, opts): 894 "Function that can be curried to provide the m2m schema name for this relation" 895 if self.rel.through is not None and self.rel.through._meta.db_schema: 896 return self.rel.through._meta.db_schema 897 elif self.db_schema: 898 return self.db_schema 899 900 def _get_m2m_qualified_name(self, opts): 901 "Function that can be curried to provide the qualified m2m table name for this relation" 902 schema = self._get_m2m_db_schema(opts) 903 table = self._get_m2m_db_table(opts) 904 return connection.ops.prep_db_table(schema, table) 905 890 906 def _get_m2m_attr(self, related, attr): 891 907 "Function that can be curried to provide the source column name for the m2m table" 892 908 cache_attr = '_m2m_%s_cache' % attr … … 976 992 977 993 # Set up the accessor for the m2m table name for the relation 978 994 self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta) 995 self.m2m_db_schema = curry(self._get_m2m_db_schema, cls._meta) 996 self.m2m_qualified_name = curry(self._get_m2m_qualified_name, 997 cls._meta) 979 998 980 999 # Populate some necessary rel arguments so that cross-app relations 981 1000 # work correctly. … … 987 1006 if isinstance(self.rel.to, basestring): 988 1007 target = self.rel.to 989 1008 else: 990 target = self.rel.to._meta. db_table1009 target = self.rel.to._meta.qualified_name 991 1010 cls._meta.duplicate_targets[self.column] = (target, "m2m") 992 1011 993 1012 def contribute_to_related_class(self, cls, related): -
django/db/backends/postgresql/introspection.py
30 30 AND pg_catalog.pg_table_is_visible(c.oid)""") 31 31 return [row[0] for row in cursor.fetchall()] 32 32 33 def get_schema_list(self, cursor): 34 cursor.execute(""" 35 SELECT DISTINCT n.nspname 36 FROM pg_catalog.pg_class c 37 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 38 WHERE c.relkind IN ('r', 'v', '') 39 AND n.nspname NOT IN ('pg_catalog', 'pg_toast', 'information_schema')""") 40 return [row[0] for row in cursor.fetchall()] 41 42 def get_schema_table_list(self, cursor, schema): 43 cursor.execute(""" 44 SELECT c.relname 45 FROM pg_catalog.pg_class c 46 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 47 WHERE c.relkind IN ('r', 'v', '') 48 AND n.nspname = '%s'""" % schema) 49 return [row[0] for row in cursor.fetchall()] 50 33 51 def get_table_description(self, cursor, table_name): 34 52 "Returns a description of the table, with the DB-API cursor.description interface." 35 53 cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) -
django/db/backends/postgresql/operations.py
52 52 return 'HOST(%s)' 53 53 return '%s' 54 54 55 def last_insert_id(self, cursor, table_name, pk_name): 56 cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name)) 55 def last_insert_id(self, cursor, schema_name, table_name, pk_name): 56 sequence_name = '%s_%s_seq' % (table_name, pk_name) 57 sequence_name = self.prep_db_table(schema_name, sequence_name) 58 cursor.execute("SELECT CURRVAL('%s')" % sequence_name) 57 59 return cursor.fetchone()[0] 58 60 59 61 def no_limit_value(self): … … 64 66 return name # Quoting once is enough. 65 67 return '"%s"' % name 66 68 69 def prep_db_table(self, db_schema, db_table): 70 qn = self.quote_name 71 if db_schema: 72 return "%s.%s" % (qn(db_schema), qn(db_table)) 73 else: 74 return qn(db_table) 75 67 76 def sql_flush(self, style, tables, sequences): 68 77 if tables: 78 qnames = [self.prep_db_name(schema, table) 79 for (schema, table) in tables] 69 80 if self.postgres_version[0:2] >= (8,1): 70 81 # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* 71 82 # in order to be able to truncate tables referenced by a foreign … … 73 84 # statement. 74 85 sql = ['%s %s;' % \ 75 86 (style.SQL_KEYWORD('TRUNCATE'), 76 style.SQL_FIELD(', '.join( [self.quote_name(table) for table in tables]))87 style.SQL_FIELD(', '.join(qnames)) 77 88 )] 78 89 else: 79 90 # Older versions of Postgres can't do TRUNCATE in a single call, so … … 81 92 sql = ['%s %s %s;' % \ 82 93 (style.SQL_KEYWORD('DELETE'), 83 94 style.SQL_KEYWORD('FROM'), 84 style.SQL_FIELD( self.quote_name(table))85 ) for table in tables]95 style.SQL_FIELD(qname) 96 ) for qname in qnames] 86 97 87 98 # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements 88 99 # to reset sequence indices 89 100 for sequence_info in sequences: 101 schema_name = sequence_info['schema'] 90 102 table_name = sequence_info['table'] 91 103 column_name = sequence_info['column'] 92 104 if column_name and len(column_name) > 0: 93 105 sequence_name = '%s_%s_seq' % (table_name, column_name) 94 106 else: 95 107 sequence_name = '%s_id_seq' % table_name 108 sequence_name = self.prep_db_table(schema_name, sequence_name) 96 109 sql.append("%s setval('%s', 1, false);" % \ 97 110 (style.SQL_KEYWORD('SELECT'), 98 style.SQL_FIELD(se lf.quote_name(sequence_name)))111 style.SQL_FIELD(sequence_name)) 99 112 ) 100 113 return sql 101 114 else: … … 111 124 # if there are records (as the max pk value is already in use), otherwise set it to false. 112 125 for f in model._meta.local_fields: 113 126 if isinstance(f, models.AutoField): 127 sequence_name = qn('%s_%s_seq' % (model._meta.db_table, 128 f.column)) 129 sequence_name = self.prep_db_table(model._meta.db_schema, 130 sequence_name) 114 131 output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ 115 132 (style.SQL_KEYWORD('SELECT'), 116 style.SQL_FIELD( qn('%s_%s_seq' % (model._meta.db_table, f.column))),133 style.SQL_FIELD(sequence_name), 117 134 style.SQL_FIELD(qn(f.column)), 118 135 style.SQL_FIELD(qn(f.column)), 119 136 style.SQL_KEYWORD('IS NOT'), 120 137 style.SQL_KEYWORD('FROM'), 121 style.SQL_TABLE( qn(model._meta.db_table))))138 style.SQL_TABLE(model._meta.qualified_name))) 122 139 break # Only one AutoField is allowed per model, so don't bother continuing. 123 140 for f in model._meta.many_to_many: 124 141 if not f.rel.through: 142 sequence_name = qn('%s_id_seq' % f.m2m_db_table()) 143 sequence_name = self.prep_db_table(f.m2m_db_schema(), 144 sequence_name) 125 145 output.append("%s setval('%s', coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \ 126 146 (style.SQL_KEYWORD('SELECT'), 127 style.SQL_FIELD( qn('%s_id_seq' % f.m2m_db_table())),147 style.SQL_FIELD(sequence_name), 128 148 style.SQL_FIELD(qn('id')), 129 149 style.SQL_FIELD(qn('id')), 130 150 style.SQL_KEYWORD('IS NOT'), 131 151 style.SQL_KEYWORD('FROM'), 132 style.SQL_TABLE(qn(f.m2m_ db_table()))))152 style.SQL_TABLE(qn(f.m2m_qualified_name())))) 133 153 return output 134 154 135 155 def savepoint_create_sql(self, sid): -
django/db/backends/sqlite3/base.py
94 94 (style.SQL_KEYWORD('DELETE'), 95 95 style.SQL_KEYWORD('FROM'), 96 96 style.SQL_FIELD(self.quote_name(table)) 97 ) for tablein tables]97 ) for (_, table) in tables] 98 98 # Note: No requirement for reset of auto-incremented indices (cf. other 99 99 # sql_flush() implementations). Just return SQL at this point 100 100 return sql -
django/db/backends/mysql/base.py
160 160 return name # Quoting once is enough. 161 161 return "`%s`" % name 162 162 163 def prep_db_table(self, db_schema, db_table): 164 qn = self.quote_name 165 if db_schema: 166 return "%s.%s" % (qn(db_schema), qn(db_table)) 167 else: 168 return qn(db_table) 169 170 def prep_db_index(self, db_schema, db_index): 171 return self.prep_db_table(db_schema, db_index) 172 163 173 def random_function_sql(self): 164 174 return 'RAND()' 165 175 … … 169 179 # to clear all tables of all data 170 180 if tables: 171 181 sql = ['SET FOREIGN_KEY_CHECKS = 0;'] 172 for table in tables: 173 sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.quote_name(table)))) 182 sql.extend(['%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.prep_db_table(schema, table))) for (schema, table) in tables]) 174 183 sql.append('SET FOREIGN_KEY_CHECKS = 1;') 175 184 176 185 # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements 177 186 # to reset sequence indices 178 sql.extend(["%s %s %s %s %s;" % \ 179 (style.SQL_KEYWORD('ALTER'), 180 style.SQL_KEYWORD('TABLE'), 181 style.SQL_TABLE(self.quote_name(sequence['table'])), 182 style.SQL_KEYWORD('AUTO_INCREMENT'), 183 style.SQL_FIELD('= 1'), 184 ) for sequence in sequences]) 187 for sequence_info in sequences: 188 schema_name = sequence_info['schema'] 189 table_name = self.prep_db_table(schema_name, sequence_info['table']) 190 sql.append("%s %s %s %s %s;" % \ 191 (style.SQL_KEYWORD('ALTER'), 192 style.SQL_KEYWORD('TABLE'), 193 style.SQL_TABLE(table_name), 194 style.SQL_KEYWORD('AUTO_INCREMENT'), 195 style.SQL_FIELD('= 1'), 196 )) 185 197 return sql 186 198 else: 187 199 return [] -
django/db/backends/mysql/introspection.py
33 33 cursor.execute("SHOW TABLES") 34 34 return [row[0] for row in cursor.fetchall()] 35 35 36 def get_schema_list(self, cursor): 37 cursor.execute("SHOW SCHEMAS") 38 return [row[0] for row in cursor.fetchall()] 39 40 def get_schema_table_list(self, cursor, schema): 41 cursor.execute("SHOW TABLES FROM %s" % self.connection.ops.quote_name(schema)) 42 return [schema + "." + row[0] for row in cursor.fetchall()] 43 36 44 def get_table_description(self, cursor, table_name): 37 45 "Returns a description of the table, with the DB-API cursor.description interface." 38 46 cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name)) -
django/db/backends/mysql/creation.py
63 63 field.rel.to._meta.db_table, field.rel.to._meta.pk.column) 64 64 ] 65 65 return table_output, deferred 66 67 No newline at end of file 66 67 def default_schema(self): 68 return settings.DATABASE_NAME 69 70 def sql_create_schema(self, schema, style): 71 """ 72 Returns the SQL required to create a single schema. 73 In MySQL schemas are synonymous to databases 74 """ 75 qn = self.connection.ops.quote_name 76 output = "%s %s;" % (style.SQL_KEYWORD('CREATE DATABASE'), qn(schema)) 77 return output 78 79 def sql_destroy_schema(self, schema, style): 80 """" 81 Returns the SQL required to create a single schema 82 """ 83 qn = self.connection.ops.quote_name 84 output = "%s %s;" % (style.SQL_KEYWORD('DROP DATABASE IF EXISTS'), qn(schema)) 85 return output 86 No newline at end of file -
django/db/backends/oracle/base.py
55 55 56 56 class DatabaseOperations(BaseDatabaseOperations): 57 57 58 def autoinc_sql(self, table, column):58 def autoinc_sql(self, schema, table, column): 59 59 # To simulate auto-incrementing primary keys in Oracle, we have to 60 60 # create a sequence and a trigger. 61 61 sq_name = get_sequence_name(table) 62 62 tr_name = get_trigger_name(table) 63 tbl_name = self.quote_name(table) 63 tbl_name = self.prep_db_table(schema, table) 64 sq_qname = self.prep_db_table(schema, sq_name) 65 tr_qname = self.prep_db_table(schema, tr_name) 64 66 col_name = self.quote_name(column) 65 67 sequence_sql = """ 66 68 DECLARE … … 69 71 SELECT COUNT(*) INTO i FROM USER_CATALOG 70 72 WHERE TABLE_NAME = '%(sq_name)s' AND TABLE_TYPE = 'SEQUENCE'; 71 73 IF i = 0 THEN 72 EXECUTE IMMEDIATE 'CREATE SEQUENCE "%(sq_name)s"';74 EXECUTE IMMEDIATE 'CREATE SEQUENCE %(sq_qname)s'; 73 75 END IF; 74 76 END; 75 77 /""" % locals() 76 78 trigger_sql = """ 77 CREATE OR REPLACE TRIGGER "%(tr_name)s"79 CREATE OR REPLACE TRIGGER %(tr_qname)s 78 80 BEFORE INSERT ON %(tbl_name)s 79 81 FOR EACH ROW 80 82 WHEN (new.%(col_name)s IS NULL) 81 83 BEGIN 82 SELECT "%(sq_name)s".nextval84 SELECT %(sq_qname)s.nextval 83 85 INTO :new.%(col_name)s FROM dual; 84 86 END; 85 87 /""" % locals() … … 108 110 def deferrable_sql(self): 109 111 return " DEFERRABLE INITIALLY DEFERRED" 110 112 111 def drop_sequence_sql(self, table): 112 return "DROP SEQUENCE %s;" % self.quote_name(get_sequence_name(table)) 113 def drop_sequence_sql(self, schema, table): 114 sequence_name = self.prep_db_table(schema, get_sequence_name(table)) 115 return "DROP SEQUENCE %s;" % sequence_name 113 116 114 117 def fetch_returned_insert_id(self, cursor): 115 118 return long(cursor._insert_id_var.getvalue()) … … 120 123 else: 121 124 return "%s" 122 125 123 def last_insert_id(self, cursor, table_name, pk_name):124 sq_name = get_sequence_name(table_name)125 cursor.execute('SELECT "%s".currval FROM dual' % sq_name)126 def last_insert_id(self, cursor, schema_name, table_name, pk_name): 127 sq_name = self.prep_db_table(schema_name, get_sequence_name(table_name)) 128 cursor.execute('SELECT %s.currval FROM dual' % sq_name) 126 129 return cursor.fetchone()[0] 127 130 128 131 def lookup_cast(self, lookup_type): … … 133 136 def max_name_length(self): 134 137 return 30 135 138 139 def prep_db_table(self, db_schema, db_table): 140 qn = self.quote_name 141 if db_schema: 142 return "%s.%s" % (qn(db_schema), qn(db_table)) 143 else: 144 return qn(db_table) 145 146 def prep_db_index(self, db_schema, db_index): 147 return self.prep_db_table(db_schema, db_index) 148 136 149 def prep_for_iexact_query(self, x): 137 150 return x 138 151 … … 186 199 def sql_flush(self, style, tables, sequences): 187 200 # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 188 201 # 'TRUNCATE z;'... style SQL statements 202 sql = [] 189 203 if tables: 190 204 # Oracle does support TRUNCATE, but it seems to get us into 191 205 # FK referential trouble, whereas DELETE FROM table works. 192 sql = ['%s %s %s;' % \ 193 (style.SQL_KEYWORD('DELETE'), 194 style.SQL_KEYWORD('FROM'), 195 style.SQL_FIELD(self.quote_name(table))) 196 for table in tables] 206 for schema, table in tables: 207 table = self.prep_db_table(schema, table) 208 sql.append('%s %s %s;' % \ 209 (style.SQL_KEYWORD('DELETE'), 210 style.SQL_KEYWORD('FROM'), 211 style.SQL_FIELD(table))) 197 212 # Since we've just deleted all the rows, running our sequence 198 213 # ALTER code will reset the sequence to 0. 199 214 for sequence_info in sequences: 200 sequence_name = get_sequence_name(sequence_info['table']) 201 table_name = self.quote_name(sequence_info['table']) 215 schema_name = sequence_info['schema'] 216 sequence_name = self.prep_db_table(schema_name, 217 get_sequence_name(sequence_info['table'])) 218 table_name = self.prep_db_table(schema_name, 219 sequence_info['table']) 202 220 column_name = self.quote_name(sequence_info['column'] or 'id') 203 221 query = _get_sequence_reset_sql() % {'sequence': sequence_name, 204 222 'table': table_name, 205 223 'column': column_name} 206 224 sql.append(query) 207 return sql 208 else: 209 return [] 225 return sql 210 226 211 227 def sequence_reset_sql(self, style, model_list): 212 228 from django.db import models … … 215 231 for model in model_list: 216 232 for f in model._meta.local_fields: 217 233 if isinstance(f, models.AutoField): 218 table_name = self.quote_name(model._meta.db_table) 219 sequence_name = get_sequence_name(model._meta.db_table) 234 table_name = model._meta.qualified_name 235 sequence_name = self.prep_db_table(model._meta.db_schema, 236 get_sequence_name(model._meta.db_table)) 220 237 column_name = self.quote_name(f.column) 221 238 output.append(query % {'sequence': sequence_name, 222 239 'table': table_name, … … 226 243 break 227 244 for f in model._meta.many_to_many: 228 245 if not f.rel.through: 229 table_name = self.quote_name(f.m2m_db_table()) 230 sequence_name = get_sequence_name(f.m2m_db_table()) 246 table_name = self.quote_name(f.m2m_qualified_name()) 247 sequence_name = self.prep_db_table(f.m2m_db_schema(), 248 get_sequence_name(f.m2m_db_table())) 231 249 column_name = self.quote_name('id') 232 250 output.append(query % {'sequence': sequence_name, 233 251 'table': table_name, … … 434 452 query = query[:-1] 435 453 query = convert_unicode(query % tuple(args), self.charset) 436 454 self._guess_input_sizes([params]) 455 print >>file('/home/ikelly/django-log.sql', 'w'), query, self._param_generator(params) 437 456 try: 438 457 return self.cursor.execute(query, self._param_generator(params)) 439 458 except DatabaseError, e: … … 551 570 BEGIN 552 571 LOCK TABLE %(table)s IN SHARE MODE; 553 572 SELECT NVL(MAX(%(column)s), 0) INTO startvalue FROM %(table)s; 554 SELECT "%(sequence)s".nextval INTO cval FROM dual;573 SELECT %(sequence)s.nextval INTO cval FROM dual; 555 574 cval := startvalue - cval; 556 575 IF cval != 0 THEN 557 EXECUTE IMMEDIATE 'ALTER SEQUENCE "%(sequence)s"MINVALUE 0 INCREMENT BY '||cval;558 SELECT "%(sequence)s".nextval INTO cval FROM dual;559 EXECUTE IMMEDIATE 'ALTER SEQUENCE "%(sequence)s"INCREMENT BY 1';576 EXECUTE IMMEDIATE 'ALTER SEQUENCE %(sequence)s MINVALUE 0 INCREMENT BY '||cval; 577 SELECT %(sequence)s.nextval INTO cval FROM dual; 578 EXECUTE IMMEDIATE 'ALTER SEQUENCE %(sequence)s INCREMENT BY 1'; 560 579 END IF; 561 580 COMMIT; 562 581 END; -
django/db/backends/oracle/introspection.py
116 116 for row in cursor.fetchall(): 117 117 indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]} 118 118 return indexes 119 120 def schema_name_converter(self, name): 121 """Convert to lowercase for case-sensitive schema name comparison.""" 122 return name.lower() 123 124 def get_schema_list(self, cursor): 125 "Returns a list of schemas that exist in the database." 126 sql = """ 127 select distinct username 128 from all_users, all_objects 129 where username = owner 130 """ 131 cursor.execute(sql) 132 return [schema.lower() for (schema,) in cursor] 133 134 def get_schema_table_list(self, cursor, schema): 135 "Returns a list of tables in a specific schema." 136 sql = """ 137 select table_name from all_tables 138 where owner = upper(%s) 139 """ 140 cursor.execute(sql, [schema]) 141 return [table.lower() for (table,) in cursor] -
django/db/backends/oracle/creation.py
39 39 'URLField': 'VARCHAR2(%(max_length)s)', 40 40 } 41 41 42 def sql_create_schema(self, schema, style, password=None, 43 tablespace=None, temp_tablespace=None): 44 qn = self.connection.ops.quote_name 45 lock_account = (password is None) 46 if lock_account: 47 password = schema 48 output = [] 49 output.append("%s %s %s %s" % (style.SQL_KEYWORD('CREATE USER'), 50 qn(schema), 51 style.SQL_KEYWORD('IDENTIFIED BY'), 52 qn(password))) 53 if tablespace: 54 output.append("%s %s" % (style.SQL_KEYWORD('DEFAULT TABLESPACE'), 55 qn(tablespace))) 56 if temp_tablespace: 57 output.append("%s %s" % (style.SQL_KEYWORD('TEMPORARY TABLESPACE'), 58 qn(temp_tablespace))) 59 if lock_account: 60 output.append(style.SQL_KEYWORD('ACCOUNT LOCK')) 61 return '\n'.join(output) 62 63 def sql_destroy_schema(self, schema, style): 64 qn = self.connection.ops.quote_name 65 return "%s %s %s" % (style.SQL_KEYWORD('DROP USER'), qn(schema), 66 style.SQL_KEYWORD('CASCADE')) 67 42 68 remember = {} 43 69 44 70 def _create_test_db(self, verbosity=1, autoclobber=False): … … 174 200 DEFAULT TABLESPACE %(tblspace)s 175 201 TEMPORARY TABLESPACE %(tblspace_temp)s 176 202 """, 177 """GRANT CONNECT, RESOURCE TO %(user)s""",203 """GRANT CONNECT, RESOURCE, CREATE USER, DROP USER, CREATE ANY TABLE, ALTER ANY TABLE, CREATE ANY INDEX, CREATE ANY SEQUENCE, CREATE ANY TRIGGER, SELECT ANY TABLE, INSERT ANY TABLE, UPDATE ANY TABLE, DELETE ANY TABLE TO %(user)s""", 178 204 ] 179 205 self._execute_statements(cursor, statements, parameters, verbosity) 180 206 -
django/db/backends/__init__.py
109 109 a backend performs ordering or calculates the ID of a recently-inserted 110 110 row. 111 111 """ 112 def autoinc_sql(self, table, column):112 def autoinc_sql(self, schema, table, column): 113 113 """ 114 114 Returns any SQL needed to support auto-incrementing primary keys, or 115 115 None if no SQL is necessary. … … 155 155 """ 156 156 return "DROP CONSTRAINT" 157 157 158 def drop_sequence_sql(self, table):158 def drop_sequence_sql(self, schema, table): 159 159 """ 160 160 Returns any SQL necessary to drop the sequence for the given table. 161 161 Returns None if no SQL is necessary. … … 216 216 217 217 return smart_unicode(sql) % u_params 218 218 219 def last_insert_id(self, cursor, table_name, pk_name):219 def last_insert_id(self, cursor, schema_name, table_name, pk_name): 220 220 """ 221 221 Given a cursor object that has just performed an INSERT statement into 222 222 a table that has an auto-incrementing ID, returns the newly created ID. … … 287 287 """ 288 288 raise NotImplementedError() 289 289 290 def prep_db_table(self, db_schema, db_table): 291 """ 292 Prepares and formats the table name if necessary. 293 Just returns quoted db_table if not supported. 294 """ 295 return self.quote_name(db_table) 296 297 def prep_db_index(self, db_schema, db_index): 298 """ 299 Prepares and formats the table index name if necessary. 300 Just returns quoted db_index if not supported. 301 """ 302 return self.quote_name(db_index) 303 290 304 def random_function_sql(self): 291 305 """ 292 306 Returns a SQL expression that returns a random value. … … 486 500 return name 487 501 488 502 def table_names(self): 489 "Returns a list of names of all tables that exist in the d atabase."503 "Returns a list of names of all tables that exist in the default schema." 490 504 cursor = self.connection.cursor() 491 505 return self.get_table_list(cursor) 492 506 507 def schema_name_converter(self, name): 508 """Apply a conversion to the name for the purposes of comparison. 509 510 The default schema name converter is for case sensitive comparison. 511 """ 512 return name 513 514 def get_schema_list(self, cursor): 515 "Returns a list of schemas that exist in the database" 516 return [] 517 518 def get_schema_table_list(self, cursor, schema): 519 "Returns a list of tables in a specific schema" 520 return [] 521 522 def schema_names(self): 523 cursor = self.connection.cursor() 524 return self.get_schema_list(cursor) 525 526 def schema_table_names(self, schema): 527 "Returns a list of names of all tables that exist in the database schema." 528 cursor = self.connection.cursor() 529 return self.get_schema_table_list(cursor, schema) 530 493 531 def django_table_names(self, only_existing=False): 494 532 """ 495 Returns a list of all table names that have associated Django models and496 are in INSTALLED_APPS.533 Returns a list of tuples containing all schema and table names that 534 have associated Django models and are in INSTALLED_APPS. 497 535 498 If only_existing is True, the resulting list will only include the tables499 t hat actually exist in the database.536 If only_existing is True, the resulting list will only include the 537 tables that actually exist in the database. 500 538 """ 501 539 from django.db import models 502 540 tables = set() 541 if only_existing: 542 existing_tables = set([('', tn) for tn in self.table_names()]) 543 seen_schemas = set() 503 544 for app in models.get_apps(): 504 545 for model in models.get_models(app): 505 546 if not model._meta.managed: 506 547 continue 507 tables.add(model._meta.db_table) 508 tables.update([f.m2m_db_table() for f in model._meta.local_many_to_many]) 548 db_schema = model._meta.db_schema 549 db_table = model._meta.db_table 550 if only_existing and db_schema and db_schema not in seen_schemas: 551 existing_tables.update([(db_schema, tn) for tn in 552 self.schema_table_names(db_schema)]) 553 seen_schemas.add(db_schema) 554 tables.add((model._meta.db_schema, model._meta.db_table)) 555 for f in model._meta.local_many_to_many: 556 m2m_schema = f.m2m_db_schema() 557 m2m_table = f.m2m_db_table() 558 if only_existing and m2m_schema and m2m_schema not in seen_schemas: 559 existing_tables.update([(m2m_schema, tn) for tn in 560 self.schema_table_names(m2m_schema)]) 561 seen_schemas.add(m2m_schema) 562 tables.add((m2m_schema, m2m_table)) 509 563 if only_existing: 510 tables = [t for t in tables if self.table_name_converter(t) in self.table_names()] 564 tables = [(s, t) for (s, t) in tables 565 if (self.schema_name_converter(s), 566 self.table_name_converter(t)) in existing_tables] 511 567 return tables 512 568 513 569 def installed_models(self, tables): … … 534 590 continue 535 591 for f in model._meta.local_fields: 536 592 if isinstance(f, models.AutoField): 537 sequence_list.append({'table': model._meta.db_table, 'column': f.column}) 593 sequence_list.append({'table': model._meta.db_table, 594 'column': f.column, 595 'schema': model._meta.db_schema}) 538 596 break # Only one AutoField is allowed per model, so don't bother continuing. 539 597 540 598 for f in model._meta.local_many_to_many: 541 599 # If this is an m2m using an intermediate table, 542 600 # we don't need to reset the sequence. 543 601 if f.rel.through is None: 544 sequence_list.append({'table': f.m2m_db_table(), 'column': None}) 602 sequence_list.append({'table': f.m2m_db_table(), 603 'column': None, 604 'schema': f.m2m_db_schema()}) 545 605 546 606 return sequence_list 547 607 -
django/db/backends/creation.py
32 32 """ 33 33 return '%x' % (abs(hash(args)) % 4294967296L) # 2**32 34 34 35 def default_schema(self): 36 return "" 37 38 def sql_create_schema(self, schema, style): 39 """" 40 Returns the SQL required to create a single schema 41 """ 42 qn = self.connection.ops.quote_name 43 output = "%s %s;" % (style.SQL_KEYWORD('CREATE SCHEMA'), qn(schema)) 44 return output 45 35 46 def sql_create_model(self, model, style, known_models=set()): 36 47 """ 37 48 Returns the SQL required to create a single model, as a tuple of: … … 80 91 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ 81 92 ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints])) 82 93 83 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE( qn(opts.db_table)) + ' (']94 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(opts.qualified_name) + ' ('] 84 95 for i, line in enumerate(table_output): # Combine and add commas. 85 96 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 86 97 full_statement.append(')') … … 92 103 if opts.has_auto_field: 93 104 # Add any extra SQL needed to support auto-incrementing primary keys. 94 105 auto_column = opts.auto_field.db_column or opts.auto_field.name 95 autoinc_sql = self.connection.ops.autoinc_sql(opts.db_table, auto_column) 106 autoinc_sql = self.connection.ops.autoinc_sql(opts.db_schema, 107 opts.db_table, 108 auto_column) 96 109 if autoinc_sql: 97 110 for stmt in autoinc_sql: 98 111 final_output.append(stmt) … … 104 117 qn = self.connection.ops.quote_name 105 118 if field.rel.to in known_models: 106 119 output = [style.SQL_KEYWORD('REFERENCES') + ' ' + \ 107 style.SQL_TABLE( qn(field.rel.to._meta.db_table)) + ' (' + \120 style.SQL_TABLE(field.rel.to._meta.qualified_name) + ' (' + \ 108 121 style.SQL_FIELD(qn(field.rel.to._meta.get_field(field.rel.field_name).column)) + ')' + 109 122 self.connection.ops.deferrable_sql() 110 123 ] … … 130 143 for rel_class, f in pending_references[model]: 131 144 rel_opts = rel_class._meta 132 145 r_table = rel_opts.db_table 146 r_qname = rel_opts.qualified_name 133 147 r_col = f.column 134 148 table = opts.db_table 149 qname = opts.qualified_name 135 150 col = opts.get_field(f.rel.field_name).column 136 151 # For MySQL, r_name must be unique in the first 64 characters. 137 152 # So we are careful with character usage here. 138 153 r_name = '%s_refs_%s_%s' % (r_col, col, self._digest(r_table, table)) 139 154 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \ 140 ( qn(r_table), qn(truncate_name(r_name, self.connection.ops.max_name_length())),141 qn(r_col), qn (table), qn(col),155 (r_qname, qn(truncate_name(r_name, self.connection.ops.max_name_length())), 156 qn(r_col), qname, qn(col), 142 157 self.connection.ops.deferrable_sql())) 143 158 del pending_references[model] 144 159 return final_output … … 170 185 else: 171 186 tablespace_sql = '' 172 187 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ 173 style.SQL_TABLE(qn(f.m2m_ db_table())) + ' (']188 style.SQL_TABLE(qn(f.m2m_qualified_name())) + ' ('] 174 189 table_output.append(' %s %s %s%s,' % 175 190 (style.SQL_FIELD(qn('id')), 176 191 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()), … … 202 217 self.connection.ops.deferrable_sql())) 203 218 204 219 # Add any extra SQL needed to support auto-incrementing PKs 205 autoinc_sql = self.connection.ops.autoinc_sql(f.m2m_db_table(), 'id') 220 autoinc_sql = self.connection.ops.autoinc_sql(f.m2m_db_schema(), 221 f.m2m_db_table(), 222 'id') 206 223 if autoinc_sql: 207 224 for stmt in autoinc_sql: 208 225 output.append(stmt) … … 219 236 (style.SQL_FIELD(qn(field.m2m_column_name())), 220 237 style.SQL_COLTYPE(models.ForeignKey(model).db_type()), 221 238 style.SQL_KEYWORD('NOT NULL REFERENCES'), 222 style.SQL_TABLE( qn(opts.db_table)),239 style.SQL_TABLE(opts.qualified_name), 223 240 style.SQL_FIELD(qn(opts.pk.column)), 224 241 self.connection.ops.deferrable_sql()), 225 242 ' %s %s %s %s (%s)%s,' % 226 243 (style.SQL_FIELD(qn(field.m2m_reverse_name())), 227 244 style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type()), 228 245 style.SQL_KEYWORD('NOT NULL REFERENCES'), 229 style.SQL_TABLE( qn(field.rel.to._meta.db_table)),246 style.SQL_TABLE(opts.qualified_name), 230 247 style.SQL_FIELD(qn(field.rel.to._meta.pk.column)), 231 248 self.connection.ops.deferrable_sql()) 232 249 ] … … 256 273 tablespace_sql = '' 257 274 else: 258 275 tablespace_sql = '' 276 index_name = '%s_%s' % (model._meta.db_table, f.column) 277 index_name = self.connection.ops.prep_db_index(model._meta.db_schema, index_name) 259 278 output = [style.SQL_KEYWORD('CREATE INDEX') + ' ' + 260 style.SQL_TABLE( qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' +279 style.SQL_TABLE(index_name) + ' ' + 261 280 style.SQL_KEYWORD('ON') + ' ' + 262 style.SQL_TABLE( qn(model._meta.db_table)) + ' ' +281 style.SQL_TABLE(model._meta.qualified_name) + ' ' + 263 282 "(%s)" % style.SQL_FIELD(qn(f.column)) + 264 283 "%s;" % tablespace_sql] 265 284 else: 266 285 output = [] 267 286 return output 268 287 288 def sql_destroy_schema(self, schema, style): 289 """" 290 Returns the SQL required to create a single schema 291 """ 292 qn = self.connection.ops.quote_name 293 output = "%s %s CASCADE;" % (style.SQL_KEYWORD('DROP SCHEMA IF EXISTS'), qn(schema)) 294 return output 295 269 296 def sql_destroy_model(self, model, references_to_delete, style): 270 297 "Return the DROP TABLE and restraint dropping statements for a single model" 271 298 if not model._meta.managed or model._meta.proxy: … … 273 300 # Drop the table now 274 301 qn = self.connection.ops.quote_name 275 302 output = ['%s %s;' % (style.SQL_KEYWORD('DROP TABLE'), 276 style.SQL_TABLE( qn(model._meta.db_table)))]303 style.SQL_TABLE(model._meta.qualified_name))] 277 304 if model in references_to_delete: 278 305 output.extend(self.sql_remove_table_constraints(model, references_to_delete, style)) 279 306 280 307 if model._meta.has_auto_field: 281 ds = self.connection.ops.drop_sequence_sql(model._meta.db_table) 308 ds = self.connection.ops.drop_sequence_sql(model._meta.db_schema, 309 model._meta.db_table) 282 310 if ds: 283 311 output.append(ds) 284 312 return output … … 292 320 qn = self.connection.ops.quote_name 293 321 for rel_class, f in references_to_delete[model]: 294 322 table = rel_class._meta.db_table 323 qname = rel_class._meta.qualified_name 295 324 col = f.column 296 325 r_table = model._meta.db_table 297 326 r_col = model._meta.get_field(f.rel.field_name).column 298 327 r_name = '%s_refs_%s_%s' % (col, r_col, self._digest(table, r_table)) 299 328 output.append('%s %s %s %s;' % \ 300 329 (style.SQL_KEYWORD('ALTER TABLE'), 301 style.SQL_TABLE(qn (table)),330 style.SQL_TABLE(qname), 302 331 style.SQL_KEYWORD(self.connection.ops.drop_foreignkey_sql()), 303 332 style.SQL_FIELD(truncate_name(r_name, self.connection.ops.max_name_length())))) 304 333 del references_to_delete[model] … … 310 339 output = [] 311 340 if f.creates_table: 312 341 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'), 313 style.SQL_TABLE(qn(f.m2m_db_table())))) 314 ds = self.connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column)) 342 style.SQL_TABLE(f.m2m_qualified_name()))) 343 ds = self.connection.ops.drop_sequence_sql(model._meta.db_schema, 344 "%s_%s" % (model._meta.db_table, f.column)) 315 345 if ds: 316 346 output.append(ds) 317 347 return output … … 333 363 settings.DATABASE_SUPPORTS_TRANSACTIONS = can_rollback 334 364 self.connection.settings_dict["DATABASE_SUPPORTS_TRANSACTIONS"] = can_rollback 335 365 366 # Create the test schemas. 367 schema_apps = self._get_app_with_schemas() 368 schemas = self._get_schemas(schema_apps) 369 cursor = self.connection.cursor() 370 self._create_test_schemas(verbosity, schemas, cursor) 371 336 372 call_command('syncdb', verbosity=verbosity, interactive=False) 337 373 338 374 if settings.CACHE_BACKEND.startswith('db://'): … … 346 382 347 383 return test_database_name 348 384 385 def _create_test_schemas(self, verbosity, schemas, cursor): 386 from django.core.management.color import no_style 387 style = no_style() 388 for schema in schemas: 389 if verbosity >= 1: 390 print "Creating schema %s" % schema 391 cursor.execute(self.sql_create_schema(schema, style)) 392 393 def _destroy_test_schemas(self, verbosity, schemas, cursor): 394 from django.core.management.color import no_style 395 style = no_style() 396 for schema in schemas: 397 if verbosity >= 1: 398 print "Destroying schema %s" % schema 399 cursor.execute(self.sql_destroy_schema(schema, style)) 400 if verbosity >= 1: 401 print "Schema %s destroyed" % schema 402 403 def _get_schemas(self, apps): 404 from django.db import models 405 schemas = set() 406 for app in apps: 407 app_models = models.get_models(app) 408 for model in app_models: 409 schema = model._meta.db_schema 410 if not schema or schema in schemas: 411 continue 412 schemas.add(schema) 413 return schemas 414 415 def _get_app_with_schemas(self): 416 from django.db import models 417 apps = models.get_apps() 418 schema_apps = set() 419 for app in apps: 420 app_models = models.get_models(app) 421 for model in app_models: 422 schema = model._meta.db_schema 423 if not schema or app in schema_apps: 424 continue 425 schema_apps.add(app) 426 continue 427 428 return schema_apps 429 349 430 def _create_test_db(self, verbosity, autoclobber): 350 431 "Internal implementation - creates the test db tables." 351 432 suffix = self.sql_table_creation_suffix() … … 372 453 try: 373 454 if verbosity >= 1: 374 455 print "Destroying old test database..." 456 self._destroy_test_schemas(verbosity, schemas, cursor) 375 457 cursor.execute("DROP DATABASE %s" % qn(test_database_name)) 376 458 if verbosity >= 1: 377 459 print "Creating test database..." -
django/core/management/commands/syncdb.py
49 49 cursor = connection.cursor() 50 50 51 51 # Get a list of already installed *models* so that references work right. 52 tables = connection.introspection.table_names()52 tables = [('', tn) for tn in connection.introspection.table_names()] 53 53 seen_models = connection.introspection.installed_models(tables) 54 seen_schemas = set() 54 55 created_models = set() 55 56 pending_references = {} 56 57 … … 59 60 app_name = app.__name__.split('.')[-2] 60 61 model_list = models.get_models(app, include_auto_created=True) 61 62 for model in model_list: 62 # Create the model's database table, if it doesn't already exist. 63 # Add model-defined schema tables if any. 64 db_schema = model._meta.db_schema 65 if db_schema: 66 db_schema = connection.introspection.schema_name_converter(db_schema) 67 if db_schema not in seen_schemas: 68 tables += [(db_schema, tn) for tn in 69 connection.introspection.schema_table_names(db_schema)] 70 seen_schemas.add(db_schema) 71 72 # Create the model's database table, 73 # if it doesn't already exist. 63 74 if verbosity >= 2: 64 75 print "Processing %s.%s model" % (app_name, model._meta.object_name) 65 76 opts = model._meta 66 if (connection.introspection.table_name_converter(opts.db_table) in tables or 77 schema_table = (db_schema, connection.introspection.table_name_converter(opts.db_table)) 78 if (schema_table in tables or 67 79 (opts.auto_created and 68 80 connection.introspection.table_name_converter(opts.auto_created._meta.db_table) in tables)): 69 81 continue … … 79 91 print "Creating table %s" % model._meta.db_table 80 92 for statement in sql: 81 93 cursor.execute(statement) 82 tables.append( connection.introspection.table_name_converter(model._meta.db_table))94 tables.append(schema_table) 83 95 84 96 85 97 transaction.commit_unless_managed() -
django/core/management/sql.py
68 68 69 69 # Figure out which tables already exist 70 70 if cursor: 71 table_names = connection.introspection.get_table_list(cursor) 71 table_names = [('', tn) for tn in 72 connection.introspection.get_table_list(cursor)] 72 73 else: 73 74 table_names = [] 74 75 … … 79 80 80 81 references_to_delete = {} 81 82 app_models = models.get_models(app, include_auto_created=True) 83 seen_schemas = set() 82 84 for model in app_models: 83 if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names: 85 db_schema = model._meta.db_schema 86 # Find additional tables in model-defined schemas. 87 if db_schema: 88 db_schema = connection.introspection.schema_name_converter(db_schema) 89 if db_schema not in seen_schemas: 90 table_names += ((db_schema, tn) for tn in connection.introspection.get_schema_table_list(cursor, db_schema)) 91 seen_schemas.add(db_schema) 92 schema_table = (db_schema, 93 connection.introspection.table_name_converter(model._meta.db_table)) 94 95 if cursor and schema_table in table_names: 84 96 # The table exists, so it needs to be dropped 85 97 opts = model._meta 86 98 for f in opts.local_fields: … … 90 102 to_delete.add(model) 91 103 92 104 for model in app_models: 93 if connection.introspection.table_name_converter(model._meta.db_table) in table_names: 105 db_schema = model._meta.db_schema 106 if db_schema: 107 db_schema = connection.introspection.schema_name_converter(db_schema) 108 schema_table = (db_schema, 109 connection.introspection.table_name_converter(model._meta.db_table)) 110 if schema_table in table_names: 94 111 output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style)) 95 112 113 # Output DROP TABLE statements for many-to-many tables. 114 for model in app_models: 115 opts = model._meta 116 db_schema = opts.db_schema 117 if db_schema: 118 db_schema = connection.introspection.schema_name_converter(db_schema) 119 for f in opts.local_many_to_many: 120 schema_table = (db_schema, 121 connection.introspection.table_name_converter(f.m2m_db_table())) 122 if cursor and schema_table in table_names: 123 output.extend(connection.creation.sql_destroy_many_to_many(model, f, style)) 124 96 125 # Close database connection explicitly, in case this output is being piped 97 126 # directly into a database client, to avoid locking issues. 98 127 if cursor: … … 116 145 if only_django: 117 146 tables = connection.introspection.django_table_names(only_existing=True) 118 147 else: 119 tables = connection.introspection.table_names()148 tables = [('', tn) for tn in connection.introspection.table_names()] 120 149 statements = connection.ops.sql_flush(style, tables, connection.introspection.sequence_list()) 121 150 return statements 122 151 -
tests/modeltests/schemas/__init__.py
1 # -
tests/modeltests/schemas/tests.py
1 # Validate that you can override the default test suite 2 3 import unittest 4 from models import * 5 6 from django.conf import settings 7 from django.db import connection, models 8 9 class SampleTests(unittest.TestCase): 10 fixtures = ['testschema',] 11 VALID_ENGINES=['postgresql_psycopg2', 'postgresql', 'mysql','oracle'] 12 13 def test_meta_information(self): 14 e=Entry.objects.get(id=1) 15 b = Blog.objects.get(id=1) 16 if settings.DATABASE_ENGINE in self.VALID_ENGINES: 17 self.assertEqual('test_schema', e._meta.db_schema) 18 if settings.DATABASE_SCHEMA: 19 self.assertEqual(settings.DATABASE_SCHEMA, b._meta.db_schema) 20 else: 21 self.assertFalse(b._meta.db_schema) 22 else: 23 self.assertFalse(e._meta.db_schema) #no model schema 24 self.assertFalse(b._meta.db_schema) #no global schema 25 26 def test_schema_in_m2m_declaring_model(self): 27 e = Entry.objects.get(id=1) 28 c = Category(name='Test') 29 c.save() 30 e.categories = [c] 31 32 categories= e.categories.filter(name='Test') 33 34 a = len(categories) 35 self.assertEqual(1, len(categories)) 36 No newline at end of file -
tests/modeltests/schemas/fixtures/testschema.json
1 [ 2 { 3 "pk": 1, 4 "model": "schemas.tag", 5 "fields": { 6 "name": "Test" 7 } 8 }, 9 { 10 "pk": 1, 11 "model": "schemas.blog", 12 "fields": { 13 "name":"Test" 14 } 15 }, 16 { 17 "pk": 1, 18 "model": "schemas.entry", 19 "fields": { 20 "blog": 1, 21 "title": "Test entry", 22 "tags": [1] 23 } 24 }, 25 { 26 "pk": 1, 27 "model": "schemas.comment", 28 "fields": { 29 "entry": 1, 30 "text": "nice entry" 31 } 32 }, 33 { 34 "pk": 2, 35 "model": "schemas.comment", 36 "fields": { 37 "entry": 1, 38 "text": "typical spam comment" 39 } 40 } 41 42 43 ] 44 No newline at end of file -
tests/modeltests/schemas/models.py
1 # coding: utf-8 2 3 from django.db import models 4 5 class Category(models.Model): 6 name = models.CharField(max_length=50) 7 8 9 class Blog(models.Model): 10 "Model in default schema" 11 name = models.CharField(max_length=50) 12 13 14 class Entry(models.Model): 15 "Model in custom schema that references the default" 16 blog = models.ForeignKey(Blog) 17 title = models.CharField(max_length=50) 18 categories = models.ManyToManyField(Category) 19 20 class Meta: 21 "using custom db_table as well" 22 db_table='schema_blog_entries' 23 db_schema = 'test_schema' 24 25 26 class Comment(models.Model): 27 "Model in the custom schema that references Entry in the same schema" 28 entry = models.ForeignKey(Entry) 29 text = models.CharField(max_length=50) 30 31 class Meta: 32 db_schema = 'test_schema' 33 34 35 class Tag(models.Model): 36 "Used for m2m relations" 37 name=models.CharField(max_length=20) 38 entries=models.ManyToManyField(Entry) 39 40 41 42 __test__ = {'API_TESTS': """ 43 44 #Test with actual data 45 # Nothing in there yet 46 >>> Blog.objects.all() 47 [] 48 49 # Create a blog 50 >>> b = Blog(name='Test') 51 >>> b.save() 52 53 # Verify that we got an ID 54 >>> b.id 55 1 56 57 # Create entry 58 >>> e = Entry(blog=b, title='Test entry') 59 >>> e.save() 60 >>> e.id 61 1 62 63 # Create Comments 64 >>> c1 = Comment(entry=e, text='nice entry') 65 >>> c1.save() 66 >>> c2 = Comment(entry=e, text='really like it') 67 >>> c2.save() 68 69 #Retrieve the stuff again. 70 >>> b2 = Blog.objects.get(id=b.id) 71 >>> b==b2 72 True 73 74 >>> b2.entry_set.all() 75 [<Entry: Entry object>] 76 77 #make sure we don't break many to many relations 78 >>> t = Tag(name="test") 79 >>> t.save() 80 >>> t.entries = [e] 81 >>> t.entries.all() 82 [<Entry: Entry object>] 83 84 85 >>> from django.conf import settings 86 >>> from django.db import connection, models 87 88 # Test if we support schemas and can find the table if so 89 >>> if e._meta.db_schema: 90 ... tables = connection.introspection.schema_table_names(e._meta.db_schema) 91 ... else: 92 ... tables = connection.introspection.table_names() 93 >>> if connection.introspection.table_name_converter(e._meta.db_table) in tables: 94 ... print "ok" 95 ... else: 96 ... print "schema=" + e._meta.db_schema 97 ... print "tables=%s" % tables 98 ok 99 100 101 """ 102 } -
docs/topics/db/models.txt
629 629 verbose_name_plural = "oxen" 630 630 631 631 Model metadata is "anything that's not a field", such as ordering options 632 (:attr:`~Options.ordering`), database table name (:attr:`~Options.db_table`), or 632 (:attr:`~Options.ordering`), database table name (:attr:`~Options.db_table`), 633 (:attr:`~Options.db_schema`) custom schema for the tables, or 633 634 human-readable singular and plural names (:attr:`~Options.verbose_name` and 634 635 :attr:`~Options.verbose_name_plural`). None are required, and adding ``class 635 636 Meta`` to a model is completely optional. -
docs/ref/models/options.txt
61 61 aren't allowed in Python variable names -- notably, the hyphen -- that's OK. 62 62 Django quotes column and table names behind the scenes. 63 63 64 .. _db_schema: 65 66 ``db_schema`` 67 ----------------- 68 69 .. attribute:: Options.db_schema 70 71 **New in Django development version** 72 73 The name of the database schema to use for the model. If the backend 74 doesn't support multiple schemas, this options is ignored. 75 76 If this is used the Django will prefix the model table names with the schema 77 name. For example MySQL Django would use ``db_schema + '.' + db_table``. 78 Be aware that PostgreSQL supports different schemas within the database. 79 MySQL solves the same thing by treating it as just another database. 80 81 82 64 83 ``db_tablespace`` 65 84 ----------------- 66 85 -
docs/ref/settings.txt
272 272 The port to use when connecting to the database. An empty string means the 273 273 default port. Not used with SQLite. 274 274 275 .. setting:: DATABASE_SCHEMA 276 277 DATABASE_SCHEMA 278 --------------- 279 280 **New in Django development version** 281 282 Default: ``''`` (Empty string) 283 284 The name of the database schema to use for models. If the backend 285 doesn't support multiple schemas, this options is ignored. An empty 286 string means the default schema. 287 288 If this is used the Django will prefix any table names with the schema name. 289 The schema can be overriden in model, for details see :ref:`db_schema`. 290 275 291 .. setting:: DATABASE_USER 276 292 277 293 DATABASE_USER