OracleBranch: django-oracle-rev5392.diff
File django-oracle-rev5392.diff, 96.1 KB (added by , 17 years ago) |
---|
-
django/test/utils.py
1 1 import sys, time 2 2 from django.conf import settings 3 from django.db import connection, transaction, backend3 from django.db import connection, backend, get_creation_module 4 4 from django.core import management, mail 5 5 from django.dispatch import dispatcher 6 6 from django.test import signals … … 88 88 return '' 89 89 90 90 def create_test_db(verbosity=1, autoclobber=False): 91 # If the database backend wants to create the test DB itself, let it 92 creation_module = get_creation_module() 93 if hasattr(creation_module, "create_test_db"): 94 creation_module.create_test_db(settings, connection, backend, verbosity, autoclobber) 95 return 96 91 97 if verbosity >= 1: 92 98 print "Creating test database..." 93 99 # If we're using SQLite, it's more convenient to test against an … … 142 148 cursor = connection.cursor() 143 149 144 150 def destroy_test_db(old_database_name, verbosity=1): 151 # If the database wants to drop the test DB itself, let it 152 creation_module = get_creation_module() 153 if hasattr(creation_module, "destroy_test_db"): 154 creation_module.destroy_test_db(settings, connection, backend, old_database_name, verbosity) 155 return 156 145 157 # Unless we're using SQLite, remove the test database to clean up after 146 158 # ourselves. Connect to the previous database (not the test database) 147 159 # to do so, because it's not allowed to delete a database while being -
django/db/models/base.py
96 96 97 97 def __init__(self, *args, **kwargs): 98 98 dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) 99 99 100 100 # There is a rather weird disparity here; if kwargs, it's set, then args 101 # overrides it. It should be one or the other; don't duplicate the work 101 # overrides it. It should be one or the other; don't duplicate the work 102 102 # The reason for the kwargs check is that standard iterator passes in by 103 103 # args, and nstantiation for iteration is 33% faster. 104 104 args_len = len(args) … … 122 122 # Maintain compatibility with existing calls. 123 123 if isinstance(field.rel, ManyToOneRel): 124 124 kwargs.pop(field.attname, None) 125 125 126 126 # Now we're left with the unprocessed fields that *must* come from 127 127 # keywords, or default. 128 128 129 129 for field in fields_iter: 130 130 if kwargs: 131 131 if isinstance(field.rel, ManyToOneRel): … … 147 147 try: 148 148 val = getattr(rel_obj, field.rel.get_related_field().attname) 149 149 except AttributeError: 150 raise TypeError("Invalid value: %r should be a %s instance, not a %s" % 150 raise TypeError("Invalid value: %r should be a %s instance, not a %s" % 151 151 (field.name, field.rel.to, type(rel_obj))) 152 152 else: 153 153 val = kwargs.pop(field.attname, field.get_default()) … … 210 210 record_exists = True 211 211 if pk_set: 212 212 # Determine whether a record with the primary key already exists. 213 cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % \ 214 (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val]) 213 cursor.execute("SELECT COUNT(*) FROM %s WHERE %s=%%s" % \ 214 (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), 215 self._meta.pk.get_db_prep_lookup('exact', pk_val)) 215 216 # If it does already exist, do an UPDATE. 216 if cursor.fetchone() :217 if cursor.fetchone()[0] > 0: 217 218 db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks] 218 219 if db_values: 219 220 cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \ 220 221 (backend.quote_name(self._meta.db_table), 221 222 ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]), 222 223 backend.quote_name(self._meta.pk.column)), 223 db_values + [pk_val])224 db_values + self._meta.pk.get_db_prep_lookup('exact', pk_val)) 224 225 else: 225 226 record_exists = False 226 227 if not pk_set or not record_exists: -
django/db/models/options.py
13 13 14 14 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering', 15 15 'unique_together', 'permissions', 'get_latest_by', 16 'order_with_respect_to', 'app_label' )16 'order_with_respect_to', 'app_label', 'db_tablespace') 17 17 18 18 class Options(object): 19 19 def __init__(self, meta): … … 27 27 self.object_name, self.app_label = None, None 28 28 self.get_latest_by = None 29 29 self.order_with_respect_to = None 30 self.db_tablespace = None 30 31 self.admin = None 31 32 self.meta = meta 32 33 self.pk = None … … 59 60 del self.meta 60 61 61 62 def _prepare(self, model): 63 from django.db import backend 64 from django.db.backends.util import truncate_name 62 65 if self.order_with_respect_to: 63 66 self.order_with_respect_to = self.get_field(self.order_with_respect_to) 64 67 self.ordering = ('_order',) … … 73 76 # If the db_table wasn't provided, use the app_label + module_name. 74 77 if not self.db_table: 75 78 self.db_table = "%s_%s" % (self.app_label, self.module_name) 79 self.db_table = truncate_name(self.db_table, 80 backend.get_max_name_length()) 76 81 77 82 def add_field(self, field): 78 83 # Insert the given field in the order in which it was created, using … … 88 93 89 94 def __repr__(self): 90 95 return '<Options for %s>' % self.object_name 91 96 92 97 def __str__(self): 93 98 return "%s.%s" % (self.app_label, self.module_name) 94 99 95 100 def get_field(self, name, many_to_many=True): 96 101 "Returns the requested field by name. Raises FieldDoesNotExist on error." 97 102 to_search = many_to_many and (self.fields + self.many_to_many) or self.fields -
django/db/models/fields/__init__.py
74 74 core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True, 75 75 prepopulate_from=None, unique_for_date=None, unique_for_month=None, 76 76 unique_for_year=None, validator_list=None, choices=None, radio_admin=None, 77 help_text='', db_column=None ):77 help_text='', db_column=None, db_tablespace=None): 78 78 self.name = name 79 79 self.verbose_name = verbose_name 80 80 self.primary_key = primary_key 81 81 self.maxlength, self.unique = maxlength, unique 82 82 self.blank, self.null = blank, null 83 # Oracle treats the empty string ('') as null, so coerce the null 84 # option whenever '' is a possible value. 85 if self.empty_strings_allowed and settings.DATABASE_ENGINE == 'oracle': 86 self.null = True 83 87 self.core, self.rel, self.default = core, rel, default 84 88 self.editable = editable 85 89 self.serialize = serialize … … 91 95 self.radio_admin = radio_admin 92 96 self.help_text = help_text 93 97 self.db_column = db_column 98 self.db_tablespace = db_tablespace 94 99 95 100 # Set db_index to True if the field has a relationship and doesn't explicitly set db_index. 96 101 self.db_index = db_index … … 875 880 Field.__init__(self, verbose_name, name, **kwargs) 876 881 877 882 def get_db_prep_lookup(self, lookup_type, value): 883 if settings.DATABASE_ENGINE == 'oracle': 884 # Oracle requires a date in order to parse. 885 def prep(value): 886 if isinstance(value, datetime.time): 887 value = datetime.datetime.combine(datetime.date(1900, 1, 1), value) 888 return str(value) 889 else: 890 prep = str 878 891 if lookup_type == 'range': 879 value = [ str(v) for v in value]892 value = [prep(v) for v in value] 880 893 else: 881 value = str(value)894 value = prep(value) 882 895 return Field.get_db_prep_lookup(self, lookup_type, value) 883 896 884 897 def pre_save(self, model_instance, add): … … 896 909 # doesn't support microseconds. 897 910 if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): 898 911 value = value.replace(microsecond=0) 912 if settings.DATABASE_ENGINE == 'oracle': 913 # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field. 914 if isinstance(value, datetime.time): 915 value = datetime.datetime(1900, 1, 1, value.hour, value.minute, 916 value.second, value.microsecond) 917 elif isinstance(value, basestring): 918 value = datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6])) 919 else: 899 920 value = str(value) 900 921 return Field.get_db_prep_save(self, value) 901 922 -
django/db/models/fields/related.py
335 335 (target_col_name, self.join_table, source_col_name, 336 336 target_col_name, ",".join(['%s'] * len(new_ids))), 337 337 [self._pk_val] + list(new_ids)) 338 if cursor.rowcount is not None and cursor.rowcount != 0: 339 existing_ids = set([row[0] for row in cursor.fetchmany(cursor.rowcount)]) 340 else: 341 existing_ids = set() 338 existing_ids = set([row[0] for row in cursor.fetchall()]) 342 339 343 340 # Add the ones that aren't there already 344 341 for obj_id in (new_ids - existing_ids): -
django/db/models/query.py
4 4 from django.dispatch import dispatcher 5 5 from django.utils.datastructures import SortedDict 6 6 from django.contrib.contenttypes import generic 7 import datetime 7 8 import operator 8 9 import re 9 10 … … 77 78 else: 78 79 return backend.quote_name(word) 79 80 80 class QuerySet(object):81 class _QuerySet(object): 81 82 "Represents a lazy database lookup for a set of objects" 82 83 def __init__(self, model=None): 83 84 self.model = model … … 181 182 182 183 cursor = connection.cursor() 183 184 cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 185 184 186 fill_cache = self._select_related 185 index_end = len(self.model._meta.fields) 187 fields = self.model._meta.fields 188 index_end = len(fields) 189 has_resolve_columns = hasattr(self, 'resolve_columns') 186 190 while 1: 187 191 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 188 192 if not rows: 189 193 raise StopIteration 190 194 for row in rows: 195 if has_resolve_columns: 196 row = self.resolve_columns(row, fields) 191 197 if fill_cache: 192 198 obj, index_end = get_cached_row(klass=self.model, row=row, 193 199 index_start=0, max_depth=self._max_related_depth) … … 551 557 552 558 return select, " ".join(sql), params 553 559 560 # Use the backend's QuerySet class if it defines one, otherwise use _QuerySet. 561 if hasattr(backend, 'get_query_set_class'): 562 QuerySet = backend.get_query_set_class(_QuerySet) 563 else: 564 QuerySet = _QuerySet 565 554 566 class ValuesQuerySet(QuerySet): 555 567 def __init__(self, *args, **kwargs): 556 568 super(ValuesQuerySet, self).__init__(*args, **kwargs) 557 # select_related isn't supported in values().569 # select_related and select aren't supported in values(). 558 570 self._select_related = False 571 self._select = {} 559 572 560 573 def iterator(self): 561 574 try: … … 565 578 566 579 # self._fields is a list of field names to fetch. 567 580 if self._fields: 568 #columns = [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields] 569 if not self._select: 570 columns = [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields] 571 else: 572 columns = [] 573 for f in self._fields: 574 if f in [field.name for field in self.model._meta.fields]: 575 columns.append( self.model._meta.get_field(f, many_to_many=False).column ) 576 elif not self._select.has_key( f ): 577 raise FieldDoesNotExist, '%s has no field named %r' % ( self.model._meta.object_name, f ) 578 579 field_names = self._fields 581 fields = [self.model._meta.get_field(f, many_to_many=False) for f in self._fields] 580 582 else: # Default to all fields. 581 columns = [f.column for f in self.model._meta.fields] 582 field_names = [f.attname for f in self.model._meta.fields] 583 fields = self.model._meta.fields 584 columns = [f.column for f in fields] 585 field_names = [f.attname for f in fields] 583 586 584 587 select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns] 585 586 # Add any additional SELECTs.587 if self._select:588 select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])589 590 588 cursor = connection.cursor() 591 589 cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 590 591 has_resolve_columns = hasattr(self, 'resolve_columns') 592 592 while 1: 593 593 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 594 594 if not rows: 595 595 raise StopIteration 596 596 for row in rows: 597 if has_resolve_columns: 598 row = self.resolve_columns(row, fields) 597 599 yield dict(zip(field_names, row)) 598 600 599 601 def _clone(self, klass=None, **kwargs): … … 604 606 class DateQuerySet(QuerySet): 605 607 def iterator(self): 606 608 from django.db.backends.util import typecast_timestamp 609 from django.db.models.fields import DateTimeField 607 610 self._order_by = () # Clear this because it'll mess things up otherwise. 608 611 if self._field.null: 609 612 self._where.append('%s.%s IS NOT NULL' % \ 610 613 (backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column))) 611 612 614 try: 613 615 select, sql, params = self._get_sql_clause() 614 616 except EmptyResultSet: 615 617 raise StopIteration 616 618 617 sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \ 619 table_name = backend.quote_name(self.model._meta.db_table) 620 field_name = backend.quote_name(self._field.column) 621 622 if backend.allows_group_by_ordinal: 623 group_by = '1' 624 else: 625 group_by = backend.get_date_trunc_sql(self._kind, 626 '%s.%s' % (table_name, field_name)) 627 628 sql = 'SELECT %s %s GROUP BY %s ORDER BY 1 %s' % \ 618 629 (backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table), 619 backend.quote_name(self._field.column))), sql, self._order)630 backend.quote_name(self._field.column))), sql, group_by, self._order) 620 631 cursor = connection.cursor() 621 632 cursor.execute(sql, params) 622 # We have to manually run typecast_timestamp(str()) on the results, because623 # MySQL doesn't automatically cast the result of date functions as datetime624 # objects -- MySQL returns the values as strings, instead.625 return [typecast_timestamp(str(row[0])) for row in cursor.fetchall()]626 633 634 has_resolve_columns = hasattr(self, 'resolve_columns') 635 needs_datetime_string_cast = backend.needs_datetime_string_cast 636 dates = [] 637 # It would be better to use self._field here instead of DateTimeField(), 638 # but in Oracle that will result in a list of datetime.date instead of 639 # datetime.datetime. 640 fields = [DateTimeField()] 641 while 1: 642 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 643 if not rows: 644 return dates 645 for row in rows: 646 date = row[0] 647 if has_resolve_columns: 648 date = self.resolve_columns([date], fields)[0] 649 elif needs_datetime_string_cast: 650 date = typecast_timestamp(str(date)) 651 dates.append(date) 652 627 653 def _clone(self, klass=None, **kwargs): 628 654 c = super(DateQuerySet, self)._clone(klass, **kwargs) 629 655 c._field = self._field … … 730 756 if table_prefix.endswith('.'): 731 757 table_prefix = backend.quote_name(table_prefix[:-1])+'.' 732 758 field_name = backend.quote_name(field_name) 759 if type(value) == datetime.datetime and backend.get_datetime_cast_sql(): 760 cast_sql = backend.get_datetime_cast_sql() 761 else: 762 cast_sql = '%s' 763 if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith') and backend.needs_upper_for_iops: 764 format = 'UPPER(%s%s) %s' 765 else: 766 format = '%s%s %s' 733 767 try: 734 return '%s%s %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s')) 768 return format % (table_prefix, field_name, 769 backend.OPERATOR_MAPPING[lookup_type] % cast_sql) 735 770 except KeyError: 736 771 pass 737 772 if lookup_type == 'in': -
django/db/backends/ado_mssql/base.py
89 89 self.connection.close() 90 90 self.connection = None 91 91 92 allows_group_by_ordinal = True 93 allows_unique_and_pk = True 94 autoindexes_primary_keys = True 95 needs_datetime_string_cast = True 96 needs_upper_for_iops = False 92 97 supports_constraints = True 98 supports_tablespaces = True 99 uses_case_insensitive_names = False 93 100 94 101 def quote_name(name): 95 102 if name.startswith('[') and name.endswith(']'): … … 117 124 if lookup_type=='day': 118 125 return "Convert(datetime, Convert(varchar(12), %s))" % field_name 119 126 127 def get_datetime_cast_sql(): 128 return None 129 120 130 def get_limit_offset_sql(limit, offset=None): 121 131 # TODO: This is a guess. Make sure this is correct. 122 132 sql = "LIMIT %s" % limit … … 139 149 def get_pk_default_value(): 140 150 return "DEFAULT" 141 151 152 def get_max_name_length(): 153 return None 154 155 def get_start_transaction_sql(): 156 return "BEGIN;" 157 158 def get_tablespace_sql(tablespace, inline=False): 159 return "ON %s" % quote_name(tablespace) 160 161 def get_autoinc_sql(table): 162 return None 163 142 164 def get_sql_flush(style, tables, sequences): 143 165 """Return a list of SQL statements required to remove all data from 144 166 all tables in the database (without actually removing the tables -
django/db/backends/postgresql/base.py
87 87 global postgres_version 88 88 if not postgres_version: 89 89 cursor.execute("SELECT version()") 90 postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')] 90 postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')] 91 91 if settings.DEBUG: 92 92 return util.CursorDebugWrapper(cursor, self) 93 93 return cursor … … 105 105 self.connection.close() 106 106 self.connection = None 107 107 108 allows_group_by_ordinal = True 109 allows_unique_and_pk = True 110 autoindexes_primary_keys = True 111 needs_datetime_string_cast = True 112 needs_upper_for_iops = False 108 113 supports_constraints = True 114 supports_tablespaces = False 115 uses_case_insensitive_names = False 109 116 110 117 def quote_name(name): 111 118 if name.startswith('"') and name.endswith('"'): … … 138 145 # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC 139 146 return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name) 140 147 148 def get_datetime_cast_sql(): 149 return None 150 141 151 def get_limit_offset_sql(limit, offset=None): 142 152 sql = "LIMIT %s" % limit 143 153 if offset and offset != 0: … … 149 159 150 160 def get_deferrable_sql(): 151 161 return " DEFERRABLE INITIALLY DEFERRED" 152 162 153 163 def get_fulltext_search_sql(field_name): 154 164 raise NotImplementedError 155 165 … … 159 169 def get_pk_default_value(): 160 170 return "DEFAULT" 161 171 172 def get_max_name_length(): 173 return None 174 175 def get_start_transaction_sql(): 176 return "BEGIN;" 177 178 def get_autoinc_sql(table): 179 return None 180 162 181 def get_sql_flush(style, tables, sequences): 163 182 """Return a list of SQL statements required to remove all data from 164 183 all tables in the database (without actually removing the tables 165 184 themselves) and put the database in an empty 'initial' state 166 167 """ 185 186 """ 168 187 if tables: 169 188 if postgres_version[0] >= 8 and postgres_version[1] >= 1: 170 189 # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to … … 175 194 style.SQL_FIELD(', '.join([quote_name(table) for table in tables])) 176 195 )] 177 196 else: 178 # Older versions of Postgres can't do TRUNCATE in a single call, so they must use 197 # Older versions of Postgres can't do TRUNCATE in a single call, so they must use 179 198 # a simple delete. 180 199 sql = ['%s %s %s;' % \ 181 200 (style.SQL_KEYWORD('DELETE'), … … 238 257 style.SQL_KEYWORD('FROM'), 239 258 style.SQL_TABLE(f.m2m_db_table()))) 240 259 return output 241 260 242 261 # Register these custom typecasts, because Django expects dates/times to be 243 262 # in Python's native (standard-library) datetime/time format, whereas psycopg 244 263 # use mx.DateTime by default. -
django/db/backends/sqlite3/base.py
107 107 def convert_query(self, query, num_params): 108 108 return query % tuple("?" * num_params) 109 109 110 allows_group_by_ordinal = True 111 allows_unique_and_pk = True 112 autoindexes_primary_keys = True 113 needs_datetime_string_cast = True 114 needs_upper_for_iops = False 110 115 supports_constraints = False 116 supports_tablespaces = False 117 uses_case_insensitive_names = False 111 118 112 119 def quote_name(name): 113 120 if name.startswith('"') and name.endswith('"'): … … 139 146 # sqlite doesn't support DATE_TRUNC, so we fake it as above. 140 147 return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name) 141 148 149 def get_datetime_cast_sql(): 150 return None 151 142 152 def get_limit_offset_sql(limit, offset=None): 143 153 sql = "LIMIT %s" % limit 144 154 if offset and offset != 0: … … 160 170 def get_pk_default_value(): 161 171 return "NULL" 162 172 173 def get_max_name_length(): 174 return None 175 176 def get_start_transaction_sql(): 177 return "BEGIN;" 178 179 def get_autoinc_sql(table): 180 return None 181 163 182 def get_sql_flush(style, tables, sequences): 164 183 """Return a list of SQL statements required to remove all data from 165 184 all tables in the database (without actually removing the tables 166 185 themselves) and put the database in an empty 'initial' state 167 186 168 187 """ 169 188 # NB: The generated SQL below is specific to SQLite 170 189 # Note: The DELETE FROM... SQL generated below works for SQLite databases … … 182 201 "Returns a list of the SQL statements to reset sequences for the given models." 183 202 # No sequence reset required 184 203 return [] 185 204 186 205 def _sqlite_date_trunc(lookup_type, dt): 187 206 try: 188 207 dt = util.typecast_timestamp(dt) -
django/db/backends/util.py
1 1 import datetime 2 import md5 2 3 from time import time 3 4 4 5 try: … … 107 108 return None 108 109 return str(d) 109 110 111 def truncate_name(name, length=None): 112 """Shortens a string to a repeatable mangled version with the given length. 113 """ 114 if length is None or len(name) <= length: 115 return name 116 117 hash = md5.md5(name).hexdigest()[:4] 118 119 return '%s%s' % (name[:length-4], hash) 120 110 121 ################################################################################## 111 122 # Helper functions for dictfetch* for databases that don't natively support them # 112 123 ################################################################################## -
django/db/backends/mysql/base.py
134 134 self.server_version = tuple([int(x) for x in m.groups()]) 135 135 return self.server_version 136 136 137 allows_group_by_ordinal = True 138 allows_unique_and_pk = True 139 autoindexes_primary_keys = False 140 needs_datetime_string_cast = True # MySQLdb requires a typecast for dates 141 needs_upper_for_iops = False 137 142 supports_constraints = True 143 supports_tablespaces = False 144 uses_case_insensitive_names = False 138 145 139 146 def quote_name(name): 140 147 if name.startswith("`") and name.endswith("`"): … … 167 174 sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str) 168 175 return sql 169 176 177 def get_datetime_cast_sql(): 178 return None 179 170 180 def get_limit_offset_sql(limit, offset=None): 171 181 sql = "LIMIT " 172 182 if offset and offset != 0: … … 188 198 def get_pk_default_value(): 189 199 return "DEFAULT" 190 200 201 def get_max_name_length(): 202 return 64; 203 204 def get_start_transaction_sql(): 205 return "BEGIN;" 206 207 def get_autoinc_sql(table): 208 return None 209 191 210 def get_sql_flush(style, tables, sequences): 192 211 """Return a list of SQL statements required to remove all data from 193 212 all tables in the database (without actually removing the tables 194 213 themselves) and put the database in an empty 'initial' state 195 214 196 215 """ 197 216 # NB: The generated SQL below is specific to MySQL 198 217 # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements … … 204 223 style.SQL_FIELD(quote_name(table)) 205 224 ) for table in tables] + \ 206 225 ['SET FOREIGN_KEY_CHECKS = 1;'] 207 226 208 227 # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements 209 228 # to reset sequence indices 210 229 sql.extend(["%s %s %s %s %s;" % \ -
django/db/backends/oracle/base.py
4 4 Requires cx_Oracle: http://www.python.net/crew/atuining/cx_Oracle/ 5 5 """ 6 6 7 from django.conf import settings 7 8 from django.db.backends import util 8 9 try: 9 10 import cx_Oracle as Database 10 11 except ImportError, e: 11 12 from django.core.exceptions import ImproperlyConfigured 12 13 raise ImproperlyConfigured, "Error loading cx_Oracle module: %s" % e 14 import datetime 15 from django.utils.datastructures import SortedDict 13 16 17 14 18 DatabaseError = Database.Error 15 19 IntegrityError = Database.IntegrityError 16 20 … … 31 35 return self.connection is not None 32 36 33 37 def cursor(self): 34 from django.conf import settings35 38 if not self._valid_connection(): 36 39 if len(settings.DATABASE_HOST.strip()) == 0: 37 40 settings.DATABASE_HOST = 'localhost' … … 41 44 else: 42 45 conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME) 43 46 self.connection = Database.connect(conn_string, **self.options) 44 return FormatStylePlaceholderCursor(self.connection) 47 cursor = FormatStylePlaceholderCursor(self.connection) 48 # default arraysize of 1 is highly sub-optimal 49 cursor.arraysize = 100 50 # set oracle date to ansi date format 51 cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'") 52 cursor.execute("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'") 53 if settings.DEBUG: 54 return util.CursorDebugWrapper(cursor, self) 55 return cursor 45 56 46 57 def _commit(self): 47 58 if self.connection is not None: 48 self.connection.commit()59 return self.connection.commit() 49 60 50 61 def _rollback(self): 51 62 if self.connection is not None: 52 try: 53 self.connection.rollback() 54 except Database.NotSupportedError: 55 pass 63 return self.connection.rollback() 56 64 57 65 def close(self): 58 66 if self.connection is not None: 59 67 self.connection.close() 60 68 self.connection = None 61 69 70 allows_group_by_ordinal = False 71 allows_unique_and_pk = False # Suppress UNIQUE/PK for Oracle (ORA-02259) 72 autoindexes_primary_keys = True 73 needs_datetime_string_cast = False 74 needs_upper_for_iops = True 62 75 supports_constraints = True 76 supports_tablespaces = True 77 uses_case_insensitive_names = True 63 78 64 79 class FormatStylePlaceholderCursor(Database.Cursor): 65 80 """ … … 67 82 This fixes it -- but note that if you want to use a literal "%s" in a query, 68 83 you'll need to use "%%s". 69 84 """ 85 def _rewrite_args(self, query, params=None): 86 if params is None: 87 params = [] 88 else: 89 # cx_Oracle can't handle unicode parameters, so cast to str for now 90 for i, param in enumerate(params): 91 if type(param) == unicode: 92 try: 93 params[i] = param.encode('utf-8') 94 except UnicodeError: 95 params[i] = str(param) 96 args = [(':arg%d' % i) for i in range(len(params))] 97 query = query % tuple(args) 98 # cx_Oracle wants no trailing ';' for SQL statements. For PL/SQL, it 99 # it does want a trailing ';' but not a trailing '/'. However, these 100 # characters must be included in the original query in case the query 101 # is being passed to SQL*Plus. 102 if query.endswith(';') or query.endswith('/'): 103 query = query[:-1] 104 return query, params 105 70 106 def execute(self, query, params=None): 71 if params is None: params = [] 72 query = self.convert_arguments(query, len(params)) 107 query, params = self._rewrite_args(query, params) 73 108 return Database.Cursor.execute(self, query, params) 74 109 75 110 def executemany(self, query, params=None): 76 if params is None: params = [] 77 query = self.convert_arguments(query, len(params[0])) 111 query, params = self._rewrite_args(query, params) 78 112 return Database.Cursor.executemany(self, query, params) 79 113 80 def convert_arguments(self, query, num_params):81 # replace occurances of "%s" with ":arg" - Oracle requires colons for parameter placeholders.82 args = [':arg' for i in range(num_params)]83 return query % tuple(args)84 85 114 def quote_name(name): 86 return name 115 # SQL92 requires delimited (quoted) names to be case-sensitive. When 116 # not quoted, Oracle has case-insensitive behavior for identifiers, but 117 # always defaults to uppercase. 118 # We simplify things by making Oracle identifiers always uppercase. 119 if not name.startswith('"') and not name.endswith('"'): 120 name = '"%s"' % util.truncate_name(name.upper(), get_max_name_length()) 121 return name.upper() 87 122 88 123 dictfetchone = util.dictfetchone 89 124 dictfetchmany = util.dictfetchmany 90 125 dictfetchall = util.dictfetchall 91 126 92 127 def get_last_insert_id(cursor, table_name, pk_name): 93 query = "SELECT %s_sq.currval from dual" % table_name94 cursor.execute( query)128 sq_name = util.truncate_name(table_name, get_max_name_length()-3) 129 cursor.execute('SELECT %s_sq.currval FROM dual' % sq_name) 95 130 return cursor.fetchone()[0] 96 131 97 132 def get_date_extract_sql(lookup_type, table_name): 98 133 # lookup_type is 'year', 'month', 'day' 99 # http:// www.psoug.org/reference/date_func.html134 # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163 100 135 return "EXTRACT(%s FROM %s)" % (lookup_type, table_name) 101 136 102 137 def get_date_trunc_sql(lookup_type, field_name): 103 return "EXTRACT(%s FROM TRUNC(%s))" % (lookup_type, field_name) 138 # lookup_type is 'year', 'month', 'day' 139 # Oracle uses TRUNC() for both dates and numbers. 140 # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions155a.htm#SQLRF06151 141 if lookup_type == 'day': 142 sql = 'TRUNC(%s)' % (field_name,) 143 else: 144 sql = "TRUNC(%s, '%s')" % (field_name, lookup_type) 145 return sql 104 146 147 def get_datetime_cast_sql(): 148 return "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')" 149 105 150 def get_limit_offset_sql(limit, offset=None): 106 151 # Limits and offset are too complicated to be handled here. 107 # Instead, they are handled in django/db/ query.py.108 pass152 # Instead, they are handled in django/db/backends/oracle/query.py. 153 return "" 109 154 110 155 def get_random_function_sql(): 111 156 return "DBMS_RANDOM.RANDOM" … … 117 162 raise NotImplementedError 118 163 119 164 def get_drop_foreignkey_sql(): 120 return "DROP FOREIGN KEY"165 return "DROP CONSTRAINT" 121 166 122 167 def get_pk_default_value(): 123 168 return "DEFAULT" 124 169 170 def get_max_name_length(): 171 return 30 172 173 def get_start_transaction_sql(): 174 return None 175 176 def get_tablespace_sql(tablespace, inline=False): 177 return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), quote_name(tablespace)) 178 179 def get_autoinc_sql(table): 180 # To simulate auto-incrementing primary keys in Oracle, we have to 181 # create a sequence and a trigger. 182 sq_name = get_sequence_name(table) 183 tr_name = get_trigger_name(table) 184 sequence_sql = 'CREATE SEQUENCE %s;' % sq_name 185 trigger_sql = """CREATE OR REPLACE TRIGGER %s 186 BEFORE INSERT ON %s 187 FOR EACH ROW 188 WHEN (new.id IS NULL) 189 BEGIN 190 SELECT %s.nextval INTO :new.id FROM dual; 191 END; 192 /""" % (tr_name, quote_name(table), sq_name) 193 return sequence_sql, trigger_sql 194 195 def get_drop_sequence(table): 196 return "DROP SEQUENCE %s;" % quote_name(get_sequence_name(table)) 197 198 def _get_sequence_reset_sql(): 199 # TODO: colorize this SQL code with style.SQL_KEYWORD(), etc. 200 return """ 201 DECLARE 202 startvalue integer; 203 cval integer; 204 BEGIN 205 LOCK TABLE %(table)s IN SHARE MODE; 206 SELECT NVL(MAX(id), 0) INTO startvalue FROM %(table)s; 207 SELECT %(sequence)s.nextval INTO cval FROM dual; 208 cval := startvalue - cval; 209 IF cval != 0 THEN 210 EXECUTE IMMEDIATE 'ALTER SEQUENCE %(sequence)s MINVALUE 0 INCREMENT BY '||cval; 211 SELECT %(sequence)s.nextval INTO cval FROM dual; 212 EXECUTE IMMEDIATE 'ALTER SEQUENCE %(sequence)s INCREMENT BY 1'; 213 END IF; 214 COMMIT; 215 END; 216 /""" 217 125 218 def get_sql_flush(style, tables, sequences): 126 219 """Return a list of SQL statements required to remove all data from 127 220 all tables in the database (without actually removing the tables 128 221 themselves) and put the database in an empty 'initial' state 129 222 """ 130 # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements 131 # TODO - SQL not actually tested against Oracle yet! 132 # TODO - autoincrement indices reset required? See other get_sql_flush() implementations 133 sql = ['%s %s;' % \ 134 (style.SQL_KEYWORD('TRUNCATE'), 223 # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 224 # 'TRUNCATE z;'... style SQL statements 225 if tables: 226 # Oracle does support TRUNCATE, but it seems to get us into 227 # FK referential trouble, whereas DELETE FROM table works. 228 sql = ['%s %s %s;' % \ 229 (style.SQL_KEYWORD('DELETE'), 230 style.SQL_KEYWORD('FROM'), 135 231 style.SQL_FIELD(quote_name(table)) 136 232 ) for table in tables] 233 # Since we've just deleted all the rows, running our sequence 234 # ALTER code will reset the sequence to 0. 235 for sequence_info in sequences: 236 table_name = sequence_info['table'] 237 seq_name = get_sequence_name(table_name) 238 query = _get_sequence_reset_sql() % {'sequence':seq_name, 239 'table':quote_name(table_name)} 240 sql.append(query) 241 return sql 242 else: 243 return [] 137 244 245 def get_sequence_name(table): 246 name_length = get_max_name_length() - 3 247 return '%s_SQ' % util.truncate_name(table, name_length).upper() 248 138 249 def get_sql_sequence_reset(style, model_list): 139 250 "Returns a list of the SQL statements to reset sequences for the given models." 140 # No sequence reset required 141 return [] 251 from django.db import models 252 output = [] 253 query = _get_sequence_reset_sql() 254 for model in model_list: 255 for f in model._meta.fields: 256 if isinstance(f, models.AutoField): 257 sequence_name = get_sequence_name(model._meta.db_table) 258 output.append(query % {'sequence':sequence_name, 259 'table':model._meta.db_table}) 260 break # Only one AutoField is allowed per model, so don't bother continuing. 261 for f in model._meta.many_to_many: 262 sequence_name = get_sequence_name(f.m2m_db_table()) 263 output.append(query % {'sequence':sequence_name, 264 'table':f.m2m_db_table()}) 265 return output 142 266 267 def get_trigger_name(table): 268 name_length = get_max_name_length() - 3 269 return '%s_TR' % util.truncate_name(table, name_length).upper() 270 271 def get_query_set_class(DefaultQuerySet): 272 "Create a custom QuerySet class for Oracle." 273 274 from django.db import backend, connection 275 from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word 276 277 class OracleQuerySet(DefaultQuerySet): 278 279 def iterator(self): 280 "Performs the SELECT database lookup of this QuerySet." 281 282 from django.db.models.query import get_cached_row 283 284 # self._select is a dictionary, and dictionaries' key order is 285 # undefined, so we convert it to a list of tuples. 286 extra_select = self._select.items() 287 288 full_query = None 289 290 try: 291 try: 292 select, sql, params, full_query = self._get_sql_clause(get_full_query=True) 293 except TypeError: 294 select, sql, params = self._get_sql_clause() 295 except EmptyResultSet: 296 raise StopIteration 297 if not full_query: 298 full_query = "SELECT %s%s\n%s" % \ 299 ((self._distinct and "DISTINCT " or ""), 300 ', '.join(select), sql) 301 302 cursor = connection.cursor() 303 cursor.execute(full_query, params) 304 305 fill_cache = self._select_related 306 fields = self.model._meta.fields 307 index_end = len(fields) 308 309 # so here's the logic; 310 # 1. retrieve each row in turn 311 # 2. convert NCLOBs 312 313 while 1: 314 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 315 if not rows: 316 raise StopIteration 317 for row in rows: 318 row = self.resolve_columns(row, fields) 319 if fill_cache: 320 obj, index_end = get_cached_row(klass=self.model, row=row, 321 index_start=0, max_depth=self._max_related_depth) 322 else: 323 obj = self.model(*row[:index_end]) 324 for i, k in enumerate(extra_select): 325 setattr(obj, k[0], row[index_end+i]) 326 yield obj 327 328 329 def _get_sql_clause(self, get_full_query=False): 330 from django.db.models.query import fill_table_cache, \ 331 handle_legacy_orderlist, orderfield2column 332 333 opts = self.model._meta 334 335 # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. 336 select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields] 337 tables = [quote_only_if_word(t) for t in self._tables] 338 joins = SortedDict() 339 where = self._where[:] 340 params = self._params[:] 341 342 # Convert self._filters into SQL. 343 joins2, where2, params2 = self._filters.get_sql(opts) 344 joins.update(joins2) 345 where.extend(where2) 346 params.extend(params2) 347 348 # Add additional tables and WHERE clauses based on select_related. 349 if self._select_related: 350 fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table]) 351 352 # Add any additional SELECTs. 353 if self._select: 354 select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()]) 355 356 # Start composing the body of the SQL statement. 357 sql = [" FROM", backend.quote_name(opts.db_table)] 358 359 # Compose the join dictionary into SQL describing the joins. 360 if joins: 361 sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition) 362 for (alias, (table, join_type, condition)) in joins.items()])) 363 364 # Compose the tables clause into SQL. 365 if tables: 366 sql.append(", " + ", ".join(tables)) 367 368 # Compose the where clause into SQL. 369 if where: 370 sql.append(where and "WHERE " + " AND ".join(where)) 371 372 # ORDER BY clause 373 order_by = [] 374 if self._order_by is not None: 375 ordering_to_use = self._order_by 376 else: 377 ordering_to_use = opts.ordering 378 for f in handle_legacy_orderlist(ordering_to_use): 379 if f == '?': # Special case. 380 order_by.append(backend.get_random_function_sql()) 381 else: 382 if f.startswith('-'): 383 col_name = f[1:] 384 order = "DESC" 385 else: 386 col_name = f 387 order = "ASC" 388 if "." in col_name: 389 table_prefix, col_name = col_name.split('.', 1) 390 table_prefix = backend.quote_name(table_prefix) + '.' 391 else: 392 # Use the database table as a column prefix if it wasn't given, 393 # and if the requested column isn't a custom SELECT. 394 if "." not in col_name and col_name not in (self._select or ()): 395 table_prefix = backend.quote_name(opts.db_table) + '.' 396 else: 397 table_prefix = '' 398 order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order)) 399 if order_by: 400 sql.append("ORDER BY " + ", ".join(order_by)) 401 402 # Look for column name collisions in the select elements 403 # and fix them with an AS alias. This allows us to do a 404 # SELECT * later in the paging query. 405 cols = [clause.split('.')[-1] for clause in select] 406 for index, col in enumerate(cols): 407 if cols.count(col) > 1: 408 col = '%s%d' % (col.replace('"', ''), index) 409 cols[index] = col 410 select[index] = '%s AS %s' % (select[index], col) 411 412 # LIMIT and OFFSET clauses 413 # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query. 414 select_clause = ",".join(select) 415 distinct = (self._distinct and "DISTINCT " or "") 416 417 if order_by: 418 order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by)) 419 else: 420 #Oracle's row_number() function always requires an order-by clause. 421 #So we need to define a default order-by, since none was provided. 422 order_by_clause = " OVER (ORDER BY %s.%s)" % \ 423 (backend.quote_name(opts.db_table), 424 backend.quote_name(opts.fields[0].db_column or opts.fields[0].column)) 425 # limit_and_offset_clause 426 if self._limit is None: 427 assert self._offset is None, "'offset' is not allowed without 'limit'" 428 429 if self._offset is not None: 430 offset = int(self._offset) 431 else: 432 offset = 0 433 if self._limit is not None: 434 limit = int(self._limit) 435 else: 436 limit = None 437 438 limit_and_offset_clause = '' 439 if limit is not None: 440 limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset) 441 elif offset: 442 limit_and_offset_clause = "WHERE rn > %s" % (offset) 443 444 if len(limit_and_offset_clause) > 0: 445 fmt = \ 446 """SELECT * FROM 447 (SELECT %s%s, 448 ROW_NUMBER()%s AS rn 449 %s) 450 %s""" 451 full_query = fmt % (distinct, select_clause, 452 order_by_clause, ' '.join(sql).strip(), 453 limit_and_offset_clause) 454 else: 455 full_query = None 456 457 if get_full_query: 458 return select, " ".join(sql), params, full_query 459 else: 460 return select, " ".join(sql), params 461 462 def resolve_columns(self, row, fields=()): 463 from django.db.models.fields import DateField, DateTimeField, \ 464 TimeField, BooleanField, NullBooleanField, DecimalField 465 values = [] 466 for value, field in map(None, row, fields): 467 if isinstance(value, Database.LOB): 468 value = value.read() 469 # Oracle stores empty strings as null. We need to undo this in 470 # order to adhere to the Django convention of using the empty 471 # string instead of null, but only if the field accepts the 472 # empty string. 473 if value is None and field.empty_strings_allowed: 474 value = '' 475 # Convert 1 or 0 to True or False 476 elif value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)): 477 value = bool(value) 478 # Convert floats to decimals 479 elif value is not None and isinstance(field, DecimalField): 480 value = util.typecast_decimal(field.format_number(value)) 481 # cx_Oracle always returns datetime.datetime objects for 482 # DATE and TIMESTAMP columns, but Django wants to see a 483 # python datetime.date, .time, or .datetime. We use the type 484 # of the Field to determine which to cast to, but it's not 485 # always available. 486 # As a workaround, we cast to date if all the time-related 487 # values are 0, or to time if the date is 1/1/1900. 488 # This could be cleaned a bit by adding a method to the Field 489 # classes to normalize values from the database (the to_python 490 # method is used for validation and isn't what we want here). 491 elif isinstance(value, Database.Timestamp): 492 # In Python 2.3, the cx_Oracle driver returns its own 493 # Timestamp object that we must convert to a datetime class. 494 if not isinstance(value, datetime.datetime): 495 value = datetime.datetime(value.year, value.month, value.day, value.hour, 496 value.minute, value.second, value.fsecond) 497 if isinstance(field, DateTimeField): 498 pass # DateTimeField subclasses DateField so must be checked first. 499 elif isinstance(field, DateField): 500 value = value.date() 501 elif isinstance(field, TimeField) or (value.year == 1900 and value.month == value.day == 1): 502 value = value.time() 503 elif value.hour == value.minute == value.second == value.microsecond == 0: 504 value = value.date() 505 values.append(value) 506 return values 507 508 return OracleQuerySet 509 510 143 511 OPERATOR_MAPPING = { 144 512 'exact': '= %s', 145 'iexact': ' LIKE %s',146 'contains': 'LIKE %s',147 'icontains': 'LIKE %s',513 'iexact': '= UPPER(%s)', 514 'contains': "LIKE %s ESCAPE '\\'", 515 'icontains': "LIKE UPPER(%s) ESCAPE '\\'", 148 516 'gt': '> %s', 149 517 'gte': '>= %s', 150 518 'lt': '< %s', 151 519 'lte': '<= %s', 152 'startswith': 'LIKE %s',153 'endswith': 'LIKE %s',154 'istartswith': 'LIKE %s',155 'iendswith': 'LIKE %s',520 'startswith': "LIKE %s ESCAPE '\\'", 521 'endswith': "LIKE %s ESCAPE '\\'", 522 'istartswith': "LIKE UPPER(%s) ESCAPE '\\'", 523 'iendswith': "LIKE UPPER(%s) ESCAPE '\\'", 156 524 } -
django/db/backends/oracle/client.py
2 2 import os 3 3 4 4 def runshell(): 5 args = '' 6 args += settings.DATABASE_USER 5 dsn = settings.DATABASE_USER 7 6 if settings.DATABASE_PASSWORD: 8 args += "/%s" % settings.DATABASE_PASSWORD 9 args += "@%s" % settings.DATABASE_NAME 10 os.execvp('sqlplus', args) 7 dsn += "/%s" % settings.DATABASE_PASSWORD 8 if settings.DATABASE_NAME: 9 dsn += "@%s" % settings.DATABASE_NAME 10 args = ["sqlplus", "-L", dsn] 11 os.execvp("sqlplus", args) -
django/db/backends/oracle/introspection.py
1 from django.db.backends.oracle.base import quote_name 1 2 import re 3 import cx_Oracle 2 4 5 3 6 foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 4 7 5 8 def get_table_list(cursor): 6 9 "Returns a list of table names in the current database." 7 10 cursor.execute("SELECT TABLE_NAME FROM USER_TABLES") 8 return [row[0] for row in cursor.fetchall()]11 return [row[0].upper() for row in cursor.fetchall()] 9 12 10 13 def get_table_description(cursor, table_name): 11 return table_name 14 "Returns a description of the table, with the DB-API cursor.description interface." 15 cursor.execute("SELECT * FROM %s WHERE ROWNUM < 2" % quote_name(table_name)) 16 return cursor.description 12 17 13 18 def _name_to_index(cursor, table_name): 14 19 """ … … 22 27 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 23 28 representing all relationships to the given table. Indexes are 0-based. 24 29 """ 25 raise NotImplementedError 30 cursor.execute(""" 31 SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1 32 FROM user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb, 33 user_tab_cols ta, user_tab_cols tb 34 WHERE user_constraints.table_name = %s AND 35 ta.table_name = %s AND 36 ta.column_name = ca.column_name AND 37 ca.table_name = %s AND 38 user_constraints.constraint_name = ca.constraint_name AND 39 user_constraints.r_constraint_name = cb.constraint_name AND 40 cb.table_name = tb.table_name AND 41 cb.column_name = tb.column_name AND 42 ca.position = cb.position""", [table_name, table_name, table_name]) 26 43 44 relations = {} 45 for row in cursor.fetchall(): 46 relations[row[0]] = (row[2], row[1]) 47 return relations 48 27 49 def get_indexes(cursor, table_name): 28 50 """ 29 51 Returns a dictionary of fieldname -> infodict for the given table, … … 31 53 {'primary_key': boolean representing whether it's the primary key, 32 54 'unique': boolean representing whether it's a unique index} 33 55 """ 34 raise NotImplementedError 56 # This query retrieves each index on the given table, including the 57 # first associated field name 58 # "We were in the nick of time; you were in great peril!" 59 sql = """ 60 WITH primarycols AS ( 61 SELECT user_cons_columns.table_name, user_cons_columns.column_name, 1 AS PRIMARYCOL 62 FROM user_cons_columns, user_constraints 63 WHERE user_cons_columns.constraint_name = user_constraints.constraint_name AND 64 user_constraints.constraint_type = 'P' AND 65 user_cons_columns.table_name = %s), 66 uniquecols AS ( 67 SELECT user_ind_columns.table_name, user_ind_columns.column_name, 1 AS UNIQUECOL 68 FROM user_indexes, user_ind_columns 69 WHERE uniqueness = 'UNIQUE' AND 70 user_indexes.index_name = user_ind_columns.index_name AND 71 user_ind_columns.table_name = %s) 72 SELECT allcols.column_name, primarycols.primarycol, uniquecols.UNIQUECOL 73 FROM (SELECT column_name FROM primarycols UNION SELECT column_name FROM 74 uniquecols) allcols, 75 primarycols, uniquecols 76 WHERE allcols.column_name = primarycols.column_name (+) AND 77 allcols.column_name = uniquecols.column_name (+) 78 """ 79 cursor.execute(sql, [table_name, table_name]) 80 indexes = {} 81 for row in cursor.fetchall(): 82 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 83 # a string of space-separated integers. This designates the field 84 # indexes (1-based) of the fields that have indexes on the table. 85 # Here, we skip any indexes across multiple fields. 86 indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]} 87 return indexes 35 88 36 # Maps type codes to Django Field types.89 # Maps type objects to Django Field types. 37 90 DATA_TYPES_REVERSE = { 38 16: 'BooleanField', 39 21: 'SmallIntegerField', 40 23: 'IntegerField', 41 25: 'TextField', 42 869: 'IPAddressField', 43 1043: 'CharField', 44 1082: 'DateField', 45 1083: 'TimeField', 46 1114: 'DateTimeField', 47 1184: 'DateTimeField', 48 1266: 'TimeField', 49 1700: 'DecimalField', 91 cx_Oracle.CLOB: 'TextField', 92 cx_Oracle.DATETIME: 'DateTimeField', 93 cx_Oracle.FIXED_CHAR: 'CharField', 94 cx_Oracle.NCLOB: 'TextField', 95 cx_Oracle.NUMBER: 'DecimalField', 96 cx_Oracle.STRING: 'CharField', 97 cx_Oracle.TIMESTAMP: 'DateTimeField', 50 98 } -
django/db/backends/oracle/creation.py
1 import sys, time 2 from django.core import management 3 4 # This dictionary maps Field objects to their associated Oracle column 5 # types, as strings. Column-type strings can contain format strings; they'll 6 # be interpolated against the values of Field.__dict__ before being output. 7 # If a column type is set to None, it won't be included in the output. 1 8 DATA_TYPES = { 2 'AutoField': 'number(38)',3 'BooleanField': 'number(1)',4 'CharField': 'varchar2(%(maxlength)s)',5 'CommaSeparatedIntegerField': 'varchar2(%(maxlength)s)',6 'DateField': 'date',7 'DateTimeField': 'date',8 'DecimalField': 'number(%(max_digits)s, %(decimal_places)s)',9 'FileField': 'varchar2(100)',10 'FilePathField': 'varchar2(100)',11 'FloatField': 'double precision',12 'ImageField': 'varchar2(100)',13 'IntegerField': 'integer',14 'IPAddressField': 'char(15)',9 'AutoField': 'NUMBER(11)', 10 'BooleanField': 'NUMBER(1) CHECK (%(column)s IN (0,1))', 11 'CharField': 'VARCHAR2(%(maxlength)s)', 12 'CommaSeparatedIntegerField': 'VARCHAR2(%(maxlength)s)', 13 'DateField': 'DATE', 14 'DateTimeField': 'TIMESTAMP', 15 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)', 16 'FileField': 'VARCHAR2(100)', 17 'FilePathField': 'VARCHAR2(100)', 18 'FloatField': 'DOUBLE PRECISION', 19 'ImageField': 'VARCHAR2(100)', 20 'IntegerField': 'NUMBER(11)', 21 'IPAddressField': 'VARCHAR2(15)', 15 22 'ManyToManyField': None, 16 'NullBooleanField': 'integer', 17 'OneToOneField': 'integer', 18 'PhoneNumberField': 'varchar(20)', 19 'PositiveIntegerField': 'integer', 20 'PositiveSmallIntegerField': 'smallint', 21 'SlugField': 'varchar(50)', 22 'SmallIntegerField': 'smallint', 23 'TextField': 'long', 24 'TimeField': 'timestamp', 25 'USStateField': 'varchar(2)', 23 'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))', 24 'OneToOneField': 'NUMBER(11)', 25 'PhoneNumberField': 'VARCHAR2(20)', 26 'PositiveIntegerField': 'NUMBER(11) CHECK (%(column)s >= 0)', 27 'PositiveSmallIntegerField': 'NUMBER(11) CHECK (%(column)s >= 0)', 28 'SlugField': 'VARCHAR2(50)', 29 'SmallIntegerField': 'NUMBER(11)', 30 'TextField': 'NCLOB', 31 'TimeField': 'TIMESTAMP', 32 'URLField': 'VARCHAR2(200)', 33 'USStateField': 'CHAR(2)', 26 34 } 35 36 TEST_DATABASE_PREFIX = 'test_' 37 PASSWORD = 'Im_a_lumberjack' 38 REMEMBER = {} 39 40 41 def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False): 42 43 TEST_DATABASE_NAME = _test_database_name(settings) 44 TEST_DATABASE_USER = _test_database_user(settings) 45 TEST_DATABASE_PASSWD = _test_database_passwd(settings) 46 TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings) 47 TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings) 48 49 parameters = { 50 'dbname': TEST_DATABASE_NAME, 51 'user': TEST_DATABASE_USER, 52 'password': TEST_DATABASE_PASSWD, 53 'tblspace': TEST_DATABASE_TBLSPACE, 54 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, 55 } 56 57 REMEMBER['user'] = settings.DATABASE_USER 58 REMEMBER['passwd'] = settings.DATABASE_PASSWORD 59 60 cursor = connection.cursor() 61 if _test_database_create(settings): 62 if verbosity >= 1: 63 print 'Creating test database...' 64 try: 65 _create_test_db(cursor, parameters, verbosity) 66 except Exception, e: 67 sys.stderr.write("Got an error creating the test database: %s\n" % e) 68 if not autoclobber: 69 confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) 70 if autoclobber or confirm == 'yes': 71 try: 72 if verbosity >= 1: 73 print "Destroying old test database..." 74 _destroy_test_db(cursor, parameters, verbosity) 75 if verbosity >= 1: 76 print "Creating test database..." 77 _create_test_db(cursor, parameters, verbosity) 78 except Exception, e: 79 sys.stderr.write("Got an error recreating the test database: %s\n" % e) 80 sys.exit(2) 81 else: 82 print "Tests cancelled." 83 sys.exit(1) 84 85 if _test_user_create(settings): 86 if verbosity >= 1: 87 print "Creating test user..." 88 try: 89 _create_test_user(cursor, parameters, verbosity) 90 except Exception, e: 91 sys.stderr.write("Got an error creating the test user: %s\n" % e) 92 if not autoclobber: 93 confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER) 94 if autoclobber or confirm == 'yes': 95 try: 96 if verbosity >= 1: 97 print "Destroying old test user..." 98 _destroy_test_user(cursor, parameters, verbosity) 99 if verbosity >= 1: 100 print "Creating test user..." 101 _create_test_user(cursor, parameters, verbosity) 102 except Exception, e: 103 sys.stderr.write("Got an error recreating the test user: %s\n" % e) 104 sys.exit(2) 105 else: 106 print "Tests cancelled." 107 sys.exit(1) 108 109 connection.close() 110 settings.DATABASE_USER = TEST_DATABASE_USER 111 settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD 112 113 management.syncdb(verbosity, interactive=False) 114 115 # Get a cursor (even though we don't need one yet). This has 116 # the side effect of initializing the test database. 117 cursor = connection.cursor() 118 119 120 def destroy_test_db(settings, connection, backend, old_database_name, verbosity=1): 121 connection.close() 122 123 TEST_DATABASE_NAME = _test_database_name(settings) 124 TEST_DATABASE_USER = _test_database_user(settings) 125 TEST_DATABASE_PASSWD = _test_database_passwd(settings) 126 TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings) 127 TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings) 128 129 settings.DATABASE_NAME = old_database_name 130 settings.DATABASE_USER = REMEMBER['user'] 131 settings.DATABASE_PASSWORD = REMEMBER['passwd'] 132 133 parameters = { 134 'dbname': TEST_DATABASE_NAME, 135 'user': TEST_DATABASE_USER, 136 'password': TEST_DATABASE_PASSWD, 137 'tblspace': TEST_DATABASE_TBLSPACE, 138 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, 139 } 140 141 REMEMBER['user'] = settings.DATABASE_USER 142 REMEMBER['passwd'] = settings.DATABASE_PASSWORD 143 144 cursor = connection.cursor() 145 time.sleep(1) # To avoid "database is being accessed by other users" errors. 146 if _test_user_create(settings): 147 if verbosity >= 1: 148 print 'Destroying test user...' 149 _destroy_test_user(cursor, parameters, verbosity) 150 if _test_database_create(settings): 151 if verbosity >= 1: 152 print 'Destroying test database...' 153 _destroy_test_db(cursor, parameters, verbosity) 154 connection.close() 155 156 157 def _create_test_db(cursor, parameters, verbosity): 158 if verbosity >= 2: 159 print "_create_test_db(): dbname = %s" % parameters['dbname'] 160 statements = [ 161 """CREATE TABLESPACE %(tblspace)s 162 DATAFILE '%(tblspace)s.dbf' SIZE 20M 163 REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M 164 """, 165 """CREATE TEMPORARY TABLESPACE %(tblspace_temp)s 166 TEMPFILE '%(tblspace_temp)s.dbf' SIZE 20M 167 REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M 168 """, 169 ] 170 _execute_statements(cursor, statements, parameters, verbosity) 171 172 173 def _create_test_user(cursor, parameters, verbosity): 174 if verbosity >= 2: 175 print "_create_test_user(): username = %s" % parameters['user'] 176 statements = [ 177 """CREATE USER %(user)s 178 IDENTIFIED BY %(password)s 179 DEFAULT TABLESPACE %(tblspace)s 180 TEMPORARY TABLESPACE %(tblspace_temp)s 181 """, 182 """GRANT CONNECT, RESOURCE TO %(user)s""", 183 ] 184 _execute_statements(cursor, statements, parameters, verbosity) 185 186 187 def _destroy_test_db(cursor, parameters, verbosity): 188 if verbosity >= 2: 189 print "_destroy_test_db(): dbname=%s" % parameters['dbname'] 190 statements = [ 191 'DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 192 'DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 193 ] 194 _execute_statements(cursor, statements, parameters, verbosity) 195 196 197 def _destroy_test_user(cursor, parameters, verbosity): 198 if verbosity >= 2: 199 print "_destroy_test_user(): user=%s" % parameters['user'] 200 print "Be patient. This can take some time..." 201 statements = [ 202 'DROP USER %(user)s CASCADE', 203 ] 204 _execute_statements(cursor, statements, parameters, verbosity) 205 206 207 def _execute_statements(cursor, statements, parameters, verbosity): 208 for template in statements: 209 stmt = template % parameters 210 if verbosity >= 2: 211 print stmt 212 try: 213 cursor.execute(stmt) 214 except Exception, err: 215 sys.stderr.write("Failed (%s)\n" % (err)) 216 raise 217 218 219 def _test_database_name(settings): 220 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 221 try: 222 if settings.TEST_DATABASE_NAME: 223 name = settings.TEST_DATABASE_NAME 224 except AttributeError: 225 pass 226 except: 227 raise 228 return name 229 230 231 def _test_database_create(settings): 232 name = True 233 try: 234 if settings.TEST_DATABASE_CREATE: 235 name = True 236 else: 237 name = False 238 except AttributeError: 239 pass 240 except: 241 raise 242 return name 243 244 245 def _test_user_create(settings): 246 name = True 247 try: 248 if settings.TEST_USER_CREATE: 249 name = True 250 else: 251 name = False 252 except AttributeError: 253 pass 254 except: 255 raise 256 return name 257 258 259 def _test_database_user(settings): 260 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 261 try: 262 if settings.TEST_DATABASE_USER: 263 name = settings.TEST_DATABASE_USER 264 except AttributeError: 265 pass 266 except: 267 raise 268 return name 269 270 271 def _test_database_passwd(settings): 272 name = PASSWORD 273 try: 274 if settings.TEST_DATABASE_PASSWD: 275 name = settings.TEST_DATABASE_PASSWD 276 except AttributeError: 277 pass 278 except: 279 raise 280 return name 281 282 283 def _test_database_tblspace(settings): 284 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 285 try: 286 if settings.TEST_DATABASE_TBLSPACE: 287 name = settings.TEST_DATABASE_TBLSPACE 288 except AttributeError: 289 pass 290 except: 291 raise 292 return name 293 294 295 def _test_database_tblspace_tmp(settings): 296 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp' 297 try: 298 if settings.TEST_DATABASE_TBLSPACE_TMP: 299 name = settings.TEST_DATABASE_TBLSPACE_TMP 300 except AttributeError: 301 pass 302 except: 303 raise 304 return name -
django/db/backends/postgresql_psycopg2/base.py
55 55 global postgres_version 56 56 if not postgres_version: 57 57 cursor.execute("SELECT version()") 58 postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')] 58 postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')] 59 59 if settings.DEBUG: 60 60 return util.CursorDebugWrapper(cursor, self) 61 61 return cursor … … 73 73 self.connection.close() 74 74 self.connection = None 75 75 76 allows_group_by_ordinal = True 77 allows_unique_and_pk = True 78 autoindexes_primary_keys = True 79 needs_datetime_string_cast = False 80 needs_upper_for_iops = False 76 81 supports_constraints = True 82 supports_tablespaces = False 83 uses_case_insensitive_names = True 77 84 78 85 def quote_name(name): 79 86 if name.startswith('"') and name.endswith('"'): … … 98 105 # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC 99 106 return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name) 100 107 108 def get_datetime_cast_sql(): 109 return None 110 101 111 def get_limit_offset_sql(limit, offset=None): 102 112 sql = "LIMIT %s" % limit 103 113 if offset and offset != 0: … … 119 129 def get_pk_default_value(): 120 130 return "DEFAULT" 121 131 132 def get_max_name_length(): 133 return None 134 135 def get_start_transaction_sql(): 136 return "BEGIN;" 137 138 def get_autoinc_sql(table): 139 return None 140 122 141 def get_sql_flush(style, tables, sequences): 123 142 """Return a list of SQL statements required to remove all data from 124 143 all tables in the database (without actually removing the tables … … 139 158 style.SQL_KEYWORD('FROM'), 140 159 style.SQL_FIELD(quote_name(table)) 141 160 ) for table in tables] 142 161 143 162 # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements 144 163 # to reset sequence indices 145 164 for sequence in sequences: … … 195 214 style.SQL_KEYWORD('FROM'), 196 215 style.SQL_TABLE(f.m2m_db_table()))) 197 216 return output 198 217 199 218 OPERATOR_MAPPING = { 200 219 'exact': '= %s', 201 220 'iexact': 'ILIKE %s', -
django/db/backends/dummy/base.py
30 30 pass # close() 31 31 32 32 supports_constraints = False 33 supports_tablespaces = False 33 34 quote_name = complain 34 35 dictfetchone = complain 35 36 dictfetchmany = complain -
django/core/management.py
55 55 56 56 def _get_installed_models(table_list): 57 57 "Gets a set of all models that are installed, given a list of existing tables" 58 from django.db import models58 from django.db import backend, models 59 59 all_models = [] 60 60 for app in models.get_apps(): 61 61 for model in models.get_models(app): 62 62 all_models.append(model) 63 return set([m for m in all_models if m._meta.db_table in table_list]) 63 if backend.uses_case_insensitive_names: 64 converter = str.upper 65 else: 66 converter = lambda x: x 67 return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)]) 64 68 65 69 def _get_table_list(): 66 70 "Gets a list of all db tables that are physically installed." … … 104 108 def get_sql_create(app): 105 109 "Returns a list of the CREATE TABLE SQL statements for the given app." 106 110 from django.db import get_creation_module, models 111 107 112 data_types = get_creation_module().DATA_TYPES 108 113 109 114 if not data_types: … … 175 180 rel_field = f 176 181 data_type = f.get_internal_type() 177 182 col_type = data_types[data_type] 183 tablespace = f.db_tablespace or opts.db_tablespace 178 184 if col_type is not None: 179 185 # Make the definition (e.g. 'foo VARCHAR(30)') for this field. 180 186 field_output = [style.SQL_FIELD(backend.quote_name(f.column)), 181 187 style.SQL_COLTYPE(col_type % rel_field.__dict__)] 182 188 field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or ''))) 183 if f.unique :189 if f.unique and (not f.primary_key or backend.allows_unique_and_pk): 184 190 field_output.append(style.SQL_KEYWORD('UNIQUE')) 185 191 if f.primary_key: 186 192 field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 193 if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys: 194 # We must specify the index tablespace inline, because we 195 # won't be generating a CREATE INDEX statement for this field. 196 field_output.append(backend.get_tablespace_sql(tablespace, inline=True)) 187 197 if f.rel: 188 198 if f.rel.to in known_models: 189 199 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \ … … 207 217 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(backend.quote_name(opts.db_table)) + ' ('] 208 218 for i, line in enumerate(table_output): # Combine and add commas. 209 219 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 210 full_statement.append(');') 220 full_statement.append(')') 221 if opts.db_tablespace and backend.supports_tablespaces: 222 full_statement.append(backend.get_tablespace_sql(opts.db_tablespace)) 223 full_statement.append(';') 211 224 final_output.append('\n'.join(full_statement)) 212 225 226 if opts.has_auto_field and hasattr(backend, 'get_autoinc_sql'): 227 # Add any extra SQL needed to support auto-incrementing primary keys 228 autoinc_sql = backend.get_autoinc_sql(opts.db_table) 229 if autoinc_sql: 230 for stmt in autoinc_sql: 231 final_output.append(stmt) 232 213 233 return final_output, pending_references 214 234 215 235 def _get_sql_for_pending_references(model, pending_references): … … 217 237 Get any ALTER TABLE statements to add constraints after the fact. 218 238 """ 219 239 from django.db import backend, get_creation_module 240 from django.db.backends.util import truncate_name 220 241 data_types = get_creation_module().DATA_TYPES 221 242 222 243 final_output = [] … … 229 250 r_col = f.column 230 251 table = opts.db_table 231 252 col = opts.get_field(f.rel.field_name).column 232 # For MySQL, r_name must be unique in the first 64 characters. 233 # So we are careful with character usage here. 234 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table)))) 253 r_name = '%s_refs_%s_%s_%s' % (r_col, col, r_table, table) 235 254 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \ 236 (backend.quote_name(r_table), r_name,255 (backend.quote_name(r_table), truncate_name(r_name, backend.get_max_name_length()), 237 256 backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col), 238 257 backend.get_deferrable_sql())) 239 258 del pending_references[model] … … 249 268 final_output = [] 250 269 for f in opts.many_to_many: 251 270 if not isinstance(f.rel, generic.GenericRel): 271 tablespace = f.db_tablespace or opts.db_tablespace 272 if tablespace and backend.supports_tablespaces and backend.autoindexes_primary_keys: 273 tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace, inline=True) 274 else: 275 tablespace_sql = '' 252 276 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ 253 277 style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' ('] 254 table_output.append(' %s %s %s ,' % \278 table_output.append(' %s %s %s%s,' % \ 255 279 (style.SQL_FIELD(backend.quote_name('id')), 256 280 style.SQL_COLTYPE(data_types['AutoField']), 257 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'))) 281 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'), 282 tablespace_sql)) 258 283 table_output.append(' %s %s %s %s (%s)%s,' % \ 259 284 (style.SQL_FIELD(backend.quote_name(f.m2m_column_name())), 260 285 style.SQL_COLTYPE(data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__), … … 269 294 style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)), 270 295 style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)), 271 296 backend.get_deferrable_sql())) 272 table_output.append(' %s (%s, %s) ' % \297 table_output.append(' %s (%s, %s)%s' % \ 273 298 (style.SQL_KEYWORD('UNIQUE'), 274 299 style.SQL_FIELD(backend.quote_name(f.m2m_column_name())), 275 style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())))) 276 table_output.append(');') 300 style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())), 301 tablespace_sql)) 302 table_output.append(')') 303 if opts.db_tablespace and backend.supports_tablespaces: 304 # f.db_tablespace is only for indices, so ignore its value here. 305 table_output.append(backend.get_tablespace_sql(opts.db_tablespace)) 306 table_output.append(';') 277 307 final_output.append('\n'.join(table_output)) 308 309 # Add any extra SQL needed to support auto-incrementing PKs 310 autoinc_sql = backend.get_autoinc_sql(f.m2m_db_table()) 311 if autoinc_sql: 312 for stmt in autoinc_sql: 313 final_output.append(stmt) 314 278 315 return final_output 279 316 280 317 def get_sql_delete(app): 281 318 "Returns a list of the DROP TABLE SQL statements for the given app." 282 319 from django.db import backend, connection, models, get_introspection_module 320 from django.db.backends.util import truncate_name 283 321 introspection = get_introspection_module() 284 322 285 323 # This should work even if a connection isn't available … … 293 331 table_names = introspection.get_table_list(cursor) 294 332 else: 295 333 table_names = [] 334 if backend.uses_case_insensitive_names: 335 table_name_converter = str.upper 336 else: 337 table_name_converter = lambda x: x 296 338 297 339 output = [] 298 340 … … 302 344 references_to_delete = {} 303 345 app_models = models.get_models(app) 304 346 for model in app_models: 305 if cursor and model._meta.db_tablein table_names:347 if cursor and table_name_converter(model._meta.db_table) in table_names: 306 348 # The table exists, so it needs to be dropped 307 349 opts = model._meta 308 350 for f in opts.fields: … … 312 354 to_delete.add(model) 313 355 314 356 for model in app_models: 315 if cursor and model._meta.db_tablein table_names:357 if cursor and table_name_converter(model._meta.db_table) in table_names: 316 358 # Drop the table now 317 359 output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'), 318 360 style.SQL_TABLE(backend.quote_name(model._meta.db_table)))) … … 322 364 col = f.column 323 365 r_table = model._meta.db_table 324 366 r_col = model._meta.get_field(f.rel.field_name).column 367 r_name = '%s_refs_%s_%s_%s' % (col, r_col, table, r_table) 325 368 output.append('%s %s %s %s;' % \ 326 369 (style.SQL_KEYWORD('ALTER TABLE'), 327 370 style.SQL_TABLE(backend.quote_name(table)), 328 371 style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()), 329 style.SQL_FIELD( backend.quote_name('%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))))))372 style.SQL_FIELD(truncate_name(r_name, backend.get_max_name_length())))) 330 373 del references_to_delete[model] 374 if model._meta.has_auto_field and hasattr(backend, 'get_drop_sequence'): 375 output.append(backend.get_drop_sequence(model._meta.db_table)) 331 376 332 377 # Output DROP TABLE statements for many-to-many tables. 333 378 for model in app_models: 334 379 opts = model._meta 335 380 for f in opts.many_to_many: 336 if cursor and f.m2m_db_table() in table_names:381 if cursor and table_name_converter(f.m2m_db_table()) in table_names: 337 382 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'), 338 383 style.SQL_TABLE(backend.quote_name(f.m2m_db_table())))) 384 if hasattr(backend, 'get_drop_sequence'): 385 output.append(backend.get_drop_sequence("%s_%s" % (model._meta.db_table, f.column))) 339 386 387 340 388 app_label = app_models[0]._meta.app_label 341 389 342 390 # Close database connection explicitly, in case this output is being piped … … 431 479 def get_sql_indexes_for_model(model): 432 480 "Returns the CREATE INDEX SQL statements for a single model" 433 481 from django.db import backend 482 from django.db.backends.util import truncate_name 434 483 output = [] 435 484 436 485 for f in model._meta.fields: 437 if f.db_index :486 if f.db_index and not ((f.primary_key or f.unique) and backend.autoindexes_primary_keys): 438 487 unique = f.unique and 'UNIQUE ' or '' 488 tablespace = f.db_tablespace or model._meta.db_tablespace 489 if tablespace and backend.supports_tablespaces: 490 tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace) 491 else: 492 tablespace_sql = '' 439 493 output.append( 440 494 style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \ 441 495 style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \ 442 496 style.SQL_KEYWORD('ON') + ' ' + \ 443 497 style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \ 444 "(%s);" % style.SQL_FIELD(backend.quote_name(f.column)) 498 "(%s)" % style.SQL_FIELD(backend.quote_name(f.column)) + \ 499 "%s;" % tablespace_sql 445 500 ) 446 501 return output 447 502 … … 465 520 466 521 def syncdb(verbosity=1, interactive=True): 467 522 "Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created." 468 from django.db import connection, transaction, models, get_creation_module523 from django.db import backend, connection, transaction, models, get_creation_module 469 524 from django.conf import settings 470 525 471 526 disable_termcolors() … … 488 543 # Get a list of all existing database tables, 489 544 # so we know what needs to be added. 490 545 table_list = _get_table_list() 546 if backend.uses_case_insensitive_names: 547 table_name_converter = str.upper 548 else: 549 table_name_converter = lambda x: x 491 550 492 551 # Get a list of already installed *models* so that references work right. 493 552 seen_models = _get_installed_models(table_list) … … 502 561 # Create the model's database table, if it doesn't already exist. 503 562 if verbosity >= 2: 504 563 print "Processing %s.%s model" % (app_name, model._meta.object_name) 505 if model._meta.db_tablein table_list:564 if table_name_converter(model._meta.db_table) in table_list: 506 565 continue 507 566 sql, references = _get_sql_model_create(model, seen_models) 508 567 seen_models.add(model) … … 514 573 print "Creating table %s" % model._meta.db_table 515 574 for statement in sql: 516 575 cursor.execute(statement) 517 table_list.append( model._meta.db_table)576 table_list.append(table_name_converter(model._meta.db_table)) 518 577 519 578 # Create the m2m tables. This must be done after all tables have been created 520 579 # to ensure that all referred tables will exist. … … 833 892 except NotImplementedError: 834 893 indexes = {} 835 894 for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)): 836 att_name = row[0] 895 att_name = row[0].lower() 837 896 comment_notes = [] # Holds Field notes, to be displayed in a Python comment. 838 897 extra_params = {} # Holds Field parameters such as 'db_column'. 839 898 … … 1326 1385 # Keep a count of the installed objects and fixtures 1327 1386 count = [0,0] 1328 1387 models = set() 1329 1388 1330 1389 humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path' 1331 1390 1332 1391 # Get a cursor (even though we don't need one yet). This has … … 1630 1689 if not mod_list: 1631 1690 parser.print_usage_and_exit() 1632 1691 if action not in NO_SQL_TRANSACTION: 1633 print style.SQL_KEYWORD("BEGIN;") 1692 from django.db import backend 1693 if backend.get_start_transaction_sql(): 1694 print style.SQL_KEYWORD(backend.get_start_transaction_sql()) 1634 1695 for mod in mod_list: 1635 1696 if action == 'reset': 1636 1697 output = action_mapping[action](mod, options.interactive) -
django/contrib/admin/models.py
9 9 10 10 class LogEntryManager(models.Manager): 11 11 def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''): 12 e = self.model(None, None, user_id, content_type_id, object_id, object_repr[:200], action_flag, change_message)12 e = self.model(None, None, user_id, content_type_id, str(object_id), object_repr[:200], action_flag, change_message) 13 13 e.save() 14 14 15 15 class LogEntry(models.Model): -
docs/install.txt
62 62 63 63 * If you're using SQLite, you'll need pysqlite_. Use version 2.0.3 or higher. 64 64 65 * If you're using Oracle, you'll need cx_Oracle_, version 4.3.1 or higher. 66 65 67 .. _PostgreSQL: http://www.postgresql.org/ 66 68 .. _MySQL: http://www.mysql.com/ 67 69 .. _Django's ticket system: http://code.djangoproject.com/report/1 … … 71 73 .. _SQLite: http://www.sqlite.org/ 72 74 .. _pysqlite: http://initd.org/tracker/pysqlite 73 75 .. _MySQL backend: ../databases/ 76 .. _cx_Oracle: http://www.python.net/crew/atuining/cx_Oracle/ 74 77 75 78 Remove any old versions of Django 76 79 ================================= -
docs/settings.txt
245 245 Default: ``''`` (Empty string) 246 246 247 247 Which database backend to use. Either ``'postgresql_psycopg2'``, 248 ``'postgresql'``, ``'mysql'``, ``'mysql_old'``, ``'sqlite3'`` or249 ``' ado_mssql'``.248 ``'postgresql'``, ``'mysql'``, ``'mysql_old'``, ``'sqlite3'``, 249 ``'oracle'``, or ``'ado_mssql'``. 250 250 251 251 DATABASE_HOST 252 252 ------------- -
docs/model-api.txt
487 487 possible values for "no data;" Django convention is to use the empty 488 488 string, not ``NULL``. 489 489 490 Due to database limitations when using the Oracle backend, the ``null=True`` 491 option will be coerced for string-based fields, and the value ``NULL`` will 492 be stored to denote the empty string. 493 490 494 ``blank`` 491 495 ~~~~~~~~~ 492 496 … … 581 585 If ``True``, ``django-admin.py sqlindexes`` will output a ``CREATE INDEX`` 582 586 statement for this field. 583 587 588 ``db_tablespace`` 589 ~~~~~~~~~~~~~~~~~ 590 591 If this field is indexed, the name of the database tablespace to use for the 592 index. The default is the ``db_tablespace`` of the model, if any. If the 593 backend doesn't support tablespaces, this option is ignored. 594 584 595 ``default`` 585 596 ~~~~~~~~~~~ 586 597 … … 991 1002 that aren't allowed in Python variable names -- notably, the hyphen -- 992 1003 that's OK. Django quotes column and table names behind the scenes. 993 1004 1005 ``db_tablespace`` 1006 ----------------- 1007 1008 The name of the database tablespace to use for the model. If the backend 1009 doesn't support tablespaces, this option is ignored. 1010 994 1011 ``get_latest_by`` 995 1012 ----------------- 996 1013 -
docs/faq.txt
301 301 302 302 If you want to use Django with a database, which is probably the case, you'll 303 303 also need a database engine. PostgreSQL_ is recommended, because we're 304 PostgreSQL fans, and MySQL_ and `SQLite 3`_ are also supported.304 PostgreSQL fans, and MySQL_, `SQLite 3`_, and Oracle_ are also supported. 305 305 306 306 .. _Python: http://www.python.org/ 307 307 .. _Apache 2: http://httpd.apache.org/ … … 310 310 .. _PostgreSQL: http://www.postgresql.org/ 311 311 .. _MySQL: http://www.mysql.com/ 312 312 .. _`SQLite 3`: http://www.sqlite.org/ 313 .. _Oracle: http://www.oracle.com/ 313 314 314 315 Do I lose anything by using Python 2.3 versus newer Python versions, such as Python 2.5? 315 316 ---------------------------------------------------------------------------------------- -
tests/modeltests/datatypes/models.py
Property changes on: tests/modeltests/datatypes ___________________________________________________________________ Name: svn:ignore + *.pyc Property changes on: tests/modeltests/datatypes/__init__.py ___________________________________________________________________ Name: svn:eol-style + native
1 """ 2 1. Simple data types testing. 3 4 This is a basic model to test saving and loading boolean and date-related 5 types, which in the past were problematic for some database backends. 6 """ 7 8 from django.db import models 9 10 class Donut(models.Model): 11 name = models.CharField(maxlength=100) 12 is_frosted = models.BooleanField(default=False) 13 has_sprinkles = models.NullBooleanField() 14 baked_date = models.DateField(null=True) 15 baked_time = models.TimeField(null=True) 16 consumed_at = models.DateTimeField(null=True) 17 18 class Meta: 19 ordering = ('consumed_at',) 20 21 def __str__(self): 22 return self.name 23 24 __test__ = {'API_TESTS': """ 25 # No donuts are in the system yet. 26 >>> Donut.objects.all() 27 [] 28 29 >>> d = Donut(name='Apple Fritter') 30 31 # Ensure we're getting True and False, not 0 and 1 32 >>> d.is_frosted 33 False 34 >>> d.has_sprinkles 35 >>> d.has_sprinkles = True 36 >>> d.has_sprinkles 37 True 38 >>> d.save() 39 >>> d2 = Donut.objects.all()[0] 40 >>> d2 41 <Donut: Apple Fritter> 42 >>> d2.is_frosted 43 False 44 >>> d2.has_sprinkles 45 True 46 47 >>> import datetime 48 >>> d2.baked_date = datetime.date(year=1938, month=6, day=4) 49 >>> d2.baked_time = datetime.time(hour=5, minute=30) 50 >>> d2.consumed_at = datetime.datetime(year=2007, month=4, day=20, hour=16, minute=19, second=59) 51 >>> d2.save() 52 53 >>> d3 = Donut.objects.all()[0] 54 >>> d3.baked_date 55 datetime.date(1938, 6, 4) 56 >>> d3.baked_time 57 datetime.time(5, 30) 58 >>> d3.consumed_at 59 datetime.datetime(2007, 4, 20, 16, 19, 59) 60 """} -
tests/modeltests/lookup/models.py
Property changes on: tests/modeltests/datatypes/models.py ___________________________________________________________________ Name: svn:eol-style + native
131 131 [('headline', 'Article 7'), ('id', 7)] 132 132 [('headline', 'Article 1'), ('id', 1)] 133 133 134 135 # you can use values() even on extra fields136 >>> for d in Article.objects.extra( select={'id_plus_one' : 'id + 1'} ).values('id', 'id_plus_one'):137 ... i = d.items()138 ... i.sort()139 ... i140 [('id', 5), ('id_plus_one', 6)]141 [('id', 6), ('id_plus_one', 7)]142 [('id', 4), ('id_plus_one', 5)]143 [('id', 2), ('id_plus_one', 3)]144 [('id', 3), ('id_plus_one', 4)]145 [('id', 7), ('id_plus_one', 8)]146 [('id', 1), ('id_plus_one', 2)]147 148 # however, an exception FieldDoesNotExist will still be thrown149 # if you try to access non-existent field (field that is neither on the model nor extra)150 >>> Article.objects.extra( select={'id_plus_one' : 'id + 1'} ).values('id', 'id_plus_two')151 Traceback (most recent call last):152 ...153 FieldDoesNotExist: Article has no field named 'id_plus_two'154 155 134 # if you don't specify which fields, all are returned 156 135 >>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}] 157 136 True -
tests/regressiontests/serializers_regress/tests.py
14 14 from django.core import serializers 15 15 from django.db import transaction 16 16 from django.core import management 17 from django.conf import settings 17 18 18 19 from models import * 19 20 try: … … 115 116 (data_obj, 31, DateTimeData, None), 116 117 (data_obj, 40, EmailData, "hovercraft@example.com"), 117 118 (data_obj, 41, EmailData, None), 119 (data_obj, 42, EmailData, ""), 118 120 (data_obj, 50, FileData, 'file:///foo/bar/whiz.txt'), 119 121 (data_obj, 51, FileData, None), 122 (data_obj, 52, FileData, ""), 120 123 (data_obj, 60, FilePathData, "/foo/bar/whiz.txt"), 121 124 (data_obj, 61, FilePathData, None), 125 (data_obj, 62, FilePathData, ""), 122 126 (data_obj, 70, DecimalData, decimal.Decimal('12.345')), 123 127 (data_obj, 71, DecimalData, decimal.Decimal('-12.345')), 124 128 (data_obj, 72, DecimalData, decimal.Decimal('0.0')), … … 134 138 #(XX, ImageData 135 139 (data_obj, 90, IPAddressData, "127.0.0.1"), 136 140 (data_obj, 91, IPAddressData, None), 141 (data_obj, 92, IPAddressData, ""), 137 142 (data_obj, 100, NullBooleanData, True), 138 143 (data_obj, 101, NullBooleanData, False), 139 144 (data_obj, 102, NullBooleanData, None), … … 145 150 (data_obj, 131, PositiveSmallIntegerData, None), 146 151 (data_obj, 140, SlugData, "this-is-a-slug"), 147 152 (data_obj, 141, SlugData, None), 153 (data_obj, 142, SlugData, ""), 148 154 (data_obj, 150, SmallData, 12), 149 155 (data_obj, 151, SmallData, -12), 150 156 (data_obj, 152, SmallData, 0), … … 159 165 (data_obj, 171, TimeData, None), 160 166 (data_obj, 180, USStateData, "MA"), 161 167 (data_obj, 181, USStateData, None), 168 (data_obj, 182, USStateData, ""), 162 169 (data_obj, 190, XMLData, "<foo></foo>"), 163 170 (data_obj, 191, XMLData, None), 171 (data_obj, 192, XMLData, ""), 164 172 165 173 (generic_obj, 200, GenericData, ['Generic Object 1', 'tag1', 'tag2']), 166 174 (generic_obj, 201, GenericData, ['Generic Object 2', 'tag2', 'tag3']), … … 240 248 # (pk_obj, 790, XMLPKData, "<foo></foo>"), 241 249 ] 242 250 251 # Because Oracle treats the empty string as NULL, Oracle is expected to fail 252 # when field.empty_strings_allowed is True and the value is None; skip these 253 # tests. 254 if settings.DATABASE_ENGINE == 'oracle': 255 test_data = [data for data in test_data 256 if not (data[0] == data_obj and 257 data[2]._meta.get_field('data').empty_strings_allowed and 258 data[3] is None)] 259 243 260 # Dynamically create serializer tests to ensure that all 244 261 # registered serializers are automatically tested. 245 262 class SerializerTests(unittest.TestCase):