Index: django/contrib/admin/models/admin.py
===================================================================
--- django/contrib/admin/models/admin.py	(revision 2074)
+++ django/contrib/admin/models/admin.py	(working copy)
@@ -6,7 +6,11 @@
     action_time = meta.DateTimeField(_('action time'), auto_now=True)
     user = meta.ForeignKey(auth.User)
     content_type = meta.ForeignKey(core.ContentType, blank=True, null=True)
-    object_id = meta.TextField(_('object id'), blank=True, null=True)
+    # begin JRH see http://code.djangoproject.com/ticket/304
+    # "Changes to auth.LogEntry in changeset [469] breaks Oracle backend."
+    #object_id = meta.TextField(_('object id'), blank=True, null=True)
+    object_id = meta.CharField(_('object id'), maxlength=100, blank=True, null=True)
+    # end JRH
     object_repr = meta.CharField(_('object repr'), maxlength=200)
     action_flag = meta.PositiveSmallIntegerField(_('action flag'))
     change_message = meta.TextField(_('change message'), blank=True)
Index: django/core/db/__init__.py
===================================================================
--- django/core/db/__init__.py	(revision 2074)
+++ django/core/db/__init__.py	(working copy)
@@ -40,3 +40,4 @@
 OPERATOR_MAPPING = dbmod.OPERATOR_MAPPING
 DATA_TYPES = dbmod.DATA_TYPES
 DATA_TYPES_REVERSE = dbmod.DATA_TYPES_REVERSE
+EMPTY_STR_EQUIV = getattr(dbmod,'EMPTY_STR_EQUIV','')
Index: django/core/meta/__init__.py
===================================================================
--- django/core/meta/__init__.py	(revision 2074)
+++ django/core/meta/__init__.py	(working copy)
@@ -995,7 +995,7 @@
     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" % \
+        cursor.execute("SELECT 1 FROM %s WHERE %s=%%s" % \
             (db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column)), [pk_val])
         # If it does already exist, do an UPDATE.
         if cursor.fetchone():
@@ -1120,8 +1120,8 @@
     cache_var = '_%s_cache' % field_with_rel.name
     if not hasattr(self, cache_var):
         mod = rel.get_model_module()
-        sql = "SELECT %s FROM %s a, %s b WHERE a.%s = b.%s AND b.%s = %%s %s" % \
-            (','.join(['a.%s' % db.db.quote_name(f.column) for f in rel.fields]),
+        sql = 'SELECT %s FROM %s "a", %s "b" WHERE "a".%s = "b".%s AND "b".%s = %%s %s' % \
+            (','.join(['"a".%s' % db.db.quote_name(f.column) for f in rel.fields]),
             db.db.quote_name(rel.db_table),
             db.db.quote_name(field_with_rel.get_m2m_db_table(self._meta)),
             db.db.quote_name(rel.pk.column),
@@ -1374,8 +1374,8 @@
     kwargs['select'] = kwargs.get('select', {}).items()
 
     cursor = db.db.cursor()
-    select, sql, params = function_get_sql_clause(opts, **kwargs)
-    cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)
+    select, sql, params, full_query = function_get_sql_clause(opts, **kwargs)
+    cursor.execute(full_query, params)
     fill_cache = kwargs.get('select_related')
     index_end = len(opts.fields)
     while 1:
@@ -1399,7 +1399,7 @@
     kwargs['offset'] = None
     kwargs['limit'] = None
     kwargs['select_related'] = False
-    _, sql, params = function_get_sql_clause(opts, **kwargs)
+    _, sql, params, full_query = function_get_sql_clause(opts, **kwargs)
     cursor = db.db.cursor()
     cursor.execute("SELECT COUNT(*)" + sql, params)
     return cursor.fetchone()[0]
@@ -1416,7 +1416,7 @@
         fields = [f.column for f in opts.fields]
 
     cursor = db.db.cursor()
-    _, sql, params = function_get_sql_clause(opts, **kwargs)
+    _, sql, params, full_query = function_get_sql_clause(opts, **kwargs)
     select = ['%s.%s' % (db.db.quote_name(opts.db_table), db.db.quote_name(f)) for f in fields]
     cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)
     while 1:
@@ -1447,7 +1447,7 @@
             where.append('%s.%s = %s.%s' % \
                 (db.db.quote_name(old_prefix), db.db.quote_name(f.column),
                 db.db.quote_name(db_table), db.db.quote_name(f.rel.get_related_field().column)))
