Index: db/models/base.py
===================================================================
--- db/models/base.py	(revision 2977)
+++ db/models/base.py	(working copy)
@@ -157,8 +157,9 @@
         record_exists = True
         if pk_set:
             # Determine whether a record with the primary key already exists.
-            cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % \
-                (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val])
+            lim = settings.DATABASE_ENGINE != 'oracle' and ' LIMIT 1' or ''
+            cursor.execute("SELECT 1 FROM %s WHERE %s=%%s %s" % \
+                (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column), lim), [pk_val])
             # If it does already exist, do an UPDATE.
             if cursor.fetchone():
                 db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.attname), False)) for f in non_pks]
Index: db/models/fields/__init__.py
===================================================================
--- db/models/fields/__init__.py	(revision 2977)
+++ db/models/fields/__init__.py	(working copy)
@@ -409,12 +409,29 @@
         return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3])
 
     def get_db_prep_lookup(self, lookup_type, value):
-        if lookup_type == 'range':
-            value = [str(v) for v in value]
-        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne'):
-            value = value.strftime('%Y-%m-%d')
+        # Oracle driver can deal with datetime.time objects natively 
+        # and doesn't need to convert to string
+        if settings.DATABASE_ENGINE == 'oracle':        
+            if lookup_type == 'range':
+                value = [str(v) for v in value]
+            #elif lookup_type == 'day':
+            #    value = int(value)
+            elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne'):
+                if type(value) == str:
+                    pattern = r'^\d\d\d\d-\d\d-\d\d$' # "YYYY-MM-DD"
+                    from re import search
+                    if search(pattern, value) != None:
+                        year, month, day = map(int, value.split('-'))
+                        value = datetime.date(year, month, day)
+            else:
+                value = value
         else:
-            value = str(value)
+            if lookup_type == 'range':
+                value = [str(v) for v in value]
+            elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne'):
+                value = value.strftime('%Y-%m-%d')
+            else:
+                value = str(value)
         return Field.get_db_prep_lookup(self, lookup_type, value)
 
     def pre_save(self, value, add):
@@ -440,7 +457,9 @@
     def get_db_prep_save(self, value):
         # Casts dates into string format for entry into database.
         if value is not None:
-            value = value.strftime('%Y-%m-%d')
+            if settings.DATABASE_ENGINE != 'oracle':
+                #Oracle does not need a string conversion
+                value = value.strftime('%Y-%m-%d')
         return Field.get_db_prep_save(self, value)
 
     def get_manipulator_field_objs(self):
@@ -473,15 +492,25 @@
             # MySQL will throw a warning if microseconds are given, because it
             # doesn't support microseconds.
             if settings.DATABASE_ENGINE == 'mysql':
+                value = str(value.replace(microsecond=0))
+            # Oracle will choke if microseconds are given...
+            elif settings.DATABASE_ENGINE == 'oracle':
                 value = value.replace(microsecond=0)
-            value = str(value)
         return Field.get_db_prep_save(self, value)
 
     def get_db_prep_lookup(self, lookup_type, value):
-        if lookup_type == 'range':
-            value = [str(v) for v in value]
+        # Oracle driver can deal with datetime.time objects natively 
+        # and doesn't need to convert to string
+        if settings.DATABASE_ENGINE == 'oracle':        
+            if lookup_type == 'range':
+                value = [v for v in value]
+            else:
+                value = value
         else:
-            value = str(value)
+            if lookup_type == 'range':
+                value = [str(v) for v in value]
+            else:
+                value = str(value)
         return Field.get_db_prep_lookup(self, lookup_type, value)
 
     def get_manipulator_field_objs(self):
@@ -735,7 +764,11 @@
             # doesn't support microseconds.
             if settings.DATABASE_ENGINE == 'mysql':
                 value = value.replace(microsecond=0)
-            value = str(value)
+                value = str(value)
+            elif settings.DATABASE_ENGINE == 'oracle':
+                value = value.replace(microsecond=0)
+            else:
+                value = str(value)
         return Field.get_db_prep_save(self, value)
 
     def get_manipulator_field_objs(self):
Index: db/models/query.py
===================================================================
--- db/models/query.py	(revision 2977)
+++ db/models/query.py	(working copy)
@@ -3,6 +3,7 @@
 from django.db.models import signals
 from django.dispatch import dispatcher
 from django.utils.datastructures import SortedDict
+from django.conf import settings
 
 import operator
 
