Index: django/test/utils.py
===================================================================
--- django/test/utils.py	(revision 5080)
+++ django/test/utils.py	(working copy)
@@ -1,6 +1,6 @@
 import sys, time
 from django.conf import settings
-from django.db import connection, transaction, backend
+from django.db import connection, transaction, backend, get_creation_module
 from django.core import management
 from django.dispatch import dispatcher
 from django.test import signals
@@ -44,6 +44,12 @@
         connection.connection.set_isolation_level(0)
 
 def create_test_db(verbosity=1, autoclobber=False):
+    # If the database backend wants to create the test DB itself, let it
+    creation_module = get_creation_module()
+    if hasattr(creation_module, "create_test_db"):
+        creation_module.create_test_db(settings, connection, backend, verbosity, autoclobber)
+        return
+    
     if verbosity >= 1:
         print "Creating test database..."
     # If we're using SQLite, it's more convenient to test against an
@@ -92,6 +98,12 @@
     cursor = connection.cursor()
 
 def destroy_test_db(old_database_name, verbosity=1):
+    # If the database wants to drop the test DB itself, let it
+    creation_module = get_creation_module()
+    if hasattr(creation_module, "destroy_test_db"):
+        creation_module.destroy_test_db(settings, connection, backend, old_database_name, verbosity)
+        return
+    
     # Unless we're using SQLite, remove the test database to clean up after
     # ourselves. Connect to the previous database (not the test database)
     # to do so, because it's not allowed to delete a database while being
Index: django/db/models/base.py
===================================================================
--- django/db/models/base.py	(revision 5080)
+++ django/db/models/base.py	(working copy)
@@ -205,7 +205,10 @@
         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" % \
+            check_sql = 'SELECT 1 FROM %s WHERE %s=%%s LIMIT 1'
+            if settings.DATABASE_ENGINE == 'firebird':
+                check_sql = 'SELECT FIRST 1 1 FROM %s WHERE %s=%%s'
+            cursor.execute(check_sql % \
                 (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val])
             # If it does already exist, do an UPDATE.
             if cursor.fetchone():
Index: django/db/models/fields/related.py
===================================================================
--- django/db/models/fields/related.py	(revision 5080)
+++ django/db/models/fields/related.py	(working copy)
@@ -335,8 +335,9 @@
                     (target_col_name, self.join_table, source_col_name,
                     target_col_name, ",".join(['%s'] * len(new_ids))),
                     [self._pk_val] + list(new_ids))
-                if cursor.rowcount is not None and cursor.rowcount != 0:
-                    existing_ids = set([row[0] for row in cursor.fetchmany(cursor.rowcount)])
+                rows = cursor.fetchall()
+                if rows:
+                    existing_ids = set([row[0] for row in rows])
                 else:
                     existing_ids = set()
 
Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py	(revision 5080)
+++ django/db/models/query.py	(working copy)
@@ -2,6 +2,7 @@
 from django.db.models.fields import DateField, FieldDoesNotExist
 from django.db.models.fields.generic import GenericRelation
 from django.db.models import signals
+from django.conf import settings
 from django.dispatch import dispatcher
 from django.utils.datastructures import SortedDict
 import operator
@@ -179,8 +180,15 @@
         # undefined, so we convert it to a list of tuples.
         extra_select = self._select.items()
 
+        pre_columns = ""
+        if settings.DATABASE_ENGINE == 'firebird' and self._limit is not None:
+            pre_columns += "FIRST %s " % self._limit
+            if self._offset:
+                pre_columns += "SKIP %s " % self._offset
+        if self._distinct:
+            pre_columns += "DISTINCT "
         cursor = connection.cursor()
-        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
+        cursor.execute("SELECT " + pre_columns + ",".join(select) + sql, params)
         fill_cache = self._select_related
         index_end = len(self.model._meta.fields)
         while 1:
@@ -502,7 +510,7 @@
 
         # Compose the join dictionary into SQL describing the joins.
         if joins:
