Django

Code

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, 1 year ago)

Partially ported patch to django trunk

  • django/db/models/query.py

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
     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

    old new  
     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

    old new  
     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

    old new  
     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() 
  • django/core/management/sql.py

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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()