OracleBranch: django-oracle-rev5392.diff

File django-oracle-rev5392.diff, 96.1 KB (added by Matt Boersma, 17 years ago)

Patch to add Oracle support to trunk as of trunk rev 5392

  • django/test/utils.py

     
    11import sys, time
    22from django.conf import settings
    3 from django.db import connection, transaction, backend
     3from django.db import connection, backend, get_creation_module
    44from django.core import management, mail
    55from django.dispatch import dispatcher
    66from django.test import signals
     
    8888    return ''
    8989
    9090def 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   
    9197    if verbosity >= 1:
    9298        print "Creating test database..."
    9399    # If we're using SQLite, it's more convenient to test against an
     
    142148    cursor = connection.cursor()
    143149
    144150def 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   
    145157    # Unless we're using SQLite, remove the test database to clean up after
    146158    # ourselves. Connect to the previous database (not the test database)
    147159    # to do so, because it's not allowed to delete a database while being
  • django/db/models/base.py

     
    9696
    9797    def __init__(self, *args, **kwargs):
    9898        dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
    99        
     99
    100100        # 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
    102102        # The reason for the kwargs check is that standard iterator passes in by
    103103        # args, and nstantiation for iteration is 33% faster.
    104104        args_len = len(args)
     
    122122                # Maintain compatibility with existing calls.
    123123                if isinstance(field.rel, ManyToOneRel):
    124124                    kwargs.pop(field.attname, None)
    125        
     125
    126126        # Now we're left with the unprocessed fields that *must* come from
    127127        # keywords, or default.
    128        
     128
    129129        for field in fields_iter:
    130130            if kwargs:
    131131                if isinstance(field.rel, ManyToOneRel):
     
    147147                            try:
    148148                                val = getattr(rel_obj, field.rel.get_related_field().attname)
    149149                            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" %
    151151                                    (field.name, field.rel.to, type(rel_obj)))
    152152                else:
    153153                    val = kwargs.pop(field.attname, field.get_default())
     
    210210        record_exists = True
    211211        if pk_set:
    212212            # 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))
    215216            # If it does already exist, do an UPDATE.
    216             if cursor.fetchone():
     217            if cursor.fetchone()[0] > 0:
    217218                db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks]
    218219                if db_values:
    219220                    cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
    220221                        (backend.quote_name(self._meta.db_table),
    221222                        ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
    222223                        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))
    224225            else:
    225226                record_exists = False
    226227        if not pk_set or not record_exists:
  • django/db/models/options.py

     
    1313
    1414DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
    1515                 'unique_together', 'permissions', 'get_latest_by',
    16                  'order_with_respect_to', 'app_label')
     16                 'order_with_respect_to', 'app_label', 'db_tablespace')
    1717
    1818class Options(object):
    1919    def __init__(self, meta):
     
    2727        self.object_name, self.app_label = None, None
    2828        self.get_latest_by = None
    2929        self.order_with_respect_to = None
     30        self.db_tablespace = None
    3031        self.admin = None
    3132        self.meta = meta
    3233        self.pk = None
     
    5960        del self.meta
    6061
    6162    def _prepare(self, model):
     63        from django.db import backend
     64        from django.db.backends.util import truncate_name
    6265        if self.order_with_respect_to:
    6366            self.order_with_respect_to = self.get_field(self.order_with_respect_to)
    6467            self.ordering = ('_order',)
     
    7376        # If the db_table wasn't provided, use the app_label + module_name.
    7477        if not self.db_table:
    7578            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())
    7681
    7782    def add_field(self, field):
    7883        # Insert the given field in the order in which it was created, using
     
    8893
    8994    def __repr__(self):
    9095        return '<Options for %s>' % self.object_name
    91        
     96
    9297    def __str__(self):
    9398        return "%s.%s" % (self.app_label, self.module_name)
    94        
     99
    95100    def get_field(self, name, many_to_many=True):
    96101        "Returns the requested field by name. Raises FieldDoesNotExist on error."
    97102        to_search = many_to_many and (self.fields + self.many_to_many) or self.fields
  • django/db/models/fields/__init__.py

     
    7474        core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True,
    7575        prepopulate_from=None, unique_for_date=None, unique_for_month=None,
    7676        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):
    7878        self.name = name
    7979        self.verbose_name = verbose_name
    8080        self.primary_key = primary_key
    8181        self.maxlength, self.unique = maxlength, unique
    8282        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
    8387        self.core, self.rel, self.default = core, rel, default
    8488        self.editable = editable
    8589        self.serialize = serialize
     
    9195        self.radio_admin = radio_admin
    9296        self.help_text = help_text
    9397        self.db_column = db_column
     98        self.db_tablespace = db_tablespace
    9499
    95100        # Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
    96101        self.db_index = db_index
     
    875880        Field.__init__(self, verbose_name, name, **kwargs)
    876881
    877882    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
    878891        if lookup_type == 'range':
    879             value = [str(v) for v in value]
     892            value = [prep(v) for v in value]
    880893        else:
    881             value = str(value)
     894            value = prep(value)
    882895        return Field.get_db_prep_lookup(self, lookup_type, value)
    883896
    884897    def pre_save(self, model_instance, add):
     
    896909            # doesn't support microseconds.
    897910            if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
    898911                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:
    899920            value = str(value)
    900921        return Field.get_db_prep_save(self, value)
    901922
  • django/db/models/fields/related.py

     
    335335                    (target_col_name, self.join_table, source_col_name,
    336336                    target_col_name, ",".join(['%s'] * len(new_ids))),
    337337                    [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()])
    342339
    343340                # Add the ones that aren't there already
    344341                for obj_id in (new_ids - existing_ids):
  • django/db/models/query.py

     
    44from django.dispatch import dispatcher
    55from django.utils.datastructures import SortedDict
    66from django.contrib.contenttypes import generic
     7import datetime
    78import operator
    89import re
    910
     
    7778    else:
    7879        return backend.quote_name(word)
    7980
    80 class QuerySet(object):
     81class _QuerySet(object):
    8182    "Represents a lazy database lookup for a set of objects"
    8283    def __init__(self, model=None):
    8384        self.model = model
     
    181182
    182183        cursor = connection.cursor()
    183184        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
     185
    184186        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')
    186190        while 1:
    187191            rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
    188192            if not rows:
    189193                raise StopIteration
    190194            for row in rows:
     195                if has_resolve_columns:
     196                    row = self.resolve_columns(row, fields)
    191197                if fill_cache:
    192198                    obj, index_end = get_cached_row(klass=self.model, row=row,
    193199                                                    index_start=0, max_depth=self._max_related_depth)
     
    551557
    552558        return select, " ".join(sql), params
    553559
     560# Use the backend's QuerySet class if it defines one, otherwise use _QuerySet.
     561if hasattr(backend, 'get_query_set_class'):
     562    QuerySet = backend.get_query_set_class(_QuerySet)
     563else:
     564    QuerySet = _QuerySet
     565
    554566class ValuesQuerySet(QuerySet):
    555567    def __init__(self, *args, **kwargs):
    556568        super(ValuesQuerySet, self).__init__(*args, **kwargs)
    557         # select_related isn't supported in values().
     569        # select_related and select aren't supported in values().
    558570        self._select_related = False
     571        self._select = {}
    559572
    560573    def iterator(self):
    561574        try:
     
    565578
    566579        # self._fields is a list of field names to fetch.
    567580        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]
    580582        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]
    583586
    584587        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 
    590588        cursor = connection.cursor()
    591589        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
     590
     591        has_resolve_columns = hasattr(self, 'resolve_columns')
    592592        while 1:
    593593            rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
    594594            if not rows:
    595595                raise StopIteration
    596596            for row in rows:
     597                if has_resolve_columns:
     598                    row = self.resolve_columns(row, fields)
    597599                yield dict(zip(field_names, row))
    598600
    599601    def _clone(self, klass=None, **kwargs):
     
    604606class DateQuerySet(QuerySet):
    605607    def iterator(self):
    606608        from django.db.backends.util import typecast_timestamp
     609        from django.db.models.fields import DateTimeField
    607610        self._order_by = () # Clear this because it'll mess things up otherwise.
    608611        if self._field.null:
    609612            self._where.append('%s.%s IS NOT NULL' % \
    610613                (backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
    611 
    612614        try:
    613615            select, sql, params = self._get_sql_clause()
    614616        except EmptyResultSet:
    615617            raise StopIteration
    616618
    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' % \
    618629            (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)
    620631        cursor = connection.cursor()
    621632        cursor.execute(sql, params)
    622         # We have to manually run typecast_timestamp(str()) on the results, because
    623         # MySQL doesn't automatically cast the result of date functions as datetime
    624         # objects -- MySQL returns the values as strings, instead.
    625         return [typecast_timestamp(str(row[0])) for row in cursor.fetchall()]
    626633
     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
    627653    def _clone(self, klass=None, **kwargs):
    628654        c = super(DateQuerySet, self)._clone(klass, **kwargs)
    629655        c._field = self._field
     
    730756    if table_prefix.endswith('.'):
    731757        table_prefix = backend.quote_name(table_prefix[:-1])+'.'
    732758    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'
    733767    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)
    735770    except KeyError:
    736771        pass
    737772    if lookup_type == 'in':
  • django/db/backends/ado_mssql/base.py

     
    8989            self.connection.close()
    9090            self.connection = None
    9191
     92allows_group_by_ordinal = True
     93allows_unique_and_pk = True
     94autoindexes_primary_keys = True
     95needs_datetime_string_cast = True
     96needs_upper_for_iops = False
    9297supports_constraints = True
     98supports_tablespaces = True
     99uses_case_insensitive_names = False
    93100
    94101def quote_name(name):
    95102    if name.startswith('[') and name.endswith(']'):
     
    117124    if lookup_type=='day':
    118125        return "Convert(datetime, Convert(varchar(12), %s))" % field_name
    119126
     127def get_datetime_cast_sql():
     128    return None
     129
    120130def get_limit_offset_sql(limit, offset=None):
    121131    # TODO: This is a guess. Make sure this is correct.
    122132    sql = "LIMIT %s" % limit
     
    139149def get_pk_default_value():
    140150    return "DEFAULT"
    141151
     152def get_max_name_length():
     153    return None
     154
     155def get_start_transaction_sql():
     156    return "BEGIN;"
     157
     158def get_tablespace_sql(tablespace, inline=False):
     159    return "ON %s" % quote_name(tablespace)
     160
     161def get_autoinc_sql(table):
     162    return None
     163
    142164def get_sql_flush(style, tables, sequences):
    143165    """Return a list of SQL statements required to remove all data from
    144166    all tables in the database (without actually removing the tables
  • django/db/backends/postgresql/base.py

     
    8787        global postgres_version
    8888        if not postgres_version:
    8989            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('.')]
    9191        if settings.DEBUG:
    9292            return util.CursorDebugWrapper(cursor, self)
    9393        return cursor
     
    105105            self.connection.close()
    106106            self.connection = None
    107107
     108allows_group_by_ordinal = True
     109allows_unique_and_pk = True
     110autoindexes_primary_keys = True
     111needs_datetime_string_cast = True
     112needs_upper_for_iops = False
    108113supports_constraints = True
     114supports_tablespaces = False
     115uses_case_insensitive_names = False
    109116
    110117def quote_name(name):
    111118    if name.startswith('"') and name.endswith('"'):
     
    138145    # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
    139146    return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
    140147
     148def get_datetime_cast_sql():
     149    return None
     150
    141151def get_limit_offset_sql(limit, offset=None):
    142152    sql = "LIMIT %s" % limit
    143153    if offset and offset != 0:
     
    149159
    150160def get_deferrable_sql():
    151161    return " DEFERRABLE INITIALLY DEFERRED"
    152    
     162
    153163def get_fulltext_search_sql(field_name):
    154164    raise NotImplementedError
    155165
     
    159169def get_pk_default_value():
    160170    return "DEFAULT"
    161171
     172def get_max_name_length():
     173    return None
     174
     175def get_start_transaction_sql():
     176    return "BEGIN;"
     177
     178def get_autoinc_sql(table):
     179    return None
     180
    162181def get_sql_flush(style, tables, sequences):
    163182    """Return a list of SQL statements required to remove all data from
    164183    all tables in the database (without actually removing the tables
    165184    themselves) and put the database in an empty 'initial' state
    166    
    167     """   
     185
     186    """
    168187    if tables:
    169188        if postgres_version[0] >= 8 and postgres_version[1] >= 1:
    170189            # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to
     
    175194                 style.SQL_FIELD(', '.join([quote_name(table) for table in tables]))
    176195            )]
    177196        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
    179198            # a simple delete.
    180199            sql = ['%s %s %s;' % \
    181200                    (style.SQL_KEYWORD('DELETE'),
     
    238257                style.SQL_KEYWORD('FROM'),
    239258                style.SQL_TABLE(f.m2m_db_table())))
    240259    return output
    241        
     260
    242261# Register these custom typecasts, because Django expects dates/times to be
    243262# in Python's native (standard-library) datetime/time format, whereas psycopg
    244263# use mx.DateTime by default.
  • django/db/backends/sqlite3/base.py

     
    107107    def convert_query(self, query, num_params):
    108108        return query % tuple("?" * num_params)
    109109
     110allows_group_by_ordinal = True
     111allows_unique_and_pk = True
     112autoindexes_primary_keys = True
     113needs_datetime_string_cast = True
     114needs_upper_for_iops = False
    110115supports_constraints = False
     116supports_tablespaces = False
     117uses_case_insensitive_names = False
    111118
    112119def quote_name(name):
    113120    if name.startswith('"') and name.endswith('"'):
     
    139146    # sqlite doesn't support DATE_TRUNC, so we fake it as above.
    140147    return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
    141148
     149def get_datetime_cast_sql():
     150    return None
     151
    142152def get_limit_offset_sql(limit, offset=None):
    143153    sql = "LIMIT %s" % limit
    144154    if offset and offset != 0:
     
    160170def get_pk_default_value():
    161171    return "NULL"
    162172
     173def get_max_name_length():
     174    return None
     175
     176def get_start_transaction_sql():
     177    return "BEGIN;"
     178
     179def get_autoinc_sql(table):
     180    return None
     181
    163182def get_sql_flush(style, tables, sequences):
    164183    """Return a list of SQL statements required to remove all data from
    165184    all tables in the database (without actually removing the tables
    166185    themselves) and put the database in an empty 'initial' state
    167    
     186
    168187    """
    169188    # NB: The generated SQL below is specific to SQLite
    170189    # Note: The DELETE FROM... SQL generated below works for SQLite databases
     
    182201    "Returns a list of the SQL statements to reset sequences for the given models."
    183202    # No sequence reset required
    184203    return []
    185    
     204
    186205def _sqlite_date_trunc(lookup_type, dt):
    187206    try:
    188207        dt = util.typecast_timestamp(dt)
  • django/db/backends/util.py

     
    11import datetime
     2import md5
    23from time import time
    34
    45try:
     
    107108        return None
    108109    return str(d)
    109110
     111def 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
    110121##################################################################################
    111122# Helper functions for dictfetch* for databases that don't natively support them #
    112123##################################################################################
  • django/db/backends/mysql/base.py

     
    134134            self.server_version = tuple([int(x) for x in m.groups()])
    135135        return self.server_version
    136136
     137allows_group_by_ordinal = True
     138allows_unique_and_pk = True
     139autoindexes_primary_keys = False
     140needs_datetime_string_cast = True     # MySQLdb requires a typecast for dates
     141needs_upper_for_iops = False
    137142supports_constraints = True
     143supports_tablespaces = False
     144uses_case_insensitive_names = False
    138145
    139146def quote_name(name):
    140147    if name.startswith("`") and name.endswith("`"):
     
    167174        sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
    168175    return sql
    169176
     177def get_datetime_cast_sql():
     178    return None
     179
    170180def get_limit_offset_sql(limit, offset=None):
    171181    sql = "LIMIT "
    172182    if offset and offset != 0:
     
    188198def get_pk_default_value():
    189199    return "DEFAULT"
    190200
     201def get_max_name_length():
     202    return 64;
     203
     204def get_start_transaction_sql():
     205    return "BEGIN;"
     206
     207def get_autoinc_sql(table):
     208    return None
     209
    191210def get_sql_flush(style, tables, sequences):
    192211    """Return a list of SQL statements required to remove all data from
    193212    all tables in the database (without actually removing the tables
    194213    themselves) and put the database in an empty 'initial' state
    195    
     214
    196215    """
    197216    # NB: The generated SQL below is specific to MySQL
    198217    # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
     
    204223                 style.SQL_FIELD(quote_name(table))
    205224                )  for table in tables] + \
    206225              ['SET FOREIGN_KEY_CHECKS = 1;']
    207              
     226
    208227        # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
    209228        # to reset sequence indices
    210229        sql.extend(["%s %s %s %s %s;" % \
  • django/db/backends/oracle/base.py

     
    44Requires cx_Oracle: http://www.python.net/crew/atuining/cx_Oracle/
    55"""
    66
     7from django.conf import settings
    78from django.db.backends import util
    89try:
    910    import cx_Oracle as Database
    1011except ImportError, e:
    1112    from django.core.exceptions import ImproperlyConfigured
    1213    raise ImproperlyConfigured, "Error loading cx_Oracle module: %s" % e
     14import datetime
     15from django.utils.datastructures import SortedDict
    1316
     17
    1418DatabaseError = Database.Error
    1519IntegrityError = Database.IntegrityError
    1620
     
    3135        return self.connection is not None
    3236
    3337    def cursor(self):
    34         from django.conf import settings
    3538        if not self._valid_connection():
    3639            if len(settings.DATABASE_HOST.strip()) == 0:
    3740                settings.DATABASE_HOST = 'localhost'
     
    4144            else:
    4245                conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
    4346                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
    4556
    4657    def _commit(self):
    4758        if self.connection is not None:
    48             self.connection.commit()
     59            return self.connection.commit()
    4960
    5061    def _rollback(self):
    5162        if self.connection is not None:
    52             try:
    53                 self.connection.rollback()
    54             except Database.NotSupportedError:
    55                 pass
     63            return self.connection.rollback()
    5664
    5765    def close(self):
    5866        if self.connection is not None:
    5967            self.connection.close()
    6068            self.connection = None
    6169
     70allows_group_by_ordinal = False
     71allows_unique_and_pk = False        # Suppress UNIQUE/PK for Oracle (ORA-02259)
     72autoindexes_primary_keys = True
     73needs_datetime_string_cast = False
     74needs_upper_for_iops = True
    6275supports_constraints = True
     76supports_tablespaces = True
     77uses_case_insensitive_names = True
    6378
    6479class FormatStylePlaceholderCursor(Database.Cursor):
    6580    """
     
    6782    This fixes it -- but note that if you want to use a literal "%s" in a query,
    6883    you'll need to use "%%s".
    6984    """
     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
    70106    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)
    73108        return Database.Cursor.execute(self, query, params)
    74109
    75110    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)
    78112        return Database.Cursor.executemany(self, query, params)
    79113
    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 
    85114def 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()
    87122
    88123dictfetchone = util.dictfetchone
    89124dictfetchmany = util.dictfetchmany
    90125dictfetchall  = util.dictfetchall
    91126
    92127def get_last_insert_id(cursor, table_name, pk_name):
    93     query = "SELECT %s_sq.currval from dual" % table_name
    94     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)
    95130    return cursor.fetchone()[0]
    96131
    97132def get_date_extract_sql(lookup_type, table_name):
    98133    # lookup_type is 'year', 'month', 'day'
    99     # http://www.psoug.org/reference/date_func.html
     134    # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163
    100135    return "EXTRACT(%s FROM %s)" % (lookup_type, table_name)
    101136
    102137def 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
    104146
     147def get_datetime_cast_sql():
     148    return "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')"
     149
    105150def get_limit_offset_sql(limit, offset=None):
    106151    # Limits and offset are too complicated to be handled here.
    107     # Instead, they are handled in django/db/query.py.
    108     pass
     152    # Instead, they are handled in django/db/backends/oracle/query.py.
     153    return ""
    109154
    110155def get_random_function_sql():
    111156    return "DBMS_RANDOM.RANDOM"
     
    117162    raise NotImplementedError
    118163
    119164def get_drop_foreignkey_sql():
    120     return "DROP FOREIGN KEY"
     165    return "DROP CONSTRAINT"
    121166
    122167def get_pk_default_value():
    123168    return "DEFAULT"
    124169
     170def get_max_name_length():
     171    return 30
     172
     173def get_start_transaction_sql():
     174    return None
     175
     176def get_tablespace_sql(tablespace, inline=False):
     177    return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), quote_name(tablespace))
     178
     179def 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
     195def get_drop_sequence(table):
     196    return "DROP SEQUENCE %s;" % quote_name(get_sequence_name(table))
     197
     198def _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
    125218def get_sql_flush(style, tables, sequences):
    126219    """Return a list of SQL statements required to remove all data from
    127220    all tables in the database (without actually removing the tables
    128221    themselves) and put the database in an empty 'initial' state
    129222    """
    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'),
    135231             style.SQL_FIELD(quote_name(table))
    136232             )  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 []
    137244
     245def get_sequence_name(table):
     246    name_length = get_max_name_length() - 3
     247    return '%s_SQ' % util.truncate_name(table, name_length).upper()
     248
    138249def get_sql_sequence_reset(style, model_list):
    139250    "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
    142266
     267def get_trigger_name(table):
     268    name_length = get_max_name_length() - 3
     269    return '%s_TR' % util.truncate_name(table, name_length).upper()
     270
     271def 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
    143511OPERATOR_MAPPING = {
    144512    '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 '\\'",
    148516    'gt': '> %s',
    149517    'gte': '>= %s',
    150518    'lt': '< %s',
    151519    '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 '\\'",
    156524}
  • django/db/backends/oracle/client.py

     
    22import os
    33
    44def runshell():
    5     args = ''
    6     args += settings.DATABASE_USER
     5    dsn = settings.DATABASE_USER
    76    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

     
     1from django.db.backends.oracle.base import quote_name
    12import re
     3import cx_Oracle
    24
     5
    36foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
    47
    58def get_table_list(cursor):
    69    "Returns a list of table names in the current database."
    710    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()]
    912
    1013def 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
    1217
    1318def _name_to_index(cursor, table_name):
    1419    """
     
    2227    Returns a dictionary of {field_index: (field_index_other_table, other_table)}
    2328    representing all relationships to the given table. Indexes are 0-based.
    2429    """
    25     raise NotImplementedError
     30    cursor.execute("""
     31SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1
     32FROM   user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb,
     33       user_tab_cols ta, user_tab_cols tb
     34WHERE  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])
    2643
     44    relations = {}
     45    for row in cursor.fetchall():
     46        relations[row[0]] = (row[2], row[1])
     47    return relations
     48
    2749def get_indexes(cursor, table_name):
    2850    """
    2951    Returns a dictionary of fieldname -> infodict for the given table,
     
    3153        {'primary_key': boolean representing whether it's the primary key,
    3254         'unique': boolean representing whether it's a unique index}
    3355    """
    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 = """
     60WITH 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)
     72SELECT allcols.column_name, primarycols.primarycol, uniquecols.UNIQUECOL
     73FROM   (SELECT column_name FROM primarycols UNION SELECT column_name FROM
     74uniquecols) allcols,
     75      primarycols, uniquecols
     76WHERE  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
    3588
    36 # Maps type codes to Django Field types.
     89# Maps type objects to Django Field types.
    3790DATA_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',
    5098}
  • django/db/backends/oracle/creation.py

     
     1import sys, time
     2from 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.
    18DATA_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)',
    1522    '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)',
    2634}
     35
     36TEST_DATABASE_PREFIX = 'test_'
     37PASSWORD = 'Im_a_lumberjack'
     38REMEMBER = {}
     39
     40
     41def 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
     120def 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
     157def _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
     173def _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
     187def _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
     197def _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
     207def _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
     219def _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
     231def _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
     245def _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
     259def _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
     271def _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
     283def _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
     295def _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

     
    5555        global postgres_version
    5656        if not postgres_version:
    5757            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('.')]
    5959        if settings.DEBUG:
    6060            return util.CursorDebugWrapper(cursor, self)
    6161        return cursor
     
    7373            self.connection.close()
    7474            self.connection = None
    7575
     76allows_group_by_ordinal = True
     77allows_unique_and_pk = True
     78autoindexes_primary_keys = True
     79needs_datetime_string_cast = False
     80needs_upper_for_iops = False
    7681supports_constraints = True
     82supports_tablespaces = False
     83uses_case_insensitive_names = True
    7784
    7885def quote_name(name):
    7986    if name.startswith('"') and name.endswith('"'):
     
    98105    # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
    99106    return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
    100107
     108def get_datetime_cast_sql():
     109    return None
     110
    101111def get_limit_offset_sql(limit, offset=None):
    102112    sql = "LIMIT %s" % limit
    103113    if offset and offset != 0:
     
    119129def get_pk_default_value():
    120130    return "DEFAULT"
    121131
     132def get_max_name_length():
     133    return None
     134
     135def get_start_transaction_sql():
     136    return "BEGIN;"
     137
     138def get_autoinc_sql(table):
     139    return None
     140
    122141def get_sql_flush(style, tables, sequences):
    123142    """Return a list of SQL statements required to remove all data from
    124143    all tables in the database (without actually removing the tables
     
    139158                     style.SQL_KEYWORD('FROM'),
    140159                     style.SQL_FIELD(quote_name(table))
    141160                     ) for table in tables]
    142                      
     161
    143162        # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
    144163        # to reset sequence indices
    145164        for sequence in sequences:
     
    195214                style.SQL_KEYWORD('FROM'),
    196215                style.SQL_TABLE(f.m2m_db_table())))
    197216    return output
    198        
     217
    199218OPERATOR_MAPPING = {
    200219    'exact': '= %s',
    201220    'iexact': 'ILIKE %s',
  • django/db/backends/dummy/base.py

     
    3030        pass # close()
    3131
    3232supports_constraints = False
     33supports_tablespaces = False
    3334quote_name = complain
    3435dictfetchone = complain
    3536dictfetchmany = complain
  • django/core/management.py

     
    5555
    5656def _get_installed_models(table_list):
    5757    "Gets a set of all models that are installed, given a list of existing tables"
    58     from django.db import models
     58    from django.db import backend, models
    5959    all_models = []
    6060    for app in models.get_apps():
    6161        for model in models.get_models(app):
    6262            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)])
    6468
    6569def _get_table_list():
    6670    "Gets a list of all db tables that are physically installed."
     
    104108def get_sql_create(app):
    105109    "Returns a list of the CREATE TABLE SQL statements for the given app."
    106110    from django.db import get_creation_module, models
     111
    107112    data_types = get_creation_module().DATA_TYPES
    108113
    109114    if not data_types:
     
    175180            rel_field = f
    176181            data_type = f.get_internal_type()
    177182        col_type = data_types[data_type]
     183        tablespace = f.db_tablespace or opts.db_tablespace
    178184        if col_type is not None:
    179185            # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
    180186            field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
    181187                style.SQL_COLTYPE(col_type % rel_field.__dict__)]
    182188            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):
    184190                field_output.append(style.SQL_KEYWORD('UNIQUE'))
    185191            if f.primary_key:
    186192                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))
    187197            if f.rel:
    188198                if f.rel.to in known_models:
    189199                    field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
     
    207217    full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(backend.quote_name(opts.db_table)) + ' (']
    208218    for i, line in enumerate(table_output): # Combine and add commas.
    209219        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(';')
    211224    final_output.append('\n'.join(full_statement))
    212225
     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
    213233    return final_output, pending_references
    214234
    215235def _get_sql_for_pending_references(model, pending_references):
     
    217237    Get any ALTER TABLE statements to add constraints after the fact.
    218238    """
    219239    from django.db import backend, get_creation_module
     240    from django.db.backends.util import truncate_name
    220241    data_types = get_creation_module().DATA_TYPES
    221242
    222243    final_output = []
     
    229250                r_col = f.column
    230251                table = opts.db_table
    231252                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)
    235254                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()),
    237256                    backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col),
    238257                    backend.get_deferrable_sql()))
    239258            del pending_references[model]
     
    249268    final_output = []
    250269    for f in opts.many_to_many:
    251270        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 = ''
    252276            table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
    253277                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,' % \
    255279                (style.SQL_FIELD(backend.quote_name('id')),
    256280                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))
    258283            table_output.append('    %s %s %s %s (%s)%s,' % \
    259284                (style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
    260285                style.SQL_COLTYPE(data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__),
     
    269294                style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
    270295                style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)),
    271296                backend.get_deferrable_sql()))
    272             table_output.append('    %s (%s, %s)' % \
     297            table_output.append('    %s (%s, %s)%s' % \
    273298                (style.SQL_KEYWORD('UNIQUE'),
    274299                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(';')
    277307            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
    278315    return final_output
    279316
    280317def get_sql_delete(app):
    281318    "Returns a list of the DROP TABLE SQL statements for the given app."
    282319    from django.db import backend, connection, models, get_introspection_module
     320    from django.db.backends.util import truncate_name
    283321    introspection = get_introspection_module()
    284322
    285323    # This should work even if a connection isn't available
     
    293331        table_names = introspection.get_table_list(cursor)
    294332    else:
    295333        table_names = []
     334    if backend.uses_case_insensitive_names:
     335        table_name_converter = str.upper
     336    else:
     337        table_name_converter = lambda x: x
    296338
    297339    output = []
    298340
     
    302344    references_to_delete = {}
    303345    app_models = models.get_models(app)
    304346    for model in app_models:
    305         if cursor and model._meta.db_table in table_names:
     347        if cursor and table_name_converter(model._meta.db_table) in table_names:
    306348            # The table exists, so it needs to be dropped
    307349            opts = model._meta
    308350            for f in opts.fields:
     
    312354            to_delete.add(model)
    313355
    314356    for model in app_models:
    315         if cursor and model._meta.db_table in table_names:
     357        if cursor and table_name_converter(model._meta.db_table) in table_names:
    316358            # Drop the table now
    317359            output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
    318360                style.SQL_TABLE(backend.quote_name(model._meta.db_table))))
     
    322364                    col = f.column
    323365                    r_table = model._meta.db_table
    324366                    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)
    325368                    output.append('%s %s %s %s;' % \
    326369                        (style.SQL_KEYWORD('ALTER TABLE'),
    327370                        style.SQL_TABLE(backend.quote_name(table)),
    328371                        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()))))
    330373                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))
    331376
    332377    # Output DROP TABLE statements for many-to-many tables.
    333378    for model in app_models:
    334379        opts = model._meta
    335380        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:
    337382                output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
    338383                    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)))
    339386
     387
    340388    app_label = app_models[0]._meta.app_label
    341389
    342390    # Close database connection explicitly, in case this output is being piped
     
    431479def get_sql_indexes_for_model(model):
    432480    "Returns the CREATE INDEX SQL statements for a single model"
    433481    from django.db import backend
     482    from django.db.backends.util import truncate_name
    434483    output = []
    435484
    436485    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):
    438487            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 = ''
    439493            output.append(
    440494                style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
    441495                style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
    442496                style.SQL_KEYWORD('ON') + ' ' + \
    443497                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
    445500            )
    446501    return output
    447502
     
    465520
    466521def syncdb(verbosity=1, interactive=True):
    467522    "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_module
     523    from django.db import backend, connection, transaction, models, get_creation_module
    469524    from django.conf import settings
    470525
    471526    disable_termcolors()
     
    488543    # Get a list of all existing database tables,
    489544    # so we know what needs to be added.
    490545    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
    491550
    492551    # Get a list of already installed *models* so that references work right.
    493552    seen_models = _get_installed_models(table_list)
     
    502561            # Create the model's database table, if it doesn't already exist.
    503562            if verbosity >= 2:
    504563                print "Processing %s.%s model" % (app_name, model._meta.object_name)
    505             if model._meta.db_table in table_list:
     564            if table_name_converter(model._meta.db_table) in table_list:
    506565                continue
    507566            sql, references = _get_sql_model_create(model, seen_models)
    508567            seen_models.add(model)
     
    514573                print "Creating table %s" % model._meta.db_table
    515574            for statement in sql:
    516575                cursor.execute(statement)
    517             table_list.append(model._meta.db_table)
     576            table_list.append(table_name_converter(model._meta.db_table))
    518577
    519578    # Create the m2m tables. This must be done after all tables have been created
    520579    # to ensure that all referred tables will exist.
     
    833892        except NotImplementedError:
    834893            indexes = {}
    835894        for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)):
    836             att_name = row[0]
     895            att_name = row[0].lower()
    837896            comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
    838897            extra_params = {}  # Holds Field parameters such as 'db_column'.
    839898
     
    13261385    # Keep a count of the installed objects and fixtures
    13271386    count = [0,0]
    13281387    models = set()
    1329    
     1388
    13301389    humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
    13311390
    13321391    # Get a cursor (even though we don't need one yet). This has
     
    16301689        if not mod_list:
    16311690            parser.print_usage_and_exit()
    16321691        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())
    16341695        for mod in mod_list:
    16351696            if action == 'reset':
    16361697                output = action_mapping[action](mod, options.interactive)
  • django/contrib/admin/models.py

     
    99
    1010class LogEntryManager(models.Manager):
    1111    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)
    1313        e.save()
    1414
    1515class LogEntry(models.Model):
  • docs/install.txt

     
    6262
    6363* If you're using SQLite, you'll need pysqlite_. Use version 2.0.3 or higher.
    6464
     65* If you're using Oracle, you'll need cx_Oracle_, version 4.3.1 or higher.
     66
    6567.. _PostgreSQL: http://www.postgresql.org/
    6668.. _MySQL: http://www.mysql.com/
    6769.. _Django's ticket system: http://code.djangoproject.com/report/1
     
    7173.. _SQLite: http://www.sqlite.org/
    7274.. _pysqlite: http://initd.org/tracker/pysqlite
    7375.. _MySQL backend: ../databases/
     76.. _cx_Oracle: http://www.python.net/crew/atuining/cx_Oracle/
    7477
    7578Remove any old versions of Django
    7679=================================
  • docs/settings.txt

     
    245245Default: ``''`` (Empty string)
    246246
    247247Which database backend to use. Either ``'postgresql_psycopg2'``,
    248 ``'postgresql'``, ``'mysql'``,  ``'mysql_old'``, ``'sqlite3'`` or
    249 ``'ado_mssql'``.
     248``'postgresql'``, ``'mysql'``,  ``'mysql_old'``, ``'sqlite3'``,
     249``'oracle'``, or ``'ado_mssql'``.
    250250
    251251DATABASE_HOST
    252252-------------
  • docs/model-api.txt

     
    487487possible values for "no data;" Django convention is to use the empty
    488488string, not ``NULL``.
    489489
     490Due to database limitations when using the Oracle backend, the ``null=True``
     491option will be coerced for string-based fields, and the value ``NULL`` will
     492be stored to denote the empty string.
     493
    490494``blank``
    491495~~~~~~~~~
    492496
     
    581585If ``True``, ``django-admin.py sqlindexes`` will output a ``CREATE INDEX``
    582586statement for this field.
    583587
     588``db_tablespace``
     589~~~~~~~~~~~~~~~~~
     590
     591If this field is indexed, the name of the database tablespace to use for the
     592index. The default is the ``db_tablespace`` of the model, if any. If the
     593backend doesn't support tablespaces, this option is ignored.
     594
    584595``default``
    585596~~~~~~~~~~~
    586597
     
    9911002that aren't allowed in Python variable names -- notably, the hyphen --
    9921003that's OK. Django quotes column and table names behind the scenes.
    9931004
     1005``db_tablespace``
     1006-----------------
     1007
     1008The name of the database tablespace to use for the model. If the backend
     1009doesn't support tablespaces, this option is ignored.
     1010
    9941011``get_latest_by``
    9951012-----------------
    9961013
  • docs/faq.txt

     
    301301
    302302If you want to use Django with a database, which is probably the case, you'll
    303303also need a database engine. PostgreSQL_ is recommended, because we're
    304 PostgreSQL fans, and MySQL_ and `SQLite 3`_ are also supported.
     304PostgreSQL fans, and MySQL_, `SQLite 3`_, and Oracle_ are also supported.
    305305
    306306.. _Python: http://www.python.org/
    307307.. _Apache 2: http://httpd.apache.org/
     
    310310.. _PostgreSQL: http://www.postgresql.org/
    311311.. _MySQL: http://www.mysql.com/
    312312.. _`SQLite 3`: http://www.sqlite.org/
     313.. _Oracle: http://www.oracle.com/
    313314
    314315Do I lose anything by using Python 2.3 versus newer Python versions, such as Python 2.5?
    315316----------------------------------------------------------------------------------------
  • 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"""
     21. Simple data types testing.
     3
     4This is a basic model to test saving and loading boolean and date-related
     5types, which in the past were problematic for some database backends.
     6"""
     7
     8from django.db import models
     9
     10class 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
     33False
     34>>> d.has_sprinkles
     35>>> d.has_sprinkles = True
     36>>> d.has_sprinkles
     37True
     38>>> d.save()
     39>>> d2 = Donut.objects.all()[0]
     40>>> d2
     41<Donut: Apple Fritter>
     42>>> d2.is_frosted
     43False
     44>>> d2.has_sprinkles
     45True
     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
     55datetime.date(1938, 6, 4)
     56>>> d3.baked_time
     57datetime.time(5, 30)
     58>>> d3.consumed_at
     59datetime.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
    
     
    131131[('headline', 'Article 7'), ('id', 7)]
    132132[('headline', 'Article 1'), ('id', 1)]
    133133
    134 
    135 # you can use values() even on extra fields
    136 >>> 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 ...     i
    140 [('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 thrown
    149 # 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 
    155134# if you don't specify which fields, all are returned
    156135>>> list(Article.objects.filter(id=5).values()) == [{'id': 5, 'headline': 'Article 5', 'pub_date': datetime(2005, 8, 1, 9, 0)}]
    157136True
  • tests/regressiontests/serializers_regress/tests.py

     
    1414from django.core import serializers
    1515from django.db import transaction
    1616from django.core import management
     17from django.conf import settings
    1718
    1819from models import *
    1920try:
     
    115116    (data_obj, 31, DateTimeData, None),
    116117    (data_obj, 40, EmailData, "hovercraft@example.com"),
    117118    (data_obj, 41, EmailData, None),
     119    (data_obj, 42, EmailData, ""),
    118120    (data_obj, 50, FileData, 'file:///foo/bar/whiz.txt'),
    119121    (data_obj, 51, FileData, None),
     122    (data_obj, 52, FileData, ""),
    120123    (data_obj, 60, FilePathData, "/foo/bar/whiz.txt"),
    121124    (data_obj, 61, FilePathData, None),
     125    (data_obj, 62, FilePathData, ""),
    122126    (data_obj, 70, DecimalData, decimal.Decimal('12.345')),
    123127    (data_obj, 71, DecimalData, decimal.Decimal('-12.345')),
    124128    (data_obj, 72, DecimalData, decimal.Decimal('0.0')),
     
    134138    #(XX, ImageData
    135139    (data_obj, 90, IPAddressData, "127.0.0.1"),
    136140    (data_obj, 91, IPAddressData, None),
     141    (data_obj, 92, IPAddressData, ""),
    137142    (data_obj, 100, NullBooleanData, True),
    138143    (data_obj, 101, NullBooleanData, False),
    139144    (data_obj, 102, NullBooleanData, None),
     
    145150    (data_obj, 131, PositiveSmallIntegerData, None),
    146151    (data_obj, 140, SlugData, "this-is-a-slug"),
    147152    (data_obj, 141, SlugData, None),
     153    (data_obj, 142, SlugData, ""),
    148154    (data_obj, 150, SmallData, 12),
    149155    (data_obj, 151, SmallData, -12),
    150156    (data_obj, 152, SmallData, 0),
     
    159165    (data_obj, 171, TimeData, None),
    160166    (data_obj, 180, USStateData, "MA"),
    161167    (data_obj, 181, USStateData, None),
     168    (data_obj, 182, USStateData, ""),
    162169    (data_obj, 190, XMLData, "<foo></foo>"),
    163170    (data_obj, 191, XMLData, None),
     171    (data_obj, 192, XMLData, ""),
    164172
    165173    (generic_obj, 200, GenericData, ['Generic Object 1', 'tag1', 'tag2']),
    166174    (generic_obj, 201, GenericData, ['Generic Object 2', 'tag2', 'tag3']),
     
    240248#     (pk_obj, 790, XMLPKData, "<foo></foo>"),
    241249]
    242250
     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.
     254if 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
    243260# Dynamically create serializer tests to ensure that all
    244261# registered serializers are automatically tested.
    245262class SerializerTests(unittest.TestCase):
Back to Top