Index: django/db/models/base.py
===================================================================
--- django/db/models/base.py	(revision 6660)
+++ 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 6660)
+++ django/db/models/fields/__init__.py	(working copy)
@@ -6,7 +6,7 @@
 except ImportError:
     from django.utils import _decimal as decimal    # for Python 2.3
 
-from django.db import get_creation_module
+from django.db import connection, get_creation_module
 from django.db.models import signals
 from django.dispatch import dispatcher
 from django.conf import settings
@@ -66,7 +66,7 @@
 #
 #     getattr(obj, opts.pk.attname)
 
-class Field(object):
+class _Field(object):
     # Provide backwards compatibility for the maxlength attribute and
     # argument for this class and all subclasses.
     __metaclass__ = LegacyMaxlength
@@ -83,11 +83,12 @@
         core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True,
         prepopulate_from=None, unique_for_date=None, unique_for_month=None,
         unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
-        help_text='', db_column=None, db_tablespace=None):
+        help_text='', db_column=None, db_tablespace=None, encoding=None):
         self.name = name
         self.verbose_name = verbose_name
         self.primary_key = primary_key
         self.max_length, self.unique = max_length, unique
+        self.encoding = encoding
         self.blank, self.null = blank, null
         # Oracle treats the empty string ('') as null, so coerce the null
         # option whenever '' is a possible value.
@@ -148,7 +149,7 @@
         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 validate_full(self, field_data, all_data):
@@ -402,6 +403,12 @@
         "Returns the value of this field in the given model instance."
         return getattr(obj, self.attname)
 
+# Use the backend's Field class if it defines one. Otherwise, use _Field.
+if connection.features.uses_custom_field:
+    Field = connection.ops.field_class(_Field)
+else:
+    Field = _Field
+
 class AutoField(Field):
     empty_strings_allowed = False
     def __init__(self, *args, **kwargs):
@@ -688,6 +695,14 @@
         defaults.update(kwargs)
         return super(DecimalField, self).formfield(**defaults)
 
+class DefaultCharField(CharField):
+    def __init__(self, *args, **kwargs):
+        DEFAULT_MAX_LENGTH = 100
+        if hasattr(settings, 'DEFAULT_MAX_LENGTH'):
+           DEFAULT_MAX_LENGTH = settings.DEFAULT_MAX_LENGT
+        kwargs['max_length'] = kwargs.get('max_length', DEFAULT_MAX_LENGTH)
+        CharField.__init__(self, *args, **kwargs)
+
 class EmailField(CharField):
     def __init__(self, *args, **kwargs):
         kwargs['max_length'] = kwargs.get('max_length', 75)
@@ -890,6 +905,15 @@
         defaults.update(kwargs)
         return super(IPAddressField, self).formfield(**defaults)
 
+class LargeTextField(Field):
+    def get_manipulator_field_objs(self):
+        return [oldforms.LargeTextField]
+
+    def formfield(self, **kwargs):
+        defaults = {'widget': forms.Textarea}
+        defaults.update(kwargs)
+        return super(LargeTextField, self).formfield(**defaults)
+
 class NullBooleanField(Field):
     empty_strings_allowed = False
     def __init__(self, *args, **kwargs):
@@ -997,8 +1021,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 6660)
+++ django/db/models/fields/related.py	(working copy)
@@ -331,18 +331,19 @@
                         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),
-                        [self._pk_val, obj_id])
+                    cursor.execute('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)' % \
+                        (qn(self.join_table), qn(source_col_name), qn(target_col_name)),
+                        (self._pk_val, obj_id))
                 transaction.commit_unless_managed()
 
         def _remove_items(self, source_col_name, target_col_name, *objs):
Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py	(revision 6660)
+++ django/db/models/query.py	(working copy)
@@ -612,7 +612,10 @@
         columns = [f.column for f in fields]
         select = ['%s.%s' % (qn(self.model._meta.db_table), qn(c)) for c in columns]
         if extra_select:
-            select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in extra_select])
+            if not settings.DATABASE_ENGINE == 'firebird':
+                select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in extra_select])
+            else:
+                select.extend(['(%s) AS %s' % (connection.ops.quote_id_plus_number(s[1]), qn(s[0])) for s in extra_select])
             field_names.extend([f[0] for f in extra_select])
 
         cursor = connection.cursor()
@@ -1111,7 +1114,6 @@
             # Last query term was a normal field.
             column = field.column
             db_type = field.db_type()
-
         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 6660)
+++ django/db/backends/__init__.py	(working copy)
@@ -48,7 +48,9 @@
     needs_upper_for_iops = False
     supports_constraints = True
     supports_tablespaces = False
+    quote_autofields = False
     uses_case_insensitive_names = False
+    uses_custom_field = False
     uses_custom_queryset = False
 
 class BaseDatabaseOperations(object):
@@ -65,7 +67,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
@@ -127,7 +136,7 @@
         contain a '%s' placeholder for the value being searched against.
         """
         raise NotImplementedError('Full-text search is not implemented for this database backend')
-
+    
     def last_executed_query(self, cursor, sql, params):
         """
         Returns a string of the query last executed by the given cursor, with
@@ -175,7 +184,7 @@
         is no limit.
         """
         return None
-
+   
     def pk_default_value(self):
         """
         Returns the value to use during an INSERT statement to specify 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,695 @@
