Ticket #1261: release-0.96-firebird.diff

File release-0.96-firebird.diff, 31.8 KB (added by david@…, 8 years ago)

Patch against 0.96 with backend included

  • django/test/utils.py

     
    11import sys, time
    22from django.conf import settings
    3 from django.db import connection, transaction, backend
     3from django.db import connection, transaction, backend, get_creation_module
    44from django.core import management
    55from django.dispatch import dispatcher
    66from django.test import signals
     
    4444        connection.connection.set_isolation_level(0)
    4545
    4646def create_test_db(verbosity=1, autoclobber=False):
     47    # If the database backend wants to create the test DB itself, let it
     48    creation_module = get_creation_module()
     49    if hasattr(creation_module, "create_test_db"):
     50        creation_module.create_test_db(settings, connection, backend, verbosity, autoclobber)
     51        return
     52   
    4753    if verbosity >= 1:
    4854        print "Creating test database..."
    4955    # If we're using SQLite, it's more convenient to test against an
     
    9298    cursor = connection.cursor()
    9399
    94100def destroy_test_db(old_database_name, verbosity=1):
     101    # If the database wants to drop the test DB itself, let it
     102    creation_module = get_creation_module()
     103    if hasattr(creation_module, "destroy_test_db"):
     104        creation_module.destroy_test_db(settings, connection, backend, old_database_name, verbosity)
     105        return
     106   
    95107    # Unless we're using SQLite, remove the test database to clean up after
    96108    # ourselves. Connect to the previous database (not the test database)
    97109    # to do so, because it's not allowed to delete a database while being
  • django/db/models/base.py

     
    205205        record_exists = True
    206206        if pk_set:
    207207            # Determine whether a record with the primary key already exists.
    208             cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % \
     208            check_sql = 'SELECT 1 FROM %s WHERE %s=%%s LIMIT 1'
     209            if settings.DATABASE_ENGINE == 'firebird':
     210                check_sql = 'SELECT FIRST 1 1 FROM %s WHERE %s=%%s'
     211            cursor.execute(check_sql % \
    209212                (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val])
    210213            # If it does already exist, do an UPDATE.
    211214            if cursor.fetchone():
  • django/db/models/fields/related.py

     
    335335                    (target_col_name, self.join_table, source_col_name,
    336336                    target_col_name, ",".join(['%s'] * len(new_ids))),
    337337                    [self._pk_val] + list(new_ids))
    338                 if cursor.rowcount is not None and cursor.rowcount != 0:
    339                     existing_ids = set([row[0] for row in cursor.fetchmany(cursor.rowcount)])
     338                rows = cursor.fetchall()
     339                if rows:
     340                    existing_ids = set([row[0] for row in rows])
    340341                else:
    341342                    existing_ids = set()
    342343
  • django/db/models/query.py

     
    22from django.db.models.fields import DateField, FieldDoesNotExist
    33from django.db.models.fields.generic import GenericRelation
    44from django.db.models import signals
     5from django.conf import settings
    56from django.dispatch import dispatcher
    67from django.utils.datastructures import SortedDict
    78import operator
     
    179180        # undefined, so we convert it to a list of tuples.
    180181        extra_select = self._select.items()
    181182
     183        pre_columns = ""
     184        if settings.DATABASE_ENGINE == 'firebird' and self._limit is not None:
     185            pre_columns += "FIRST %s " % self._limit
     186            if self._offset:
     187                pre_columns += "SKIP %s " % self._offset
     188        if self._distinct:
     189            pre_columns += "DISTINCT "
    182190        cursor = connection.cursor()
    183         cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
     191        cursor.execute("SELECT " + pre_columns + ",".join(select) + sql, params)
    184192        fill_cache = self._select_related
    185193        index_end = len(self.model._meta.fields)
    186194        while 1:
     
    502510
    503511        # Compose the join dictionary into SQL describing the joins.
    504512        if joins:
    505             sql.append(" ".join(["%s %s AS %s ON %s" % (join_type, table, alias, condition)
     513            sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition)
    506514                            for (alias, (table, join_type, condition)) in joins.items()]))
    507515
    508516        # Compose the tables clause into SQL.
     
    717725        table_prefix = backend.quote_name(table_prefix[:-1])+'.'
    718726    field_name = backend.quote_name(field_name)
    719727    try:
    720         return '%s%s %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s'))
     728        lookup_sql = '%s%s %s'
     729        if settings.DATABASE_ENGINE == 'firebird' and lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'):
     730            lookup_sql = 'UPPER(%s%s) %s'
     731        return lookup_sql % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s'))
    721732    except KeyError:
    722733        pass
    723734    if lookup_type == 'in':
  • django/db/backends/util.py

     
    1 import datetime
     1import datetime, md5
    22from time import time
    33
    44class CursorDebugWrapper(object):
     
    3838        else:
    3939            return getattr(self.cursor, attr)
    4040
     41def truncate_name(name, length=None):
     42    """Shortens a string to a repeatable mangled version with the given length.
     43    """
     44    if length is None or len(name) <= length:
     45        return name
     46    hash = md5.md5(name).hexdigest()[:4]
     47    return '%s%s' % (name[:length-4], hash)
     48
    4149###############################################
    4250# Converters from database (string) to Python #
    4351###############################################
  • django/db/backends/firebird/base.py

     
     1"""
     2Firebird database backend for Django.
     3
     4Requires kinterbasdb: http://kinterbasdb.sourceforge.net/
     5"""
     6
     7from django.conf import settings
     8from django.db.backends import util
     9import re
     10try:
     11    import kinterbasdb as Database
     12    import kinterbasdb.typeconv_datetime_stdlib as typeconv_datetime
     13except ImportError, e:
     14    from django.core.exceptions import ImproperlyConfigured
     15    raise ImproperlyConfigured, "Error loading kinterbasdb module: %s" % e
     16
     17DatabaseError = Database.DatabaseError
     18Database.init(type_conv=199)
     19
     20try:
     21    # Only exists in Python 2.4+
     22    from threading import local
     23except ImportError:
     24    # Import copy of _thread_local.py from Python 2.4
     25    from django.utils._threading_local import local
     26
     27server_version = None
     28
     29def unicode_conv_in(text):
     30    #Type converter for columns with charsets NONE, OCTETS, or ASCII
     31    if isinstance(text, unicode):
     32        return text.encode(settings.DEFAULT_CHARSET)
     33    return text
     34
     35def timestamp_conv_in(datetime):
     36    #Type converter for datetime casted strings.
     37    #Replaces 6 digits microseconds to 4 digits allowed in Firebird
     38    if isinstance(datetime, basestring) and datetime.find('.') > 0 and len(datetime) == 26:
     39        datetime = datetime[0:-2]
     40    return typeconv_datetime.timestamp_conv_in(datetime)
     41
     42class DatabaseWrapper(local):
     43    def __init__(self, **kwargs):
     44        self.connection = None
     45        self.queries = []
     46        self.options = kwargs
     47
     48    def cursor(self):
     49        if self.connection is None:
     50            if settings.DATABASE_NAME == '':
     51                from django.core.exceptions import ImproperlyConfigured
     52                raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file."
     53            kwargs = {'database': settings.DATABASE_NAME}
     54            if settings.DATABASE_HOST:
     55                kwargs['host'] = settings.DATABASE_HOST
     56            if settings.DATABASE_USER:
     57                kwargs['user'] = settings.DATABASE_USER
     58            if settings.DATABASE_PASSWORD:
     59                kwargs['password'] = settings.DATABASE_PASSWORD
     60            self.connection = Database.connect(**kwargs)
     61            self.connection.set_type_trans_in({
     62                'TEXT': unicode_conv_in,
     63                'BLOB': unicode_conv_in,
     64                'TIMESTAMP': timestamp_conv_in
     65            })
     66            global server_version
     67            if not server_version:
     68                import re
     69                version_re = re.compile('.*Firebird\s([\d\.]+)')
     70                m = version_re.match(self.connection.server_version)
     71                if not m:
     72                    raise Exception('Unable to determine Firebird version from version string %r' % self.connection.server_version)
     73                server_version = m.groups()[0]
     74        cursor = FirebirdCursorWrapper(self.connection)
     75        if settings.DEBUG:
     76            return util.CursorDebugWrapper(cursor, self)
     77        return cursor
     78
     79    def _commit(self):
     80        if self.connection is not None:
     81            return self.connection.commit()
     82
     83    def _rollback(self):
     84        if self.connection is not None:
     85            return self.connection.rollback()
     86
     87    def close(self):
     88        if self.connection is not None:
     89            self.connection.close()
     90            self.connection = None
     91
     92class FirebirdCursorWrapper(Database.Cursor):
     93    """
     94    Django uses "format" ('%s') style placeholders, but firebird uses "qmark" ('?') style.
     95    This fixes it -- but note that if you want to use a literal "%s" in a query,
     96    you'll need to use "%%s".
     97    """
     98    def execute(self, query, params=()):
     99        query = self._convert_query(query, len(params))
     100        #print "%s %s" % (query, params)
     101        return Database.Cursor.execute(self, query, params)
     102
     103    def executemany(self, query, params):
     104        query = self._convert_query(query, len(params[0]))
     105        return Database.Cursor.executemany(self, query, params)
     106
     107    def _convert_query(self, query, num_params):
     108        return query % tuple("?" * num_params)
     109
     110supports_constraints = True
     111
     112def quote_name(name):
     113    # the standard for firebird is not to quote names but in django
     114    # it will quote all names uppercased so we can write sql without quotes
     115    # because all names without quotes will defualt to uppercased,
     116    # like oracle truncate names bigger than 30 chars
     117    if not name.startswith('"') and not name.endswith('"'):
     118        name = '"%s"' % util.truncate_name(name, get_max_name_length())
     119    return name.upper()
     120
     121_quote_sequence_name = lambda n: '"%s_SQ"' % util.truncate_name(n.upper(), get_max_name_length()-3)
     122_quote_trigger_name = lambda n: '"%s_TR"' % util.truncate_name(n.upper(), get_max_name_length()-3)
     123
     124def dictfetchone(cursor):
     125    "Returns a row from the cursor as a dict"
     126    return cursor.fetchonemap()
     127
     128def dictfetchmany(cursor, number):
     129    "Returns a certain number of rows from a cursor as a dict"
     130    return cursor.fetchmanymap(number)
     131
     132def dictfetchall(cursor):
     133    "Returns all rows from a cursor as a dict"
     134    return cursor.fetchallmap()
     135
     136def get_last_insert_id(cursor, table_name, pk_name):
     137    stmt = server_version < '2' and 'SELECT GEN_ID(%s, 0) FROM RDB$DATABASE' or 'NEXT VALUE FOR %s'
     138    cursor.execute(stmt % _quote_sequence_name(table_name))
     139    return cursor.fetchone()[0]
     140
     141def get_date_extract_sql(lookup_type, column_name):
     142    # lookup_type is 'year', 'month', 'day'
     143    return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), column_name)
     144
     145def get_date_trunc_sql(lookup_type, column_name):
     146    if lookup_type == 'year':
     147         sql = "EXTRACT(year FROM %s)||'-01-01 00:00:00'" % column_name
     148    elif lookup_type == 'month':
     149        sql = "EXTRACT(year FROM %s)||'-'||EXTRACT(month FROM %s)||'-01 00:00:00'" % (column_name, column_name)
     150    elif lookup_type == 'day':
     151        sql = "EXTRACT(year FROM %s)||'-'||EXTRACT(month FROM %s)||'-'||EXTRACT(day FROM %s)||' 00:00:00'" % (column_name, column_name, column_name)
     152    return "CAST(%s AS TIMESTAMP)" % sql
     153
     154def get_datetime_cast_sql():
     155    return None
     156
     157def get_limit_offset_sql(limit, offset=None):
     158    return ""
     159
     160def get_random_function_sql():
     161    return "RAND()"
     162
     163def get_deferrable_sql():
     164    # Not supported, maybe in Firebird 3.0
     165    return ""
     166
     167def get_fulltext_search_sql(field_name):
     168    # maybe in Firebird 3.0
     169    raise NotImplementedError
     170
     171def get_drop_foreignkey_sql():
     172    return "DROP CONSTRAINT"
     173
     174def get_pk_default_value():
     175    return "NULL"
     176
     177def get_max_name_length():
     178    return 30
     179
     180def get_sequence_sql(style, table_name, column_name):
     181    """To simulate auto-incrementing primary keys in Firebird, we have to
     182    create a generator (sequence in Firebird 2) and a trigger.
     183
     184    Create the sequences and triggers names based only on table name
     185    since django only support one auto field per model"""
     186    KEYWORD = style.SQL_KEYWORD
     187    TABLE = style.SQL_TABLE
     188    FIELD = style.SQL_FIELD
     189
     190    sequence_name = _quote_sequence_name(table_name)
     191    column_name = quote_name(column_name)
     192    return ["%s %s;" % ( \
     193            KEYWORD(server_version < '2' and 'CREATE GENERATOR' or 'CREATE SEQUENCE'),
     194            TABLE(sequence_name)),
     195        "\n".join(["%s %s %s %s" % ( \
     196            KEYWORD('CREATE TRIGGER'),
     197            TABLE(_quote_trigger_name(table_name)),
     198            KEYWORD('FOR'),
     199            TABLE(quote_name(table_name))),
     200        "%s 0 %s" % ( \
     201            KEYWORD('ACTIVE BEFORE INSERT POSITION'),
     202            KEYWORD('AS')),
     203        KEYWORD('BEGIN'),
     204        "  %s ((%s.%s %s) %s (%s.%s = 0)) %s" % ( \
     205            KEYWORD('IF'),
     206            KEYWORD('NEW'),
     207            FIELD(column_name),
     208            KEYWORD('IS NULL'),
     209            KEYWORD('OR'),
     210            KEYWORD('NEW'),
     211            FIELD(column_name),
     212            KEYWORD('THEN')),
     213        "  %s" % KEYWORD('BEGIN'),
     214        "    %s.%s = %s(%s, 1);" % ( \
     215            KEYWORD('NEW'),
     216            FIELD(column_name),
     217            KEYWORD('GEN_ID'),
     218            TABLE(sequence_name)),
     219        "  %s" % KEYWORD('END'),
     220        KEYWORD('END')])]
     221
     222def get_sql_flush(style, tables, sequences):
     223    """Return a list of SQL statements required to remove all data from
     224    all tables in the database (without actually removing the tables
     225    themselves) and put the database in an empty 'initial' state
     226
     227    For Firebird we gonna take a dangerous workaround:
     228        - first create a temporary table 'django_flush$constraints' that
     229        will contain all Foreignkey definitions for this database.
     230        - next import this definitions into the new table and delete them
     231        from system table 'rdb$relation_constraints'.
     232        - after the flush is done import the definitions back to the system table
     233        and delete the temporary table.
     234    """
     235    KEYWORD = style.SQL_KEYWORD
     236    TABLE = style.SQL_TABLE
     237    FIELD = style.SQL_FIELD
     238
     239    if tables:
     240        temp_table_name = quote_name('django_flush$constraints')
     241        orig_table_name = 'RDB$RELATION_CONSTRAINTS'
     242        sql = ["\n".join([
     243            "%s %s (" % (KEYWORD('CREATE TABLE'), TABLE(temp_table_name)),
     244            "  %s %s(31) %s," % (FIELD(quote_name('rdb$constraint_name')), KEYWORD('CHAR'), KEYWORD('CHARACTER SET UNICODE_FSS')),
     245            "  %s %s(11)," % (FIELD(quote_name('rdb$constraint_type')), KEYWORD('CHAR')),
     246            "  %s %s(31) %s," % (FIELD(quote_name('rdb$relation_name')), KEYWORD('CHAR'), KEYWORD('CHARACTER SET UNICODE_FSS')),
     247            "  %s %s(3)," % (FIELD(quote_name('rdb$deferrable')), KEYWORD('CHAR')),
     248            "  %s %s(3)," % (FIELD(quote_name('rdb$initially_deferred')), KEYWORD('CHAR')),
     249            "  %s %s(31) %s" % (FIELD(quote_name('rdb$index_name')), KEYWORD('CHAR'), KEYWORD('CHARACTER SET UNICODE_FSS')),
     250            ");"]),
     251            "%s;" % KEYWORD('COMMIT'),
     252            "%s %s %s %s %s %s %s %s = 'FOREIGN KEY';" % ( \
     253                KEYWORD('INSERT INTO'), TABLE(temp_table_name),
     254                KEYWORD('SELECT'), FIELD('*'), KEYWORD('FROM'), TABLE(orig_table_name),
     255                KEYWORD('WHERE'), FIELD('rdb$constraint_type')),
     256            "%s %s %s %s = 'FOREIGN KEY';" % ( \
     257                KEYWORD('DELETE FROM'), TABLE(orig_table_name),
     258                KEYWORD('WHERE'), FIELD('rdb$constraint_type')),
     259            "%s;" % KEYWORD('COMMIT')]
     260
     261        sql += ['%s %s;' % \
     262                (KEYWORD('DELETE FROM'),
     263                 TABLE(quote_name(table))
     264                 ) for table in tables]
     265
     266        sql += ["%s %s %s 0;" % \
     267                (KEYWORD(server_version < '2' and 'SET GENERATOR' or 'ALTER SEQUENCE'),
     268                 TABLE(_quote_sequence_name(sequence['table'])),
     269                 KEYWORD(server_version < '2' and 'TO' or 'RESTART WITH')
     270                 ) for sequence in sequences]
     271        return sql + [
     272            "%s %s %s %s %s %s;" % ( \
     273                KEYWORD('INSERT INTO'), TABLE(orig_table_name),
     274                KEYWORD('SELECT'), FIELD('*'), KEYWORD('FROM'), TABLE(temp_table_name)),
     275            "%s %s;" % (KEYWORD('DROP TABLE'), TABLE(temp_table_name)),
     276            "%s;" % KEYWORD('COMMIT')]
     277    return []
     278
     279OPERATOR_MAPPING = {
     280    'exact': '= %s',
     281    'iexact': "= UPPER(%s)",
     282    'contains': "LIKE %s ESCAPE '\\'",
     283    'icontains': "LIKE UPPER(%s) ESCAPE '\\'",
     284    'gt': '> %s',
     285    'gte': '>= %s',
     286    'lt': '< %s',
     287    'lte': '<= %s',
     288    'startswith': "LIKE %s ESCAPE '\\'",
     289    'endswith': "LIKE %s ESCAPE '\\'",
     290    'istartswith': "LIKE UPPER(%s) ESCAPE '\\'",
     291    'iendswith': "LIKE UPPER(%s) ESCAPE '\\'",
     292
     293    'text_icontains': "CONTAINING %s",
     294}
  • django/db/backends/firebird/client.py

     
     1from django.conf import settings
     2import os
     3
     4def runshell():
     5    args = [settings.DATABASE_NAME]
     6    args += ["-u %s" % settings.DATABASE_USER]
     7    if settings.DATABASE_PASSWORD:
     8        args += ["-p %s" % settings.DATABASE_PASSWORD]
     9    if 'FIREBIRD' not in os.environ:
     10        path = '/opt/firebird/bin/'
     11    os.system(path + 'isql ' + ' '.join(args))
  • django/db/backends/firebird/introspection.py

     
     1from django.db import transaction
     2from django.db.backends.firebird.base import quote_name
     3
     4def get_table_list(cursor):
     5    "Returns a list of table names in the current database."
     6    cursor.execute("""
     7        SELECT rdb$relation_name FROM rdb$relations
     8        WHERE rdb$system_flag = 0 AND rdb$view_blr IS NULL ORDER BY rdb$relation_name""")
     9    return [str(row[0].strip().lower()) for row in cursor.fetchall()]
     10
     11def get_table_description(cursor, table_name):
     12    "Returns a description of the table, with the DB-API cursor.description interface."
     13    #cursor.execute("SELECT FIRST 1 * FROM %s" % quote_name(table_name))
     14    #return cursor.description
     15    # (name, type_code, display_size, internal_size, precision, scale, null_ok)
     16    cursor.execute("""
     17        SELECT DISTINCT R.RDB$FIELD_NAME AS FNAME,
     18                  F.RDB$FIELD_TYPE AS FTYPE,
     19                  F.RDB$FIELD_LENGTH AS FLENGTH,
     20                  F.RDB$FIELD_PRECISION AS FPRECISION,
     21                  F.RDB$FIELD_SCALE AS FSCALE,
     22                  R.RDB$NULL_FLAG AS NULL_FLAG,
     23                  R.RDB$FIELD_POSITION
     24        FROM RDB$RELATION_FIELDS R
     25             JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME
     26        WHERE F.RDB$SYSTEM_FLAG=0 and R.RDB$RELATION_NAME= %s
     27        ORDER BY R.RDB$FIELD_POSITION
     28    """, (table_name,))
     29    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()]
     30
     31
     32def get_relations(cursor, table_name):
     33    """
     34    Returns a dictionary of {field_index: (field_index_other_table, other_table)}
     35    representing all relationships to the given table. Indexes are 0-based.
     36    """
     37    cursor.execute("""
     38        SELECT seg.rdb$field_name, seg_ref.rdb$field_name, idx_ref.rdb$relation_name
     39        FROM rdb$indices idx
     40        INNER JOIN rdb$index_segments seg
     41            ON seg.rdb$index_name = idx.rdb$index_name
     42        INNER JOIN rdb$indices idx_ref
     43            ON idx_ref.rdb$index_name = idx.rdb$foreign_key
     44        INNER JOIN rdb$index_segments seg_ref
     45            ON seg_ref.rdb$index_name = idx_ref.rdb$index_name
     46        WHERE idx.rdb$relation_name = %s
     47            AND idx.rdb$foreign_key IS NOT NULL""", [table_name])
     48
     49    relations = {}
     50    for row in cursor.fetchall():
     51        relations[row[0].rstrip()] = (row[1].strip(), row[2].strip())
     52    return relations
     53
     54def get_indexes(cursor, table_name):
     55    """
     56    Returns a dictionary of fieldname -> infodict for the given table,
     57    where each infodict is in the format:
     58        {'primary_key': boolean representing whether it's the primary key,
     59         'unique': boolean representing whether it's a unique index}
     60    """
     61
     62    # This query retrieves each field name and index type on the given table.
     63    cursor.execute("""
     64        SELECT seg.rdb$field_name, const.rdb$constraint_type
     65        FROM rdb$relation_constraints const
     66        LEFT JOIN rdb$index_segments seg
     67            ON seg.rdb$index_name = const.rdb$index_name
     68        WHERE const.rdb$relation_name = %s
     69            AND (const.rdb$constraint_type = 'PRIMARY KEY'
     70                OR const.rdb$constraint_type = 'UNIQUE')""", [table_name])
     71    indexes = {}
     72    for row in cursor.fetchall():
     73        indexes[row[0].strip()] = {
     74            'primary_key': ('PRIMARY KEY' == row[1].strip()),
     75            'unique': ('UNIQUE' == row[1].strip())}
     76    return indexes
     77
     78# Maps type codes to Django Field types.
     79# !todo
     80DATA_TYPES_REVERSE = {
     81    7: 'BooleanField',
     82    7: 'SmallIntegerField',
     83    8: 'IntegerField',
     84    261: 'TextField',
     85    37: 'IPAddressField',
     86    37: 'CharField',
     87    12: 'DateField',
     88    13: 'TimeField',
     89    35: 'DateTimeField',
     90    10: 'FloatField',
     91}
  • django/db/backends/firebird/creation.py

     
     1from django.core import management
     2import sys, os, time
     3
     4# This dictionary maps Field objects to their associated PostgreSQL column
     5# types, as strings. Column-type strings can contain format strings; they'll
     6# be interpolated against the values of Field.__dict__ before being output.
     7# If a column type is set to None, it won't be included in the output.
     8
     9DATA_TYPES = {
     10    'AutoField':                     'INTEGER',
     11    'BooleanField':                  'SMALLINT',
     12    'CharField':                     'VARCHAR(%(maxlength)s)',
     13    'CommaSeparatedIntegerField':    'VARCHAR(%(maxlength)s)',
     14    'DateField':                     'DATE',
     15    'DateTimeField':                 'TIMESTAMP',
     16    'FileField':                     'VARCHAR(100)',
     17    'FilePathField':                 'VARCHAR(100)',
     18    'FloatField':                    'NUMERIC(%(max_digits)s, %(decimal_places)s)',
     19    'ImageField':                    'VARCHAR(100)',
     20    'IntegerField':                  'INTEGER',
     21    'IPAddressField':                'VARCHAR(15)',
     22    'ManyToManyField':               None,
     23    'NullBooleanField':              'SMALLINT',
     24    'OneToOneField':                 'INTEGER',
     25    'PhoneNumberField':              'VARCHAR(20)',
     26    'PositiveIntegerField':          'INTEGER',
     27    'PositiveSmallIntegerField':     'SMALLINT',
     28    'SlugField':                     'VARCHAR(%(maxlength)s)',
     29    'SmallIntegerField':             'SMALLINT',
     30    'TextField':                     'BLOB SUB_TYPE TEXT',
     31    'TimeField':                     'TIME',
     32    'URLField':                      'VARCHAR(200)',
     33    'USStateField':                  'VARCHAR(2)',
     34}
     35
     36TEST_DATABASE_PREFIX = 'test_'
     37
     38def create_test_db(settings, connection, backend, verbosity, autoclobber):
     39
     40    if verbosity >= 1:
     41        print "Creating test database..."
     42
     43    if settings.TEST_DATABASE_NAME:
     44        if os.path.isfile(settings.DATABASE_NAME):
     45            TEST_DATABASE_NAME = os.path.join(
     46                os.path.dirname(settings.DATABASE_NAME),
     47                settings.TEST_DATABASE_NAME)
     48        else:
     49            import tempfile
     50            tempfile.gettempdir()
     51            TEST_DATABASE_NAME = os.path.join(
     52                tempfile.gettempdir(),
     53                settings.TEST_DATABASE_NAME)
     54    else:
     55        if os.path.isfile(settings.DATABASE_NAME):
     56            TEST_DATABASE_NAME = os.path.join(
     57                os.path.dirname(settings.DATABASE_NAME),
     58                TEST_DATABASE_PREFIX + os.path.basename(settings.DATABASE_NAME))
     59        else:
     60            import tempfile
     61            tempfile.gettempdir()
     62            TEST_DATABASE_NAME = os.path.join(
     63                tempfile.gettempdir(),
     64                TEST_DATABASE_PREFIX + settings.DATABASE_NAME)
     65
     66    settings.DATABASE_NAME = TEST_DATABASE_NAME
     67
     68    try:
     69        _create_test_db(backend, settings)
     70    except Exception, e:
     71        sys.stderr.write("Got an error creating the test database: %s\n" % e)
     72        if not autoclobber:
     73            confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME)
     74        if autoclobber or confirm == 'yes':
     75            try:
     76                if verbosity >= 1:
     77                    print "Destroying old test database..."
     78                _destroy_test_db(connection)
     79                if verbosity >= 1:
     80                    print "Creating test database..."
     81                _create_test_db(backend, settings)
     82            except Exception, e:
     83                sys.stderr.write("Got an error recreating the test database: %s\n" % e)
     84                sys.exit(2)
     85        else:
     86            print "Tests cancelled."
     87            sys.exit(1)
     88
     89    management.syncdb(verbosity, interactive=False)
     90
     91    # Get a cursor (even though we don't need one yet). This has
     92    # the side effect of initializing the test database.
     93    cursor = connection.cursor()
     94
     95
     96def destroy_test_db(settings, connection, backend, old_database_name, verbosity):
     97    if verbosity >= 1:
     98        print "Destroying test database..."
     99
     100    # To avoid "database is being accessed by other users" errors.
     101    time.sleep(1)
     102    _destroy_test_db(connection)
     103
     104def _create_test_db(backend, settings):
     105    connection = backend.Database.create_database("""
     106        CREATE DATABASE '%s' user '%s' password '%s'""" % \
     107        (settings.DATABASE_NAME, settings.DATABASE_USER, settings.DATABASE_PASSWORD))
     108    cursor = connection.cursor()
     109    cursor.execute("""
     110    DECLARE EXTERNAL FUNCTION rand
     111        RETURNS DOUBLE PRECISION
     112        BY VALUE ENTRY_POINT 'IB_UDF_rand' MODULE_NAME 'ib_udf';
     113    """)
     114    connection.commit()
     115    connection.close()
     116
     117def _destroy_test_db(connection):
     118    cursor = connection.cursor()
     119    connection.connection.drop_database()
     120    connection.connection = None
     121 No newline at end of file
  • django/core/management.py

     
    159159    Returns list_of_sql, pending_references_dict
    160160    """
    161161    from django.db import backend, get_creation_module, models
     162    from django.conf import settings
    162163    data_types = get_creation_module().DATA_TYPES
    163164
    164165    opts = model._meta
     
    177178            # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
    178179            field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
    179180                style.SQL_COLTYPE(col_type % rel_field.__dict__)]
    180             field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
     181            column_null_sql = '%sNULL' % (not f.null and 'NOT ' or '')
     182            if settings.DATABASE_ENGINE == 'firebird' and f.null:
     183                column_null_sql = (not f.null or f.primary_key) and 'NOT NULL' or ''
     184            if column_null_sql:
     185                field_output.append(style.SQL_KEYWORD(column_null_sql))
    181186            if f.unique:
    182187                field_output.append(style.SQL_KEYWORD('UNIQUE'))
    183188            if f.primary_key:
     
    207212        full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
    208213    full_statement.append(');')
    209214    final_output.append('\n'.join(full_statement))
     215   
     216    if opts.has_auto_field and hasattr(backend, 'get_sequence_sql'):
     217        final_output += backend.get_sequence_sql(style, opts.db_table, opts.pk.column)
    210218
    211219    return final_output, pending_references
    212220
     
    231239                # So we are careful with character usage here.
    232240                r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
    233241                final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
    234                     (backend.quote_name(r_table), r_name,
     242                    (backend.quote_name(r_table), backend.quote_name(r_name),
    235243                    backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col),
    236244                    backend.get_deferrable_sql()))
    237245            del pending_references[model]
     
    273281                style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name()))))
    274282            table_output.append(');')
    275283            final_output.append('\n'.join(table_output))
     284            if hasattr(backend, 'get_sequence_sql'):
     285                final_output += backend.get_sequence_sql(style, f.m2m_db_table(), 'id')
    276286    return final_output
    277287
    278288def get_sql_delete(app):
     
    456466            unique = f.unique and 'UNIQUE ' or ''
    457467            output.append(
    458468                style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
    459                 style.SQL_TABLE('%s_%s' % (model._meta.db_table, f.column)) + ' ' + \
     469                style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
    460470                style.SQL_KEYWORD('ON') + ' ' + \
    461471                style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
    462472                "(%s);" % style.SQL_FIELD(backend.quote_name(f.column))
  • django/contrib/redirects/models.py

     
    44
    55class Redirect(models.Model):
    66    site = models.ForeignKey(Site, radio_admin=models.VERTICAL)
    7     old_path = models.CharField(_('redirect from'), maxlength=200, db_index=True,
     7    old_path = models.CharField(_('redirect from'), maxlength=100, db_index=False,
    88        help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'."))
    9     new_path = models.CharField(_('redirect to'), maxlength=200, blank=True,
     9    new_path = models.CharField(_('redirect to'), maxlength=100, blank=True,
    1010        help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'."))
    1111
    1212    class Meta:
Back to Top