Index: django/db/models/base.py
===================================================================
--- django/db/models/base.py	(revision 6654)
+++ django/db/models/base.py	(working copy)
@@ -241,7 +241,10 @@
             db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]
             # If the PK has been manually set, respect that.
             if pk_set:
-                field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)]
+                if connection.features.quote_autofields:
+                    field_names += [qn(f.column) for f in self._meta.fields if isinstance(f, AutoField)]
+                else:
+                    field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)]
                 db_values += [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
             placeholders = ['%s'] * len(field_names)
             if self._meta.order_with_respect_to:
Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py	(revision 6654)
+++ django/db/models/fields/__init__.py	(working copy)
@@ -148,9 +148,18 @@
         data_types = get_creation_module().DATA_TYPES
         internal_type = self.get_internal_type()
         if internal_type not in data_types:
-            return None
+            return None    
         return data_types[internal_type] % self.__dict__
-
+    
+    def db_type_check(self):
+        creation_module = get_creation_module() 
+        if hasattr(creation_module, 'DATA_TYPE_CHECKS'):
+            internal_type = self.get_internal_type()
+            data_checks = creation_module.DATA_TYPE_CHECKS
+            if internal_type in data_checks:
+                return data_checks[internal_type] % self.__dict__
+        return None
+    
     def validate_full(self, field_data, all_data):
         """
         Returns a list of errors for this field. This is the main interface,
@@ -208,16 +217,21 @@
         return value
 
     def get_db_prep_lookup(self, lookup_type, value):
+        from django.db import connection
         "Returns field's value prepared for database lookup."
         if lookup_type in ('exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 'lte', 'month', 'day', 'search'):
             return [value]
         elif lookup_type in ('range', 'in'):
             return value
         elif lookup_type in ('contains', 'icontains'):
+            if connection.features.uses_custom_icontains and lookup_type == 'icontains':
+                return [value]    
             return ["%%%s%%" % prep_for_like_query(value)]
         elif lookup_type == 'iexact':
             return [prep_for_like_query(value)]
         elif lookup_type in ('startswith', 'istartswith'):
+            if connection.features.uses_custom_startswith:
+                return [value]
             return ["%s%%" % prep_for_like_query(value)]
         elif lookup_type in ('endswith', 'iendswith'):
             return ["%%%s" % prep_for_like_query(value)]
@@ -589,7 +603,9 @@
             # doesn't support microseconds.
             if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
                 value = value.replace(microsecond=0)
-            value = smart_unicode(value)
+            #Firebird supports native datetime
+            if settings.DATABASE_ENGINE != 'firebird':
+                value = smart_unicode(value)
         return Field.get_db_prep_save(self, value)
 
     def get_db_prep_lookup(self, lookup_type, value):
@@ -997,8 +1013,8 @@
             # doesn't support microseconds.
             if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
                 value = value.replace(microsecond=0)
-            if settings.DATABASE_ENGINE == 'oracle':
-                # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field.
+            if settings.DATABASE_ENGINE in ('oracle', 'firebird'):
+                # cx_Oracle and kinterbasdb expect a datetime.datetime to persist into TIMESTAMP field.
                 if isinstance(value, datetime.time):
                     value = datetime.datetime(1900, 1, 1, value.hour, value.minute,
                                               value.second, value.microsecond)
Index: django/db/models/fields/related.py
===================================================================
--- django/db/models/fields/related.py	(revision 6654)
+++ django/db/models/fields/related.py	(working copy)
@@ -331,17 +331,18 @@
                         new_ids.add(obj)
                 # Add the newly created or already existing objects to the join table.
                 # First find out which items are already added, to avoid adding them twice
+                qn = connection.ops.quote_name
                 cursor = connection.cursor()
                 cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \
-                    (target_col_name, self.join_table, source_col_name,
-                    target_col_name, ",".join(['%s'] * len(new_ids))),
+                    (qn(target_col_name), qn(self.join_table), qn(source_col_name),
+                    qn(target_col_name), ",".join(['%s'] * len(new_ids))),
                     [self._pk_val] + list(new_ids))
                 existing_ids = set([row[0] for row in cursor.fetchall()])
 
                 # Add the ones that aren't there already
                 for obj_id in (new_ids - existing_ids):
                     cursor.execute("INSERT INTO %s (%s, %s) VALUES (%%s, %%s)" % \
-                        (self.join_table, source_col_name, target_col_name),
+                        (qn(self.join_table), qn(source_col_name), qn(target_col_name)),
                         [self._pk_val, obj_id])
                 transaction.commit_unless_managed()
 
Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py	(revision 6654)
+++ django/db/models/query.py	(working copy)
@@ -1111,7 +1111,9 @@
             # Last query term was a normal field.
             column = field.column
             db_type = field.db_type()
-
+        if settings.DATABASE_ENGINE == 'firebird':
+            current_table = qn(current_table)
+            column = qn(column)   
         where.append(get_where_clause(lookup_type, current_table + '.', column, value, db_type))
         params.extend(field.get_db_prep_lookup(lookup_type, value))
 
@@ -1146,6 +1148,8 @@
             if isinstance(f, generic.GenericRelation):
                 from django.contrib.contenttypes.models import ContentType
                 query_extra = 'AND %s=%%s' % f.rel.to._meta.get_field(f.content_type_field_name).column
+                if settings.DATABASE_ENGINE == 'firebird':
+                    query_extra = 'AND %s=%%s' % qn(f.rel.to._meta.get_field(f.content_type_field_name).column)
                 args_extra = [ContentType.objects.get_for_model(cls).id]
             else:
                 query_extra = ''
Index: django/db/backends/__init__.py
===================================================================
--- django/db/backends/__init__.py	(revision 6654)
+++ django/db/backends/__init__.py	(working copy)
@@ -45,10 +45,14 @@
     autoindexes_primary_keys = True
     inline_fk_references = True
     needs_datetime_string_cast = True
+    needs_default_null = False
     needs_upper_for_iops = False
     supports_constraints = True
     supports_tablespaces = False
+    quote_autofields = False
     uses_case_insensitive_names = False
+    uses_custom_icontains = False
+    uses_custom_startswith = False
     uses_custom_queryset = False
 
 class BaseDatabaseOperations(object):
@@ -65,7 +69,14 @@
         This SQL is executed when a table is created.
         """
         return None
-
+    
+    def cascade_delete_update_sql(self):
+        """
+        Returns the SQL necessary to make a cascading deletes and updates
+        of foreign key references during a CREATE TABLE statement.
+        """
+        return ''
+    
     def date_extract_sql(self, lookup_type, field_name):
         """
         Given a lookup_type of 'year', 'month' or 'day', returns the SQL that
Index: django/db/backends/firebird/base.py
===================================================================
--- django/db/backends/firebird/base.py	(revision 0)
+++ django/db/backends/firebird/base.py	(revision 0)
@@ -0,0 +1,595 @@
+"""
+Firebird database backend for Django.
+
+Requires KInterbasDB 3.2: http://kinterbasdb.sourceforge.net/
+The egenix mx (mx.DateTime) is NOT required
+
+Database charset should be UNICODE_FSS or UTF8 (FireBird 2.0+)
+To use UTF8 encoding add FIREBIRD_CHARSET = 'UTF8' to your settings.py 
+UNICODE_FSS works with all versions and uses less memory
+"""
+
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
+
+try:
+    import kinterbasdb as Database
+except ImportError, e:
+    from django.core.exceptions import ImproperlyConfigured
+    raise ImproperlyConfigured, "Error loading KInterbasDB module: %s" % e
+
+DatabaseError = Database.DatabaseError
+IntegrityError = Database.IntegrityError
+
+class DatabaseFeatures(BaseDatabaseFeatures):
+    needs_datetime_string_cast = False
+    needs_default_null = True
+    needs_upper_for_iops = True
+    quote_autofields = True
+    supports_constraints = False #some tests went strange without it
+    uses_custom_icontains = True #CONTAINING <value> op instead of LIKE %<value>%
+    uses_custom_startswith = True #STARTING WITH op. Faster than LIKE
+    uses_custom_queryset = True
+
+class DatabaseOperations(BaseDatabaseOperations):
+    _max_name_length = 27
+    def __init__(self):
+        self._firebird_version = None
+        self._page_size = None
+    
+    def get_generator_name(self, name):
+        return '%s_G' % util.truncate_name(name, self._max_name_length-2).upper()
+        
+    def get_trigger_name(self, name):
+        return '%s_T' % util.truncate_name(name, self._max_name_length-2).upper() 
+    
+    def _get_firebird_version(self):
+        if self._firebird_version is None:
+            from django.db import connection
+            self._firebird_version = [int(val) for val in connection.server_version.split()[-1].split('.')]
+        return self._firebird_version
+    firebird_version = property(_get_firebird_version)
+  
+    def _get_page_size(self):
+        if self._page_size is None:
+            from django.db import connection
+            self._page_size = connection.database_info(Database.isc_info_page_size, 'i')
+            return self._page_size
+    page_size = property(_get_page_size)
+    
+    def _get_index_limit(self):
+        if self.firebird_version[0] < 2:
+            self._index_limit = 252 
+        else:
+            page_size = self.page_size
+            self._index_limit = page_size/4
+        return self._index_limit
+    index_limit = property(_get_index_limit)
+    
+    def _autoinc_sql_with_style(self, style, table_name, column_name):
+        """
+        To simulate auto-incrementing primary keys in Firebird, we have to
+        create a generator and a trigger.
+    
+        Create the generators and triggers names based only on table name
+        since django only support one auto field per model
+        """
+        
+        KWD = style.SQL_KEYWORD
+        TBL = style.SQL_TABLE
+        FLD = style.SQL_FIELD
+    
+        generator_name = self.get_generator_name(table_name)
+        trigger_name = self.get_trigger_name(table_name)
+        column_name = self.quote_name(column_name)
+        table_name = self.quote_name(table_name)
+        
+        generator_sql = "%s %s;" % ( KWD('CREATE GENERATOR'), 
+                                     TBL(generator_name))      
+        trigger_sql = "\n".join([
+            "%s %s %s %s" % ( \
+            KWD('CREATE TRIGGER'), TBL(trigger_name), KWD('FOR'),
+            TBL(table_name)),
+            "%s 0 %s" % (KWD('ACTIVE BEFORE INSERT POSITION'), KWD('AS')),
+            KWD('BEGIN'), 
+            "  %s ((%s.%s %s) %s (%s.%s = 0)) %s" % ( \
+                KWD('IF'),
+                KWD('NEW'), FLD(column_name), KWD('IS NULL'),
+                KWD('OR'), KWD('NEW'), FLD(column_name),
+                KWD('THEN')
+            ),
+            "  %s" % KWD('BEGIN'), 
+            "    %s.%s = %s(%s, 1);" % ( \
+                KWD('NEW'), FLD(column_name),
+                KWD('GEN_ID'), TBL(generator_name)
+            ),
+            "  %s" % KWD('END'),
+            KWD('END')
+            ])
+        return (generator_sql, trigger_sql)
+    
+    def autoinc_sql(self, table_name, column_name):
+        # style argument disappeared, so we'll just import django's dummy
+        from django.core.management.color import no_style, color_style
+        return self._autoinc_sql_with_style(no_style(), table_name, column_name)
+
+    def max_name_length(self):
+        return self._max_name_length
+
+    def query_set_class(this, DefaultQuerySet):
+        from django.db import connection
+        from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word
+
+        class FirebirdQuerySet(DefaultQuerySet):
+            def _get_sql_clause(self):
+                from django.db.models.query import SortedDict, handle_legacy_orderlist, orderfield2column, fill_table_cache
+                qn = connection.ops.quote_name
+                opts = self.model._meta
+
+                # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z.
+                select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields]
+                tables = [qn(t) for t in self._tables]
+                joins = SortedDict()
+                where = self._where[:]
+                params = self._params[:]
+
+                # Convert self._filters into SQL.
+                joins2, where2, params2 = self._filters.get_sql(opts)
+                joins.update(joins2)
+                where.extend(where2)
+                params.extend(params2)
+
+                # Add additional tables and WHERE clauses based on select_related.
+                if self._select_related:
+                    fill_table_cache(opts, select, tables, where,
+                                     old_prefix=opts.db_table,
+                                     cache_tables_seen=[opts.db_table],
+                                     max_depth=self._max_related_depth)
+                
+                # Add any additional SELECTs.
+                if self._select:
+                    select.extend([('(%s AS %s') % (qn(s[1]), qn(s[0])) for s in self._select.items()])
+
+                # Start composing the body of the SQL statement.
+                sql = [" FROM", qn(opts.db_table)]
+
+                # Compose the join dictionary into SQL describing the joins.
+                if joins:
+                    sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition)
+                                    for (alias, (table, join_type, condition)) in joins.items()]))
+
+                # Compose the tables clause into SQL.
+                if tables:
+                    sql.append(", " + ", ".join(tables))
+
+                # Compose the where clause into SQL.
+                if where:
+                    sql.append(where and "WHERE " + " AND ".join(where))
+
+                # ORDER BY clause
+                order_by = []
+                if self._order_by is not None:
+                    ordering_to_use = self._order_by
+                else:
+                    ordering_to_use = opts.ordering
+                for f in handle_legacy_orderlist(ordering_to_use):
+                    if f == '?': # Special case.
+                        order_by.append(connection.ops.random_function_sql())
+                    else:
+                        if f.startswith('-'):
+                            col_name = f[1:]
+                            order = "DESC"
+                        else:
+                            col_name = f
+                            order = "ASC"
+                        if "." in col_name:
+                            table_prefix, col_name = col_name.split('.', 1)
+                            table_prefix = qn(table_prefix) + '.'
+                        else:
+                            # Use the database table as a column prefix if it wasn't given,
+                            # and if the requested column isn't a custom SELECT.
+                            if "." not in col_name and col_name not in (self._select or ()):
+                                table_prefix = qn(opts.db_table) + '.'
+                            else:
+                                table_prefix = ''
+                        order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order))
+                if order_by:
+                    sql.append("ORDER BY " + ", ".join(order_by))
+
+                return select, " ".join(sql), params
+            
+            def iterator(self):
+                "Performs the SELECT database lookup of this QuerySet."
+                from django.db.models.query import get_cached_row
+                
+                try:
+                    select, sql, params = self._get_sql_clause()
+                except EmptyResultSet:
+                    raise StopIteration 
+                    
+                # self._select is a dictionary, and dictionaries' key order is
+                # undefined, so we convert it to a list of tuples.
+                extra_select = self._select.items()
+                
+                cursor = connection.cursor() 
+                limit_offset_before = "" 
+                if self._limit is not None: 
+                    limit_offset_before += "FIRST %s " % self._limit 
+                    if self._offset: 
+                        limit_offset_before += "SKIP %s " % self._offset
+                else:
+                    assert self._offset is None, "'offset' is not allowed without 'limit'"
+                cursor.execute("SELECT " + limit_offset_before + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
+                fill_cache = self._select_related
+                fields = self.model._meta.fields
+                index_end = len(fields)
+                while 1:
+                    rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)
+                    if not rows:
+                        raise StopIteration
+                    for row in rows:
+                        row = self.resolve_columns(row, fields)
+                        if fill_cache:
+                            obj, index_end = get_cached_row(klass=self.model, row=row,
+                                                            index_start=0, max_depth=self._max_related_depth)
+                        else:
+                            obj = self.model(*row[:index_end])
+                        for i, k in enumerate(extra_select):
+                            setattr(obj, k[0], row[index_end+i])
+                        yield obj
+            
+            def resolve_columns(self, row, fields=()):
+                from django.db.models.fields import DateField, DateTimeField, \
+                    TimeField, BooleanField, NullBooleanField, DecimalField, Field
+                values = []
+                for value, field in map(None, row, fields):
+                    #if value is None and isinstance(field, Field) and field.empty_strings_allowed:
+                    #    value = u''
+                    # Convert 1 or 0 to True or False
+                    if value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)):
+                        value = bool(value)
+
+                    values.append(value)
+                return values
+        
+        return FirebirdQuerySet
+
+    def quote_name(self, name):
+        # Trancate and quote once. No need for uppercase since
+        # we quote autofields too
+        if not name.startswith('"') and not name.endswith('"'):
+            name = '"%s"' % util.truncate_name(name, self._max_name_length)
+        return name
+    
+    def field_cast_sql(self, db_type):
+        return '%s'
+    
+    def last_insert_id(self, cursor, table_name, pk_name):
+        generator_name = self.get_generator_name(table_name)
+        cursor.execute('SELECT GEN_ID(%s, 0) from RDB$DATABASE' % generator_name)
+        return cursor.fetchone()[0]
+
+    def date_extract_sql(self, lookup_type, column_name):
+        # lookup_type is 'year', 'month', 'day'
+        return "EXTRACT(%s FROM %s)" % (lookup_type, column_name)
+
+    def date_trunc_sql(self, lookup_type, column_name):
+        if lookup_type == 'year':
+             sql = "EXTRACT(year FROM %s)||'-01-01 00:00:00'" % column_name
+        elif lookup_type == 'month':
+            sql = "EXTRACT(year FROM %s)||'-'||EXTRACT(month FROM %s)||'-01 00:00:00'" % (column_name, column_name)
+        elif lookup_type == 'day':
+            sql = "EXTRACT(year FROM %s)||'-'||EXTRACT(month FROM %s)||'-'||EXTRACT(day FROM %s)||' 00:00:00'" % (column_name, column_name, column_name)
+        return "CAST(%s AS TIMESTAMP)" % sql
+    
+    def cascade_delete_update_sql(self):
+        # Solves FK problems with sql_flush
+        return " ON DELETE CASCADE ON UPDATE CASCADE"
+    
+    def datetime_cast_sql(self):
+        return None
+
+    def limit_offset_sql(self, limit, offset=None):
+        # limits are handled in custom FirebirdQuerySet 
+        assert False, 'Limits are handled in a different way in Firebird'
+        return ""
+
+    def random_function_sql(self):
+        return "rand()"
+
+    def pk_default_value(self):
+        return "NULL"
+    
+    def start_transaction_sql(self):
+        return "START TRANSACTION;"
+
+    def sequence_reset_sql(self, style, model_list):
+        from django.db import models
+        output = []
+        sql = """\
+CREATE OR ALTER PROCEDURE "GENERATOR_RESET" AS
+        DECLARE VARIABLE start_val integer;
+        DECLARE VARIABLE gen_val integer;
+        BEGIN
+            SELECT MAX(%(col)s) FROM %(table)s INTO :start_val;
+            IF (start_val IS NULL) THEN
+                gen_val = GEN_ID(%(gen)s, 1 - GEN_ID(%(gen)s, 0));
+            ELSE
+                gen_val = GEN_ID(%(gen)s, start_val - GEN_ID(%(gen)s, 0));
+            EXIT;
+        END;"""
+        for model in model_list:
+            for f in model._meta.fields:
+                if isinstance(f, models.AutoField):
+                    generator_name = self.get_generator_name(model._meta.db_table)
+                    column_name = self.quote_name(f.db_column or f.name)
+                    table_name = self.quote_name(model._meta.db_table)
+                    output.append(sql % {'col' : column_name, 'table' : table_name, 'gen' : generator_name})
+                    output.append('EXECUTE PROCEDURE "GENERATOR_RESET";')
+                    break # Only one AutoField is allowed per model, so don't bother continuing.
+            for f in model._meta.many_to_many:
+                generator_name = self.get_generator_name(f.m2m_db_table())
+                table_name = self.quote_name(f.m2m_db_table())
+                column_name = '"id"'
+                output.append(sql % {'col' : column_name, 'table' : table_name, 'gen' : generator_name})
+                output.append('EXECUTE PROCEDURE "GENERATOR_RESET";')
+        return output
+    
+    def sql_flush(self, style, tables, sequences):
+        if tables:
+            # FK constraints gave us a lot of trouble with default values
+            # that was a reason behind very ugly and dangerous code here
+            # Solved with "ON DELETE CASCADE" with all FK references        
+            sql = ['%s %s %s;' % \
+                    (style.SQL_KEYWORD('DELETE'),
+                     style.SQL_KEYWORD('FROM'),
+                     style.SQL_FIELD(self.quote_name(table))
+                     ) for table in tables]
+            for generator_info in sequences:
+                table_name = generator_info['table']
+                query = "SET GENERATOR %s TO 0;" % self.get_generator_name(table_name)
+                sql.append(query)
+            return sql
+        else:
+            return []
+
+#    def fulltext_search_sql(self, field_name):
+#        return field_name + ' CONTAINING %s'
+        
+    def drop_sequence_sql(self, table):
+        return "DROP GENERATOR %s;" % self.get_generator_name(table)
+        
+    def last_executed_query(self, cursor, sql, params):
+        """
+        Returns a string of the query last executed by the given cursor, with
+        placeholders replaced with actual values.
+
+        `sql` is the raw query containing placeholders, and `params` is the
+        sequence of parameters. These are used by default, but this method
+        exists for database backends to provide a better implementation
+        according to their own quoting schemes.
+        """
+        from django.utils.encoding import smart_unicode, force_unicode
+
+        # Convert params to contain Unicode values.
+        to_unicode = lambda s: force_unicode(s, strings_only=True)
+        if isinstance(params, (list, tuple)):
+            u_params = tuple([to_unicode(val) for val in params])
+        else:
+            u_params = dict([(to_unicode(k), to_unicode(v)) for k, v in params.items()])
+        try:
+            #Extracts sql right from KInterbasDB's prepared statement
+            return smart_unicode(cursor.query) % u_params
+        except TypeError:
+            return smart_unicode(sql) % u_params
+
+class FirebirdCursorWrapper(object):
+    """
+    Django uses "format" ('%s') style placeholders, but firebird uses "qmark" ('?') style.
+    This fixes it -- but note that if you want to use a literal "%s" in a query,
+    you'll need to use "%%s".
+    
+    We also do all automatic type conversions here.
+    """
+    import kinterbasdb.typeconv_datetime_stdlib as tc_dt
+    import kinterbasdb.typeconv_fixed_decimal as tc_fd
+    import kinterbasdb.typeconv_text_unicode as tc_tu
+    import django.utils.encoding as dj_ue
+   
+    def timestamp_conv_in(self, timestamp):
+        if isinstance(timestamp, basestring):
+            #Replaces 6 digits microseconds to 4 digits allowed in Firebird
+            timestamp = timestamp[:24]
+        return self.tc_dt.timestamp_conv_in(timestamp)
+    
+    def time_conv_in(self, value):
+        import datetime
+        if isinstance(value, datetime.datetime):
+            value = datetime.time(value.hour, value.minute, value.second, value.microsecond)       
+        return self.tc_dt.time_conv_in(value) 
+    
+    def ascii_conv_in(self, text):  
+        return self.dj_ue.smart_str(text, 'ascii')
+
+    def unicode_conv_in(self, text):
+        return self.tc_tu.unicode_conv_in((self.dj_ue.force_unicode(text[0]), self.FB_CHARSET_CODE))
+
+    def blob_conv_in(self, text): 
+        return self.tc_tu.unicode_conv_in((self.dj_ue.force_unicode(text), self.FB_CHARSET_CODE))
+
+    def blob_conv_out(self, text):
+        return self.tc_tu.unicode_conv_out((text, self.FB_CHARSET_CODE))
+        
+    def __init__(self, cursor):
+        from django.conf import settings
+        self.FB_CHARSET_CODE = 3 #UNICODE_FSS
+        if hasattr(settings, 'FIREBIRD_CHARSET'):
+            if settings.FIREBIRD_CHARSET == 'UTF8':
+                self.FB_CHARSET_CODE = 4 # UTF-8 with Firebird 2.0+    
+        self.cursor = cursor
+        
+        # Prepared Statement 
+        # http://kinterbasdb.sourceforge.net/dist_docs/usage.html#adv_prepared_statements
+        # Need to decide wether they are useful or not
+        # Maybe add prepare, execute_prep and executemany_pep methods here
+        # and rewrite QuerySet to take advantage of them?
+        # Could speed the things up
+        self._statement = None
+        self.cursor.set_type_trans_in({
+            'DATE':             self.tc_dt.date_conv_in,
+            'TIME':             self.time_conv_in,
+            'TIMESTAMP':        self.timestamp_conv_in,
+            'FIXED':            self.tc_fd.fixed_conv_in_imprecise,
+            'TEXT':             self.ascii_conv_in,
+            'TEXT_UNICODE':     self.unicode_conv_in,
+            'BLOB':             self.blob_conv_in
+        })
+        self.cursor.set_type_trans_out({
+            'DATE':             self.tc_dt.date_conv_out,
+            'TIME':             self.tc_dt.time_conv_out,
+            'TIMESTAMP':        self.tc_dt.timestamp_conv_out,
+            'FIXED':            self.tc_fd.fixed_conv_out_imprecise,
+            'TEXT':             self.dj_ue.force_unicode,
+            'TEXT_UNICODE':     self.tc_tu.unicode_conv_out,
+            'BLOB':             self.blob_conv_out
+        })
+    
+    def _get_query(self):
+        if self._statement:
+            return self._statement.sql
+    def _get_statement(self):
+        if self._statement:
+            return self._statement
+    query = property(_get_query)
+    statement = property(_get_statement)
+        
+    def execute(self, query, params=()):
+        cquery = self.convert_query(query, len(params))
+        if self._get_query() != cquery:
+            try:
+                self._statement = self.cursor.prep(cquery)
+            except Database.ProgrammingError, e:
+                output = ["Error preparing query."]
+                output.extend(str(e).split(', ')[1].strip("'").split('\\n'))
+                output.append("\nThe problem query was:")
+                output.append(query % params)
+                raise DatabaseError, "\n".join(output)
+        try:
+            return self.cursor.execute(self._statement, params)
+        except Database.ProgrammingError, e:
+            err_no = int(str(e).split()[0].strip(',()'))
+            output = ["Error executing query. FB error No. %i" % err_no]
+            output.extend(str(e).split(', ')[1].strip("'").split('\\n'))
+            #e.append(err_no)
+            output.append("\nThe problem query was:")
+            output.append(query % params)
+            raise DatabaseError, "\n".join(output)
+    
+    def executemany(self, query, param_list):
+        try:
+            cquery = self.convert_query(query, len(param_list[0]))
+        except IndexError:
+            return None
+        if self._get_query() != cquery:
+            self._statement = self.cursor.prep(cquery)
+        return self.cursor.executemany(self._statement, param_list)
+
+    def convert_query(self, query, num_params):
+        try:
+            return query % tuple("?" * num_params)
+        except TypeError, e:
+            print query, num_params
+            raise TypeError, e
+    
+    def __getattr__(self, attr):
+        if attr in self.__dict__:
+            return self.__dict__[attr]
+        else:
+            return getattr(self.cursor, attr)
+
+class DatabaseWrapper(BaseDatabaseWrapper):
+    features = DatabaseFeatures()
+    ops = DatabaseOperations()
+    operators = {
+        'exact': '= %s',
+        'iexact': '= UPPER(%s)',
+        'contains': "LIKE %s ESCAPE'\\'",
+        'icontains': 'CONTAINING %s', #case is ignored
+        'gt': '> %s',
+        'gte': '>= %s',
+        'lt': '< %s',
+        'lte': '<= %s',
+        'startswith': 'STARTING WITH %s', #looks to be faster then LIKE
+        'endswith': "LIKE %s ESCAPE'\\'",
+        'istartswith': 'STARTING WITH UPPER(%s)',
+        'iendswith': "LIKE UPPER(%s) ESCAPE'\\'",
+    }
+    _current_cursor = None
+    def _connect(self, settings):
+        if settings.DATABASE_NAME == '':
+            from django.core.exceptions import ImproperlyConfigured
+            raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file."
+        charset = 'UNICODE_FSS'
+        if hasattr(settings, 'FIREBIRD_CHARSET'):
+            if settings.FIREBIRD_CHARSET == 'UTF8':
+                charset = 'UTF8'    
+        kwargs = {'charset' : charset }
+        if settings.DATABASE_HOST:
+            kwargs['dsn'] = "%s:%s" % (settings.DATABASE_HOST, settings.DATABASE_NAME)
+        else:
+            kwargs['dsn'] = "localhost:%s" % settings.DATABASE_NAME
+        if settings.DATABASE_USER:
+            kwargs['user'] = settings.DATABASE_USER
+        if settings.DATABASE_PASSWORD:
+            kwargs['password'] = settings.DATABASE_PASSWORD
+        self.connection = Database.connect(**kwargs)
+        assert self.charset == charset
+        try:
+            self.connection.execute_immediate("""
+                DECLARE EXTERNAL FUNCTION rand
+                RETURNS DOUBLE PRECISION
+                BY VALUE ENTRY_POINT 'IB_UDF_rand' MODULE_NAME 'ib_udf';
+            """)
+        except Database.ProgrammingError:
+            pass #Already defined
+        
+        
+        
+    def cursor(self, name=None):
+        #Cursors can be named
+        #http://kinterbasdb.sourceforge.net/dist_docs/usage.html#adv_named_cursors
+        #and maybe useful for scrolling updates and deletes
+        from django.conf import settings
+        cursor = self._cursor(settings, name)
+        if settings.DEBUG:
+            return self.make_debug_cursor(cursor)
+        return cursor
+    
+    def _cursor(self, settings, name):
+        if self.connection is None:
+            self._connect(settings)
+        cursor = self.connection.cursor()
+        if name:
+            cursor.name = name
+        cursor = FirebirdCursorWrapper(cursor)
+        self._current_cursor = cursor
+        return cursor
+    
+    #Returns query from prepared statement
+    def _get_query(self):
+        if self._current_cursor:
+            return self._current_cursor.query
+    query = property(_get_query)
+    #Returns prepared statement itself
+    def _get_statement(self):
+        if self._current_cursor:
+            return self._current_cursor.statement
+    statement = property(_get_statement)
+        
+    
+    def __getattr__(self, attr):
+        if attr in self.__dict__:
+            return self.__dict__[attr]
+        else:
+            return getattr(self.connection, attr)
+    
+
Index: django/db/backends/firebird/client.py
===================================================================
--- django/db/backends/firebird/client.py	(revision 0)
+++ django/db/backends/firebird/client.py	(revision 0)
@@ -0,0 +1,11 @@
+from django.conf import settings
+import os
+
+def runshell():
+    args = [settings.DATABASE_NAME]
+    args += ["-u %s" % settings.DATABASE_USER]
+    if settings.DATABASE_PASSWORD:
+        args += ["-p %s" % settings.DATABASE_PASSWORD]
+    if 'FIREBIRD' not in os.environ:
+        path = '/opt/firebird/bin/'
+    os.system(path + 'isql ' + ' '.join(args))
Index: django/db/backends/firebird/__init__.py
===================================================================
Index: django/db/backends/firebird/introspection.py
===================================================================
--- django/db/backends/firebird/introspection.py	(revision 0)
+++ django/db/backends/firebird/introspection.py	(revision 0)
@@ -0,0 +1,93 @@
+from django.db import transaction
+from django.db.backends.firebird.base import DatabaseOperations
+
+quote_name = DatabaseOperations().quote_name
+
+def get_table_list(cursor):
+    "Returns a list of table names in the current database."
+    cursor.execute("""
+        SELECT rdb$relation_name FROM rdb$relations
+        WHERE rdb$system_flag = 0 AND rdb$view_blr IS NULL ORDER BY rdb$relation_name""")
+    return [str(row[0].strip().lower()) for row in cursor.fetchall()]
+
+def get_table_description(cursor, table_name):
+    "Returns a description of the table, with the DB-API cursor.description interface."
+    #cursor.execute("SELECT FIRST 1 * FROM %s" % quote_name(table_name))
+    #return cursor.description
+    # (name, type_code, display_size, internal_size, precision, scale, null_ok)
+    cursor.execute("""
+        SELECT DISTINCT R.RDB$FIELD_NAME AS FNAME,
+                  F.RDB$FIELD_TYPE AS FTYPE,
+                  F.RDB$FIELD_LENGTH AS FLENGTH,
+                  F.RDB$FIELD_PRECISION AS FPRECISION,
+                  F.RDB$FIELD_SCALE AS FSCALE,
+                  R.RDB$NULL_FLAG AS NULL_FLAG,
+                  R.RDB$FIELD_POSITION
+        FROM RDB$RELATION_FIELDS R
+             JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME
+        WHERE F.RDB$SYSTEM_FLAG=0 and R.RDB$RELATION_NAME= %s
+        ORDER BY R.RDB$FIELD_POSITION
+    """, (table_name,))
+    return [(row[0].lower().rstrip(), row[1], row[2], row[2] or 0, row[3], row[4], row[5] and True or False) for row in cursor.fetchall()]
+
+
+def get_relations(cursor, table_name):
+    """
+    Returns a dictionary of {field_index: (field_index_other_table, other_table)}
+    representing all relationships to the given table. Indexes are 0-based.
+    """
+    cursor.execute("""
+        SELECT seg.rdb$field_name, seg_ref.rdb$field_name, idx_ref.rdb$relation_name
+        FROM rdb$indices idx
+        INNER JOIN rdb$index_segments seg
+            ON seg.rdb$index_name = idx.rdb$index_name
+        INNER JOIN rdb$indices idx_ref
+            ON idx_ref.rdb$index_name = idx.rdb$foreign_key
+        INNER JOIN rdb$index_segments seg_ref
+            ON seg_ref.rdb$index_name = idx_ref.rdb$index_name
+        WHERE idx.rdb$relation_name = %s
+            AND idx.rdb$foreign_key IS NOT NULL""", [table_name])
+
+    relations = {}
+    for row in cursor.fetchall():
+        relations[row[0].rstrip()] = (row[1].strip(), row[2].strip())
+    return relations
+
+def get_indexes(cursor, table_name):
+    """
+    Returns a dictionary of fieldname -> infodict for the given table,
+    where each infodict is in the format:
+        {'primary_key': boolean representing whether it's the primary key,
+         'unique': boolean representing whether it's a unique index}
+    """
+
+    # This query retrieves each field name and index type on the given table.
+    cursor.execute("""
+        SELECT seg.rdb$field_name, const.rdb$constraint_type
+        FROM rdb$relation_constraints const
+        LEFT JOIN rdb$index_segments seg
+            ON seg.rdb$index_name = const.rdb$index_name
+        WHERE const.rdb$relation_name = %s
+            AND (const.rdb$constraint_type = 'PRIMARY KEY'
+                OR const.rdb$constraint_type = 'UNIQUE')""", [table_name])
+    indexes = {}
+    for row in cursor.fetchall():
+        indexes[row[0].strip()] = {
+            'primary_key': ('PRIMARY KEY' == row[1].strip()),
+            'unique': ('UNIQUE' == row[1].strip())}
+    return indexes
+
+# Maps type codes to Django Field types.
+# !todo
+DATA_TYPES_REVERSE = {
+    7: 'BooleanField',
+    7: 'SmallIntegerField',
+    8: 'IntegerField',
+    261: 'TextField',
+    37: 'IPAddressField',
+    37: 'CharField',
+    12: 'DateField',
+    13: 'TimeField',
+    35: 'DateTimeField',
+    10: 'FloatField',
+}
Index: django/db/backends/firebird/creation.py
===================================================================
--- django/db/backends/firebird/creation.py	(revision 0)
+++ django/db/backends/firebird/creation.py	(revision 0)
@@ -0,0 +1,108 @@
+# This dictionary maps Field objects to their associated Firebird column
+# types, as strings. Column-type strings can contain format strings; they'll
+# be interpolated against the values of Field.__dict__ before being output.
+# If a column type is set to None, it won't be included in the output.
+
+import sys, os.path
+from kinterbasdb import connect, create_database
+from django.core.management import call_command
+
+DATA_TYPES = {
+    'AutoField':                     'integer',
+    'BooleanField':                  'smallint',
+    'CharField':                     'varchar(%(max_length)s)',
+    'CommaSeparatedIntegerField':    'varchar(%(max_length)s) CHARACTER SET ASCII',
+    'DateField':                     'date',
+    'DateTimeField':                 'timestamp',
+    'DecimalField':                  'numeric(%(max_digits)s, %(decimal_places)s)',
+    'FileField':                     'varchar(%(max_length)s)',
+    'FilePathField':                 'varchar(%(max_length)s)',
+    'FloatField':                    'double precision',
+    'ImageField':                    'varchar(%(max_length)s)',
+    'IntegerField':                  'integer',
+    'IPAddressField':                'varchar(15) CHARACTER SET ASCII',
+    'NullBooleanField':              'smallint', 
+    'OneToOneField':                 'integer',
+    'PhoneNumberField':              'varchar(20)', 
+    'PositiveIntegerField':          'integer',
+    'PositiveSmallIntegerField':     'smallint',
+    'SlugField':                     'varchar(%(max_length)s)',
+    'SmallIntegerField':             'smallint',
+    'TextField':                     'blob sub_type text',
+    'TimeField':                     'time',
+    'URLField':                      'varchar(%(max_length)s) CHARACTER SET ASCII',
+    'USStateField':                  'char(2) CHARACTER SET ASCII',
+}
+
+DATA_TYPE_CHECKS = {
+    'BooleanField':                  '("%(column)s" IN (0,1))',
+    'NullBooleanField':              '(("%(column)s" IN (0,1)) OR ("%(column)s" IS NULL))',
+    'PositiveIntegerField':          '("%(column)s" >= 0)',
+    'PositiveSmallIntegerField':     '("%(column)s" >= 0)'
+}
+
+TEST_DATABASE_PREFIX = 'test_'
+
+def create_test_db(settings, connection, verbosity, autoclobber):
+    # KInterbasDB supports dynamic database creation and deletion 
+    # via the module-level function create_database and the method Connection.drop_database.
+       
+    if settings.TEST_DATABASE_NAME:
+        TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME
+    else:
+        dbnametuple = os.path.split(settings.DATABASE_NAME)
+        TEST_DATABASE_NAME = os.path.join(dbnametuple[0], TEST_DATABASE_PREFIX + dbnametuple[1])
+    
+    dsn = "localhost:%s" % TEST_DATABASE_NAME
+    if settings.DATABASE_HOST:
+        dsn = "%s:%s" % (settings.DATABASE_HOST, TEST_DATABASE_NAME)
+    
+    if os.path.isfile(TEST_DATABASE_NAME):
+        sys.stderr.write("Database %s already exists\n" % TEST_DATABASE_NAME)
+        if not autoclobber:
+            confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)
+        if autoclobber or confirm == 'yes':
+            if verbosity >= 1:
+                print "Destroying old test database..."
+            old_connection = connect(dsn=dsn, user=settings.DATABASE_USER, password=settings.DATABASE_PASSWORD)
+            old_connection.drop_database()
+        else:
+                print "Tests cancelled."
+                sys.exit(1)
+            
+    if verbosity >= 1:
+        print "Creating test database..."
+    try:
+        charset = 'UNICODE_FSS'
+        if hasattr(settings, 'FIREBIRD_CHARSET'):
+            if settings.FIREBIRD_CHARSET == 'UTF8':
+                charset='UTF8'                
+        create_database("create database '%s' user '%s' password '%s' default character set %s" % \
+            (dsn, settings.DATABASE_USER, settings.DATABASE_PASSWORD, charset))
+    except Exception, e:
+        sys.stderr.write("Got an error creating the test database: %s\n" % e)
+        sys.exit(2)
+            
+
+    connection.close() 
+    settings.DATABASE_NAME = TEST_DATABASE_NAME
+
+    call_command('syncdb', verbosity=verbosity, interactive=False)
+
+    if settings.CACHE_BACKEND.startswith('db://'):
+        cache_name = settings.CACHE_BACKEND[len('db://'):]
+        call_command('createcachetable', cache_name)
+
+    # Get a cursor (even though we don't need one yet). This has
+    # the side effect of initializing the test database.
+    cursor = connection.cursor()
+
+    return TEST_DATABASE_NAME
+
+def destroy_test_db(settings, connection, old_database_name, verbosity):
+    # KInterbasDB supports dynamic database deletion via the method Connection.drop_database.
+    if verbosity >= 1:
+        print "Destroying test database..."
+    connection.drop_database()
+    
+
Index: django/core/cache/backends/db.py
===================================================================
--- django/core/cache/backends/db.py	(revision 6654)
+++ django/core/cache/backends/db.py	(working copy)
@@ -47,19 +47,20 @@
         if timeout is None:
             timeout = self.default_timeout
         cursor = connection.cursor()
-        cursor.execute("SELECT COUNT(*) FROM %s" % self._table)
+        qn = connection.ops.quote_name
+        cursor.execute("SELECT COUNT(*) FROM %s" % qn(self._table))
         num = cursor.fetchone()[0]
         now = datetime.now().replace(microsecond=0)
         exp = datetime.fromtimestamp(time.time() + timeout).replace(microsecond=0)
         if num > self._max_entries:
             self._cull(cursor, now)
         encoded = base64.encodestring(pickle.dumps(value, 2)).strip()
-        cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % self._table, [key])
+        cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % qn(self._table), [key])
         try:
             if mode == 'set' and cursor.fetchone():
-                cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % self._table, [encoded, str(exp), key])
+                cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % qn(self._table), [encoded, str(exp), key])
             else:
-                cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % self._table, [key, encoded, str(exp)])
+                cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % qn(self._table), [key, encoded, str(exp)])
         except DatabaseError:
             # To be threadsafe, updates/inserts are allowed to fail silently
             pass
Index: django/core/management/sql.py
===================================================================
--- django/core/management/sql.py	(revision 6654)
+++ django/core/management/sql.py	(working copy)
@@ -1,4 +1,5 @@
 from django.core.management.base import CommandError
+from django.conf import settings
 import os
 import re
 
@@ -253,8 +254,41 @@
     pending_references = {}
     qn = connection.ops.quote_name
     inline_references = connection.features.inline_fk_references
+    is_firebird = hasattr(connection.ops, "firebird_version") 
     for f in opts.fields:
-        col_type = f.db_type()
+        col_type, col_type_check = f.db_type(), f.db_type_check()
+        if is_firebird:
+            fb_version = "%s.%s" % (connection.ops.firebird_version[0], connection.ops.firebird_version[1])
+            page_size = connection.ops.page_size
+            #look at: http://www.volny.cz/iprenosil/interbase/ip_ib_indexcalculator.htm
+            if connection.ops.index_limit < 1000:
+                strip2ascii = False
+                if (f.unique or f.primary_key or f.db_index):
+                    strip2ascii = True
+                if len(opts.unique_together) > 0:
+                    if f.column in opts.unique_together[0]:
+                        strip2ascii = True      
+                if strip2ascii:
+                    if col_type.startswith('varchar'):
+                        if not col_type.endswith('ASCII'):
+                            col_type += " CHARACTER SET ASCII"
+                            msg =  "WARNING: Character encoding of the column '%s' has changed to ASCII\n"
+                            msg += "         due to restriction of %s bytes in Firebird %s"
+                            if not page_size:
+                                print  msg % (f.column, connection.ops.index_limit, fb_version)
+                            else:
+                                msg += " with page size %s"
+                                print  msg % (f.column, connection.ops.index_limit, fb_version, page_size)
+                        if opts.unique_together:
+                            num_ufields = len(opts.unique_together[0])
+                            limit = connection.ops.index_limit - ((num_ufields - 1)*64)
+                            max_length = int(limit/float(num_ufields))
+                            old_length = int(f.__dict__["max_length"])
+                            if old_length > max_length:
+                                col_type = "varchar(%i) CHARACTER SET ASCII" % max_length
+                                print "         The maximum length of '%s' is now %s instead of %s"\
+                                 % (f.column, max_length, old_length)
+               
         tablespace = f.db_tablespace or opts.db_tablespace
         if col_type is None:
             # Skip ManyToManyFields, because they're not represented as
@@ -263,7 +297,10 @@
         # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
         field_output = [style.SQL_FIELD(qn(f.column)),
             style.SQL_COLTYPE(col_type)]
-        field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
+        nullstring = ""
+        if connection.features.needs_default_null:
+            nullstring = "DEFAULT "
+        field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or nullstring)))
         if f.unique and (not f.primary_key or connection.features.allows_unique_and_pk):
             field_output.append(style.SQL_KEYWORD('UNIQUE'))
         if f.primary_key:
@@ -276,13 +313,15 @@
             if inline_references and f.rel.to in known_models:
                 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
                     style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \
-                    style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
-                    connection.ops.deferrable_sql()
+                    style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' + \
+                    connection.ops.cascade_delete_update_sql() + connection.ops.deferrable_sql()
                 )
             else:
                 # We haven't yet created the table to which this field
                 # is related, so save it for later.
                 pr = pending_references.setdefault(f.rel.to, []).append((model, f))
+        if col_type_check:
+            field_output.extend([ style.SQL_KEYWORD('CHECK'), style.SQL_COLTYPE(col_type_check)  ])          
         table_output.append(' '.join(field_output))
     if opts.order_with_respect_to:
         table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
@@ -335,6 +374,7 @@
                 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
                     (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
                     qn(r_col), qn(table), qn(col),
+                    connection.ops.cascade_delete_update_sql(),
                     connection.ops.deferrable_sql()))
             del pending_references[model]
     return final_output
@@ -364,19 +404,21 @@
                 tablespace_sql))
             if inline_references:
                 deferred = []
-                table_output.append('    %s %s %s %s (%s)%s,' %
+                table_output.append('    %s %s %s %s (%s)%s%s,' %
                     (style.SQL_FIELD(qn(f.m2m_column_name())),
                     style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
                     style.SQL_KEYWORD('NOT NULL REFERENCES'),
                     style.SQL_TABLE(qn(opts.db_table)),
                     style.SQL_FIELD(qn(opts.pk.column)),
+                    connection.ops.cascade_delete_update_sql(),
                     connection.ops.deferrable_sql()))
-                table_output.append('    %s %s %s %s (%s)%s,' %
+                table_output.append('    %s %s %s %s (%s)%s%s,' %
                     (style.SQL_FIELD(qn(f.m2m_reverse_name())),
                     style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
                     style.SQL_KEYWORD('NOT NULL REFERENCES'),
                     style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
                     style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
+                    connection.ops.cascade_delete_update_sql(),
                     connection.ops.deferrable_sql()))
             else:
                 table_output.append('    %s %s %s,' %
@@ -412,6 +454,7 @@
                 (qn(r_table),
                 truncate_name(r_name, connection.ops.max_name_length()),
                 qn(r_col), qn(table), qn(col),
+                connection.ops.cascade_delete_update_sql(),
                 connection.ops.deferrable_sql()))
 
             # Add any extra SQL needed to support auto-incrementing PKs
Index: tests/regressiontests/initial_sql_regress/sql/simple.sql
===================================================================
--- tests/regressiontests/initial_sql_regress/sql/simple.sql	(revision 6654)
+++ tests/regressiontests/initial_sql_regress/sql/simple.sql	(working copy)
@@ -1,8 +1,8 @@
-INSERT INTO initial_sql_regress_simple (name) VALUES ('John');
-INSERT INTO initial_sql_regress_simple (name) VALUES ('Paul');
-INSERT INTO initial_sql_regress_simple (name) VALUES ('Ringo');
-INSERT INTO initial_sql_regress_simple (name) VALUES ('George');
-INSERT INTO initial_sql_regress_simple (name) VALUES ('Miles O''Brien');
-INSERT INTO initial_sql_regress_simple (name) VALUES ('Semicolon;Man');
-INSERT INTO initial_sql_regress_simple (name) VALUES ('This line has a Windows line ending');
+INSERT INTO "initial_sql_regress_simple" ("name") VALUES ('John');
+INSERT INTO "initial_sql_regress_simple" ("name") VALUES ('Paul');
+INSERT INTO "initial_sql_regress_simple" ("name") VALUES ('Ringo');
+INSERT INTO "initial_sql_regress_simple" ("name") VALUES ('George');
+INSERT INTO "initial_sql_regress_simple" ("name") VALUES ('Miles O''Brien');
+INSERT INTO "initial_sql_regress_simple" ("name") VALUES ('Semicolon;Man');
+INSERT INTO "initial_sql_regress_simple" ("name") VALUES ('This line has a Windows line ending');
 
Index: tests/regressiontests/backends/models.py
===================================================================
--- tests/regressiontests/backends/models.py	(revision 6654)
+++ tests/regressiontests/backends/models.py	(working copy)
@@ -22,7 +22,7 @@
 >>> opts = Square._meta
 >>> f1, f2 = opts.get_field('root'), opts.get_field('square')
 >>> query = ('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)'
-...         % (t_convert(opts.db_table), qn(f1.column), qn(f2.column)))
+...         % qn((t_convert(opts.db_table)), qn(f1.column), qn(f2.column)))
 >>> cursor.executemany(query, [(i, i**2) for i in range(-5, 6)]) and None or None
 >>> Square.objects.order_by('root')
 [<Square: -5 ** 2 == 25>, <Square: -4 ** 2 == 16>, <Square: -3 ** 2 == 9>, <Square: -2 ** 2 == 4>, <Square: -1 ** 2 == 1>, <Square: 0 ** 2 == 0>, <Square: 1 ** 2 == 1>, <Square: 2 ** 2 == 4>, <Square: 3 ** 2 == 9>, <Square: 4 ** 2 == 16>, <Square: 5 ** 2 == 25>]