+"""
+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
+import sys
+try:
+    import decimal
+except ImportError:
+    from django.utils import _decimal as decimal    # for Python 2.3
+
+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):
+    inline_fk_references = False 
+    needs_datetime_string_cast = False
+    needs_upper_for_iops = True
+    quote_autofields = True
+    supports_constraints = True #turn this off to pass the tests with forward/post references
+    uses_custom_field = True
+    uses_custom_queryset = True
+
+class DatabaseOperations(BaseDatabaseOperations):
+    _max_name_length = 31
+    def __init__(self):
+        self._firebird_version = None
+        self._page_size = None
+    
+    def get_generator_name(self, name):
+        return '%s_G' % util.truncate_name(name.strip('"'), self._max_name_length-2).upper()
+
+    def get_trigger_name(self, name):
+        return '%s_T' % util.truncate_name(name.strip('"'), 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._get_page_size()
+            self._index_limit = page_size/4
+        return self._index_limit
+    index_limit = property(_get_index_limit)
+
+    def autoinc_sql(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
+        """
+   
+        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;" % ( style.SQL_KEYWORD('CREATE GENERATOR'), 
+                                     style.SQL_TABLE(generator_name))      
+        trigger_sql = "\n".join([
+            "%s %s %s %s" % ( \
+            style.SQL_KEYWORD('CREATE TRIGGER'), style.SQL_TABLE(trigger_name), style.SQL_KEYWORD('FOR'),
+            style.SQL_TABLE(table_name)),
+            "%s 0 %s" % (style.SQL_KEYWORD('ACTIVE BEFORE INSERT POSITION'), style.SQL_KEYWORD('AS')),
+            style.SQL_KEYWORD('BEGIN'), 
+            "  %s ((%s.%s %s) %s (%s.%s = 0)) %s" % ( \
+                style.SQL_KEYWORD('IF'),
+                style.SQL_KEYWORD('NEW'), style.SQL_FIELD(column_name), style.SQL_KEYWORD('IS NULL'),
+                style.SQL_KEYWORD('OR'), style.SQL_KEYWORD('NEW'), style.SQL_FIELD(column_name),
+                style.SQL_KEYWORD('THEN')
+            ),
+            "  %s" % style.SQL_KEYWORD('BEGIN'), 
+            "    %s.%s = %s(%s, 1);" % ( \
+                style.SQL_KEYWORD('NEW'), style.SQL_FIELD(column_name),
+                style.SQL_KEYWORD('GEN_ID'), style.SQL_TABLE(generator_name)
+            ),
+            "  %s" % style.SQL_KEYWORD('END'),
+            style.SQL_KEYWORD('END')
+            ])
+        return (generator_sql, trigger_sql)
+
+    def max_name_length(self):
+        return self._max_name_length
+         
+    def field_class(this, DefaultField):
+        from django.db import connection
+        from django.db.models.fields import prep_for_like_query
+        class FirebirdField(DefaultField):
+            def get_db_prep_lookup(self, lookup_type, value):       
+                "Returns field's value prepared for database lookup."
+                if lookup_type in ('exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 
+                    'lte', 'month', 'day', 'search', 'icontains', 
+                    'startswith', 'istartswith'):
+                    return [value]
+                elif lookup_type in ('range', 'in'):
+                    return value
+                elif lookup_type in ('contains',):
+                    return ["%%%s%%" % prep_for_like_query(value)]
+                elif lookup_type == 'iexact':
+                    return [prep_for_like_query(value)]
+                elif lookup_type in ('endswith', 'iendswith'):
+                    return ["%%%s" % prep_for_like_query(value)]
+                elif lookup_type == 'isnull':
+                    return []
+                elif lookup_type == 'year':
+                    try:
+                        value = int(value)
+                    except ValueError:
+                        raise ValueError("The __year lookup type requires an integer argument")
+                    return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.999999' % value]
+                raise TypeError("Field has invalid lookup: %s" % lookup_type)
+        return FirebirdField
+
+    def query_set_class(this, DefaultQuerySet):
+        from django.db import connection
+        from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE
+        class FirebirdQuerySet(DefaultQuerySet):
+            def _get_sql_clause(self):
+                from django.db.models.query import SortedDict, handle_legacy_orderlist, orderfield2column, fill_table_cache
+                qn = this.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
+                
+            def extra(self, select=None, where=None, params=None, tables=None):
+                assert self._limit is None and self._offset is None, \
+                        "Cannot change a query once a slice has been taken"
+                clone = self._clone()
+                qn = this.quote_name
+                if select: clone._select.update(select)
+                if where:
+                    qn_where = []
+                    for where_item in where:
+                        try:
+                            table, col_exact = where_item.split(".")
+                            col, value = col_exact.split("=")
+                            where_item = "%s.%s = %s" % (qn(table.strip()), 
+                                qn(col.strip()), value.strip())
+                        except:
+                            try:
+                                table, value = where_item.split("=")
+                                where_item = "%s = %s" % (qn(table.strip()), qn(value.strip()))
+                            except:
+                                raise TypeError, "Can't understand extra WHERE clause: %s" % where 
+                        qn_where.append(where_item)
+                    clone._where.extend(qn_where)
+                if params: clone._params.extend(params)
+                if tables: clone._tables.extend(tables)
+                return clone
+                
+        return FirebirdQuerySet
+
+    def quote_name(self, name):
+        name = '"%s"' % util.truncate_name(name.strip('"'), self._max_name_length)
+        return name
+    
+    def quote_id_plus_number(self, name):
+        try:
+            return '"%s" + %s' % tuple(s.strip() for s in name.strip('"').split('+'))
+        except:
+            return self.quote_name(name)
+            
+    def pk_default_value(self):
+        """
+        Returns the value to use during an INSERT statement to specify that
+        the field should use its default value.
+        """
+        return 'NULL'
+    
+    def field_cast_sql(self, db_type):
+        return '%s'
+    
+    def last_insert_id(self, cursor, table_name, pk_name=None):
+        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):
+        #TODO: Use ON DELETE CASCADE only on M2M tables by default 
+        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 start_transaction_sql(self):
+        return ""
+
+    def sequence_reset_sql(self, style, model_list):
+        from django.db import models
+        output = []
+        sql = ['%s %s %s' % (style.SQL_KEYWORD('CREATE OR ALTER PROCEDURE'),
+                             style.SQL_TABLE('"GENERATOR_RESET"'),
+                             style.SQL_KEYWORD('AS'))]
+        sql.append('%s %s' % (style.SQL_KEYWORD('DECLARE VARIABLE'), style.SQL_COLTYPE('start_val integer;')))
+        sql.append('%s %s' % (style.SQL_KEYWORD('DECLARE VARIABLE'), style.SQL_COLTYPE('gen_val integer;')))
+        sql.append('\t%s' % style.SQL_KEYWORD('BEGIN'))
+        sql.append('\t\t%s %s %s %s %s %s;' % (style.SQL_KEYWORD('SELECT MAX'), style.SQL_FIELD('(%(col)s)'),
+                                           style.SQL_KEYWORD('FROM'), style.SQL_TABLE('%(table)s'),
+                                           style.SQL_KEYWORD('INTO'), style.SQL_COLTYPE(':start_val')))
+        sql.append('\t\t%s (%s %s) %s' % (style.SQL_KEYWORD('IF'), style.SQL_COLTYPE('start_val'),
+                                    style.SQL_KEYWORD('IS NULL'), style.SQL_KEYWORD('THEN')))
+        sql.append('\t\t\t%s = %s(%s, 1 - %s(%s, 0));' %\
+            (style.SQL_COLTYPE('gen_val'), style.SQL_KEYWORD('GEN_ID'), style.SQL_TABLE('%(gen)s'),
+             style.SQL_KEYWORD('GEN_ID'), style.SQL_TABLE('%(gen)s')))
+        sql.append('\t\t%s' % style.SQL_KEYWORD('ELSE'))
+        sql.append('\t\t\t%s = %s(%s, %s - %s(%s, 0));' %\
+            (style.SQL_COLTYPE('gen_val'), style.SQL_KEYWORD('GEN_ID'),
+             style.SQL_TABLE('%(gen)s'), style.SQL_COLTYPE('start_val'), style.SQL_KEYWORD('GEN_ID'),
+             style.SQL_TABLE('%(gen)s')))
+        sql.append('\t\t%s;' % style.SQL_KEYWORD('EXIT'))
+        sql.append('%s;' % style.SQL_KEYWORD('END'))
+        sql ="\n".join(sql)
+        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('%s %s;' % (style.SQL_KEYWORD('EXECUTE PROCEDURE'), 
+                                              style.SQL_TABLE('"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('%s %s;' % (style.SQL_KEYWORD('EXECUTE PROCEDURE'), 
+                                          style.SQL_TABLE('"GENERATOR_RESET"')))
+        return output
+    
+    def sql_flush(self, style, tables, sequences):
+        if tables:
+            #TODO: Alter all tables witk FKs without ON DELETE CASCADE to set it
+            # Them reset to previous state when all are deleted
+            # Becasue we may not want to have ON DELETE CASCADE by default on all FK fields
+            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 = "%s %s %s 0;" % (style.SQL_KEYWORD('SET GENERATOR'), 
+                    style.SQL_TABLE(self.get_generator_name(table_name)), style.SQL_KEYWORD('TO'))
+                sql.append(query)
+            return sql
+        else:
+            return []
+
+    def fulltext_search_sql(self, field_name):
+        # We use varchar for TextFields so this is possible
+        # Look at http://www.volny.cz/iprenosil/interbase/ip_ib_strings.htm
+        return '%%s CONTAINING %s' % self.quote_name(field_name)
+        
+    def drop_sequence_sql(self, table):
+        return "DROP GENERATOR %s;" % self.get_generator_name(table)
+        
+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):
+        if text is not None:  
+            return self.dj_ue.smart_str(text, 'ascii')
+    
+    def ascii_conv_out(self, text):
+        if text is not None:
+            return self.dj_ue.smart_unicode(text)
+    
+    def fixed_conv_in(self, (val, scale)):
+        if val is not None:
+            if isinstance(val, basestring):
+                val = decimal.Decimal(val)
+            return self.tc_fd.fixed_conv_in_precise((val, scale))
+
+    def unicode_conv_in(self, text):
+        if text[0] is not None:
+            return self.tc_tu.unicode_conv_in((self.dj_ue.smart_unicode(text[0]), self.FB_CHARSET_CODE))
+
+    def blob_conv_in(self, text): 
+        return self.tc_tu.unicode_conv_in((self.dj_ue.smart_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, connection):   
+        self.cursor = cursor
+        self._connection = connection
+        self._statement = None #prepared statement
+        self.FB_CHARSET_CODE = 3 #UNICODE_FSS
+        if connection.charset == 'UTF8':
+            self.FB_CHARSET_CODE = 4 # UTF-8 with Firebird 2.0+
+        DEFAULT_MAX_LENGTH = connection.DEFAULT_MAX_LENGTH
+        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.fixed_conv_in,
+            '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_precise,
+            'TEXT':             self.ascii_conv_out,
+            'TEXT_UNICODE':     self.tc_tu.unicode_conv_out,
+            'BLOB':             self.blob_conv_out
+        })
+        # Create DOMAINS
+        domains = [ ('AutoField', 'integer'),
+                    ('BooleanField', 'smallint CHECK (VALUE IN (0,1))'),
+                    ('DateField', 'date'),
+                    ('CharField', 'varchar(%i)' % DEFAULT_MAX_LENGTH),
+                    ('DateTimeField', 'timestamp'),
+                    ('FloatField', 'double precision'),
+                    ('IntegerField', 'integer'),
+                    ('IPAddressField', 'varchar(15) CHARACTER SET ASCII'),
+                    ('NullBooleanField', 'smallint CHECK ((VALUE IN (0,1)) OR (VALUE IS NULL))'),
+                    ('OneToOneField', 'integer'),
+                    ('PhoneNumberField', 'varchar(20) CHARACTER SET ASCII'),
+                    ('PositiveIntegerField', 'integer CHECK ((VALUE >= 0) OR (VALUE IS NULL))'),
+                    ('PositiveSmallIntegerField', 'smallint CHECK ((VALUE >= 0) OR (VALUE IS NULL))'),
+                    ('SmallIntegerField', 'smallint'),
+                    ('TextField', 'varchar(%s)' % connection.FB_MAX_VARCHAR),
+                    ('LargeTextField', 'blob sub_type text'),
+                    ('TimeField', 'time'),
+                    ('USStateField', 'varchar(2) CHARACTER SET ASCII') ]
+        # Create domains only if they do not exist already    
+        cursor.execute("SELECT RDB$FIELD_NAME FROM RDB$FIELDS")
+        existing_domains = set([row[0].strip() for row in cursor.fetchall() if not row[0].startswith('RDB$')])
+        domains = map(lambda domain: '%s "%s" AS %s;' % ('CREATE DOMAIN', domain[0], domain[1]), 
+            filter(lambda x: x[0] not in existing_domains, domains))
+        for domain in domains:
+            connection.execute_immediate(domain)
+        # But alter CharField to sync with any changes in settings for use with DefaultCharField object
+        connection.execute_immediate('ALTER DOMAIN "CharField" TYPE varchar(%i)' % DEFAULT_MAX_LENGTH)
+        
+        # Declare FUNCTIONS
+        cursor.execute("SELECT RDB$FUNCTION_NAME FROM RDB$FUNCTIONS")
+        existing_functions = set([row[0].strip().upper() for row in cursor.fetchall()])
+        if 'RAND' not in existing_functions:
+            connection.execute_immediate("""
+                DECLARE EXTERNAL FUNCTION RAND
+                RETURNS DOUBLE PRECISION
+                BY VALUE ENTRY_POINT 'IB_UDF_rand' MODULE_NAME 'ib_udf';
+                """)
+ 
+    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_immediate(self, query, params=()):
+        query = query % tuple(params)
+        self._connection.execute_immediate(query)
+    
+    # Prepared Statement 
+    # http://kinterbasdb.sourceforge.net/dist_docs/usage.html#adv_prepared_statements
+    def prepare(self, query):
+        query.replace("%s", "?")
+        return self.cursor.prep(query)
+    
+    def execute_prepared(self, statement, params):
+        return self.cursor.execute(statement, params)
+    
+    def execute_straight(self, query, params=()):
+        # Use kinterbasdb style with '?' instead of '%s'
+        return self.cursor.execute(query, params)
+    
+    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 = ["Prepare query error."]
+                output.extend(str(e).split("'")[1].split('\\n'))
+                output.append("Query:")
+                output.append(cquery)
+                raise Database.ProgrammingError, "\n".join(output)
+        try:
+            return self.cursor.execute(self._statement, params)
+        except Database.ProgrammingError, e:
+            err_no = int(str(e).split()[0].strip(',()'))
+            output = ["Execute query error. FB error No. %i" % err_no]
+            output.extend(str(e).split("'")[1].split('\\n'))
+            output.append("Query:")
+            output.append(cquery)
+            output.append("Parameters:")
+            output.append(str(params))
+            raise Database.ProgrammingError, "\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'\\'"
+    }
+   
+    def __init__(self, **kwargs):
+        from django.conf import settings
+        super(DatabaseWrapper, self).__init__(**kwargs)
+        self. _current_cursor = None
+        self._raw_cursor = None
+        self.charset = 'UNICODE_FSS'
+        self.FB_MAX_VARCHAR = 10921 #32765 MAX /3
+        self.BYTES_PER_DEFAULT_CHAR = 3
+        if hasattr(settings, 'FIREBIRD_CHARSET'):
+            if settings.FIREBIRD_CHARSET == 'UTF8':
+                self.charset = 'UTF8' 
+                self.FB_MAX_VARCHAR = 8191 #32765 MAX /4
+                self.BYTES_PER_DEFAULT_CHAR = 4
+        self.DEFAULT_MAX_LENGTH = 100
+        if hasattr(settings, 'DEFAULT_MAX_LENGTH'):
+           # You can set DEFAULT_MAX_LENGTH in settings.py and all
+           # DefaultCharField objects will have this value automaticaly
+           # with a little help from Firebird's domains
+           self.DEFAULT_MAX_LENGTH = settings.DEFAULT_MAX_LENGTH  
+    
+        
+    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."
+        kwargs = {'charset' : self.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.connection.charset == self.charset
+       
+    def cursor(self):
+        from django.conf import settings
+        cursor = self._cursor(settings)
+        if settings.DEBUG:
+            self._debug_cursor = self.make_debug_cursor(cursor)
+            return self._debug_cursor
+        return cursor
+    
+    def _cursor(self, settings):
+        if self.connection is None:
+            self._connect(settings)
+        cursor = self.connection.cursor()
+        self._raw_cursor = cursor
+        cursor = FirebirdCursorWrapper(cursor, self)
+        self._current_cursor = cursor
+        return cursor
+
+    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,394 @@
+# 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, codecs
+from kinterbasdb import connect, create_database
+from django.core.management import call_command
+from django.conf import settings
+from django.db import connection
+
+
+
+DATA_TYPES = {
+    'AutoField':                     '"AutoField"',
+    'BooleanField':                  '"BooleanField"',
+    'CharField':                     'varchar(%(max_length)s)',
+    'CommaSeparatedIntegerField':    'varchar(%(max_length)s) CHARACTER SET ASCII',
+    'DateField':                     '"DateField"',
+    'DateTimeField':                 '"DateTimeField"',
+    'DecimalField':                  'numeric(%(max_digits)s, %(decimal_places)s)',
+    'DefaultCharField':              '"CharField"',
+    'FileField':                     'varchar(%(max_length)s)',
+    'FilePathField':                 'varchar(%(max_length)s)',
+    'FloatField':                    '"FloatField"',
+    'ImageField':                    '"varchar(%(max_length)s)"',
+    'IntegerField':                  '"IntegerField"',
+    'IPAddressField':                'varchar(15) CHARACTER SET ASCII',
+    'NullBooleanField':              '"NullBooleanField"', 
+    'OneToOneField':                 '"OneToOneField"',
+    'PhoneNumberField':              '"PhoneNumberField"', 
+    'PositiveIntegerField':          '"PositiveIntegerField"',
+    'PositiveSmallIntegerField':     '"PositiveSmallIntegerField"',
+    'SlugField':                     'varchar(%(max_length)s)',
+    'SmallIntegerField':             '"SmallIntegerField"',
+    'LargeTextField':                '"LargeTextField"',
+    'TextField':                     '"TextField"',
+    'TimeField':                     '"TimeField"',
+    'URLField':                      'varchar(%(max_length)s) CHARACTER SET ASCII',
+    'USStateField':                  '"USStateField"'
+}
+      
+PYTHON_TO_FB_ENCODING_MAP = {
+    'ascii':        'ASCII',
+    'utf_8':        connection.charset,
+    'shift_jis':    'SJIS_0208',
+    'euc_jp':       'EUCJ_0208',
+    'cp737':        'DOS737',
+    'cp437':        'DOS437',
+    'cp850':        'DOS850',
+    'cp865':        'DOS865',
+    'cp860':        'DOS860',
+    'cp863':        'DOS863',
+    'cp775':        'DOS775',
+    'cp862':        'DOS862',
+    'cp864':        'DOS864',
+    'iso8859_1':    'ISO8859_1',
+    'iso8859_2':    'ISO8859_2',
+    'iso8859_3':    'ISO8859_3',
+    'iso8859_4':    'ISO8859_4',
+    'iso8859_5':    'ISO8859_5',
+    'iso8859_6':    'ISO8859_6',
+    'iso8859_7':    'ISO8859_7',
+    'iso8859_8':    'ISO8859_8',
+    'iso8859_9':    'ISO8859_9',
+    'iso8859_13':   'ISO8859_13',
+    'euc_kr':       'KSC_5601',
+    'cp852':        'DOS852',
+    'cp857':        'DOS857',
+    'cp861':        'DOS861',
+    'cp866':        'DOS866',
+    'cp869':        'DOS869',
+    'cp1250':       'WIN1250',
+    'cp1251':       'WIN1251',
+    'cp1252':       'WIN1252',
+    'cp1253':       'WIN1253',
+    'cp1254':       'WIN1254',
+    'big5':         'BIG_5',
+    'gb2312':       'GB_2312',
+    'cp1255':       'WIN1255',
+    'cp1256':       'WIN1256',
+    'cp1257':       'WIN1257',
+    'koi8_r':       'KOI8-R',
+    'koi8_u':       'KOI8-U',
+    'cp1258':       'WIN1258'
+  }
+
+def get_data_size(data_type, max_length = 100):
+    char_bytes = connection.BYTES_PER_DEFAULT_CHAR
+    size_map = {
+        'AutoField':                     8,
+        'BooleanField':                  4,
+        'CharField':                     char_bytes*max_length,
+        'CommaSeparatedIntegerField':    max_length,
+        'DateField':                     16,
+        'DateTimeField':                 16,
+        'DecimalField':                  16,
+        'FileField':                     char_bytes*max_length,
+        'FilePathField':                 'varchar(%(max_length)s)',
+        'FloatField':                    16,
+        'ImageField':                    char_bytes*max_length,
+        'IntegerField':                  8,
+        'IPAddressField':                15,
+        'NullBooleanField':              4, 
+        'OneToOneField':                 8,
+        'PhoneNumberField':              20, 
+        'PositiveIntegerField':          8,
+        'PositiveSmallIntegerField':     4,
+        'SlugField':                     char_bytes*max_length,
+        'SmallIntegerField':             4,
+        'TextBlob':                      8,
+        'TextField':                     32767,
+        'TimeField':                     16,
+        'URLField':                      max_length,
+        'USStateField':                  char_bytes*2
+    }
+    return size_map[data_type]
+
+def sql_model_create(model, style, known_models=set()):
+    """
+    Returns the SQL required to create a single model, as a tuple of:
+        (list_of_sql, pending_references_dict)
+    """
+    from django.db import connection, models
+
+    opts = model._meta
+    final_output = []
+    table_output = []
+    pending_references = {}
+    qn = connection.ops.quote_name
+    inline_references = connection.features.inline_fk_references
+    # Check that row size is less than 64k and adjust TextFields if needed
+    row_size = 0
+    columns = [(f.db_type().strip('"'), f.get_internal_type(), f) for f in opts.fields]
+    columns_simple = [col[0] for col in columns] 
+    text_field_type = '"TextField"'
+    max_alowed_bytes = 32765
+    if 'TextField' in columns_simple:
+        max_length = 100
+        num_text_fields = 0
+        for column in columns:
+            num_text_fields += (column[0] == 'TextField')
+            if column[0].startswith('varchar'):
+                max_length = int(column[0].split('(')[1].split(')')[0])
+            if column[1] in DATA_TYPES:
+                row_size += get_data_size(column[1], max_length)
+        if row_size > 65536:
+            max_alowed_bytes = int( (max_alowed_bytes/num_text_fields) - (row_size-65536) )
+            n = max_alowed_bytes / connection.BYTES_PER_DEFAULT_CHAR
+            if n > 512: 
+                text_field_type = 'varchar(%s)' % n
+                FB_TEXTFIELD_ALTERED = True    
+                print
+                print "WARNING: Maximum number of characters in TextFields has changed to %s." % n
+                print "         TextField columns with custom charsets will have %s chars available" % max_alowed_bytes 
+                print "         The change affects %s table only." % opts.db_table
+                print "         TextFields in other tables will have %s characters maximum" % connection.FB_MAX_VARCHAR
+                print "         or 32765 characters with custom (non-UTF) encoding."
+                print "         If you need more space in those fields try LargeTextFields instead." 
+                print
+            else:
+                # Swich to blobs if size is too small (<1024)    
+                text_field_type = '"LargeTextField"'    
+    for f in opts.fields:
+        col_type = f.db_type()
+
+        if col_type.strip('"') == 'TextField':
+            col_type = text_field_type
+        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
+            custom_charset = False
+            if col_type.startswith('varchar'):
+                if (f.unique or f.primary_key or f.db_index):
+                    length = f.max_length
+                    if f.encoding:
+                        if not f.encoding.upper().startswith('UTF'):
+                            custom_charset = True
+                    if not custom_charset:
+                        try:
+                            length = f.max_length * connection.BYTES_PER_DEFAULT_CHAR 
+                        except TypeError:
+                            length = 100*connection.BYTES_PER_DEFAULT_CHAR #Default for CharField
+                    if length >= connection.ops.index_limit:   
+                        strip2ascii = True
+                if len(opts.unique_together) > 0:
+                    if f.column in opts.unique_together[0]:
+                        num_unique_char_fields = len([ fld for fld in opts.unique_together[0] if opts.get_field(fld).db_type().startswith('varchar') ])
+                        num_unique_fileds = len(opts.unique_together[0])
+                        num_unique_nonchar_fileds = num_unique_fileds - num_unique_char_fields
+                        limit = connection.ops.index_limit
+                        limit -= ((num_unique_fileds - 1)*64)
+                        limit -= 8*num_unique_nonchar_fileds
+                        max_length = limit/num_unique_char_fields
+                        ascii_length = int(f.max_length)
+                        old_length = ascii_length*connection.BYTES_PER_DEFAULT_CHAR
+                         
+                        if (old_length >= max_length) and (ascii_length < max_length):
+                            strip2ascii = True
+                        elif old_length > max_length:
+                            strip2ascii = False #We change it here
+                            col_type = "varchar(%i) CHARACTER SET ASCII" % max_length
+                            msg =  "WARNING: Character set of the '%s' field\n"
+                            msg += "         (table %s)\n"
+                            msg += "         has changed to ASCII"
+                            msg += " to fit %s-byte limit in FB %s"
+                            if not page_size:
+                                print  msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version)
+                            else:
+                                msg += " with page size %s"
+                                print  msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version, page_size)
+                            print "         The maximum length of '%s' is now %s instead of %s"\
+                             % (f.column, max_length, old_length)     
+            if strip2ascii:
+                col_type = "%s %s %s" % (col_type, "CHARACTER SET", "ASCII")
+                msg =  "WARNING: Character set of the '%s' field\n"
+                msg += "         (table %s)\n"
+                msg += "         has changed to ASCII"
+                msg += " to fit %s-byte limit in FB %s"
+                if not page_size:
+                    print  msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version)
+                else:
+                    msg += " with page size %s"
+                    print  msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version, page_size)
+                    
+        if (col_type.startswith('varchar') or col_type.strip('"') == 'TextField') and f.encoding:
+            charset = PYTHON_TO_FB_ENCODING_MAP[codecs.lookup(f.encoding).name]
+            if col_type.strip('"') == 'TextField':
+                col_type = 'varchar(%i)' % max_alowed_bytes
+            col_type = "%s %s %s" % (col_type, "CHARACTER SET", charset)
+ 
+            
+        if col_type is None:
+            # Skip ManyToManyFields, because they're not represented as
+            # database columns in this table.
+            continue
+        # 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('%s' % (not f.null and 'NOT NULL' or 'DEFAULT NULL')))
+        if f.unique:
+            field_output.append(style.SQL_KEYWORD('UNIQUE'))
+        if f.primary_key:
+            field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
+        if f.rel:
+            # 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))
+        table_output.append(' '.join(field_output))
+    if opts.order_with_respect_to:
+        table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
+            style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
+            style.SQL_KEYWORD('NULL'))
+    for field_constraints in opts.unique_together:
+        table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
+            ", ".join([qn(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
+
+    full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
+    for i, line in enumerate(table_output): # Combine and add commas.
+        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:
+        # Add any extra SQL needed to support auto-incrementing primary keys.
+        auto_column = opts.auto_field.db_column or opts.auto_field.name
+        autoinc_sql = connection.ops.autoinc_sql(style, opts.db_table, auto_column)
+        if autoinc_sql:
+            for stmt in autoinc_sql:
+                final_output.append(stmt)
+
+    return final_output, pending_references
+
+def many_to_many_sql_for_model(model, style):
+    from django.db import connection, models
+    from django.contrib.contenttypes import generic
+    from django.db.backends.util import truncate_name
+
+    opts = model._meta
+    final_output = []
+    qn = connection.ops.quote_name
+    for f in opts.many_to_many:
+        if not isinstance(f.rel, generic.GenericRel):
+            table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
+                style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
+            table_output.append('    %s %s %s,' %
+                (style.SQL_FIELD(qn('id')),
+                style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
+                style.SQL_KEYWORD('NOT NULL PRIMARY KEY')))
+
+            table_output.append('    %s %s %s,' %
+                (style.SQL_FIELD(qn(f.m2m_column_name())),
+                style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
+                style.SQL_KEYWORD('NOT NULL')))
+            table_output.append('    %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')))
+            deferred = [
+                (f.m2m_db_table(), f.m2m_column_name(), opts.db_table,
+                    opts.pk.column),
+                ( f.m2m_db_table(), f.m2m_reverse_name(),
+                    f.rel.to._meta.db_table, f.rel.to._meta.pk.column)
+                ]
+
+            table_output.append('    %s (%s, %s)' %
+                (style.SQL_KEYWORD('UNIQUE'),
+                style.SQL_FIELD(qn(f.m2m_column_name())),
+                style.SQL_FIELD(qn(f.m2m_reverse_name()))))
+            table_output.append(');')
+            final_output.append('\n'.join(table_output))
+            
+            autoinc_sql = connection.ops.autoinc_sql(style, f.m2m_db_table(), 'id')
+            if autoinc_sql:
+                for stmt in autoinc_sql:
+                    final_output.append(stmt)
+            
+            if connection.features.supports_constraints:
+                for r_table, r_col, table, col in deferred:
+                    r_name = '%s_%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;' % 
+                    (qn(r_table),
+                    truncate_name(r_name, connection.ops.max_name_length()),
+                    qn(r_col), qn(table), qn(col),
+                    'ON DELETE CASCADE ON UPDATE CASCADE'))
+
+    return final_output
+
+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 6660)
+++ 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 6660)
+++ 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
 