-            select.extend(['%s.%s' % (db.db.quote_name(db_table), db.db.quote_name(f2.column)) for f2 in f.rel.to.fields])
+            select.extend(['%s.%s as "%s.%s"' % (db.db.quote_name(db_table), db.db.quote_name(f2.column), db_table, f2.column) for f2 in f.rel.to.fields])
             _fill_table_cache(f.rel.to, select, tables, where, db_table, cache_tables_seen)
 
 def _throw_bad_kwarg_error(kwarg):
@@ -1639,15 +1639,61 @@
             order_by.append('%s%s %s' % (table_prefix, db.db.quote_name(orderfield2column(col_name, opts)), order))
     order_by = ", ".join(order_by)
 
-    # LIMIT and OFFSET clauses
-    if kwargs.get('limit') is not None:
-        limit_sql = " %s " % db.get_limit_offset_sql(kwargs['limit'], kwargs.get('offset'))
+    sql = " FROM " + ",".join(tables) + (where and " WHERE " + " AND ".join(where) or "") + (order_by and " ORDER BY " + order_by or "")
+
+    if (db.DATABASE_ENGINE != 'oracle'):
+        # LIMIT and OFFSET clauses
+        if kwargs.get('limit') is not None:
+            limit_sql = " %s " % db.get_limit_offset_sql(kwargs['limit'], kwargs.get('offset'))
+        else:
+            assert kwargs.get('offset') is None, "'offset' is not allowed without 'limit'"
+            limit_sql = ""
+
+
+        full_query = "SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql + limit_sql
+        return select, sql + limit_sql, params, full_query
     else:
-        assert kwargs.get('offset') is None, "'offset' is not allowed without 'limit'"
-        limit_sql = ""
+        # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query.
+        
+        select_clause = ",".join(select)
+        distinct = (kwargs.get('distinct') and "DISTINCT " or "")
+        from_clause = ",".join(tables)
+        where_clause = (where and " WHERE " + " AND ".join(where) or "")
+        
+        if order_by:            
+            order_by_clause = " OVER (ORDER BY %s )" % (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)" % \
+                (db.db.quote_name(opts.db_table), 
+                 db.db.quote_name(opts.fields[0].name))
+        
+        # limit_and_offset_clause
+        limit = kwargs.get('limit',0)
+        offset = kwargs.get('offset',0)
+        if offset == None:
+            offset = 0
+        
+        limit_and_offset_clause = ''
+        if limit:
+            limit = int(limit)
+            offset = int(offset)
+            limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset)
+        else:
+            limit_and_offset_clause = "WHERE rn > %s" % (offset)
+                                 
+        full_query = """SELECT * FROM 
+                         (SELECT %s                  
+                          %s,
+                          ROW_NUMBER() %s AS rn
+                          FROM %s
+                          %s
+                         )
+                         %s
+                     """ % (distinct, select_clause, order_by_clause, from_clause, where_clause, limit_and_offset_clause)
+        return select, sql, params, full_query                               
 
-    return select, " FROM " + ",".join(tables) + (where and " WHERE " + " AND ".join(where) or "") + (order_by and " ORDER BY " + order_by or "") + limit_sql, params
-
 def function_get_in_bulk(opts, klass, *args, **kwargs):
     id_list = args and args[0] or kwargs.get('id_list', [])
     assert id_list != [], "get_in_bulk() cannot be passed an empty list."
@@ -1674,7 +1720,7 @@
     if field.null:
         kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \
             (db.db.quote_name(opts.db_table), db.db.quote_name(field.column)))
-    select, sql, params = function_get_sql_clause(opts, **kwargs)
+    select, sql, params, full_query = function_get_sql_clause(opts, **kwargs)
     sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1' % (db.get_date_trunc_sql(kind, '%s.%s' % (db.db.quote_name(opts.db_table), db.db.quote_name(field.column))), sql)
     cursor = db.db.cursor()
     cursor.execute(sql, params)
Index: django/core/meta/fields.py
===================================================================
--- django/core/meta/fields.py	(revision 2074)
+++ django/core/meta/fields.py	(working copy)
@@ -1,4 +1,5 @@
 from django.conf import settings