@@ -156,8 +157,11 @@
         extra_select = self._select.items()
 
         cursor = connection.cursor()
-        select, sql, params = self._get_sql_clause()
-        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
+        select, sql, params, full_query = self._get_sql_clause()
+        if not full_query:
+            cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
+        else:
+            cursor.execute(full_query, params)
         fill_cache = self._select_related
         index_end = len(self.model._meta.fields)
         while 1:
@@ -180,7 +184,7 @@
         counter._offset = None
         counter._limit = None
         counter._select_related = False
-        select, sql, params = counter._get_sql_clause()
+        select, sql, params, full_query = counter._get_sql_clause()
         cursor = connection.cursor()
         if self._distinct:
             id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table),
@@ -455,14 +459,55 @@
         if order_by:
             sql.append("ORDER BY " + ", ".join(order_by))
 
-        # LIMIT and OFFSET clauses
-        if self._limit is not None:
-            sql.append("%s " % backend.get_limit_offset_sql(self._limit, self._offset))
+        
+        
+        if (settings.DATABASE_ENGINE != 'oracle'):
+            # LIMIT and OFFSET clauses
+            if self._limit is not None:
+                sql.append("%s " % backend.get_limit_offset_sql(self._limit, self._offset))
+            else:
+                assert self._offset is None, "'offset' is not allowed without 'limit'"
+    
+            return select, " ".join(sql), params, None
+
         else:
-            assert self._offset is None, "'offset' is not allowed without 'limit'"
+            # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query.
+            select_clause = ",".join(select)
+            distinct = (self._distinct and "DISTINCT " or "")
+            
+            if order_by:            
+                order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by))
+            else:
+                #Oracle's row_number() function always requires an order-by clause.
+                #So we need to define a default order-by, since none was provided.
+                order_by_clause = " OVER (ORDER BY %s.%s)" % \
+                    (backend.quote_name(opts.db_table), 
+                     backend.quote_name(opts.fields[0].db_column or opts.fields[0].column))
+            
+            # limit_and_offset_clause
+            offset = self._offset and int(self._offset) or 0
+            limit = self._limit and int(self._limit) or None
+            limit_and_offset_clause = ''
+            if limit:
+                limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset)
+            elif offset:
+                limit_and_offset_clause = "WHERE rn > %s" % (offset)
+            
+            if len(limit_and_offset_clause) > 0:
+                full_query = """SELECT * FROM 
+                             (SELECT %s                  
+                              %s,
+                              ROW_NUMBER() %s AS rn
+                              %s
+                             )
+                             %s
+                         """ % (distinct, select_clause, order_by_clause, " ".join(sql), limit_and_offset_clause)
+            else:
+                 full_query = None
+            
+            return select, " ".join(sql), params, full_query                               
 
-        return select, " ".join(sql), params
-
+        
 class ValuesQuerySet(QuerySet):
     def iterator(self):
         # select_related and select aren't supported in values().
@@ -478,7 +523,7 @@
             field_names = [f.attname for f in self.model._meta.fields]
 
         cursor = connection.cursor()
-        select, sql, params = self._get_sql_clause()
+        select, sql, params, full_query = self._get_sql_clause()
         select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns]
         cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
         while 1:
@@ -500,7 +545,7 @@
         if self._field.null:
             self._where.append('%s.%s IS NOT NULL' % \
                 (backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column)))
-        select, sql, params = self._get_sql_clause()
+        select, sql, params, full_query = self._get_sql_clause()
         sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \
             (backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table),
             backend.quote_name(self._field.column))), sql, self._order)
@@ -589,6 +634,11 @@
     if table_prefix.endswith('.'):
         table_prefix = backend.quote_name(table_prefix[:-1])+'.'
     field_name = backend.quote_name(field_name)
+    
+    #put some oracle exceptions here
+    if lookup_type == "icontains" and settings.DATABASE_ENGINE == 'oracle':
+        return 'lower(%s%s) %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s'))
+    
     try:
         return '%s%s %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s'))
     except KeyError:
@@ -618,6 +668,7 @@
     Helper function that recursively populates the select, tables and where (in
     place) for fill-cache queries.
     """
+    from django.db.models.fields import AutoField
     for f in opts.fields:
         if f.rel and not f.null:
             db_table = f.rel.to._meta.db_table
@@ -631,7 +682,10 @@
             where.append('%s.%s = %s.%s' % \
                 (backend.quote_name(old_prefix), backend.quote_name(f.column),
                 backend.quote_name(db_table), backend.quote_name(f.rel.get_related_field().column)))
-            select.extend(['%s.%s' % (backend.quote_name(db_table), backend.quote_name(f2.column)) for f2 in f.rel.to._meta.fields])
+            if settings.DATABASE_ENGINE == 'oracle':
+                select.extend(['%s.%s' % (backend.quote_name(db_table), backend.quote_name(f2.column)) for f2 in f.rel.to._meta.fields if not isinstance(f2, AutoField)])
+            else:
+                select.extend(['%s.%s' % (backend.quote_name(db_table), backend.quote_name(f2.column)) for f2 in f.rel.to._meta.fields])
             fill_table_cache(f.rel.to._meta, select, tables, where, db_table, cache_tables_seen)
 
 def parse_lookup(kwarg_items, opts):
Index: core/management.py
===================================================================
--- core/management.py	(revision 2977)
+++ core/management.py	(working copy)
@@ -6,6 +6,7 @@
 import os, re, shutil, sys, textwrap
 from optparse import OptionParser
 from django.utils import termcolors
+from django.conf import settings
 
 # For Python 2.3
 if not hasattr(__builtins__, 'set'):
@@ -83,7 +84,7 @@
 
 def get_sql_create(app):
     "Returns a list of the CREATE TABLE SQL statements for the given app."
-    from django.db import get_creation_module, models
+    from django.db import get_creation_module, models, backend
     data_types = get_creation_module().DATA_TYPES
 
     if not data_types:
@@ -110,7 +111,23 @@
         final_output.extend(_get_sql_for_pending_references(klass, pending_references))
         # Keep track of the fact that we've created the table for this model.
         models_output.add(klass)
-
+        
+        opts = klass._meta
+        if (settings.DATABASE_ENGINE == 'oracle') & (opts.has_auto_field):
+            # To simulate auto-incrementing primary keys in Oracle
+            sequence_statement = 'CREATE SEQUENCE %s_sq;' % opts.db_table
+            final_output.append(sequence_statement)
+            trigger_statement = '' + \
+                'CREATE OR REPLACE trigger %s_tr\n'    % opts.db_table + \
+                '  before insert on %s\n'           % backend.quote_name(opts.db_table) + \
+                '    for each row\n'  + \
+                '      when (new.id is NULL)\n' + \
+                '        begin\n' + \
+                '         select %s_sq.NEXTVAL into :new.id from DUAL;\n' % opts.db_table + \
+                '      end;\n'  + \
+                '      /'
+            final_output.append(trigger_statement)
+        
     # Create the many-to-many join tables.
     for klass in app_models:
         final_output.extend(_get_many_to_many_sql_for_model(klass))
@@ -1202,13 +1219,15 @@
         if not mod_list:
             parser.print_usage_and_exit()
         if action not in NO_SQL_TRANSACTION:
-            print style.SQL_KEYWORD("BEGIN;")
+            if settings.DATABASE_ENGINE != 'oracle':
+                print style.SQL_KEYWORD("BEGIN;")
         for mod in mod_list:
             output = action_mapping[action](mod)
             if output:
                 print '\n'.join(output)
         if action not in NO_SQL_TRANSACTION:
-            print style.SQL_KEYWORD("COMMIT;")
+            if settings.DATABASE_ENGINE != 'oracle':
+                print style.SQL_KEYWORD("COMMIT;")
 
 def execute_manager(settings_mod):
     # Add this project to sys.path so that it's importable in the conventional
Index: contrib/admin/models.py
===================================================================
--- contrib/admin/models.py	(revision 2977)
+++ contrib/admin/models.py	(working copy)
@@ -16,7 +16,9 @@
     action_time = models.DateTimeField(_('action time'), auto_now=True)
     user = models.ForeignKey(User)
     content_type = models.ForeignKey(ContentType, blank=True, null=True)
-    object_id = models.TextField(_('object id'), blank=True, null=True)
+    #changed for Oracle support
+    object_id = models.CharField(_('object id'), maxlength=200, blank=True, null=True)
+#    object_id = models.TextField(_('object id'), blank=True, null=True)
     object_repr = models.CharField(_('object repr'), maxlength=200)
     action_flag = models.PositiveSmallIntegerField(_('action flag'))
     change_message = models.TextField(_('change message'), blank=True)