@@ -245,8 +246,11 @@
     Returns the SQL required to create a single model, as a tuple of:
         (list_of_sql, pending_references_dict)
     """
-    from django.db import connection, models
-
+    from django.db import connection, models, get_creation_module
+    creation_module = get_creation_module()
+    # If the database backend wants to create model itself, let it
+    if hasattr(creation_module, "sql_model_create"):
+        return creation_module.sql_model_create(model, style, known_models)
     opts = model._meta
     final_output = []
     table_output = []
@@ -332,18 +336,24 @@
                 # For MySQL, r_name must be unique in the first 64 characters.
                 # 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;' % \
+                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%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
 
 def many_to_many_sql_for_model(model, style):
-    from django.db import connection, models
+    from django.db import connection, models, get_creation_module
     from django.contrib.contenttypes import generic
     from django.db.backends.util import truncate_name
-
+    
+    creation_module = get_creation_module()
+    # If the database backend wants to create many_to_many sql itself, let it
+    if hasattr(creation_module, "many_to_many_sql_for_model"):
+        return creation_module.many_to_many_sql_for_model(model, style)
+        
     opts = model._meta
     final_output = []
     qn = connection.ops.quote_name
Index: tests/modeltests/custom_methods/models.py
===================================================================
--- tests/modeltests/custom_methods/models.py	(revision 6660)
+++ tests/modeltests/custom_methods/models.py	(working copy)
@@ -27,15 +27,16 @@
         """
         from django.db import connection
         cursor = connection.cursor()
+        # Some backends really really need quotes!
         cursor.execute("""
-            SELECT id, headline, pub_date
-            FROM custom_methods_article
-            WHERE pub_date = %s
-                AND id != %s""", [str(self.pub_date), self.id])
+            SELECT "id", "headline", "pub_date"
+            FROM "custom_methods_article"
+            WHERE "pub_date" = %s
+                AND "id" != %s""", [str(self.pub_date), self.id])
         # The asterisk in "(*row)" tells Python to expand the list into
         # positional arguments to Article().
         return [self.__class__(*row) for row in cursor.fetchall()]
-
+    
 __test__ = {'API_TESTS':"""
 # Create a couple of Articles.
 >>> from datetime import date
Index: tests/modeltests/lookup/models.py
===================================================================
--- tests/modeltests/lookup/models.py	(revision 6660)
+++ tests/modeltests/lookup/models.py	(working copy)
@@ -274,7 +274,34 @@
 >>> a4.save()
 >>> a5 = Article(pub_date=now, headline='hey-Foo')
 >>> a5.save()
+"""}
 
+# Firebird support 'magic values'
+if settings.DATABASE_ENGINE in ('firebird',):
+    __test__['API_TESTS'] += r"""
+# and yet more:
+>>> a10 = Article(pub_date='today', headline='foobar')
+>>> a10.save()
+>>> a11 = Article(pub_date='tomorrow', headline='foobaz')
+>>> a11.save()
+>>> a12 = Article(pub_date='yesterday', headline='ooF')
+>>> a12.save()
+>>> a13 = Article(pub_date='now', headline='foobarbaz')
+>>> a13.save()
+>>> a14 = Article(pub_date='today', headline='zoocarfaz')
+>>> a14.save()
+>>> a15 = Article(pub_date='today', headline='barfoobaz')
+>>> a15.save()
+>>> a16 = Article(pub_date='today', headline='bazbaRFOO')
+>>> a16.save()
+>>> Article.objects.filter(pub_date__exact='yesterday')
+[<Article: ooF>]
+"""
+
+
+# Firebird doesn't support regular expression lookups
+if settings.DATABASE_ENGINE not in ('firebird',):
+    __test__['API_TESTS'] += r"""
 # zero-or-more
 >>> Article.objects.filter(headline__regex=r'fo*')
 [<Article: f>, <Article: fo>, <Article: foo>, <Article: fooo>]
