Ticket #1261: firebird-port-svn-trunk-6186-not-completed.diff

File firebird-port-svn-trunk-6186-not-completed.diff, 30.2 KB (added by Almad, 8 years ago)

Partially ported patch to django trunk

  • django/db/models/query.py

     
    184184        # self._select is a dictionary, and dictionaries' key order is
    185185        # undefined, so we convert it to a list of tuples.
    186186        extra_select = self._select.items()
     187        pre_columns = ""
     188        # this is perhaps solvable by custom query set
     189        if settings.DATABASE_ENGINE == 'firebird' and self._limit is not None:
     190            pre_columns += "FIRST %s " % self._limit
     191            if self._offset:
     192                pre_columns += "SKIP %s " % self._offset
     193        if self._distinct:
     194            pre_columns += "DISTINCT "
     195        cursor = connection.cursor()
     196        cursor.execute("SELECT " + pre_columns + ",".join(select) + sql, params)
    187197
    188198        cursor = connection.cursor()
    189199        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)
     
    515525
    516526        # Compose the join dictionary into SQL describing the joins.
    517527        if joins:
    518             sql.append(" ".join(["%s %s AS %s ON %s" % (join_type, table, alias, condition)
     528            sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition)
    519529                            for (alias, (table, join_type, condition)) in joins.items()]))
    520530
    521531        # Compose the tables clause into SQL.
  • django/db/backends/oracle/base.py

     
    8383        cursor.execute('SELECT %s_sq.currval FROM dual' % sq_name)
    8484        return cursor.fetchone()[0]
    8585
    86     def limit_offset_sql(self, limit, offset=None):
    87         # Limits and offset are too complicated to be handled here.
    88         # Instead, they are handled in django/db/backends/oracle/query.py.
    89         return ""
     86#    def limit_offset_sql(self, limit, offset=None):
     87#        # Limits and offset are too complicated to be handled here.
     88#        # Instead, they are handled in django/db/backends/oracle/query.py.
     89#        return ""
    9090
    9191    def max_name_length(self):
    9292        return 30
  • django/db/backends/oracle/creation.py

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

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

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

     
    11from django.core.management.base import CommandError
     2from django.conf import settings
    23import os
    34import re
    45
     
    262263        # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
    263264        field_output = [style.SQL_FIELD(qn(f.column)),
    264265            style.SQL_COLTYPE(col_type)]
    265         field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
     266        #field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
     267        column_null_sql = '%sNULL' % (not f.null and 'NOT ' or '')
     268        if settings.DATABASE_ENGINE == 'firebird' and f.null:
     269            column_null_sql = (not f.null or f.primary_key) and 'NOT NULL' or ''
     270        if column_null_sql:
     271            field_output.append(style.SQL_KEYWORD(column_null_sql))
     272           
    266273        if f.unique and (not f.primary_key or connection.features.allows_unique_and_pk):
    267274            field_output.append(style.SQL_KEYWORD('UNIQUE'))
    268275        if f.primary_key:
  • tests/modeltests/serializers/models.py

     
    125125
    126126# You can easily create new objects by deserializing data with an empty PK
    127127# (It's easier to demo this with JSON...)
    128 >>> new_author_json = '[{"pk": null, "model": "serializers.author", "fields": {"name": "Bill"}}]'
     128>>> new_author_json = '[{"pk" : null, "model": "serializers.author", "fields": {"name": "Bill"}}]'
    129129>>> for obj in serializers.deserialize("json", new_author_json):
    130130...     obj.save()
    131131>>> Author.objects.all()
  • tests/regressiontests/string_lookup/models.py

     
    9191<Foo: Foo Bjorn>
    9292
    9393# Regression tests for #5087: make sure we can perform queries on TextFields.
     94# This is unsupported for Firebird < 2.1
    9495>>> a = Article(name='Test', text='The quick brown fox jumps over the lazy dog.')
    9596>>> a.save()
    9697>>> Article.objects.get(text__exact='The quick brown fox jumps over the lazy dog.')
  • tests/regressiontests/fixtures_regress/models.py

     
    3636       
    3737# Create a new animal. Without a sequence reset, this new object
    3838# will take a PK of 1 (on Postgres), and the save will fail.
     39# Same goes for Firebird
    3940# This is a regression test for ticket #3790.
    4041>>> animal = Animal(name='Platypus', latin_name='Ornithorhynchus anatinus')
    4142>>> animal.save()
Back to Top