+from django.core import db
 from django.core import formfields, validators
 from django.core.exceptions import ObjectDoesNotExist
 from django.utils.functional import curry, lazy
@@ -171,6 +172,11 @@
 
     def get_db_prep_save(self, value):
         "Returns field's value prepared for saving into a database."
+        
+        # Oracle treats empty strings ('') the same as NULLs.
+        # To get around this wart, we need to change it to something else...
+        if value == '':
+            value = db.EMPTY_STR_EQUIV
         return value
 
     def get_db_prep_lookup(self, lookup_type, value):
@@ -180,7 +186,12 @@
         elif lookup_type in ('range', 'in'):
             return value
         elif lookup_type == 'year':
-            return ['%s-01-01' % value, '%s-12-31' % value]
+            if settings.DATABASE_ENGINE == 'oracle':              
+                from_dt = datetime.date(int(value), 01, 01)
+                to_dt = datetime.date(int(value), 12, 31)
+                return [from_dt, to_dt]
+            else:            
+                return ['%s-01-01' % value, '%s-12-31' % value]
         elif lookup_type in ('contains', 'icontains'):
             return ["%%%s%%" % prep_for_like_query(value)]
         elif lookup_type == 'iexact':
@@ -368,6 +379,14 @@
         kwargs['blank'] = True
         Field.__init__(self, *args, **kwargs)
 
+    def get_db_prep_lookup(self, lookup_type, value):
+        if settings.DATABASE_ENGINE == 'oracle':
+            if value == 'True':
+                value = 1
+            elif value == 'False':
+                value = 0
+        return Field.get_db_prep_lookup(self, lookup_type, value)
+
     def get_manipulator_field_objs(self):
         return [formfields.CheckboxField]
 
@@ -388,12 +407,30 @@
             kwargs['editable'] = False
             kwargs['blank'] = True
         Field.__init__(self, verbose_name, name, **kwargs)
-
-    def get_db_prep_lookup(self, lookup_type, value):
-        if lookup_type == 'range':
-            value = [str(v) for v in value]
-        else:
-            value = str(value)
+
+    def get_db_prep_lookup(self, lookup_type, 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]
+            #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:
+            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 pre_save(self, value, add):
@@ -411,8 +448,10 @@
     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')
-        return Field.get_db_prep_save(self, value)
+            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):
         return [formfields.DateField]
@@ -423,14 +462,20 @@
 
 class DateTimeField(DateField):
     def get_db_prep_save(self, value):
-        # Casts dates into string format for entry into database.
-        if value is not None:
-            # MySQL will throw a warning if microseconds are given, because it
-            # doesn't support microseconds.
-            if settings.DATABASE_ENGINE == 'mysql':
-                value = value.replace(microsecond=0)
-            value = str(value)
-        return Field.get_db_prep_save(self, value)
+        # Casts dates into string format for entry into database.
+        if value is not None:
+            # MySQL will throw a warning if microseconds are given, because it
+            # doesn't support microseconds.
+            if settings.DATABASE_ENGINE == 'mysql':
+                value = value.replace(microsecond=0)
+                value = str(value)
+            # Oracle will choke if microseconds are given...
+            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):
         return [formfields.DateField, formfields.TimeField]
@@ -629,12 +674,21 @@
         if auto_now or auto_now_add:
             kwargs['editable'] = False
         Field.__init__(self, verbose_name, name, **kwargs)
-
+
     def get_db_prep_lookup(self, lookup_type, value):
-        if lookup_type == 'range':
-            value = [str(v) for v in value]
-        else:
-            value = str(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:
+            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 pre_save(self, value, add):
@@ -645,11 +699,16 @@
     def get_db_prep_save(self, value):
         # Casts dates into string format for entry into database.
         if value is not None:
-            # MySQL will throw a warning if microseconds are given, because it
-            # doesn't support microseconds.
-            if settings.DATABASE_ENGINE == 'mysql':
-                value = value.replace(microsecond=0)
-            value = str(value)
+            # MySQL will throw a warning if microseconds are given, because it
+            # doesn't support microseconds.
+            if settings.DATABASE_ENGINE == 'mysql':
+                value = value.replace(microsecond=0)
+                value = str(value)
+            # Oracle will choke if microseconds are given...
+            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: django/core/management.py
===================================================================
--- django/core/management.py	(revision 2074)
+++ django/core/management.py	(working copy)
@@ -97,6 +97,22 @@
             full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
         full_statement.append(');')
         final_output.append('\n'.join(full_statement))
+        
+        if (db.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'           % db.db.quote_name(opts.db_table) + \
+                '    for each row\n'  + \
+                '      begin\n' + \
+                '        select "%s_sq".NEXTVAL into :new."id" from DUAL;\n' % opts.db_table + \
+                '      end;\n'
+            final_output.append(trigger_statement)
+                                
 
     for klass in mod._MODELS:
         opts = klass._meta
@@ -118,6 +134,20 @@
                 db.db.quote_name(f.rel.to.object_name.lower() + '_id')))
             table_output.append(');')
             final_output.append('\n'.join(table_output))