-            sql.append(" ".join(["%s %s AS %s ON %s" % (join_type, table, alias, condition)
+            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.
@@ -717,7 +725,10 @@
         table_prefix = backend.quote_name(table_prefix[:-1])+'.'
     field_name = backend.quote_name(field_name)
     try:
-        return '%s%s %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s'))
+        lookup_sql = '%s%s %s'
+        if settings.DATABASE_ENGINE == 'firebird' and lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'):
+            lookup_sql = 'UPPER(%s%s) %s'
+        return lookup_sql % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s'))
     except KeyError:
         pass
     if lookup_type == 'in':
Index: django/db/backends/util.py
===================================================================
--- django/db/backends/util.py	(revision 5080)
+++ django/db/backends/util.py	(working copy)
@@ -1,4 +1,4 @@
-import datetime
+import datetime, md5
 from time import time
 
 class CursorDebugWrapper(object):
@@ -38,6 +38,14 @@
         else:
             return getattr(self.cursor, attr)
 
+def truncate_name(name, length=None):
+    """Shortens a string to a repeatable mangled version with the given length.
+    """
+    if length is None or len(name) <= length:
+        return name
+    hash = md5.md5(name).hexdigest()[:4]
+    return '%s%s' % (name[:length-4], hash)
+
 ###############################################
 # Converters from database (string) to Python #
 ###############################################
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,294 @@
+"""
+Firebird database backend for Django.
+
+Requires kinterbasdb: http://kinterbasdb.sourceforge.net/
+"""
+
+from django.conf import settings
+from django.db.backends import util
+import re
+try:
+    import kinterbasdb as Database
+    import kinterbasdb.typeconv_datetime_stdlib as typeconv_datetime
+except ImportError, e:
+    from django.core.exceptions import ImproperlyConfigured
+    raise ImproperlyConfigured, "Error loading kinterbasdb module: %s" % e
+
+DatabaseError = Database.DatabaseError
+Database.init(type_conv=199)
+
+try:
+    # Only exists in Python 2.4+
+    from threading import local
+except ImportError:
+    # Import copy of _thread_local.py from Python 2.4
+    from django.utils._threading_local import local
+
+server_version = None
+
+def unicode_conv_in(text):
+    #Type converter for columns with charsets NONE, OCTETS, or ASCII
+    if isinstance(text, unicode):
+        return text.encode(settings.DEFAULT_CHARSET)
+    return text
+
+def timestamp_conv_in(datetime):
+    #Type converter for datetime casted strings.
+    #Replaces 6 digits microseconds to 4 digits allowed in Firebird
+    if isinstance(datetime, basestring) and datetime.find('.') > 0 and len(datetime) == 26:
+        datetime = datetime[0:-2]
+    return typeconv_datetime.timestamp_conv_in(datetime)
+
+class DatabaseWrapper(local):
+    def __init__(self, **kwargs):
+        self.connection = None
+        self.queries = []
+        self.options = kwargs
+
+    def cursor(self):
+        if self.connection is None:
+            if settings.DATABASE_NAME == '':
+                from django.core.exceptions import ImproperlyConfigured
+                raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file."
+            kwargs = {'database': settings.DATABASE_NAME}
+            if settings.DATABASE_HOST:
+                kwargs['host'] = settings.DATABASE_HOST
+            if settings.DATABASE_USER:
+                kwargs['user'] = settings.DATABASE_USER
+            if settings.DATABASE_PASSWORD:
+                kwargs['password'] = settings.DATABASE_PASSWORD
+            self.connection = Database.connect(**kwargs)
+            self.connection.set_type_trans_in({
+                'TEXT': unicode_conv_in,
+                'BLOB': unicode_conv_in,
+                'TIMESTAMP': timestamp_conv_in
+            })
+            global server_version
+            if not server_version:
+                import re
+                version_re = re.compile('.*Firebird\s([\d\.]+)')
+                m = version_re.match(self.connection.server_version)
+                if not m:
+                    raise Exception('Unable to determine Firebird version from version string %r' % self.connection.server_version)
+                server_version = m.groups()[0]
+        cursor = FirebirdCursorWrapper(self.connection)
+        if settings.DEBUG:
+            return util.CursorDebugWrapper(cursor, self)
+        return cursor
+
+    def _commit(self):
+        if self.connection is not None:
+            return self.connection.commit()
+
+    def _rollback(self):
+        if self.connection is not None:
+            return self.connection.rollback()
+
+    def close(self):
+        if self.connection is not None:
+            self.connection.close()
+            self.connection = None
+
+class FirebirdCursorWrapper(Database.Cursor):
+    """
+    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".
+    """
+    def execute(self, query, params=()):
+        query = self._convert_query(query, len(params))
+        #print "%s %s" % (query, params)
+        return Database.Cursor.execute(self, query, params)
+
+    def executemany(self, query, params):
+        query = self._convert_query(query, len(params[0]))
+        return Database.Cursor.executemany(self, query, params)
+
+    def _convert_query(self, query, num_params):
+        return query % tuple("?" * num_params)
+
+supports_constraints = True
+
+def quote_name(name):
+    # the standard for firebird is not to quote names but in django
+    # it will quote all names uppercased so we can write sql without quotes
+    # because all names without quotes will defualt to uppercased,
+    # like oracle truncate names bigger than 30 chars
+    if not name.startswith('"') and not name.endswith('"'):
+        name = '"%s"' % util.truncate_name(name, get_max_name_length())
+    return name.upper()
+
+_quote_sequence_name = lambda n: '"%s_SQ"' % util.truncate_name(n.upper(), get_max_name_length()-3)
+_quote_trigger_name = lambda n: '"%s_TR"' % util.truncate_name(n.upper(), get_max_name_length()-3)
+
+def dictfetchone(cursor):
+    "Returns a row from the cursor as a dict"
+    return cursor.fetchonemap()
+
+def dictfetchmany(cursor, number):
+    "Returns a certain number of rows from a cursor as a dict"
+    return cursor.fetchmanymap(number)
+
+def dictfetchall(cursor):
+    "Returns all rows from a cursor as a dict"
+    return cursor.fetchallmap()
+
+def get_last_insert_id(cursor, table_name, pk_name):
+    stmt = server_version < '2' and 'SELECT GEN_ID(%s, 0) FROM RDB$DATABASE' or 'NEXT VALUE FOR %s'
+    cursor.execute(stmt % _quote_sequence_name(table_name))
+    return cursor.fetchone()[0]
+
+def get_date_extract_sql(lookup_type, column_name):
+    # lookup_type is 'year', 'month', 'day'
+    return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), column_name)
+
+def get_date_trunc_sql(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 get_datetime_cast_sql():
+    return None
+
+def get_limit_offset_sql(limit, offset=None):
+    return ""
+
+def get_random_function_sql():
+    return "RAND()"
+
+def get_deferrable_sql():
+    # Not supported, maybe in Firebird 3.0
+    return ""
+
+def get_fulltext_search_sql(field_name):
+    # maybe in Firebird 3.0
+    raise NotImplementedError
+
+def get_drop_foreignkey_sql():
+    return "DROP CONSTRAINT"
+
+def get_pk_default_value():
+    return "NULL"
+
+def get_max_name_length():
+    return 30
+
+def get_sequence_sql(style, table_name, column_name):
+    """To simulate auto-incrementing primary keys in Firebird, we have to
+    create a generator (sequence in Firebird 2) and a trigger.
+
+    Create the sequences and triggers names based only on table name
+    since django only support one auto field per model"""
+    KEYWORD = style.SQL_KEYWORD
+    TABLE = style.SQL_TABLE
+    FIELD = style.SQL_FIELD
+
+    sequence_name = _quote_sequence_name(table_name)
+    column_name = quote_name(column_name)
+    return ["%s %s;" % ( \
+            KEYWORD(server_version < '2' and 'CREATE GENERATOR' or 'CREATE SEQUENCE'),
+            TABLE(sequence_name)),
+        "\n".join(["%s %s %s %s" % ( \
+            KEYWORD('CREATE TRIGGER'),
+            TABLE(_quote_trigger_name(table_name)),
+            KEYWORD('FOR'),
+            TABLE(quote_name(table_name))),
+        "%s 0 %s" % ( \
+            KEYWORD('ACTIVE BEFORE INSERT POSITION'),
+            KEYWORD('AS')),
+        KEYWORD('BEGIN'),
+        "  %s ((%s.%s %s) %s (%s.%s = 0)) %s" % ( \
+            KEYWORD('IF'),
+            KEYWORD('NEW'),
+            FIELD(column_name),
+            KEYWORD('IS NULL'),
+            KEYWORD('OR'),
+            KEYWORD('NEW'),
+            FIELD(column_name),
+            KEYWORD('THEN')),
+        "  %s" % KEYWORD('BEGIN'),
+        "    %s.%s = %s(%s, 1);" % ( \
+            KEYWORD('NEW'),
+            FIELD(column_name),
+            KEYWORD('GEN_ID'),
+            TABLE(sequence_name)),
+        "  %s" % KEYWORD('END'),
+        KEYWORD('END')])]
+
+def get_sql_flush(style, tables, sequences):
+    """Return a list of SQL statements required to remove all data from
+    all tables in the database (without actually removing the tables
+    themselves) and put the database in an empty 'initial' state
+
+    For Firebird we gonna take a dangerous workaround:
+        - first create a temporary table 'django_flush$constraints' that
+        will contain all Foreignkey definitions for this database.
+        - next import this definitions into the new table and delete them
+        from system table 'rdb$relation_constraints'.
+        - after the flush is done import the definitions back to the system table
+        and delete the temporary table.
+    """
+    KEYWORD = style.SQL_KEYWORD
+    TABLE = style.SQL_TABLE
+    FIELD = style.SQL_FIELD
+
+    if tables:
+        temp_table_name = quote_name('django_flush$constraints')
+        orig_table_name = 'RDB$RELATION_CONSTRAINTS'
+        sql = ["\n".join([
+            "%s %s (" % (KEYWORD('CREATE TABLE'), TABLE(temp_table_name)),
+            "  %s %s(31) %s," % (FIELD(quote_name('rdb$constraint_name')), KEYWORD('CHAR'), KEYWORD('CHARACTER SET UNICODE_FSS')),
+            "  %s %s(11)," % (FIELD(quote_name('rdb$constraint_type')), KEYWORD('CHAR')),
+            "  %s %s(31) %s," % (FIELD(quote_name('rdb$relation_name')), KEYWORD('CHAR'), KEYWORD('CHARACTER SET UNICODE_FSS')),
+            "  %s %s(3)," % (FIELD(quote_name('rdb$deferrable')), KEYWORD('CHAR')),
+            "  %s %s(3)," % (FIELD(quote_name('rdb$initially_deferred')), KEYWORD('CHAR')),
+            "  %s %s(31) %s" % (FIELD(quote_name('rdb$index_name')), KEYWORD('CHAR'), KEYWORD('CHARACTER SET UNICODE_FSS')),
+            ");"]),
+            "%s;" % KEYWORD('COMMIT'),
+            "%s %s %s %s %s %s %s %s = 'FOREIGN KEY';" % ( \
+                KEYWORD('INSERT INTO'), TABLE(temp_table_name),
+                KEYWORD('SELECT'), FIELD('*'), KEYWORD('FROM'), TABLE(orig_table_name),
+                KEYWORD('WHERE'), FIELD('rdb$constraint_type')),
+            "%s %s %s %s = 'FOREIGN KEY';" % ( \
+                KEYWORD('DELETE FROM'), TABLE(orig_table_name),
+                KEYWORD('WHERE'), FIELD('rdb$constraint_type')),
+            "%s;" % KEYWORD('COMMIT')]
+
+        sql += ['%s %s;' % \
+                (KEYWORD('DELETE FROM'),
+                 TABLE(quote_name(table))
+                 ) for table in tables]
+
+        sql += ["%s %s %s 0;" % \
+                (KEYWORD(server_version < '2' and 'SET GENERATOR' or 'ALTER SEQUENCE'),
+                 TABLE(_quote_sequence_name(sequence['table'])),
+                 KEYWORD(server_version < '2' and 'TO' or 'RESTART WITH')
+                 ) for sequence in sequences]
+        return sql + [
+            "%s %s %s %s %s %s;" % ( \
+                KEYWORD('INSERT INTO'), TABLE(orig_table_name),
+                KEYWORD('SELECT'), FIELD('*'), KEYWORD('FROM'), TABLE(temp_table_name)),
+            "%s %s;" % (KEYWORD('DROP TABLE'), TABLE(temp_table_name)),
+            "%s;" % KEYWORD('COMMIT')]
+    return []
+
+OPERATOR_MAPPING = {
+    'exact': '= %s',
+    'iexact': "= UPPER(%s)",
+    'contains': "LIKE %s ESCAPE '\\'",
+    'icontains': "LIKE UPPER(%s) ESCAPE '\\'",
+    'gt': '> %s',
+    'gte': '>= %s',
+    'lt': '< %s',
+    'lte': '<= %s',
+    'startswith': "LIKE %s ESCAPE '\\'",
+    'endswith': "LIKE %s ESCAPE '\\'",
+    'istartswith': "LIKE UPPER(%s) ESCAPE '\\'",
+    'iendswith': "LIKE UPPER(%s) ESCAPE '\\'",
+
+    'text_icontains': "CONTAINING %s",
+}
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,91 @@
+from django.db import transaction
+from django.db.backends.firebird.base import 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,120 @@
+from django.core import management
+import sys, os, time
+
+# This dictionary maps Field objects to their associated PostgreSQL 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.
+
+DATA_TYPES = {
+    'AutoField':                     'INTEGER',
+    'BooleanField':                  'SMALLINT',
+    'CharField':                     'VARCHAR(%(maxlength)s)',
+    'CommaSeparatedIntegerField':    'VARCHAR(%(maxlength)s)',
+    'DateField':                     'DATE',
+    'DateTimeField':                 'TIMESTAMP',
+    'FileField':                     'VARCHAR(100)',
+    'FilePathField':                 'VARCHAR(100)',
+    'FloatField':                    'NUMERIC(%(max_digits)s, %(decimal_places)s)',
+    'ImageField':                    'VARCHAR(100)',
+    'IntegerField':                  'INTEGER',
+    'IPAddressField':                'VARCHAR(15)',
+    'ManyToManyField':               None,
+    'NullBooleanField':              'SMALLINT',
+    'OneToOneField':                 'INTEGER',
+    'PhoneNumberField':              'VARCHAR(20)',
+    'PositiveIntegerField':          'INTEGER',
+    'PositiveSmallIntegerField':     'SMALLINT',
+    'SlugField':                     'VARCHAR(%(maxlength)s)',
+    'SmallIntegerField':             'SMALLINT',
+    'TextField':                     'BLOB SUB_TYPE TEXT',
+    'TimeField':                     'TIME',
+    'URLField':                      'VARCHAR(200)',
+    'USStateField':                  'VARCHAR(2)',
+}
+
+TEST_DATABASE_PREFIX = 'test_'
+
+def create_test_db(settings, connection, backend, verbosity, autoclobber):
+
+    if verbosity >= 1:
+        print "Creating test database..."
+
+    if settings.TEST_DATABASE_NAME:
+        if os.path.isfile(settings.DATABASE_NAME):
+            TEST_DATABASE_NAME = os.path.join(
+                os.path.dirname(settings.DATABASE_NAME),
+                settings.TEST_DATABASE_NAME)
+        else:
+            import tempfile
+            tempfile.gettempdir()
+            TEST_DATABASE_NAME = os.path.join(
+                tempfile.gettempdir(),
+                settings.TEST_DATABASE_NAME)
+    else:
+        if os.path.isfile(settings.DATABASE_NAME):
+            TEST_DATABASE_NAME = os.path.join(
+                os.path.dirname(settings.DATABASE_NAME),
+                TEST_DATABASE_PREFIX + os.path.basename(settings.DATABASE_NAME))
+        else:
+            import tempfile
+            tempfile.gettempdir()
+            TEST_DATABASE_NAME = os.path.join(
+                tempfile.gettempdir(),
+                TEST_DATABASE_PREFIX + settings.DATABASE_NAME)
+
+    settings.DATABASE_NAME = TEST_DATABASE_NAME
+
+    try:
+        _create_test_db(backend, settings)
+    except Exception, e:
+        sys.stderr.write("Got an error creating the test database: %s\n" % e)
+        if not autoclobber:
+            confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)
+        if autoclobber or confirm == 'yes':
+            try:
+                if verbosity >= 1:
+                    print "Destroying old test database..."
+                _destroy_test_db(connection)
+                if verbosity >= 1:
+                    print "Creating test database..."
+                _create_test_db(backend, settings)
+            except Exception, e:
+                sys.stderr.write("Got an error recreating the test database: %s\n" % e)
+                sys.exit(2)
+        else:
+            print "Tests cancelled."
+            sys.exit(1)
+
+    management.syncdb(verbosity, interactive=False)
+
+    # Get a cursor (even though we don't need one yet). This has
+    # the side effect of initializing the test database.
+    cursor = connection.cursor()
+
+
+def destroy_test_db(settings, connection, backend, old_database_name, verbosity):
+    if verbosity >= 1:
+        print "Destroying test database..."
+
+    # To avoid "database is being accessed by other users" errors.
+    time.sleep(1)
+    _destroy_test_db(connection)
+
+def _create_test_db(backend, settings):
+    connection = backend.Database.create_database("""
+        CREATE DATABASE '%s' user '%s' password '%s'""" % \
+        (settings.DATABASE_NAME, settings.DATABASE_USER, settings.DATABASE_PASSWORD))
+    cursor = connection.cursor()
+    cursor.execute("""
+    DECLARE EXTERNAL FUNCTION rand
+        RETURNS DOUBLE PRECISION
+        BY VALUE ENTRY_POINT 'IB_UDF_rand' MODULE_NAME 'ib_udf';
+    """)
+    connection.commit()
+    connection.close()
+
+def _destroy_test_db(connection):
+    cursor = connection.cursor()
+    connection.connection.drop_database()
+    connection.connection = None
\ No newline at end of file
Index: django/core/management.py
===================================================================
--- django/core/management.py	(revision 5080)
+++ django/core/management.py	(working copy)
@@ -159,6 +159,7 @@
     Returns list_of_sql, pending_references_dict
     """
     from django.db import backend, get_creation_module, models
+    from django.conf import settings
     data_types = get_creation_module().DATA_TYPES
 
     opts = model._meta
@@ -177,7 +178,11 @@
             # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
             field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
                 style.SQL_COLTYPE(col_type % rel_field.__dict__)]
-            field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
+            column_null_sql = '%sNULL' % (not f.null and 'NOT ' or '')
+            if settings.DATABASE_ENGINE == 'firebird' and f.null:
+                column_null_sql = (not f.null or f.primary_key) and 'NOT NULL' or ''
+            if column_null_sql:
+                field_output.append(style.SQL_KEYWORD(column_null_sql))
             if f.unique:
                 field_output.append(style.SQL_KEYWORD('UNIQUE'))
             if f.primary_key:
@@ -207,6 +212,9 @@
         full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
     full_statement.append(');')
     final_output.append('\n'.join(full_statement))
+    
+    if opts.has_auto_field and hasattr(backend, 'get_sequence_sql'):
+        final_output += backend.get_sequence_sql(style, opts.db_table, opts.pk.column)
 
     return final_output, pending_references
 
@@ -231,7 +239,7 @@
                 # So we are careful with character usage here.
                 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
                 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
-                    (backend.quote_name(r_table), r_name,
+                    (backend.quote_name(r_table), backend.quote_name(r_name),
                     backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col), 
                     backend.get_deferrable_sql()))
             del pending_references[model]
@@ -273,6 +281,8 @@
                 style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name()))))
             table_output.append(');')
             final_output.append('\n'.join(table_output))
+            if hasattr(backend, 'get_sequence_sql'):
+                final_output += backend.get_sequence_sql(style, f.m2m_db_table(), 'id')
     return final_output
 
 def get_sql_delete(app):
@@ -456,7 +466,7 @@
             unique = f.unique and 'UNIQUE ' or ''
             output.append(
                 style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
-                style.SQL_TABLE('%s_%s' % (model._meta.db_table, f.column)) + ' ' + \
+                style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
                 style.SQL_KEYWORD('ON') + ' ' + \
                 style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
                 "(%s);" % style.SQL_FIELD(backend.quote_name(f.column))
Index: django/contrib/redirects/models.py
===================================================================
--- django/contrib/redirects/models.py	(revision 5080)
+++ django/contrib/redirects/models.py	(working copy)
@@ -4,9 +4,9 @@
 
 class Redirect(models.Model):
     site = models.ForeignKey(Site, radio_admin=models.VERTICAL)
-    old_path = models.CharField(_('redirect from'), maxlength=200, db_index=True,
+    old_path = models.CharField(_('redirect from'), maxlength=100, db_index=False,
         help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'."))
-    new_path = models.CharField(_('redirect to'), maxlength=200, blank=True,
+    new_path = models.CharField(_('redirect to'), maxlength=100, blank=True,
         help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'."))
 
     class Meta:
