OracleBranch: django-oracle-rev5036.diff

File django-oracle-rev5036.diff, 87.4 KB (added by ian.g.kelly@…, 8 years ago)

Diff of the Oracle branch at revision 5036

  • django.oracle/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
    55from django.dispatch import dispatcher
    66from django.test import signals
     
    4444        connection.connection.set_isolation_level(0)
    4545
    4646def create_test_db(verbosity=1, autoclobber=False):
     47    # If the database backend wants to create the test DB itself, let it
     48    creation_module = get_creation_module()
     49    if hasattr(creation_module, "create_test_db"):
     50        creation_module.create_test_db(settings, connection, backend, verbosity, autoclobber)
     51        return
     52   
    4753    if verbosity >= 1:
    4854        print "Creating test database..."
    4955    # If we're using SQLite, it's more convenient to test against an
     
    9298    cursor = connection.cursor()
    9399
    94100def destroy_test_db(old_database_name, verbosity=1):
     101    # If the database wants to drop the test DB itself, let it
     102    creation_module = get_creation_module()
     103    if hasattr(creation_module, "destroy_test_db"):
     104        creation_module.destroy_test_db(settings, connection, backend, old_database_name, verbosity)
     105        return
     106   
    95107    # Unless we're using SQLite, remove the test database to clean up after
    96108    # ourselves. Connect to the previous database (not the test database)
    97109    # to do so, because it's not allowed to delete a database while being
  • django.oracle/django/db/models/base.py

     
    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" % \
     213            cursor.execute("SELECT COUNT(*) FROM %s WHERE %s=%%s" % \
    214214                (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val])
    215215            # If it does already exist, do an UPDATE.
    216             if cursor.fetchone():
     216            if cursor.fetchone()[0] > 0:
    217217                db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks]
    218218                if db_values:
    219219                    cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
  • django.oracle/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.oracle/django/db/models/fields/__init__.py

     
    7070        core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True,
    7171        prepopulate_from=None, unique_for_date=None, unique_for_month=None,
    7272        unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
    73         help_text='', db_column=None):
     73        help_text='', db_column=None, db_tablespace=None):
    7474        self.name = name
    7575        self.verbose_name = verbose_name
    7676        self.primary_key = primary_key
     
    8787        self.radio_admin = radio_admin
    8888        self.help_text = help_text
    8989        self.db_column = db_column
     90        self.db_tablespace = db_tablespace
    9091
    9192        # Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
    9293        self.db_index = db_index
     
    161162
    162163    def get_db_prep_save(self, value):
    163164        "Returns field's value prepared for saving into a database."
     165        # Oracle treats empty strings ('') the same as NULLs.
     166        # To get around this wart, we need to change it to something else...
     167        if settings.DATABASE_ENGINE == 'oracle' and value == '':
     168            value = ' '
    164169        return value
    165170
    166171    def get_db_prep_lookup(self, lookup_type, value):
     
    528533    def get_db_prep_save(self, value):
    529534        # Casts dates into string format for entry into database.
    530535        if value is not None:
    531             # MySQL will throw a warning if microseconds are given, because it
    532             # doesn't support microseconds.
    533             if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
     536            # MySQL/Oracle will throw a warning if microseconds are given, because
     537            # neither database supports microseconds.
     538            if settings.DATABASE_ENGINE in ('mysql', 'oracle') and hasattr(value, 'microsecond'):
    534539                value = value.replace(microsecond=0)
    535             value = str(value)
    536540        return Field.get_db_prep_save(self, value)
    537541
    538542    def get_db_prep_lookup(self, lookup_type, value):
     543        # Oracle will throw an error if microseconds are given, because it
     544        # doesn't support microseconds.
     545        if settings.DATABASE_ENGINE == 'oracle' and hasattr(value, 'microsecond'):
     546            value = value.replace(microsecond=0)
    539547        if lookup_type == 'range':
    540548            value = [str(v) for v in value]
    541549        else:
     
    808816        Field.__init__(self, verbose_name, name, **kwargs)
    809817
    810818    def get_db_prep_lookup(self, lookup_type, value):
     819        if settings.DATABASE_ENGINE == 'oracle':
     820            # Oracle requires a date in order to parse.
     821            def prep(value):
     822                if isinstance(value, datetime.time):
     823                    value = datetime.datetime.combine(datetime.date(1900, 1, 1), value)
     824                return str(value)
     825        else:
     826            prep = str
    811827        if lookup_type == 'range':
    812             value = [str(v) for v in value]
     828            value = [prep(v) for v in value]
    813829        else:
    814             value = str(value)
     830            value = prep(value)
    815831        return Field.get_db_prep_lookup(self, lookup_type, value)
    816832
    817833    def pre_save(self, model_instance, add):
     
    827843        if value is not None:
    828844            # MySQL will throw a warning if microseconds are given, because it
    829845            # doesn't support microseconds.
    830             if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
     846            if settings.DATABASE_ENGINE in ('mysql', 'oracle') and hasattr(value, 'microsecond'):
    831847                value = value.replace(microsecond=0)
    832             value = str(value)
     848            if settings.DATABASE_ENGINE == 'oracle':
     849                # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field.
     850                if isinstance(value, datetime.time):
     851                    value = datetime.datetime(1900, 1, 1, value.hour, value.minute, value.second)
     852                elif isinstance(value, basestring):
     853                    value = datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6]))
     854            else:
     855                value = str(value)
    833856        return Field.get_db_prep_save(self, value)
    834857
    835858    def get_manipulator_field_objs(self):
  • django.oracle/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.oracle/django/db/models/query.py

     
    44from django.db.models import signals
    55from django.dispatch import dispatcher
    66from django.utils.datastructures import SortedDict
     7from django.conf import settings
     8import datetime
    79import operator
    810import re
    911
     
    7779    else:
    7880        return backend.quote_name(word)
    7981
    80 class QuerySet(object):
     82class _QuerySet(object):
    8183    "Represents a lazy database lookup for a set of objects"
    8284    def __init__(self, model=None):
    8385        self.model = model
     
    181183
    182184        cursor = connection.cursor()
    183185        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
     186
    184187        fill_cache = self._select_related
    185         index_end = len(self.model._meta.fields)
     188        fields = self.model._meta.fields
     189        index_end = len(fields)
     190        has_resolve_columns = hasattr(self, 'resolve_columns')
    186191        while 1:
    187192            rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
    188193            if not rows:
    189194                raise StopIteration
    190195            for row in rows:
     196                if has_resolve_columns:
     197                    row = self.resolve_columns(row, fields)
    191198                if fill_cache:
    192199                    obj, index_end = get_cached_row(klass=self.model, row=row,
    193200                                                    index_start=0, max_depth=self._max_related_depth)
     
    551558
    552559        return select, " ".join(sql), params
    553560
     561# Use the backend's QuerySet class if it defines one, otherwise use _QuerySet.
     562if hasattr(backend, 'get_query_set_class'):
     563    QuerySet = backend.get_query_set_class(_QuerySet)
     564else:
     565    QuerySet = _QuerySet
     566
    554567class ValuesQuerySet(QuerySet):
    555568    def __init__(self, *args, **kwargs):
    556569        super(ValuesQuerySet, self).__init__(*args, **kwargs)
     
    566579
    567580        # self._fields is a list of field names to fetch.
    568581        if self._fields:
    569             columns = [self.model._meta.get_field(f, many_to_many=False).column for f in self._fields]
    570             field_names = self._fields
     582            fields = [self.model._meta.get_field(f, many_to_many=False) for f in self._fields]
    571583        else: # Default to all fields.
    572             columns = [f.column for f in self.model._meta.fields]
    573             field_names = [f.attname for f in self.model._meta.fields]
     584            fields = self.model._meta.fields
     585        columns = [f.column for f in fields]
     586        field_names = [f.attname for f in fields]
    574587
    575588        select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
    576589        cursor = connection.cursor()
    577590        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
     591
     592        has_resolve_columns = hasattr(self, 'resolve_columns')
    578593        while 1:
    579594            rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
    580595            if not rows:
    581596                raise StopIteration
    582597            for row in rows:
     598                if has_resolve_columns:
     599                    row = self.resolve_columns(row, fields)
    583600                yield dict(zip(field_names, row))
    584601
    585602    def _clone(self, klass=None, **kwargs):
     
    590607class DateQuerySet(QuerySet):
    591608    def iterator(self):
    592609        from django.db.backends.util import typecast_timestamp
     610        from django.db.models.fields import DateTimeField
    593611        self._order_by = () # Clear this because it'll mess things up otherwise.
    594612        if self._field.null:
    595613            self._where.append('%s.%s IS NOT NULL' % \
    596614                (backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
    597 
    598615        try:
    599616            select, sql, params = self._get_sql_clause()
    600617        except EmptyResultSet:
    601618            raise StopIteration
    602619
    603         sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \
     620        table_name = backend.quote_name(self.model._meta.db_table)
     621        field_name = backend.quote_name(self._field.column)
     622
     623        if backend.allows_group_by_ordinal:
     624            group_by = '1'
     625        else:
     626            group_by = backend.get_date_trunc_sql(self._kind,
     627                                                  '%s.%s' % (table_name, field_name))
     628
     629        sql = 'SELECT %s %s GROUP BY %s ORDER BY 1 %s' % \
    604630            (backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table),
    605             backend.quote_name(self._field.column))), sql, self._order)
     631            backend.quote_name(self._field.column))), sql, group_by, self._order)
    606632        cursor = connection.cursor()
    607633        cursor.execute(sql, params)
    608         # We have to manually run typecast_timestamp(str()) on the results, because
    609         # MySQL doesn't automatically cast the result of date functions as datetime
    610         # objects -- MySQL returns the values as strings, instead.
    611         return [typecast_timestamp(str(row[0])) for row in cursor.fetchall()]
    612634
     635        has_resolve_columns = hasattr(self, 'resolve_columns')
     636        needs_datetime_string_cast = backend.needs_datetime_string_cast
     637        dates = []
     638        # It would be better to use self._field here instead of DateTimeField(),
     639        # but in Oracle that will result in a list of datetime.date instead of
     640        # datetime.datetime.
     641        fields = [DateTimeField()]
     642        while 1:
     643            rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
     644            if not rows:
     645                return dates
     646            for row in rows:
     647                date = row[0]
     648                if has_resolve_columns:
     649                    date = self.resolve_columns([date], fields)[0]
     650                elif needs_datetime_string_cast:
     651                    date = typecast_timestamp(str(date))
     652                dates.append(date)
     653
    613654    def _clone(self, klass=None, **kwargs):
    614655        c = super(DateQuerySet, self)._clone(klass, **kwargs)
    615656        c._field = self._field
     
    716757    if table_prefix.endswith('.'):
    717758        table_prefix = backend.quote_name(table_prefix[:-1])+'.'
    718759    field_name = backend.quote_name(field_name)
     760    if type(value) == datetime.datetime and backend.get_datetime_cast_sql():
     761        cast_sql = backend.get_datetime_cast_sql()
     762    else:
     763        cast_sql = '%s'
     764    if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith') and backend.needs_upper_for_iops:
     765        format = 'UPPER(%s%s) %s'
     766    else:
     767        format = '%s%s %s'
    719768    try:
    720         return '%s%s %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s'))
     769        return format % (table_prefix, field_name,
     770                         backend.OPERATOR_MAPPING[lookup_type] % cast_sql)
    721771    except KeyError:
    722772        pass
    723773    if lookup_type == 'in':
  • django.oracle/django/db/backends/ado_mssql/base.py

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

     
    8686        global postgres_version
    8787        if not postgres_version:
    8888            cursor.execute("SELECT version()")
    89             postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]       
     89            postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
    9090        if settings.DEBUG:
    9191            return util.CursorDebugWrapper(cursor, self)
    9292        return cursor
     
    104104            self.connection.close()
    105105            self.connection = None
    106106
     107allows_group_by_ordinal = True
     108allows_unique_and_pk = True
     109autoindexes_primary_keys = True
     110needs_datetime_string_cast = True
     111needs_upper_for_iops = False
    107112supports_constraints = True
     113supports_tablespaces = False
     114uses_case_insensitive_names = False
    108115
    109116def quote_name(name):
    110117    if name.startswith('"') and name.endswith('"'):
     
    137144    # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
    138145    return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
    139146
     147def get_datetime_cast_sql():
     148    return None
     149
    140150def get_limit_offset_sql(limit, offset=None):
    141151    sql = "LIMIT %s" % limit
    142152    if offset and offset != 0:
     
    148158
    149159def get_deferrable_sql():
    150160    return " DEFERRABLE INITIALLY DEFERRED"
    151    
     161
    152162def get_fulltext_search_sql(field_name):
    153163    raise NotImplementedError
    154164
     
    158168def get_pk_default_value():
    159169    return "DEFAULT"
    160170
     171def get_max_name_length():
     172    return None
     173
     174def get_start_transaction_sql():
     175    return "BEGIN;"
     176
     177def get_autoinc_sql(table):
     178    return None
     179
    161180def get_sql_flush(style, tables, sequences):
    162181    """Return a list of SQL statements required to remove all data from
    163182    all tables in the database (without actually removing the tables
    164183    themselves) and put the database in an empty 'initial' state
    165    
    166     """   
     184
     185    """
    167186    if tables:
    168187        if postgres_version[0] >= 8 and postgres_version[1] >= 1:
    169188            # Postgres 8.1+ can do 'TRUNCATE x, y, z...;'. In fact, it *has to* in order to be able to
     
    174193                 style.SQL_FIELD(', '.join([quote_name(table) for table in tables]))
    175194            )]
    176195        else:
    177             # Older versions of Postgres can't do TRUNCATE in a single call, so they must use 
     196            # Older versions of Postgres can't do TRUNCATE in a single call, so they must use
    178197            # a simple delete.
    179198            sql = ['%s %s %s;' % \
    180199                    (style.SQL_KEYWORD('DELETE'),
     
    237256                style.SQL_KEYWORD('FROM'),
    238257                style.SQL_TABLE(f.m2m_db_table())))
    239258    return output
    240        
     259
    241260# Register these custom typecasts, because Django expects dates/times to be
    242261# in Python's native (standard-library) datetime/time format, whereas psycopg
    243262# use mx.DateTime by default.
  • django.oracle/django/db/backends/sqlite3/base.py

     
    9999    def convert_query(self, query, num_params):
    100100        return query % tuple("?" * num_params)
    101101
     102allows_group_by_ordinal = True
     103allows_unique_and_pk = True
     104autoindexes_primary_keys = True
     105needs_datetime_string_cast = True
     106needs_upper_for_iops = False
    102107supports_constraints = False
     108supports_tablespaces = False
     109uses_case_insensitive_names = False
    103110
    104111def quote_name(name):
    105112    if name.startswith('"') and name.endswith('"'):
     
    131138    # sqlite doesn't support DATE_TRUNC, so we fake it as above.
    132139    return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
    133140
     141def get_datetime_cast_sql():
     142    return None
     143
    134144def get_limit_offset_sql(limit, offset=None):
    135145    sql = "LIMIT %s" % limit
    136146    if offset and offset != 0:
     
    152162def get_pk_default_value():
    153163    return "NULL"
    154164
     165def get_max_name_length():
     166    return None
     167
     168def get_start_transaction_sql():
     169    return "BEGIN;"
     170
     171def get_autoinc_sql(table):
     172    return None
     173
    155174def get_sql_flush(style, tables, sequences):
    156175    """Return a list of SQL statements required to remove all data from
    157176    all tables in the database (without actually removing the tables
    158177    themselves) and put the database in an empty 'initial' state
    159    
     178
    160179    """
    161180    # NB: The generated SQL below is specific to SQLite
    162181    # Note: The DELETE FROM... SQL generated below works for SQLite databases
     
    174193    "Returns a list of the SQL statements to reset sequences for the given models."
    175194    # No sequence reset required
    176195    return []
    177    
     196
    178197def _sqlite_date_trunc(lookup_type, dt):
    179198    try:
    180199        dt = util.typecast_timestamp(dt)
  • django.oracle/django/db/backends/util.py

     
    11import datetime
     2import md5
    23from time import time
    34
    45class CursorDebugWrapper(object):
     
    9293def rev_typecast_boolean(obj, d):
    9394    return obj and '1' or '0'
    9495
     96def truncate_name(name, length=None):
     97    """Shortens a string to a repeatable mangled version with the given length.
     98    """
     99    if length is None or len(name) <= length:
     100        return name
     101
     102    hash = md5.md5(name).hexdigest()[:4]
     103
     104    return '%s%s' % (name[:length-4], hash)
     105
    95106##################################################################################
    96107# Helper functions for dictfetch* for databases that don't natively support them #
    97108##################################################################################
  • django.oracle/django/db/backends/mysql/base.py

     
    1515# lexicographic ordering in this check because then (1, 2, 1, 'gamma')
    1616# inadvertently passes the version test.
    1717version = Database.version_info
    18 if (version < (1,2,1) or (version[:3] == (1, 2, 1) and 
     18if (version < (1,2,1) or (version[:3] == (1, 2, 1) and
    1919        (len(version) < 5 or version[3] != 'final' or version[4] < 2))):
    2020    raise ImportError, "MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__
    2121
     
    131131            self.server_version = tuple([int(x) for x in m.groups()])
    132132        return self.server_version
    133133
     134allows_group_by_ordinal = True
     135allows_unique_and_pk = True
     136autoindexes_primary_keys = False
     137needs_datetime_string_cast = True     # MySQLdb requires a typecast for dates
     138needs_upper_for_iops = False
    134139supports_constraints = True
     140supports_tablespaces = False
     141uses_case_insensitive_names = False
    135142
    136143def quote_name(name):
    137144    if name.startswith("`") and name.endswith("`"):
     
    164171        sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
    165172    return sql
    166173
     174def get_datetime_cast_sql():
     175    return None
     176
    167177def get_limit_offset_sql(limit, offset=None):
    168178    sql = "LIMIT "
    169179    if offset and offset != 0:
     
    185195def get_pk_default_value():
    186196    return "DEFAULT"
    187197
     198def get_max_name_length():
     199    return 64;
     200
     201def get_start_transaction_sql():
     202    return "BEGIN;"
     203
     204def get_autoinc_sql(table):
     205    return None
     206
    188207def get_sql_flush(style, tables, sequences):
    189208    """Return a list of SQL statements required to remove all data from
    190209    all tables in the database (without actually removing the tables
    191210    themselves) and put the database in an empty 'initial' state
    192    
     211
    193212    """
    194213    # NB: The generated SQL below is specific to MySQL
    195214    # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
     
    201220                 style.SQL_FIELD(quote_name(table))
    202221                )  for table in tables] + \
    203222              ['SET FOREIGN_KEY_CHECKS = 1;']
    204              
     223
    205224        # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
    206225        # to reset sequence indices
    207226        sql.extend(["%s %s %s %s %s;" % \
  • django.oracle/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
    1519
    1620try:
     
    3034        return self.connection is not None
    3135
    3236    def cursor(self):
    33         from django.conf import settings
    3437        if not self._valid_connection():
    3538            if len(settings.DATABASE_HOST.strip()) == 0:
    3639                settings.DATABASE_HOST = 'localhost'
     
    4043            else:
    4144                conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
    4245                self.connection = Database.connect(conn_string, **self.options)
    43         return FormatStylePlaceholderCursor(self.connection)
     46        cursor = FormatStylePlaceholderCursor(self.connection)
     47        # default arraysize of 1 is highly sub-optimal
     48        cursor.arraysize = 100
     49        # set oracle date to ansi date format
     50        cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'")
     51        cursor.execute("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'")
     52        if settings.DEBUG:
     53            return util.CursorDebugWrapper(cursor, self)
     54        return cursor
    4455
    4556    def _commit(self):
    4657        if self.connection is not None:
    47             self.connection.commit()
     58            return self.connection.commit()
    4859
    4960    def _rollback(self):
    5061        if self.connection is not None:
    51             try:
    52                 self.connection.rollback()
    53             except Database.NotSupportedError:
    54                 pass
     62            return self.connection.rollback()
    5563
    5664    def close(self):
    5765        if self.connection is not None:
    5866            self.connection.close()
    5967            self.connection = None
    6068
     69allows_group_by_ordinal = False
     70allows_unique_and_pk = False        # Suppress UNIQUE/PK for Oracle (ORA-02259)
     71autoindexes_primary_keys = True
     72needs_datetime_string_cast = False
     73needs_upper_for_iops = True
    6174supports_constraints = True
     75supports_tablespaces = True
     76uses_case_insensitive_names = True
    6277
    6378class FormatStylePlaceholderCursor(Database.Cursor):
    6479    """
     
    6681    This fixes it -- but note that if you want to use a literal "%s" in a query,
    6782    you'll need to use "%%s".
    6883    """
     84    def _rewrite_args(self, query, params=None):
     85        if params is None:
     86            params = []
     87        else:
     88            # cx_Oracle can't handle unicode parameters, so cast to str for now
     89            for i, param in enumerate(params):
     90                if type(param) == unicode:
     91                    try:
     92                        params[i] = param.encode('utf-8')
     93                    except UnicodeError:
     94                        params[i] = str(param)
     95        args = [(':arg%d' % i) for i in range(len(params))]
     96        query = query % tuple(args)
     97        # cx_Oracle cannot execute a query with the closing ';'
     98        if query.endswith(';'):
     99            query = query[:-1]
     100        return query, params
     101
    69102    def execute(self, query, params=None):
    70         if params is None: params = []
    71         query = self.convert_arguments(query, len(params))
     103        query, params = self._rewrite_args(query, params)
    72104        return Database.Cursor.execute(self, query, params)
    73105
    74106    def executemany(self, query, params=None):
    75         if params is None: params = []
    76         query = self.convert_arguments(query, len(params[0]))
     107        query, params = self._rewrite_args(query, params)
    77108        return Database.Cursor.executemany(self, query, params)
    78109
    79     def convert_arguments(self, query, num_params):
    80         # replace occurances of "%s" with ":arg" - Oracle requires colons for parameter placeholders.
    81         args = [':arg' for i in range(num_params)]
    82         return query % tuple(args)
    83 
    84110def quote_name(name):
    85     return name
     111    # SQL92 requires delimited (quoted) names to be case-sensitive.  When
     112    # not quoted, Oracle has case-insensitive behavior for identifiers, but
     113    # always defaults to uppercase.
     114    # We simplify things by making Oracle identifiers always uppercase.
     115    if not name.startswith('"') and not name.endswith('"'):
     116        name = '"%s"' % util.truncate_name(name.upper(), get_max_name_length())
     117    return name.upper()
    86118
    87119dictfetchone = util.dictfetchone
    88120dictfetchmany = util.dictfetchmany
    89121dictfetchall  = util.dictfetchall
    90122
    91123def get_last_insert_id(cursor, table_name, pk_name):
    92     query = "SELECT %s_sq.currval from dual" % table_name
    93     cursor.execute(query)
     124    sq_name = util.truncate_name(table_name, get_max_name_length()-3)
     125    cursor.execute('SELECT %s_sq.currval FROM dual' % sq_name)
    94126    return cursor.fetchone()[0]
    95127
    96128def get_date_extract_sql(lookup_type, table_name):
    97129    # lookup_type is 'year', 'month', 'day'
    98     # http://www.psoug.org/reference/date_func.html
     130    # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163
    99131    return "EXTRACT(%s FROM %s)" % (lookup_type, table_name)
    100132
    101133def get_date_trunc_sql(lookup_type, field_name):
    102     return "EXTRACT(%s FROM TRUNC(%s))" % (lookup_type, field_name)
     134    # lookup_type is 'year', 'month', 'day'
     135    # Oracle uses TRUNC() for both dates and numbers.
     136    # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions155a.htm#SQLRF06151
     137    if lookup_type == 'day':
     138        sql = 'TRUNC(%s)' % (field_name,)
     139    else:
     140        sql = "TRUNC(%s, '%s')" % (field_name, lookup_type)
     141    return sql
    103142
     143def get_datetime_cast_sql():
     144    return "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS')"
     145
    104146def get_limit_offset_sql(limit, offset=None):
    105147    # Limits and offset are too complicated to be handled here.
    106     # Instead, they are handled in django/db/query.py.
    107     pass
     148    # Instead, they are handled in django/db/backends/oracle/query.py.
     149    return ""
    108150
    109151def get_random_function_sql():
    110152    return "DBMS_RANDOM.RANDOM"
     
    116158    raise NotImplementedError
    117159
    118160def get_drop_foreignkey_sql():
    119     return "DROP FOREIGN KEY"
     161    return "DROP CONSTRAINT"
    120162
    121163def get_pk_default_value():
    122164    return "DEFAULT"
    123165
     166def get_max_name_length():
     167    return 30
     168
     169def get_start_transaction_sql():
     170    return None
     171
     172def get_tablespace_sql(tablespace, inline=False):
     173    return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), quote_name(tablespace))
     174
     175def get_autoinc_sql(table):
     176    # To simulate auto-incrementing primary keys in Oracle, we have to
     177    # create a sequence and a trigger.
     178    sq_name = get_sequence_name(table)
     179    tr_name = get_trigger_name(table)
     180    sequence_sql = 'CREATE SEQUENCE %s;' % sq_name
     181    trigger_sql = """CREATE OR REPLACE TRIGGER %s
     182  BEFORE INSERT ON %s
     183  FOR EACH ROW
     184  WHEN (new.id IS NULL)
     185    BEGIN
     186      SELECT %s.nextval INTO :new.id FROM dual;
     187    END;\n""" % (tr_name, quote_name(table), sq_name)
     188    return sequence_sql, trigger_sql
     189
     190def get_drop_sequence(table):
     191    return "DROP SEQUENCE %s;" % quote_name(get_sequence_name(table))
     192
     193def _get_sequence_reset_sql():
     194    # TODO: colorize this SQL code with style.SQL_KEYWORD(), etc.
     195    return """
     196        DECLARE
     197            startvalue integer;
     198            cval integer;
     199        BEGIN
     200            LOCK TABLE %(table)s IN SHARE MODE;
     201            SELECT NVL(MAX(id), 0) INTO startvalue FROM %(table)s;
     202            SELECT %(sequence)s.nextval INTO cval FROM dual;
     203            cval := startvalue - cval;
     204            IF cval != 0 THEN
     205                EXECUTE IMMEDIATE 'ALTER SEQUENCE %(sequence)s MINVALUE 0 INCREMENT BY '||cval;
     206                SELECT %(sequence)s.nextval INTO cval FROM dual;
     207                EXECUTE IMMEDIATE 'ALTER SEQUENCE %(sequence)s INCREMENT BY 1';
     208            END IF;
     209            COMMIT;
     210        END;\n"""
     211
    124212def get_sql_flush(style, tables, sequences):
    125213    """Return a list of SQL statements required to remove all data from
    126214    all tables in the database (without actually removing the tables
    127215    themselves) and put the database in an empty 'initial' state
    128216    """
    129     # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
    130     # TODO - SQL not actually tested against Oracle yet!
    131     # TODO - autoincrement indices reset required? See other get_sql_flush() implementations
    132     sql = ['%s %s;' % \
    133             (style.SQL_KEYWORD('TRUNCATE'),
    134              style.SQL_FIELD(quote_name(table))
    135              )  for table in tables]
     217    # Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
     218    # 'TRUNCATE z;'... style SQL statements
     219    if tables:
     220        # Oracle does support TRUNCATE, but it seems to get us into
     221        # FK referential trouble, whereas DELETE FROM table works.
     222        sql = ['%s %s %s;' % \
     223                (style.SQL_KEYWORD('DELETE'),
     224                 style.SQL_KEYWORD('FROM'),
     225                 style.SQL_FIELD(quote_name(table))
     226                 ) for table in tables]
     227        # Since we've just deleted all the rows, running our sequence
     228        # ALTER code will reset the sequence to 0.
     229        for sequence_info in sequences:
     230            table_name = sequence_info['table']
     231            seq_name = get_sequence_name(table_name)
     232            query = _get_sequence_reset_sql() % {'sequence':seq_name,
     233                                                 'table':quote_name(table_name)}
     234            sql.append(query)
     235        return sql
     236    else:
     237        return []
    136238
     239def get_sequence_name(table):
     240    name_length = get_max_name_length() - 3
     241    return '%s_SQ' % util.truncate_name(table, name_length).upper()
     242
    137243def get_sql_sequence_reset(style, model_list):
    138244    "Returns a list of the SQL statements to reset sequences for the given models."
    139     # No sequence reset required
    140     return []
     245    from django.db import models
     246    output = []
     247    query = _get_sequence_reset_sql()
     248    for model in model_list:
     249        for f in model._meta.fields:
     250            if isinstance(f, models.AutoField):
     251                sequence_name = get_sequence_name(model._meta.db_table)
     252                output.append(query % {'sequence':sequence_name,
     253                                       'table':model._meta.db_table})
     254                break # Only one AutoField is allowed per model, so don't bother continuing.
     255        for f in model._meta.many_to_many:
     256            sequence_name = get_sequence_name(f.m2m_db_table())
     257            output.append(query % {'sequence':sequence_name,
     258                                   'table':f.m2m_db_table()})
     259    return output
    141260
     261def get_trigger_name(table):
     262    name_length = get_max_name_length() - 3
     263    return '%s_TR' % util.truncate_name(table, name_length).upper()
     264
     265def get_query_set_class(DefaultQuerySet):
     266    "Create a custom QuerySet class for Oracle."
     267
     268    from django.db import backend, connection
     269    from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE
     270
     271    class OracleQuerySet(DefaultQuerySet):
     272
     273        def iterator(self):
     274            "Performs the SELECT database lookup of this QuerySet."
     275
     276            from django.db.models.query import get_cached_row
     277
     278            # self._select is a dictionary, and dictionaries' key order is
     279            # undefined, so we convert it to a list of tuples.
     280            extra_select = self._select.items()
     281
     282            full_query = None
     283
     284            try:
     285                try:
     286                    select, sql, params, full_query = self._get_sql_clause(get_full_query=True)
     287                except TypeError:
     288                    select, sql, params = self._get_sql_clause()
     289            except EmptyResultSet:
     290                raise StopIteration
     291            if not full_query:
     292                full_query = "SELECT %s%s\n%s" % \
     293                             ((self._distinct and "DISTINCT " or ""),
     294                              ', '.join(select), sql)
     295
     296            cursor = connection.cursor()
     297            cursor.execute(full_query, params)
     298
     299            fill_cache = self._select_related
     300            fields = self.model._meta.fields
     301            index_end = len(fields)
     302
     303            # so here's the logic;
     304            # 1. retrieve each row in turn
     305            # 2. convert NCLOBs
     306
     307            while 1:
     308                rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
     309                if not rows:
     310                    raise StopIteration
     311                for row in rows:
     312                    row = self.resolve_columns(row, fields)
     313                    if fill_cache:
     314                        obj, index_end = get_cached_row(klass=self.model, row=row,
     315                                                        index_start=0, max_depth=self._max_related_depth)
     316                    else:
     317                        obj = self.model(*row[:index_end])
     318                    for i, k in enumerate(extra_select):
     319                        setattr(obj, k[0], row[index_end+i])
     320                    yield obj
     321
     322
     323        def _get_sql_clause(self, get_full_query=False):
     324            from django.db.models.query import fill_table_cache, \
     325                handle_legacy_orderlist, orderfield2column
     326
     327            opts = self.model._meta
     328
     329            # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
     330            select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields]
     331            tables = [quote_only_if_word(t) for t in self._tables]
     332            joins = SortedDict()
     333            where = self._where[:]
     334            params = self._params[:]
     335
     336            # Convert self._filters into SQL.
     337            joins2, where2, params2 = self._filters.get_sql(opts)
     338            joins.update(joins2)
     339            where.extend(where2)
     340            params.extend(params2)
     341
     342            # Add additional tables and WHERE clauses based on select_related.
     343            if self._select_related:
     344                fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table])
     345
     346            # Add any additional SELECTs.
     347            if self._select:
     348                select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()])
     349
     350            # Start composing the body of the SQL statement.
     351            sql = [" FROM", backend.quote_name(opts.db_table)]
     352
     353            # Compose the join dictionary into SQL describing the joins.
     354            if joins:
     355                sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition)
     356                                for (alias, (table, join_type, condition)) in joins.items()]))
     357
     358            # Compose the tables clause into SQL.
     359            if tables:
     360                sql.append(", " + ", ".join(tables))
     361
     362            # Compose the where clause into SQL.
     363            if where:
     364                sql.append(where and "WHERE " + " AND ".join(where))
     365
     366            # ORDER BY clause
     367            order_by = []
     368            if self._order_by is not None:
     369                ordering_to_use = self._order_by
     370            else:
     371                ordering_to_use = opts.ordering
     372            for f in handle_legacy_orderlist(ordering_to_use):
     373                if f == '?': # Special case.
     374                    order_by.append(backend.get_random_function_sql())
     375                else:
     376                    if f.startswith('-'):
     377                        col_name = f[1:]
     378                        order = "DESC"
     379                    else:
     380                        col_name = f
     381                        order = "ASC"
     382                    if "." in col_name:
     383                        table_prefix, col_name = col_name.split('.', 1)
     384                        table_prefix = backend.quote_name(table_prefix) + '.'
     385                    else:
     386                        # Use the database table as a column prefix if it wasn't given,
     387                        # and if the requested column isn't a custom SELECT.
     388                        if "." not in col_name and col_name not in (self._select or ()):
     389                            table_prefix = backend.quote_name(opts.db_table) + '.'
     390                        else:
     391                            table_prefix = ''
     392                    order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order))
     393            if order_by:
     394                sql.append("ORDER BY " + ", ".join(order_by))
     395
     396            # Look for column name collisions in the select elements
     397            # and fix them with an AS alias.  This allows us to do a
     398            # SELECT * later in the paging query.
     399            cols = [clause.split('.')[-1] for clause in select]
     400            for index, col in enumerate(cols):
     401                if cols.count(col) > 1:
     402                    col = '%s%d' % (col.replace('"', ''), index)
     403                    cols[index] = col
     404                    select[index] = '%s AS %s' % (select[index], col)
     405
     406            # LIMIT and OFFSET clauses
     407            # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query.
     408            select_clause = ",".join(select)
     409            distinct = (self._distinct and "DISTINCT " or "")
     410
     411            if order_by:
     412                order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by))
     413            else:
     414                #Oracle's row_number() function always requires an order-by clause.
     415                #So we need to define a default order-by, since none was provided.
     416                order_by_clause = " OVER (ORDER BY %s.%s)" % \
     417                    (backend.quote_name(opts.db_table),
     418                    backend.quote_name(opts.fields[0].db_column or opts.fields[0].column))
     419            # limit_and_offset_clause
     420            if self._limit is None:
     421                assert self._offset is None, "'offset' is not allowed without 'limit'"
     422
     423            if self._offset is not None:
     424                offset = int(self._offset)
     425            else:
     426                offset = 0
     427            if self._limit is not None:
     428                limit = int(self._limit)
     429            else:
     430                limit = None
     431
     432            limit_and_offset_clause = ''
     433            if limit is not None:
     434                limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset)
     435            elif offset:
     436                limit_and_offset_clause = "WHERE rn > %s" % (offset)
     437
     438            if len(limit_and_offset_clause) > 0:
     439                fmt = \
     440"""SELECT * FROM
     441  (SELECT %s%s,
     442          ROW_NUMBER()%s AS rn
     443   %s)
     444%s"""
     445                full_query = fmt % (distinct, select_clause,
     446                                    order_by_clause, ' '.join(sql).strip(),
     447                                    limit_and_offset_clause)
     448            else:
     449                full_query = None
     450
     451            if get_full_query:
     452                return select, " ".join(sql), params, full_query
     453            else:
     454                return select, " ".join(sql), params
     455
     456        def resolve_columns(self, row, fields=()):
     457            from django.db.models.fields import DateField, DateTimeField, TimeField
     458            values = []
     459            for value, field in map(None, row, fields):
     460                if isinstance(value, Database.LOB):
     461                    value = value.read()
     462                # Since Oracle won't distinguish between NULL and an empty
     463                # string (''), we store empty strings as a space.  Here is
     464                # where we undo that treachery.
     465                if value == ' ':
     466                    value = ''
     467                # cx_Oracle always returns datetime.datetime objects for
     468                # DATE and TIMESTAMP columns, but Django wants to see a
     469                # python datetime.date, .time, or .datetime.  We use the type
     470                # of the Field to determine which to cast to, but it's not
     471                # always available.
     472                # As a workaround, we cast to date if all the time-related
     473                # values are 0, or to time if the date is 1/1/1900.
     474                # This could be cleaned a bit by adding a method to the Field
     475                # classes to normalize values from the database (the to_python
     476                # method is used for validation and isn't what we want here).
     477                elif isinstance(value, Database.Timestamp):
     478                    # In Python 2.3, the cx_Oracle driver returns its own
     479                    # Timestamp object that we must convert to a datetime class.
     480                    if not isinstance(value, datetime.datetime):
     481                        value = datetime.datetime(value.year, value.month, value.day, value.hour,
     482                                                  value.minute, value.second, value.fsecond)
     483                    if isinstance(field, DateTimeField):
     484                        pass  # DateTimeField subclasses DateField so must be checked first.
     485                    elif isinstance(field, DateField):
     486                        value = value.date()
     487                    elif isinstance(field, TimeField) or (value.year == 1900 and value.month == value.day == 1):
     488                        value = value.time()
     489                    elif value.hour == value.minute == value.second == value.microsecond == 0:
     490                        value = value.date()
     491                values.append(value)
     492            return values
     493
     494    return OracleQuerySet
     495
     496
    142497OPERATOR_MAPPING = {
    143498    'exact': '= %s',
    144     'iexact': 'LIKE %s',
    145     'contains': 'LIKE %s',
    146     'icontains': 'LIKE %s',
     499    'iexact': '= UPPER(%s)',
     500    'contains': "LIKE %s ESCAPE '\\'",
     501    'icontains': "LIKE UPPER(%s) ESCAPE '\\'",
    147502    'gt': '> %s',
    148503    'gte': '>= %s',
    149504    'lt': '< %s',
    150505    'lte': '<= %s',
    151     'startswith': 'LIKE %s',
    152     'endswith': 'LIKE %s',
    153     'istartswith': 'LIKE %s',
    154     'iendswith': 'LIKE %s',
     506    'startswith': "LIKE %s ESCAPE '\\'",
     507    'endswith': "LIKE %s ESCAPE '\\'",
     508    'istartswith': "LIKE UPPER(%s) ESCAPE '\\'",
     509    'iendswith': "LIKE UPPER(%s) ESCAPE '\\'",
    155510}
  • django.oracle/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.oracle/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: 'FloatField',
     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: 'FloatField',
     96    cx_Oracle.STRING: 'TextField',
     97    cx_Oracle.TIMESTAMP: 'DateTimeField',
    5098}
  • django.oracle/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     'FileField':         'varchar2(100)',
    9     'FilePathField':     'varchar2(100)',
    10     'FloatField':        'number(%(max_digits)s, %(decimal_places)s)',
    11     'ImageField':        'varchar2(100)',
    12     'IntegerField':      'integer',
    13     'IPAddressField':    'char(15)',
    14     'ManyToManyField':   None,
    15     'NullBooleanField':  'integer',
    16     'OneToOneField':     'integer',
    17     'PhoneNumberField':  'varchar(20)',
    18     'PositiveIntegerField': 'integer',
    19     'PositiveSmallIntegerField': 'smallint',
    20     'SlugField':         'varchar(50)',
    21     'SmallIntegerField': 'smallint',
    22     'TextField':         'long',
    23     'TimeField':         'timestamp',
    24     'USStateField':      'varchar(2)',
     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    'FileField':                    'VARCHAR2(100)',
     16    'FilePathField':                'VARCHAR2(100)',
     17    'FloatField':                   'NUMBER(%(max_digits)s, %(decimal_places)s)',
     18    'ImageField':                   'VARCHAR2(100)',
     19    'IntegerField':                 'NUMBER(11)',
     20    'IPAddressField':               'VARCHAR2(15)',
     21    'ManyToManyField':              None,
     22    'NullBooleanField':             'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))',
     23    'OneToOneField':                'NUMBER(11)',
     24    'PhoneNumberField':             'VARCHAR2(20)',
     25    'PositiveIntegerField':         'NUMBER(11) CHECK (%(column)s >= 0)',
     26    'PositiveSmallIntegerField':    'NUMBER(11) CHECK (%(column)s >= 0)',
     27    'SlugField':                    'VARCHAR2(50)',
     28    'SmallIntegerField':            'NUMBER(11)',
     29    'TextField':                    'NCLOB',
     30    'TimeField':                    'TIMESTAMP',
     31    'URLField':                     'VARCHAR2(200)',
     32    'USStateField':                 'CHAR(2)',
    2533}
     34
     35TEST_DATABASE_PREFIX = 'test_'
     36PASSWORD = 'Im_a_lumberjack'
     37REMEMBER = {}
     38
     39
     40def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False):
     41
     42    TEST_DATABASE_NAME = _test_database_name(settings)
     43    TEST_DATABASE_USER = _test_database_user(settings)
     44    TEST_DATABASE_PASSWD = _test_database_passwd(settings)
     45    TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings)
     46    TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings)
     47
     48    parameters = {
     49        'dbname': TEST_DATABASE_NAME,
     50        'user': TEST_DATABASE_USER,
     51        'password': TEST_DATABASE_PASSWD,
     52        'tblspace': TEST_DATABASE_TBLSPACE,
     53        'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP,
     54        }
     55
     56    REMEMBER['user'] = settings.DATABASE_USER
     57    REMEMBER['passwd'] = settings.DATABASE_PASSWORD
     58
     59    cursor = connection.cursor()
     60    if _test_database_create(settings):
     61        if verbosity >= 1:
     62            print 'Creating test database...'
     63        try:
     64            _create_test_db(cursor, parameters, verbosity)
     65        except Exception, e:
     66            sys.stderr.write("Got an error creating the test database: %s\n" % e)
     67            if not autoclobber:
     68                confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)
     69            if autoclobber or confirm == 'yes':
     70                try:
     71                    if verbosity >= 1:
     72                        print "Destroying old test database..."
     73                    _destroy_test_db(cursor, parameters, verbosity)
     74                    if verbosity >= 1:
     75                        print "Creating test database..."
     76                    _create_test_db(cursor, parameters, verbosity)
     77                except Exception, e:
     78                    sys.stderr.write("Got an error recreating the test database: %s\n" % e)
     79                    sys.exit(2)
     80            else:
     81                print "Tests cancelled."
     82                sys.exit(1)
     83
     84    if _test_user_create(settings):
     85        if verbosity >= 1:
     86            print "Creating test user..."
     87        try:
     88            _create_test_user(cursor, parameters, verbosity)
     89        except Exception, e:
     90            sys.stderr.write("Got an error creating the test user: %s\n" % e)
     91            if not autoclobber:
     92                confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER)
     93            if autoclobber or confirm == 'yes':
     94                try:
     95                    if verbosity >= 1:
     96                        print "Destroying old test user..."
     97                    _destroy_test_user(cursor, parameters, verbosity)
     98                    if verbosity >= 1:
     99                        print "Creating test user..."
     100                    _create_test_user(cursor, parameters, verbosity)
     101                except Exception, e:
     102                    sys.stderr.write("Got an error recreating the test user: %s\n" % e)
     103                    sys.exit(2)
     104            else:
     105                print "Tests cancelled."
     106                sys.exit(1)
     107
     108    connection.close()
     109    settings.DATABASE_USER = TEST_DATABASE_USER
     110    settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD
     111
     112    management.syncdb(verbosity, interactive=False)
     113
     114    # Get a cursor (even though we don't need one yet). This has
     115    # the side effect of initializing the test database.
     116    cursor = connection.cursor()
     117
     118
     119def destroy_test_db(settings, connection, backend, old_database_name, verbosity=1):
     120    connection.close()
     121
     122    TEST_DATABASE_NAME = _test_database_name(settings)
     123    TEST_DATABASE_USER = _test_database_user(settings)
     124    TEST_DATABASE_PASSWD = _test_database_passwd(settings)
     125    TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings)
     126    TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings)
     127
     128    settings.DATABASE_NAME = old_database_name
     129    settings.DATABASE_USER = REMEMBER['user']
     130    settings.DATABASE_PASSWORD = REMEMBER['passwd']
     131
     132    parameters = {
     133        'dbname': TEST_DATABASE_NAME,
     134        'user': TEST_DATABASE_USER,
     135        'password': TEST_DATABASE_PASSWD,
     136        'tblspace': TEST_DATABASE_TBLSPACE,
     137        'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP,
     138        }
     139
     140    REMEMBER['user'] = settings.DATABASE_USER
     141    REMEMBER['passwd'] = settings.DATABASE_PASSWORD
     142
     143    cursor = connection.cursor()
     144    time.sleep(1) # To avoid "database is being accessed by other users" errors.
     145    if _test_user_create(settings):
     146        if verbosity >= 1:
     147            print 'Destroying test user...'
     148        _destroy_test_user(cursor, parameters, verbosity)
     149    if _test_database_create(settings):
     150        if verbosity >= 1:
     151            print 'Destroying test database...'
     152        _destroy_test_db(cursor, parameters, verbosity)
     153    connection.close()
     154
     155
     156def _create_test_db(cursor, parameters, verbosity):
     157    if verbosity >= 2:
     158        print "_create_test_db(): dbname = %s" % parameters['dbname']
     159    statements = [
     160        """CREATE TABLESPACE %(tblspace)s
     161           DATAFILE '%(tblspace)s.dbf' SIZE 20M
     162           REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M
     163        """,
     164        """CREATE TEMPORARY TABLESPACE %(tblspace_temp)s
     165           TEMPFILE '%(tblspace_temp)s.dbf' SIZE 20M
     166           REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M
     167        """,
     168    ]
     169    _execute_statements(cursor, statements, parameters, verbosity)
     170
     171
     172def _create_test_user(cursor, parameters, verbosity):
     173    if verbosity >= 2:
     174        print "_create_test_user(): username = %s" % parameters['user']
     175    statements = [
     176        """CREATE USER %(user)s
     177           IDENTIFIED BY %(password)s
     178           DEFAULT TABLESPACE %(tblspace)s
     179           TEMPORARY TABLESPACE %(tblspace_temp)s
     180        """,
     181        """GRANT CONNECT, RESOURCE TO %(user)s""",
     182    ]
     183    _execute_statements(cursor, statements, parameters, verbosity)
     184
     185
     186def _destroy_test_db(cursor, parameters, verbosity):
     187    if verbosity >= 2:
     188        print "_destroy_test_db(): dbname=%s" % parameters['dbname']
     189    statements = [
     190        'DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS',
     191        'DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS',
     192        ]
     193    _execute_statements(cursor, statements, parameters, verbosity)
     194
     195
     196def _destroy_test_user(cursor, parameters, verbosity):
     197    if verbosity >= 2:
     198        print "_destroy_test_user(): user=%s" % parameters['user']
     199        print "Be patient.  This can take some time..."
     200    statements = [
     201        'DROP USER %(user)s CASCADE',
     202    ]
     203    _execute_statements(cursor, statements, parameters, verbosity)
     204
     205
     206def _execute_statements(cursor, statements, parameters, verbosity):
     207    for template in statements:
     208        stmt = template % parameters
     209        if verbosity >= 2:
     210            print stmt
     211        try:
     212            cursor.execute(stmt)
     213        except Exception, err:
     214            sys.stderr.write("Failed (%s)\n" % (err))
     215            raise
     216
     217
     218def _test_database_name(settings):
     219    name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
     220    try:
     221        if settings.TEST_DATABASE_NAME:
     222            name = settings.TEST_DATABASE_NAME
     223    except AttributeError:
     224        pass
     225    except:
     226        raise
     227    return name
     228
     229
     230def _test_database_create(settings):
     231    name = True
     232    try:
     233        if settings.TEST_DATABASE_CREATE:
     234            name = True
     235        else:
     236            name = False
     237    except AttributeError:
     238        pass
     239    except:
     240        raise
     241    return name
     242
     243
     244def _test_user_create(settings):
     245    name = True
     246    try:
     247        if settings.TEST_USER_CREATE:
     248            name = True
     249        else:
     250            name = False
     251    except AttributeError:
     252        pass
     253    except:
     254        raise
     255    return name
     256
     257
     258def _test_database_user(settings):
     259    name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
     260    try:
     261        if settings.TEST_DATABASE_USER:
     262            name = settings.TEST_DATABASE_USER
     263    except AttributeError:
     264        pass
     265    except:
     266        raise
     267    return name
     268
     269
     270def _test_database_passwd(settings):
     271    name = PASSWORD
     272    try:
     273        if settings.TEST_DATABASE_PASSWD:
     274            name = settings.TEST_DATABASE_PASSWD
     275    except AttributeError:
     276        pass
     277    except:
     278        raise
     279    return name
     280
     281
     282def _test_database_tblspace(settings):
     283    name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
     284    try:
     285        if settings.TEST_DATABASE_TBLSPACE:
     286            name = settings.TEST_DATABASE_TBLSPACE
     287    except AttributeError:
     288        pass
     289    except:
     290        raise
     291    return name
     292
     293
     294def _test_database_tblspace_tmp(settings):
     295    name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp'
     296    try:
     297        if settings.TEST_DATABASE_TBLSPACE_TMP:
     298            name = settings.TEST_DATABASE_TBLSPACE_TMP
     299    except AttributeError:
     300        pass
     301    except:
     302        raise
     303    return name
  • django.oracle/django/db/backends/postgresql_psycopg2/base.py

     
    5454        global postgres_version
    5555        if not postgres_version:
    5656            cursor.execute("SELECT version()")
    57             postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]       
     57            postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]
    5858        if settings.DEBUG:
    5959            return util.CursorDebugWrapper(cursor, self)
    6060        return cursor
     
    7272            self.connection.close()
    7373            self.connection = None
    7474
     75allows_group_by_ordinal = True
     76allows_unique_and_pk = True
     77autoindexes_primary_keys = True
     78needs_datetime_string_cast = False
     79needs_upper_for_iops = False
    7580supports_constraints = True
     81supports_tablespaces = False
     82uses_case_insensitive_names = True
    7683
    7784def quote_name(name):
    7885    if name.startswith('"') and name.endswith('"'):
     
    97104    # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
    98105    return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
    99106
     107def get_datetime_cast_sql():
     108    return None
     109
    100110def get_limit_offset_sql(limit, offset=None):
    101111    sql = "LIMIT %s" % limit
    102112    if offset and offset != 0:
     
    118128def get_pk_default_value():
    119129    return "DEFAULT"
    120130
     131def get_max_name_length():
     132    return None
     133
     134def get_start_transaction_sql():
     135    return "BEGIN;"
     136
     137def get_autoinc_sql(table):
     138    return None
     139
    121140def get_sql_flush(style, tables, sequences):
    122141    """Return a list of SQL statements required to remove all data from
    123142    all tables in the database (without actually removing the tables
     
    138157                     style.SQL_KEYWORD('FROM'),
    139158                     style.SQL_FIELD(quote_name(table))
    140159                     ) for table in tables]
    141                      
     160
    142161        # 'ALTER SEQUENCE sequence_name RESTART WITH 1;'... style SQL statements
    143162        # to reset sequence indices
    144163        for sequence in sequences:
     
    194213                style.SQL_KEYWORD('FROM'),
    195214                style.SQL_TABLE(f.m2m_db_table())))
    196215    return output
    197        
     216
    198217OPERATOR_MAPPING = {
    199218    'exact': '= %s',
    200219    'iexact': 'ILIKE %s',
  • django.oracle/django/db/backends/dummy/base.py

     
    2727        pass # close()
    2828
    2929supports_constraints = False
     30supports_tablespaces = False
    3031quote_name = complain
    3132dictfetchone = complain
    3233dictfetchmany = complain
  • django.oracle/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:
     
    173178            rel_field = f
    174179            data_type = f.get_internal_type()
    175180        col_type = data_types[data_type]
     181        tablespace = f.db_tablespace or opts.db_tablespace
    176182        if col_type is not None:
    177183            # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
    178184            field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
    179185                style.SQL_COLTYPE(col_type % rel_field.__dict__)]
    180186            field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
    181             if f.unique:
     187            if f.unique and (not f.primary_key or backend.allows_unique_and_pk):
    182188                field_output.append(style.SQL_KEYWORD('UNIQUE'))
    183189            if f.primary_key:
    184190                field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
     191            if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys:
     192                # We must specify the index tablespace inline, because we
     193                # won't be generating a CREATE INDEX statement for this field.
     194                field_output.append(backend.get_tablespace_sql(tablespace, inline=True))
    185195            if f.rel:
    186196                if f.rel.to in known_models:
    187197                    field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
     
    205215    full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(backend.quote_name(opts.db_table)) + ' (']
    206216    for i, line in enumerate(table_output): # Combine and add commas.
    207217        full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
    208     full_statement.append(');')
     218    full_statement.append(')')
     219    if opts.db_tablespace and backend.supports_tablespaces:
     220        full_statement.append(backend.get_tablespace_sql(opts.db_tablespace))
     221    full_statement.append(';')
    209222    final_output.append('\n'.join(full_statement))
    210223
     224    if opts.has_auto_field and hasattr(backend, 'get_autoinc_sql'):
     225        # Add any extra SQL needed to support auto-incrementing primary keys
     226        autoinc_sql = backend.get_autoinc_sql(opts.db_table)
     227        if autoinc_sql:
     228            for stmt in autoinc_sql:
     229                final_output.append(stmt)
     230
    211231    return final_output, pending_references
    212232
    213233def _get_sql_for_pending_references(model, pending_references):
     
    215235    Get any ALTER TABLE statements to add constraints after the fact.
    216236    """
    217237    from django.db import backend, get_creation_module
     238    from django.db.backends.util import truncate_name
    218239    data_types = get_creation_module().DATA_TYPES
    219240
    220241    final_output = []
     
    227248                r_col = f.column
    228249                table = opts.db_table
    229250                col = opts.get_field(f.rel.field_name).column
    230                 # For MySQL, r_name must be unique in the first 64 characters.
    231                 # So we are careful with character usage here.
    232                 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
     251                r_name = '%s_refs_%s_%s_%s' % (r_col, col, r_table, table)
    233252                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
    234                     (backend.quote_name(r_table), r_name,
     253                    (backend.quote_name(r_table), truncate_name(r_name, backend.get_max_name_length()),
    235254                    backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col),
    236255                    backend.get_deferrable_sql()))
    237256            del pending_references[model]
     
    247266    final_output = []
    248267    for f in opts.many_to_many:
    249268        if not isinstance(f.rel, GenericRel):
     269            tablespace = f.db_tablespace or opts.db_tablespace
     270            if tablespace and backend.supports_tablespaces and backend.autoindexes_primary_keys:
     271                tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace, inline=True)
     272            else:
     273                tablespace_sql = ''
    250274            table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
    251275                style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
    252             table_output.append('    %s %s %s,' % \
     276            table_output.append('    %s %s %s%s,' % \
    253277                (style.SQL_FIELD(backend.quote_name('id')),
    254278                style.SQL_COLTYPE(data_types['AutoField']),
    255                 style.SQL_KEYWORD('NOT NULL PRIMARY KEY')))
     279                style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
     280                tablespace_sql))
    256281            table_output.append('    %s %s %s %s (%s)%s,' % \
    257282                (style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
    258283                style.SQL_COLTYPE(data_types[get_rel_data_type(opts.pk)] % opts.pk.__dict__),
     
    267292                style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
    268293                style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)),
    269294                backend.get_deferrable_sql()))
    270             table_output.append('    %s (%s, %s)' % \
     295            table_output.append('    %s (%s, %s)%s' % \
    271296                (style.SQL_KEYWORD('UNIQUE'),
    272297                style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
    273                 style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name()))))
    274             table_output.append(');')
     298                style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
     299                tablespace_sql))
     300            table_output.append(')')
     301            if opts.db_tablespace and backend.supports_tablespaces:
     302                # f.db_tablespace is only for indices, so ignore its value here.
     303                table_output.append(backend.get_tablespace_sql(opts.db_tablespace))
     304            table_output.append(';')
    275305            final_output.append('\n'.join(table_output))
     306
     307            # Add any extra SQL needed to support auto-incrementing PKs
     308            autoinc_sql = backend.get_autoinc_sql(f.m2m_db_table())
     309            if autoinc_sql:
     310                for stmt in autoinc_sql:
     311                    final_output.append(stmt)
     312
    276313    return final_output
    277314
    278315def get_sql_delete(app):
    279316    "Returns a list of the DROP TABLE SQL statements for the given app."
    280317    from django.db import backend, connection, models, get_introspection_module
     318    from django.db.backends.util import truncate_name
    281319    introspection = get_introspection_module()
    282320
    283321    # This should work even if a connection isn't available
     
    291329        table_names = introspection.get_table_list(cursor)
    292330    else:
    293331        table_names = []
     332    if backend.uses_case_insensitive_names:
     333        table_name_converter = str.upper
     334    else:
     335        table_name_converter = lambda x: x
    294336
    295337    output = []
    296338
     
    300342    references_to_delete = {}
    301343    app_models = models.get_models(app)
    302344    for model in app_models:
    303         if cursor and model._meta.db_table in table_names:
     345        if cursor and table_name_converter(model._meta.db_table) in table_names:
    304346            # The table exists, so it needs to be dropped
    305347            opts = model._meta
    306348            for f in opts.fields:
     
    310352            to_delete.add(model)
    311353
    312354    for model in app_models:
    313         if cursor and model._meta.db_table in table_names:
     355        if cursor and table_name_converter(model._meta.db_table) in table_names:
    314356            # Drop the table now
    315357            output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
    316358                style.SQL_TABLE(backend.quote_name(model._meta.db_table))))
     
    320362                    col = f.column
    321363                    r_table = model._meta.db_table
    322364                    r_col = model._meta.get_field(f.rel.field_name).column
     365                    r_name = '%s_refs_%s_%s_%s' % (col, r_col, table, r_table)
    323366                    output.append('%s %s %s %s;' % \
    324367                        (style.SQL_KEYWORD('ALTER TABLE'),
    325368                        style.SQL_TABLE(backend.quote_name(table)),
    326369                        style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()),
    327                         style.SQL_FIELD(backend.quote_name('%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))))))
     370                        style.SQL_FIELD(truncate_name(r_name, backend.get_max_name_length()))))
    328371                del references_to_delete[model]
     372            if hasattr(backend, 'get_drop_sequence'):
     373                output.append(backend.get_drop_sequence(model._meta.db_table))
    329374
    330375    # Output DROP TABLE statements for many-to-many tables.
    331376    for model in app_models:
    332377        opts = model._meta
    333378        for f in opts.many_to_many:
    334             if cursor and f.m2m_db_table() in table_names:
     379            if cursor and table_name_converter(f.m2m_db_table()) in table_names:
    335380                output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
    336381                    style.SQL_TABLE(backend.quote_name(f.m2m_db_table()))))
     382                if hasattr(backend, 'get_drop_sequence'):
     383                    output.append(backend.get_drop_sequence("%s_%s" % (model._meta.db_table, f.column)))
    337384
     385
    338386    app_label = app_models[0]._meta.app_label
    339387
    340388    # Close database connection explicitly, in case this output is being piped
     
    429477def get_sql_indexes_for_model(model):
    430478    "Returns the CREATE INDEX SQL statements for a single model"
    431479    from django.db import backend
     480    from django.db.backends.util import truncate_name
    432481    output = []
    433482
    434483    for f in model._meta.fields:
    435         if f.db_index:
     484        if f.db_index and not ((f.primary_key or f.unique) and backend.autoindexes_primary_keys):
    436485            unique = f.unique and 'UNIQUE ' or ''
     486            tablespace = f.db_tablespace or model._meta.db_tablespace
     487            if tablespace and backend.supports_tablespaces:
     488                tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace)
     489            else:
     490                tablespace_sql = ''
    437491            output.append(
    438492                style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
    439493                style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
    440494                style.SQL_KEYWORD('ON') + ' ' + \
    441495                style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
    442                 "(%s);" % style.SQL_FIELD(backend.quote_name(f.column))
     496                "(%s)" % style.SQL_FIELD(backend.quote_name(f.column)) + \
     497                "%s;" % tablespace_sql
    443498            )
    444499    return output
    445500
     
    463518
    464519def syncdb(verbosity=1, interactive=True):
    465520    "Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
    466     from django.db import connection, transaction, models, get_creation_module
     521    from django.db import backend, connection, transaction, models, get_creation_module
    467522    from django.conf import settings
    468523
    469524    disable_termcolors()
     
    486541    # Get a list of all existing database tables,
    487542    # so we know what needs to be added.
    488543    table_list = _get_table_list()
     544    if backend.uses_case_insensitive_names:
     545        table_name_converter = str.upper
     546    else:
     547        table_name_converter = lambda x: x
    489548
    490549    # Get a list of already installed *models* so that references work right.
    491550    seen_models = _get_installed_models(table_list)
     
    500559            # Create the model's database table, if it doesn't already exist.
    501560            if verbosity >= 2:
    502561                print "Processing %s.%s model" % (app_name, model._meta.object_name)
    503             if model._meta.db_table in table_list:
     562            if table_name_converter(model._meta.db_table) in table_list:
    504563                continue
    505564            sql, references = _get_sql_model_create(model, seen_models)
    506565            seen_models.add(model)
     
    512571                print "Creating table %s" % model._meta.db_table
    513572            for statement in sql:
    514573                cursor.execute(statement)
    515             table_list.append(model._meta.db_table)
     574            table_list.append(table_name_converter(model._meta.db_table))
    516575
    517576    # Create the m2m tables. This must be done after all tables have been created
    518577    # to ensure that all referred tables will exist.
     
    830889        except NotImplementedError:
    831890            indexes = {}
    832891        for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)):
    833             att_name = row[0]
     892            att_name = row[0].lower()
    834893            comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
    835894            extra_params = {}  # Holds Field parameters such as 'db_column'.
    836895
     
    13211380    # Keep a count of the installed objects and fixtures
    13221381    count = [0,0]
    13231382    models = set()
    1324    
     1383
    13251384    humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
    13261385
    13271386    # Get a cursor (even though we don't need one yet). This has
     
    16211680        if not mod_list:
    16221681            parser.print_usage_and_exit()
    16231682        if action not in NO_SQL_TRANSACTION:
    1624             print style.SQL_KEYWORD("BEGIN;")
     1683            from django.db import backend
     1684            if backend.get_start_transaction_sql():
     1685                print style.SQL_KEYWORD(backend.get_start_transaction_sql())
    16251686        for mod in mod_list:
    16261687            if action == 'reset':
    16271688                output = action_mapping[action](mod, options.interactive)
  • django.oracle/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):
  • django.oracle/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=================================
  • django.oracle/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-------------
  • django.oracle/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----------------------------------------------------------------------------------------
Back to Top