+            
+            if (db.DATABASE_ENGINE == 'oracle') & (opts.has_auto_field):
+                sequence_statement = 'CREATE SEQUENCE "%s_sq";' % f.get_m2m_db_table(opts)
+                final_output.append(sequence_statement)    
+                                
+                trigger_statement = "" + \
+                    'CREATE OR REPLACE trigger "%s_tr"\n'    % f.get_m2m_db_table(opts) + \
+                    '  before insert on "%s"\n'           % f.get_m2m_db_table(opts) + \
+                    '    for each row\n'  + \
+                    '      begin\n' + \
+                    '        select "%s_sq".NEXTVAL into :new."id" from DUAL;\n' % f.get_m2m_db_table(opts) + \
+                    '      end;\n'
+                final_output.append(trigger_statement) 
+            
     return final_output
 get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given model module name(s)."
 get_sql_create.args = APP_ARGS
@@ -135,7 +165,7 @@
     try:
         if cursor is not None:
             # Check whether the table exists.
-            cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name('django_admin_log'))
+            cursor.execute("SELECT 1 FROM %s" % db.db.quote_name('django_admin_log'))
     except:
         # The table doesn't exist, so it doesn't need to be dropped.
         db.db.rollback()
@@ -150,12 +180,15 @@
         try:
             if cursor is not None:
                 # Check whether the table exists.
-                cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name(klass._meta.db_table))
+                cursor.execute("SELECT 1 FROM %s" % db.db.quote_name(klass._meta.db_table))
         except:
             # The table doesn't exist, so it doesn't need to be dropped.
             db.db.rollback()
         else:
             output.append("DROP TABLE %s;" % db.db.quote_name(klass._meta.db_table))
+            if db.DATABASE_ENGINE == 'oracle':
+                output.append('DROP SEQUENCE "%s_sq";' % klass._meta.db_table)
+                output.append('DROP TRIGGER "%s_tr";' % klass._meta.db_table)
 
     # Output DROP TABLE statements for many-to-many tables.
     for klass in mod._MODELS:
@@ -163,11 +196,14 @@
         for f in opts.many_to_many:
             try:
                 if cursor is not None:
-                    cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name(f.get_m2m_db_table(opts)))
+                    cursor.execute("SELECT 1 FROM %s" % db.db.quote_name(f.get_m2m_db_table(opts)))
             except:
                 db.db.rollback()
             else:
                 output.append("DROP TABLE %s;" % db.db.quote_name(f.get_m2m_db_table(opts)))
+                if db.DATABASE_ENGINE == 'oracle':
+                    output.append('DROP SEQUENCE "%s_sq";' % f.get_m2m_db_table(opts))
+                    output.append('DROP TRIGGER "%s_tr";' % f.get_m2m_db_table(opts))                
 
     app_label = mod._MODELS[0]._meta.app_label
 
@@ -963,7 +999,7 @@
                 addr, port = '', args[1]
         action_mapping[action](addr, port)
     else:
-        from django.core import meta
+        from django.core import meta, db
         if action == 'dbcheck':
             mod_list = meta.get_all_installed_modules()
         else:
@@ -975,13 +1011,15 @@
             if not mod_list:
                 parser.print_usage_and_exit()
         if action not in NO_SQL_TRANSACTION:
-            print "BEGIN;"
+            if db.DATABASE_ENGINE != 'oracle':
+                print "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 "COMMIT;"
+            if db.DATABASE_ENGINE != 'oracle':
+                print "COMMIT;"
 
 def execute_manager(settings_mod):
     # Add this project to sys.path so that it's importable in the conventional