@@ -348,10 +375,10 @@
 [<Article: barfoobaz>, <Article: baz>, <Article: bazbaRFOO>, <Article: foobarbaz>, <Article: foobaz>]
 >>> Article.objects.filter(headline__iregex=r'b.*ar')
 [<Article: bar>, <Article: barfoobaz>, <Article: bazbaRFOO>, <Article: foobar>, <Article: foobarbaz>]
-"""}
+"""
 
 
-if settings.DATABASE_ENGINE not in ('mysql', 'mysql_old'):
+if settings.DATABASE_ENGINE not in ('mysql', 'mysql_old', 'firebird'):
     __test__['API_TESTS'] += r"""
 # grouping and backreferences
 >>> Article.objects.filter(headline__regex=r'b(.).*b\1')
Index: tests/regressiontests/serializers_regress/tests.py
===================================================================
--- tests/regressiontests/serializers_regress/tests.py	(revision 6660)
+++ tests/regressiontests/serializers_regress/tests.py	(working copy)
@@ -22,6 +22,10 @@
     import decimal
 except ImportError:
     from django.utils import _decimal as decimal
+try:
+    set
+except NameError:
+    from sets import Set as set   # Python 2.3 fallback 
 
 # A set of functions that can be used to recreate
 # test data objects of various kinds.
@@ -83,8 +87,9 @@
     testcase.assertEqual(data, instance.data_id)
 
 def m2m_compare(testcase, pk, klass, data):
+    # Use sets to ignore order of data
     instance = klass.objects.get(id=pk)
-    testcase.assertEqual(data, [obj.id for obj in instance.data.all()])
+    testcase.assertEqual(set(data), set([obj.id for obj in instance.data.all()]))
 
 def o2o_compare(testcase, pk, klass, data):
     instance = klass.objects.get(data=data)
Index: tests/regressiontests/backends/models.py
===================================================================
--- tests/regressiontests/backends/models.py	(revision 6660)
+++ 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>]
