Ticket #6148: generic-db_schema-r11231.diff
File generic-db_schema-r11231.diff, 65.9 KB (added by , 15 years ago) |
---|
-
django/db/models/sql/query.py
581 581 might not have all the pieces in place at that time. 582 582 """ 583 583 if not self.tables: 584 self.join((None, self.model._meta. db_table, None, None))584 self.join((None, self.model._meta.qualified_name, None, None)) 585 585 if (not self.select and self.default_cols and not 586 586 self.included_inherited_models): 587 587 self.setup_inherited_models() … … 681 681 Callback used by deferred_to_columns(). The "target" parameter should 682 682 be a set instance. 683 683 """ 684 table = model._meta. db_table684 table = model._meta.qualified_name 685 685 if table not in target: 686 686 target[table] = set() 687 687 for field in fields: … … 798 798 alias = start_alias 799 799 else: 800 800 link_field = opts.get_ancestor_link(model) 801 alias = self.join((start_alias, model._meta.db_table, 801 alias = self.join((start_alias, 802 model._meta.qualified_name, 802 803 link_field.column, model._meta.pk.column)) 803 804 seen[model] = alias 804 805 else: … … 1206 1207 alias = self.tables[0] 1207 1208 self.ref_alias(alias) 1208 1209 else: 1209 alias = self.join((None, self.model._meta.db_table, None, None)) 1210 alias = self.join((None, self.model._meta.qualified_name, 1211 None, None)) 1210 1212 return alias 1211 1213 1212 1214 def count_active_tables(self): … … 1319 1321 seen[model] = root_alias 1320 1322 else: 1321 1323 link_field = opts.get_ancestor_link(model) 1322 seen[model] = self.join((root_alias, model._meta.db_table, 1324 seen[model] = self.join((root_alias, 1325 model._meta.qualified_name, 1323 1326 link_field.column, model._meta.pk.column)) 1324 1327 self.included_inherited_models = seen 1325 1328 … … 1377 1380 # what "used" specifies). 1378 1381 avoid = avoid_set.copy() 1379 1382 dupe_set = orig_dupe_set.copy() 1380 table = f.rel.to._meta. db_table1383 table = f.rel.to._meta.qualified_name 1381 1384 if nullable or f.null: 1382 1385 promote = True 1383 1386 else: … … 1401 1404 ()) 1402 1405 dupe_set.add((opts, lhs_col)) 1403 1406 int_opts = int_model._meta 1404 alias = self.join((alias, int_opts. db_table, lhs_col,1405 int_opts.pk.column), exclusions=used,1407 alias = self.join((alias, int_opts.qualified_name, 1408 lhs_col, int_opts.pk.column), exclusions=used, 1406 1409 promote=promote) 1407 1410 alias_chain.append(alias) 1408 1411 for (dupe_opts, dupe_col) in dupe_set: … … 1756 1759 (id(opts), lhs_col), ())) 1757 1760 dupe_set.add((opts, lhs_col)) 1758 1761 opts = int_model._meta 1759 alias = self.join((alias, opts.db_table, lhs_col, 1760 opts.pk.column), exclusions=exclusions) 1762 alias = self.join((alias, opts.qualified_name, 1763 lhs_col, opts.pk.column), 1764 exclusions=exclusions) 1761 1765 joins.append(alias) 1762 1766 exclusions.add(alias) 1763 1767 for (dupe_opts, dupe_col) in dupe_set: … … 1782 1786 (table1, from_col1, to_col1, table2, from_col2, 1783 1787 to_col2, opts, target) = cached_data 1784 1788 else: 1785 table1 = field.m2m_ db_table()1789 table1 = field.m2m_qualified_name() 1786 1790 from_col1 = opts.pk.column 1787 1791 to_col1 = field.m2m_column_name() 1788 1792 opts = field.rel.to._meta 1789 table2 = opts. db_table1793 table2 = opts.qualified_name 1790 1794 from_col2 = field.m2m_reverse_name() 1791 1795 to_col2 = opts.pk.column 1792 1796 target = opts.pk … … 1813 1817 else: 1814 1818 opts = field.rel.to._meta 1815 1819 target = field.rel.get_related_field() 1816 table = opts. db_table1820 table = opts.qualified_name 1817 1821 from_col = field.column 1818 1822 to_col = target.column 1819 1823 orig_opts._join_cache[name] = (table, from_col, to_col, … … 1835 1839 (table1, from_col1, to_col1, table2, from_col2, 1836 1840 to_col2, opts, target) = cached_data 1837 1841 else: 1838 table1 = field.m2m_ db_table()1842 table1 = field.m2m_qualified_name() 1839 1843 from_col1 = opts.pk.column 1840 1844 to_col1 = field.m2m_reverse_name() 1841 1845 opts = orig_field.opts 1842 table2 = opts. db_table1846 table2 = opts.qualified_name 1843 1847 from_col2 = field.m2m_column_name() 1844 1848 to_col2 = opts.pk.column 1845 1849 target = opts.pk … … 1862 1866 local_field = opts.get_field_by_name( 1863 1867 field.rel.field_name)[0] 1864 1868 opts = orig_field.opts 1865 table = opts. db_table1869 table = opts.qualified_name 1866 1870 from_col = local_field.column 1867 1871 to_col = field.column 1868 1872 target = opts.pk … … 2101 2105 self.group_by = [] 2102 2106 if self.connection.features.allows_group_by_pk: 2103 2107 if len(self.select) == len(self.model._meta.fields): 2104 self.group_by.append((self.model._meta. db_table,2108 self.group_by.append((self.model._meta.qualified_name, 2105 2109 self.model._meta.pk.column)) 2106 2110 return 2107 2111 … … 2123 2127 else: 2124 2128 opts = self.model._meta 2125 2129 if not self.select: 2126 count = self.aggregates_module.Count((self.join((None, opts.db_table, None, None)), opts.pk.column), 2130 count = self.aggregates_module.Count((self.join((None, 2131 opts.qualified_name, None, None)), opts.pk.column), 2127 2132 is_summary=True, distinct=True) 2128 2133 else: 2129 2134 # 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
597 597 # into a pure queryset operation. 598 598 where = ['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \ 599 599 (qn('_order'), op, qn('_order'), 600 qn(self._meta.db_table), qn(self._meta.pk.column))]600 self._meta.qualified_name, qn(self._meta.pk.column))] 601 601 params = [self.pk] 602 602 obj = self._default_manager.filter(**{order_field.name: getattr(self, order_field.attname)}).extra(where=where, params=params).order_by(order)[:1].get() 603 603 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' )24 'abstract', 'managed', 'proxy', '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 = '' 34 self.qualified_name = '' 33 35 self.ordering = [] 34 36 self.unique_together = [] 35 37 self.permissions = [] … … 103 105 self.db_table = "%s_%s" % (self.app_label, self.module_name) 104 106 self.db_table = truncate_name(self.db_table, connection.ops.max_name_length()) 105 107 108 # Construct qualified table name. 109 self.qualified_name = connection.ops.prep_db_table(self.db_schema, 110 self.db_table) 111 if self.qualified_name == connection.ops.quote_name(self.db_table): 112 # If unchanged, the backend doesn't support schemas. 113 self.db_schema = '' 106 114 107 115 def _prepare(self, model): 108 116 if self.order_with_respect_to: … … 176 184 self.pk = target._meta.pk 177 185 self.proxy_for_model = target 178 186 self.db_table = target._meta.db_table 187 self.db_schema = target._meta.db_schema 179 188 180 189 def __repr__(self): 181 190 return '<Options for %s>' % self.object_name -
django/db/models/fields/related.py
562 562 core_filters={'%s__pk' % self.related.field.name: instance._get_pk_val()}, 563 563 instance=instance, 564 564 symmetrical=False, 565 join_table= qn(self.related.field.m2m_db_table()),565 join_table=self.related.field.m2m_qualified_name(), 566 566 source_col_name=qn(self.related.field.m2m_reverse_name()), 567 567 target_col_name=qn(self.related.field.m2m_column_name()) 568 568 ) … … 607 607 core_filters={'%s__pk' % self.field.related_query_name(): instance._get_pk_val()}, 608 608 instance=instance, 609 609 symmetrical=(self.field.rel.symmetrical and isinstance(instance, rel_model)), 610 join_table= qn(self.field.m2m_db_table()),610 join_table=self.field.m2m_qualified_name(), 611 611 source_col_name=qn(self.field.m2m_column_name()), 612 612 target_col_name=qn(self.field.m2m_reverse_name()) 613 613 ) … … 739 739 if isinstance(self.rel.to, basestring): 740 740 target = self.rel.to 741 741 else: 742 target = self.rel.to._meta. db_table742 target = self.rel.to._meta.qualified_name 743 743 cls._meta.duplicate_targets[self.column] = (target, "o2m") 744 744 745 745 def contribute_to_related_class(self, cls, related): … … 805 805 through=kwargs.pop('through', None)) 806 806 807 807 self.db_table = kwargs.pop('db_table', None) 808 self.db_schema = kwargs.pop('db_schema', '') 808 809 if kwargs['rel'].through is not None: 809 810 self.creates_table = False 810 811 assert self.db_table is None, "Cannot specify a db_table if an intermediary model is used." … … 829 830 return util.truncate_name('%s_%s' % (opts.db_table, self.name), 830 831 connection.ops.max_name_length()) 831 832 833 def _get_m2m_db_schema(self, opts): 834 "Function that can be curried to provide the m2m schema name for this relation" 835 if self.rel.through is not None and self.rel.through_model._meta.db_schema: 836 return self.rel.through_model._meta.db_schema 837 elif self.db_schema: 838 return self.db_schema 839 else: 840 return opts.db_schema 841 842 def _get_m2m_qualified_name(self, opts): 843 "Function that can be curried to provide the qualified m2m table name for this relation" 844 schema = self._get_m2m_db_schema(opts) 845 table = self._get_m2m_db_table(opts) 846 return connection.ops.prep_db_table(schema, table) 847 832 848 def _get_m2m_column_name(self, related): 833 849 "Function that can be curried to provide the source column name for the m2m table" 834 850 try: … … 928 944 929 945 # Set up the accessor for the m2m table name for the relation 930 946 self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta) 947 self.m2m_db_schema = curry(self._get_m2m_db_schema, cls._meta) 948 self.m2m_qualified_name = curry(self._get_m2m_qualified_name, 949 cls._meta) 931 950 932 951 # Populate some necessary rel arguments so that cross-app relations 933 952 # work correctly. … … 942 961 if isinstance(self.rel.to, basestring): 943 962 target = self.rel.to 944 963 else: 945 target = self.rel.to._meta. db_table964 target = self.rel.to._meta.qualified_name 946 965 cls._meta.duplicate_targets[self.column] = (target, "m2m") 947 966 948 967 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 [schema + "." + 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 163 170 def random_function_sql(self): 164 171 return 'RAND()' 165 172 … … 169 176 # to clear all tables of all data 170 177 if tables: 171 178 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)))) 179 sql.extend(['%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.prep_db_table(schema, table))) for (schema, table) in tables]) 174 180 sql.append('SET FOREIGN_KEY_CHECKS = 1;') 175 181 176 182 # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements 177 183 # 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]) 184 for sequence_info in sequences: 185 schema_name = sequence_info['schema'] 186 table_name = self.prep_db_table(schema_name, sequence_info['table']) 187 sql.append("%s %s %s %s %s;" % \ 188 (style.SQL_KEYWORD('ALTER'), 189 style.SQL_KEYWORD('TABLE'), 190 style.SQL_TABLE(table_name), 191 style.SQL_KEYWORD('AUTO_INCREMENT'), 192 style.SQL_FIELD('= 1'), 193 )) 185 194 return sql 186 195 else: 187 196 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
47 47 48 48 class DatabaseOperations(BaseDatabaseOperations): 49 49 50 def autoinc_sql(self, table, column):50 def autoinc_sql(self, schema, table, column): 51 51 # To simulate auto-incrementing primary keys in Oracle, we have to 52 52 # create a sequence and a trigger. 53 53 sq_name = get_sequence_name(table) 54 54 tr_name = get_trigger_name(table) 55 tbl_name = self.quote_name(table) 55 tbl_name = self.prep_db_table(schema, table) 56 sq_qname = self.prep_db_table(schema, sq_name) 57 tr_qname = self.prep_db_table(schema, tr_name) 56 58 col_name = self.quote_name(column) 57 59 sequence_sql = """ 58 60 DECLARE … … 61 63 SELECT COUNT(*) INTO i FROM USER_CATALOG 62 64 WHERE TABLE_NAME = '%(sq_name)s' AND TABLE_TYPE = 'SEQUENCE'; 63 65 IF i = 0 THEN 64 EXECUTE IMMEDIATE 'CREATE SEQUENCE "%(sq_name)s"';66 EXECUTE IMMEDIATE 'CREATE SEQUENCE %(sq_qname)s'; 65 67 END IF; 66 68 END; 67 69 /""" % locals() 68 70 trigger_sql = """ 69 CREATE OR REPLACE TRIGGER "%(tr_name)s"71 CREATE OR REPLACE TRIGGER %(tr_qname)s 70 72 BEFORE INSERT ON %(tbl_name)s 71 73 FOR EACH ROW 72 74 WHEN (new.%(col_name)s IS NULL) 73 75 BEGIN 74 SELECT "%(sq_name)s".nextval76 SELECT %(sq_qname)s.nextval 75 77 INTO :new.%(col_name)s FROM dual; 76 78 END; 77 79 /""" % locals() … … 100 102 def deferrable_sql(self): 101 103 return " DEFERRABLE INITIALLY DEFERRED" 102 104 103 def drop_sequence_sql(self, table): 104 return "DROP SEQUENCE %s;" % self.quote_name(get_sequence_name(table)) 105 def drop_sequence_sql(self, schema, table): 106 sequence_name = self.prep_db_table(schema, get_sequence_name(table)) 107 return "DROP SEQUENCE %s;" % sequence_name 105 108 106 109 def fetch_returned_insert_id(self, cursor): 107 110 return long(cursor._insert_id_var.getvalue()) … … 112 115 else: 113 116 return "%s" 114 117 115 def last_insert_id(self, cursor, table_name, pk_name):116 sq_name = get_sequence_name(table_name)117 cursor.execute('SELECT "%s".currval FROM dual' % sq_name)118 def last_insert_id(self, cursor, schema_name, table_name, pk_name): 119 sq_name = self.prep_db_table(schema_name, get_sequence_name(table_name)) 120 cursor.execute('SELECT %s.currval FROM dual' % sq_name) 118 121 return cursor.fetchone()[0] 119 122 120 123 def lookup_cast(self, lookup_type): … … 125 128 def max_name_length(self): 126 129 return 30 127 130 131 def prep_db_table(self, db_schema, db_table): 132 qn = self.quote_name 133 if db_schema: 134 return "%s.%s" % (qn(db_schema), qn(db_table)) 135 else: 136 return qn(db_table) 137 128 138 def prep_for_iexact_query(self, x): 129 139 return x 130 140 … … 178 188 def sql_flush(self, style, tables, sequences): 179 189 # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 180 190 # 'TRUNCATE z;'... style SQL statements 191 sql = [] 181 192 if tables: 182 193 # Oracle does support TRUNCATE, but it seems to get us into 183 194 # FK referential trouble, whereas DELETE FROM table works. 184 sql = ['%s %s %s;' % \ 185 (style.SQL_KEYWORD('DELETE'), 186 style.SQL_KEYWORD('FROM'), 187 style.SQL_FIELD(self.quote_name(table))) 188 for table in tables] 195 for schema, table in tables: 196 table = self.prep_db_table(schema, table) 197 sql.append('%s %s %s;' % \ 198 (style.SQL_KEYWORD('DELETE'), 199 style.SQL_KEYWORD('FROM'), 200 style.SQL_FIELD(table))) 189 201 # Since we've just deleted all the rows, running our sequence 190 202 # ALTER code will reset the sequence to 0. 191 203 for sequence_info in sequences: 192 sequence_name = get_sequence_name(sequence_info['table']) 193 table_name = self.quote_name(sequence_info['table']) 204 schema_name = sequence_info['schema'] 205 sequence_name = self.prep_db_table(schema_name, 206 get_sequence_name(sequence_info['table'])) 207 table_name = self.prep_db_table(schema_name, 208 sequence_info['table']) 194 209 column_name = self.quote_name(sequence_info['column'] or 'id') 195 210 query = _get_sequence_reset_sql() % {'sequence': sequence_name, 196 211 'table': table_name, 197 212 'column': column_name} 198 213 sql.append(query) 199 return sql 200 else: 201 return [] 214 return sql 202 215 203 216 def sequence_reset_sql(self, style, model_list): 204 217 from django.db import models … … 207 220 for model in model_list: 208 221 for f in model._meta.local_fields: 209 222 if isinstance(f, models.AutoField): 210 table_name = self.quote_name(model._meta.db_table) 211 sequence_name = get_sequence_name(model._meta.db_table) 223 table_name = model._meta.qualified_name 224 sequence_name = self.prep_db_table(model._meta.db_schema, 225 get_sequence_name(model._meta.db_table)) 212 226 column_name = self.quote_name(f.column) 213 227 output.append(query % {'sequence': sequence_name, 214 228 'table': table_name, … … 218 232 break 219 233 for f in model._meta.many_to_many: 220 234 if not f.rel.through: 221 table_name = self.quote_name(f.m2m_db_table()) 222 sequence_name = get_sequence_name(f.m2m_db_table()) 235 table_name = self.quote_name(f.m2m_qualified_name()) 236 sequence_name = self.prep_db_table(f.m2m_db_schema(), 237 get_sequence_name(f.m2m_db_table())) 223 238 column_name = self.quote_name('id') 224 239 output.append(query % {'sequence': sequence_name, 225 240 'table': table_name, … … 425 440 query = query[:-1] 426 441 query = smart_str(query, self.charset) % tuple(args) 427 442 self._guess_input_sizes([params]) 443 print >>file('/home/ikelly/django-log.sql', 'w'), query, self._param_generator(params) 428 444 try: 429 445 return self.cursor.execute(query, self._param_generator(params)) 430 446 except DatabaseError, e: … … 542 558 BEGIN 543 559 LOCK TABLE %(table)s IN SHARE MODE; 544 560 SELECT NVL(MAX(%(column)s), 0) INTO startvalue FROM %(table)s; 545 SELECT "%(sequence)s".nextval INTO cval FROM dual;561 SELECT %(sequence)s.nextval INTO cval FROM dual; 546 562 cval := startvalue - cval; 547 563 IF cval != 0 THEN 548 EXECUTE IMMEDIATE 'ALTER SEQUENCE "%(sequence)s"MINVALUE 0 INCREMENT BY '||cval;549 SELECT "%(sequence)s".nextval INTO cval FROM dual;550 EXECUTE IMMEDIATE 'ALTER SEQUENCE "%(sequence)s"INCREMENT BY 1';564 EXECUTE IMMEDIATE 'ALTER SEQUENCE %(sequence)s MINVALUE 0 INCREMENT BY '||cval; 565 SELECT %(sequence)s.nextval INTO cval FROM dual; 566 EXECUTE IMMEDIATE 'ALTER SEQUENCE %(sequence)s INCREMENT BY 1'; 551 567 END IF; 552 568 COMMIT; 553 569 END; -
django/db/backends/oracle/introspection.py
108 108 for row in cursor.fetchall(): 109 109 indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]} 110 110 return indexes 111 112 def schema_name_converter(self, name): 113 """Convert to lowercase for case-sensitive schema name comparison.""" 114 return name.lower() 115 116 def get_schema_list(self, cursor): 117 "Returns a list of schemas that exist in the database." 118 sql = """ 119 select distinct username 120 from all_users, all_objects 121 where username = owner 122 """ 123 cursor.execute(sql) 124 return [schema.lower() for (schema,) in cursor] 125 126 def get_schema_table_list(self, cursor, schema): 127 "Returns a list of tables in a specific schema." 128 sql = """ 129 select table_name from all_tables 130 where owner = upper(%s) 131 """ 132 cursor.execute(sql, [schema]) 133 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 the db_table if not supported. 294 """ 295 return db_table 296 290 297 def random_function_sql(self): 291 298 """ 292 299 Returns a SQL expression that returns a random value. … … 478 485 return name 479 486 480 487 def table_names(self): 481 "Returns a list of names of all tables that exist in the d atabase."488 "Returns a list of names of all tables that exist in the default schema." 482 489 cursor = self.connection.cursor() 483 490 return self.get_table_list(cursor) 484 491 492 def schema_name_converter(self, name): 493 """Apply a conversion to the name for the purposes of comparison. 494 495 The default schema name converter is for case sensitive comparison. 496 """ 497 return name 498 499 def get_schema_list(self, cursor): 500 "Returns a list of schemas that exist in the database" 501 return [] 502 503 def get_schema_table_list(self, cursor, schema): 504 "Returns a list of tables in a specific schema" 505 return [] 506 507 def schema_names(self): 508 cursor = self.connection.cursor() 509 return self.get_schema_list(cursor) 510 511 def schema_table_names(self, schema): 512 "Returns a list of names of all tables that exist in the database schema." 513 cursor = self.connection.cursor() 514 return self.get_schema_table_list(cursor, schema) 515 485 516 def django_table_names(self, only_existing=False): 486 517 """ 487 Returns a list of all table names that have associated Django models and488 are in INSTALLED_APPS.518 Returns a list of tuples containing all schema and table names that 519 have associated Django models and are in INSTALLED_APPS. 489 520 490 If only_existing is True, the resulting list will only include the tables491 t hat actually exist in the database.521 If only_existing is True, the resulting list will only include the 522 tables that actually exist in the database. 492 523 """ 493 524 from django.db import models 494 525 tables = set() 526 if only_existing: 527 existing_tables = set([('', tn) for tn in self.table_names()]) 528 seen_schemas = set() 495 529 for app in models.get_apps(): 496 530 for model in models.get_models(app): 497 531 if not model._meta.managed: 498 532 continue 499 tables.add(model._meta.db_table) 500 tables.update([f.m2m_db_table() for f in model._meta.local_many_to_many]) 533 db_schema = model._meta.db_schema 534 db_table = model._meta.db_table 535 if only_existing and db_schema and db_schema not in seen_schemas: 536 existing_tables.update([(db_schema, tn) for tn in 537 self.schema_table_names(db_schema)]) 538 seen_schemas.add(db_schema) 539 tables.add((model._meta.db_schema, model._meta.db_table)) 540 for f in model._meta.local_many_to_many: 541 m2m_schema = f.m2m_db_schema() 542 m2m_table = f.m2m_db_table() 543 if only_existing and m2m_schema and m2m_schema not in seen_schemas: 544 existing_tables.update([(m2m_schema, tn) for tn in 545 self.schema_table_names(m2m_schema)]) 546 seen_schemas.add(m2m_schema) 547 tables.add((m2m_schema, m2m_table)) 501 548 if only_existing: 502 tables = [t for t in tables if self.table_name_converter(t) in self.table_names()] 549 tables = [(s, t) for (s, t) in tables 550 if (self.schema_name_converter(s), 551 self.table_name_converter(t)) in existing_tables] 503 552 return tables 504 553 505 554 def installed_models(self, tables): … … 526 575 continue 527 576 for f in model._meta.local_fields: 528 577 if isinstance(f, models.AutoField): 529 sequence_list.append({'table': model._meta.db_table, 'column': f.column}) 578 sequence_list.append({'table': model._meta.db_table, 579 'column': f.column, 580 'schema': model._meta.db_schema}) 530 581 break # Only one AutoField is allowed per model, so don't bother continuing. 531 582 532 583 for f in model._meta.local_many_to_many: 533 584 # If this is an m2m using an intermediate table, 534 585 # we don't need to reset the sequence. 535 586 if f.rel.through is None: 536 sequence_list.append({'table': f.m2m_db_table(), 'column': None}) 587 sequence_list.append({'table': f.m2m_db_table(), 588 'column': None, 589 'schema': f.m2m_db_schema()}) 537 590 538 591 return sequence_list 539 592 -
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_table(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: … … 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) 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 # Create the model's database table, 72 # if it doesn't already exist. 63 73 if verbosity >= 2: 64 74 print "Processing %s.%s model" % (app_name, model._meta.object_name) 65 if connection.introspection.table_name_converter(model._meta.db_table) in tables: 75 schema_table = (db_schema, 76 connection.introspection.table_name_converter(model._meta.db_table)) 77 if schema_table in tables: 66 78 continue 67 79 sql, references = connection.creation.sql_create_model(model, self.style, seen_models) 68 80 seen_models.add(model) … … 76 88 print "Creating table %s" % model._meta.db_table 77 89 for statement in sql: 78 90 cursor.execute(statement) 79 tables.append( connection.introspection.table_name_converter(model._meta.db_table))91 tables.append(schema_table) 80 92 81 93 # Create the m2m tables. This must be done after all tables have been created 82 94 # to ensure that all referred tables will exist. -
django/core/management/sql.py
72 72 73 73 # Figure out which tables already exist 74 74 if cursor: 75 table_names = connection.introspection.get_table_list(cursor) 75 table_names = [('', tn) for tn in 76 connection.introspection.get_table_list(cursor)] 76 77 else: 77 78 table_names = [] 78 79 … … 83 84 84 85 references_to_delete = {} 85 86 app_models = models.get_models(app) 87 seen_schemas = set() 86 88 for model in app_models: 87 if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names: 89 db_schema = model._meta.db_schema 90 # Find additional tables in model-defined schemas. 91 if db_schema: 92 db_schema = connection.introspection.schema_name_converter(db_schema) 93 if db_schema not in seen_schemas: 94 table_names += connection.introspection.get_schema_table_list(cursor, db_schema) 95 seen_schemas.add(db_schema) 96 schema_table = (db_schema, 97 connection.introspection.table_name_converter(model._meta.db_table)) 98 if cursor and schema_table in table_names: 88 99 # The table exists, so it needs to be dropped 89 100 opts = model._meta 90 101 for f in opts.local_fields: … … 94 105 to_delete.add(model) 95 106 96 107 for model in app_models: 97 if connection.introspection.table_name_converter(model._meta.db_table) in table_names: 108 db_schema = model._meta.db_schema 109 if db_schema: 110 db_schema = connection.introspection.schema_name_converter(db_schema) 111 schema_table = (db_schema, 112 connection.introspection.table_name_converter(model._meta.db_table)) 113 if schema_table in table_names: 98 114 output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style)) 99 115 100 116 # Output DROP TABLE statements for many-to-many tables. 101 117 for model in app_models: 102 118 opts = model._meta 119 db_schema = opts.db_schema 120 if db_schema: 121 db_schema = connection.introspection.schema_name_converter(db_schema) 103 122 for f in opts.local_many_to_many: 104 if cursor and connection.introspection.table_name_converter(f.m2m_db_table()) in table_names: 123 schema_table = (db_schema, 124 connection.introspection.table_name_converter(f.m2m_db_table())) 125 if cursor and schema_table in table_names: 105 126 output.extend(connection.creation.sql_destroy_many_to_many(model, f, style)) 106 127 107 128 # Close database connection explicitly, in case this output is being piped … … 127 148 if only_django: 128 149 tables = connection.introspection.django_table_names(only_existing=True) 129 150 else: 130 tables = connection.introspection.table_names()151 tables = [('', tn) for tn in connection.introspection.table_names()] 131 152 statements = connection.ops.sql_flush(style, tables, connection.introspection.sequence_list()) 132 153 return statements 133 154 -
tests/modeltests/schemas/__init__.py
1 # -
tests/modeltests/schemas/models.py
1 # coding: utf-8 2 3 from django.db import models 4 5 6 class Blog(models.Model): 7 "Model in default schema" 8 name = models.CharField(max_length=50) 9 10 11 class Entry(models.Model): 12 "Model in custom schema that references the default" 13 blog = models.ForeignKey(Blog) 14 title = models.CharField(max_length=50) 15 16 class Meta: 17 "using custom db_table as well" 18 db_table='schema_blog_entries' 19 db_schema = 'test_schema' 20 21 22 class Comment(models.Model): 23 "Model in the custom schema that references Entry in the same schema" 24 entry = models.ForeignKey(Entry) 25 text = models.CharField(max_length=50) 26 27 class Meta: 28 db_schema = 'test_schema' 29 30 __test__ = {'API_TESTS': """ 31 32 #Test with actual data 33 # Nothing in there yet 34 >>> Blog.objects.all() 35 [] 36 37 # Create a blog 38 >>> b = Blog(name='Test') 39 >>> b.save() 40 41 # Verify that we got an ID 42 >>> b.id 43 1 44 45 # Create entry 46 >>> e = Entry(blog=b, title='Test entry') 47 >>> e.save() 48 >>> e.id 49 1 50 51 # Create Comments 52 >>> c1 = Comment(entry=e, text='nice entry') 53 >>> c1.save() 54 >>> c2 = Comment(entry=e, text='really like it') 55 >>> c2.save() 56 57 #Retrieve the stuff again. 58 >>> b2 = Blog.objects.get(id=b.id) 59 >>> b==b2 60 True 61 62 >>> b2.entry_set.all() 63 [<Entry: Entry object>] 64 65 >>> from django.conf import settings 66 >>> from django.db import connection, models 67 68 # Test if we support schemas and can find the table if so 69 >>> if e._meta.db_schema: 70 ... tables = connection.introspection.schema_table_names(e._meta.db_schema) 71 ... else: 72 ... tables = connection.introspection.table_names() 73 >>> if connection.introspection.table_name_converter(e._meta.db_table) in tables: 74 ... print "ok" 75 ... else: 76 ... print "schema=" + e._meta.db_schema 77 ... print tables 78 ok 79 80 # Test that all but sqlite3 backend supports schema. 81 >>> if settings.DATABASE_ENGINE != 'sqlite3': 82 ... e._meta.db_schema 83 'test_schema' 84 85 """ 86 } -
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
50 50 aren't allowed in Python variable names -- notably, the hyphen -- that's OK. 51 51 Django quotes column and table names behind the scenes. 52 52 53 ``db_schema`` 54 ----------------- 55 56 **New in Django development version** 57 58 The name of the database schema to use for the model. If the backend 59 doesn't support multiple schemas, this options is ignored. 60 61 If this is used Django will prefix any table names with the schema name. 62 For example MySQL Django would use ``db_schema + '.' + db_table``. 63 Be aware that postgres supports different schemas within the database. 64 MySQL solves the same thing by treating it as just another database. 65 66 67 53 68 ``db_tablespace`` 54 69 ----------------- 55 70