Ticket #1261: firebird-6669.diff
File firebird-6669.diff, 86.3 KB (added by , 17 years ago) |
---|
-
django/db/models/base.py
4 4 from django.core.exceptions import ObjectDoesNotExist 5 5 from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist 6 6 from django.db.models.fields.related import OneToOneRel, ManyToOneRel 7 from django.db.models.fields.computed import ComputedField 7 8 from django.db.models.query import delete_objects 8 9 from django.db.models.options import Options, AdminOptions 9 10 from django.db import connection, transaction … … 227 228 self._meta.pk.get_db_prep_lookup('exact', pk_val)) 228 229 # If it does already exist, do an UPDATE. 229 230 if cursor.fetchone(): 230 db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False)) for f in non_pks ]231 db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False)) for f in non_pks if not isinstance(f, ComputedField)] 231 232 if db_values: 232 233 cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \ 233 234 (qn(self._meta.db_table), 234 ','.join(['%s=%%s' % qn(f.column) for f in non_pks ]),235 ','.join(['%s=%%s' % qn(f.column) for f in non_pks if not isinstance(f, ComputedField)]), 235 236 qn(self._meta.pk.column)), 236 237 db_values + self._meta.pk.get_db_prep_lookup('exact', pk_val)) 237 238 else: 238 239 record_exists = False 239 240 if not pk_set or not record_exists: 240 field_names = [qn(f.column) for f in self._meta.fields if not isinstance(f, AutoField)]241 db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]241 field_names = [qn(f.column) for f in self._meta.fields if not isinstance(f, (AutoField, ComputedField))] 242 db_values = [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, (AutoField, ComputedField))] 242 243 # If the PK has been manually set, respect that. 243 244 if pk_set: 244 field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)] 245 if connection.features.quote_autofields: 246 field_names += [qn(f.column) for f in self._meta.fields if isinstance(f, AutoField)] 247 else: 248 field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)] 245 249 db_values += [f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)] 246 250 placeholders = ['%s'] * len(field_names) 247 251 if self._meta.order_with_respect_to: -
django/db/models/fields/__init__.py
6 6 except ImportError: 7 7 from django.utils import _decimal as decimal # for Python 2.3 8 8 9 from django.db import get_creation_module9 from django.db import connection, get_creation_module 10 10 from django.db.models import signals 11 11 from django.dispatch import dispatcher 12 12 from django.conf import settings … … 66 66 # 67 67 # getattr(obj, opts.pk.attname) 68 68 69 class Field(object):69 class _Field(object): 70 70 # Provide backwards compatibility for the maxlength attribute and 71 71 # argument for this class and all subclasses. 72 72 __metaclass__ = LegacyMaxlength … … 83 83 core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True, 84 84 prepopulate_from=None, unique_for_date=None, unique_for_month=None, 85 85 unique_for_year=None, validator_list=None, choices=None, radio_admin=None, 86 help_text='', db_column=None, db_tablespace=None): 86 help_text='', db_column=None, db_tablespace=None, encoding=None, 87 on_update=None, on_delete=None): 87 88 self.name = name 88 89 self.verbose_name = verbose_name 89 90 self.primary_key = primary_key 90 91 self.max_length, self.unique = max_length, unique 92 self.encoding = encoding 91 93 self.blank, self.null = blank, null 92 94 # Oracle treats the empty string ('') as null, so coerce the null 93 95 # option whenever '' is a possible value. … … 105 107 self.help_text = help_text 106 108 self.db_column = db_column 107 109 self.db_tablespace = db_tablespace 110 self.on_update = on_update 111 self.on_delete = on_delete 108 112 109 113 # Set db_index to True if the field has a relationship and doesn't explicitly set db_index. 110 114 self.db_index = db_index … … 148 152 data_types = get_creation_module().DATA_TYPES 149 153 internal_type = self.get_internal_type() 150 154 if internal_type not in data_types: 151 return None 155 return None 152 156 return data_types[internal_type] % self.__dict__ 153 157 154 158 def validate_full(self, field_data, all_data): … … 402 406 "Returns the value of this field in the given model instance." 403 407 return getattr(obj, self.attname) 404 408 409 # Use the backend's Field class if it defines one. Otherwise, use _Field. 410 if connection.features.uses_custom_field: 411 Field = connection.ops.field_class(_Field) 412 else: 413 Field = _Field 414 405 415 class AutoField(Field): 406 416 empty_strings_allowed = False 407 417 def __init__(self, *args, **kwargs): … … 688 698 defaults.update(kwargs) 689 699 return super(DecimalField, self).formfield(**defaults) 690 700 701 class DefaultCharField(CharField): 702 def __init__(self, *args, **kwargs): 703 DEFAULT_MAX_LENGTH = 100 704 if hasattr(settings, 'DEFAULT_MAX_LENGTH'): 705 DEFAULT_MAX_LENGTH = settings.DEFAULT_MAX_LENGT 706 kwargs['max_length'] = kwargs.get('max_length', DEFAULT_MAX_LENGTH) 707 CharField.__init__(self, *args, **kwargs) 708 691 709 class EmailField(CharField): 692 710 def __init__(self, *args, **kwargs): 693 711 kwargs['max_length'] = kwargs.get('max_length', 75) … … 890 908 defaults.update(kwargs) 891 909 return super(IPAddressField, self).formfield(**defaults) 892 910 911 class LargeTextField(Field): 912 def get_manipulator_field_objs(self): 913 return [oldforms.LargeTextField] 914 915 def formfield(self, **kwargs): 916 defaults = {'widget': forms.Textarea} 917 defaults.update(kwargs) 918 return super(LargeTextField, self).formfield(**defaults) 919 893 920 class NullBooleanField(Field): 894 921 empty_strings_allowed = False 895 922 def __init__(self, *args, **kwargs): … … 997 1024 # doesn't support microseconds. 998 1025 if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): 999 1026 value = value.replace(microsecond=0) 1000 if settings.DATABASE_ENGINE == 'oracle':1001 # cx_Oracle expectsa datetime.datetime to persist into TIMESTAMP field.1027 if settings.DATABASE_ENGINE in ('oracle', 'firebird'): 1028 # cx_Oracle and kinterbasdb expect a datetime.datetime to persist into TIMESTAMP field. 1002 1029 if isinstance(value, datetime.time): 1003 1030 value = datetime.datetime(1900, 1, 1, value.hour, value.minute, 1004 1031 value.second, value.microsecond) -
django/db/models/fields/related.py
331 331 new_ids.add(obj) 332 332 # Add the newly created or already existing objects to the join table. 333 333 # First find out which items are already added, to avoid adding them twice 334 qn = connection.ops.quote_name 334 335 cursor = connection.cursor() 335 336 cursor.execute("SELECT %s FROM %s WHERE %s = %%s AND %s IN (%s)" % \ 336 ( target_col_name, self.join_table, source_col_name,337 target_col_name, ",".join(['%s'] * len(new_ids))),337 (qn(target_col_name), qn(self.join_table), qn(source_col_name), 338 qn(target_col_name), ",".join(['%s'] * len(new_ids))), 338 339 [self._pk_val] + list(new_ids)) 339 340 existing_ids = set([row[0] for row in cursor.fetchall()]) 340 341 341 342 # Add the ones that aren't there already 342 343 for obj_id in (new_ids - existing_ids): 343 cursor.execute( "INSERT INTO %s (%s, %s) VALUES (%%s, %%s)"% \344 ( self.join_table, source_col_name, target_col_name),345 [self._pk_val, obj_id])344 cursor.execute('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)' % \ 345 (qn(self.join_table), qn(source_col_name), qn(target_col_name)), 346 (self._pk_val, obj_id)) 346 347 transaction.commit_unless_managed() 347 348 348 349 def _remove_items(self, source_col_name, target_col_name, *objs): -
django/db/models/fields/computed.py
1 from django.db.models.fields import IntegerField 2 3 class ComputedField(IntegerField): 4 def __init__(self, **kwargs): 5 expression = kwargs.pop('expression') 6 raw_params = kwargs.pop('params') 7 params = [] 8 for rp in raw_params: 9 params.append('"%s"' % rp) 10 self.expression = expression % tuple(params) 11 IntegerField.__init__(self, **kwargs) 12 13 def db_type(self): 14 return 'ComputedField' 15 16 #TODO: Add support for other field types 17 # Add support for fields which values are depended on INSERT, UPDATE or DLETE 18 # triggers of other fields/models 19 20 21 22 23 24 25 -
django/db/models/__init__.py
7 7 from django.db.models.manager import Manager 8 8 from django.db.models.base import Model, AdminOptions 9 9 from django.db.models.fields import * 10 from django.db.models.procedures import Procedure 10 11 from django.db.models.fields.subclassing import SubfieldBase 11 12 from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel, TABULAR, STACKED 13 from django.db.models.fields.computed import ComputedField 12 14 from django.db.models import signals 13 15 from django.utils.functional import curry 14 16 from django.utils.text import capfirst -
django/db/models/procedures/__init__.py
1 from django.db import connection, transaction 2 3 class procedure_meta(type): 4 """ 5 Metaclass for native stored procedures behaving as normal Django model methods 6 Subclass Procedure inside your model, create procedures tuple 7 and use the class as ordinary method 8 Please treat the resulting classes as methods because they don't 9 behave like classes anymore 10 Look at tests/customtests/custom_methods/model.py for demonstration 11 """ 12 def __init__(cls, name, bases, attrs): 13 super(procedure_meta, cls).__init__(name, bases, attrs) 14 params, returns, body = None, None, None 15 if '__params__' in attrs: 16 params = attrs['__params__'] 17 if '__returns__' in attrs: 18 returns = attrs['__returns__'] 19 if name != 'Procedure': 20 assert '__body__' in attrs, "Procedure must have body" 21 header = ['CREATE PROCEDURE %s ' % name] 22 if params: 23 header.append('(') 24 header.append(', '.join([param + ' ' + f for param, f in params])) 25 header.append(')') 26 if returns: 27 header.append('\nRETURNS (') 28 header.append(', '.join([ret + ' ' + f for ret, f in returns])) 29 header.append(')') 30 cls.__sql__ = [''.join(header)] 31 cls.__sql__.extend(['AS', 'BEGIN', attrs['__body__'], 'END']) 32 cls.sql = '\n'.join(cls.__sql__) 33 cls.params = params 34 cls.returns = returns 35 cls.procedure_name = name 36 37 def create_procedure_sql(cls): 38 return cls.sql 39 40 def __call__(cls, *args): 41 cursor = connection.cursor() 42 if not cls.returns: 43 cursor.execute('EXECUTE PROCEDURE "%s" %s;' %\ 44 (cls.procedure_name, 45 ' ,'.join("'%s'" % arg for arg in args))) 46 else: 47 cursor.execute_straight('SELECT %s FROM %s(%s);' %\ 48 (', '.join("%s" % ret[0] for ret in cls.returns), 49 cls.procedure_name, 50 ', '.join("?" * len(args))), args) 51 return cursor.fetchall() 52 53 class Procedure(object): 54 __metaclass__ = procedure_meta 55 -
django/db/models/query.py
612 612 columns = [f.column for f in fields] 613 613 select = ['%s.%s' % (qn(self.model._meta.db_table), qn(c)) for c in columns] 614 614 if extra_select: 615 select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in extra_select]) 615 if not settings.DATABASE_ENGINE == 'firebird': 616 select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in extra_select]) 617 else: 618 select.extend(['(%s) AS %s' % (connection.ops.quote_id_plus_number(s[1]), qn(s[0])) for s in extra_select]) 616 619 field_names.extend([f[0] for f in extra_select]) 617 620 618 621 cursor = connection.cursor() … … 1111 1114 # Last query term was a normal field. 1112 1115 column = field.column 1113 1116 db_type = field.db_type() 1114 1115 1117 where.append(get_where_clause(lookup_type, current_table + '.', column, value, db_type)) 1116 1118 params.extend(field.get_db_prep_lookup(lookup_type, value)) 1117 1119 … … 1146 1148 if isinstance(f, generic.GenericRelation): 1147 1149 from django.contrib.contenttypes.models import ContentType 1148 1150 query_extra = 'AND %s=%%s' % f.rel.to._meta.get_field(f.content_type_field_name).column 1151 if settings.DATABASE_ENGINE == 'firebird': 1152 query_extra = 'AND %s=%%s' % qn(f.rel.to._meta.get_field(f.content_type_field_name).column) 1149 1153 args_extra = [ContentType.objects.get_for_model(cls).id] 1150 1154 else: 1151 1155 query_extra = '' -
django/db/backends/__init__.py
48 48 needs_upper_for_iops = False 49 49 supports_constraints = True 50 50 supports_tablespaces = False 51 quote_autofields = False 51 52 uses_case_insensitive_names = False 53 uses_custom_field = False 52 54 uses_custom_queryset = False 53 55 54 56 class BaseDatabaseOperations(object): … … 199 201 """ 200 202 raise NotImplementedError() 201 203 204 def reference_name(self, r_col, col, r_table, table): 205 return '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table)))) 206 202 207 def random_function_sql(self): 203 208 """ 204 209 Returns a SQL expression that returns a random value. -
django/db/backends/firebird/base.py
1 """ 2 Firebird database backend for Django. 3 4 Requires KInterbasDB 3.2: http://kinterbasdb.sourceforge.net/ 5 The egenix mx (mx.DateTime) is NOT required 6 7 Database charset should be UNICODE_FSS or UTF8 (FireBird 2.0+) 8 To use UTF8 encoding add FIREBIRD_CHARSET = 'UTF8' to your settings.py 9 UNICODE_FSS works with all versions and uses less memory 10 """ 11 12 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 13 import sys 14 try: 15 import decimal 16 except ImportError: 17 from django.utils import _decimal as decimal # for Python 2.3 18 19 try: 20 import kinterbasdb as Database 21 except ImportError, e: 22 from django.core.exceptions import ImproperlyConfigured 23 raise ImproperlyConfigured, "Error loading KInterbasDB module: %s" % e 24 25 DatabaseError = Database.DatabaseError 26 IntegrityError = Database.IntegrityError 27 28 class DatabaseFeatures(BaseDatabaseFeatures): 29 inline_fk_references = False 30 needs_datetime_string_cast = False 31 needs_upper_for_iops = True 32 quote_autofields = True 33 uses_custom_field = True 34 uses_custom_queryset = True 35 36 ################################################################################ 37 # Database operations (db.connection.ops) 38 class DatabaseOperations(BaseDatabaseOperations): 39 """ 40 This class encapsulates all backend-specific differences, such as the way 41 a backend performs ordering or calculates the ID of a recently-inserted 42 row. 43 """ 44 # Utility ops: names, version, page size etc.: 45 _max_name_length = 31 46 def __init__(self): 47 self._firebird_version = None 48 self._page_size = None 49 50 def get_generator_name(self, name): 51 return '%s$G' % util.truncate_name(name.strip('"'), self._max_name_length-2).upper() 52 53 def get_trigger_name(self, name): 54 return '%s$T' % util.truncate_name(name.strip('"'), self._max_name_length-2).upper() 55 56 def _get_firebird_version(self): 57 if self._firebird_version is None: 58 from django.db import connection 59 self._firebird_version = [int(val) for val in connection.server_version.split()[-1].split('.')] 60 return self._firebird_version 61 firebird_version = property(_get_firebird_version) 62 63 def reference_name(self, r_col, col, r_table, table): 64 base_name = util.truncate_name('%s$%s' % (r_col, col), self._max_name_length-5) 65 return ('%s$%x' % (base_name, abs(hash((r_table, table))))).upper() 66 67 def _get_page_size(self): 68 if self._page_size is None: 69 from django.db import connection 70 self._page_size = connection.database_info(Database.isc_info_page_size, 'i') 71 return self._page_size 72 page_size = property(_get_page_size) 73 74 def _get_index_limit(self): 75 if self.firebird_version[0] < 2: 76 self._index_limit = 252 77 else: 78 page_size = self._get_page_size() 79 self._index_limit = page_size/4 80 return self._index_limit 81 index_limit = property(_get_index_limit) 82 83 def max_name_length(self): 84 return self._max_name_length 85 86 def quote_name(self, name): 87 name = '"%s"' % util.truncate_name(name.strip('"'), self._max_name_length) 88 return name 89 90 def quote_id_plus_number(self, name): 91 try: 92 return '"%s" + %s' % tuple(s.strip() for s in name.strip('"').split('+')) 93 except: 94 return self.quote_name(name) 95 96 def field_cast_sql(self, db_type): 97 return '%s' 98 99 ############################################################################ 100 # Basic SQL ops: 101 def last_insert_id(self, cursor, table_name, pk_name=None): 102 generator_name = self.get_generator_name(table_name) 103 cursor.execute('SELECT GEN_ID(%s, 0) from RDB$DATABASE' % generator_name) 104 return cursor.fetchone()[0] 105 106 def date_extract_sql(self, lookup_type, column_name): 107 # lookup_type is 'year', 'month', 'day' 108 return "EXTRACT(%s FROM %s)" % (lookup_type, column_name) 109 110 def date_trunc_sql(self, lookup_type, column_name): 111 if lookup_type == 'year': 112 sql = "EXTRACT(year FROM %s)||'-01-01 00:00:00'" % column_name 113 elif lookup_type == 'month': 114 sql = "EXTRACT(year FROM %s)||'-'||EXTRACT(month FROM %s)||'-01 00:00:00'" % (column_name, column_name) 115 elif lookup_type == 'day': 116 sql = "EXTRACT(year FROM %s)||'-'||EXTRACT(month FROM %s)||'-'||EXTRACT(day FROM %s)||' 00:00:00'" % (column_name, column_name, column_name) 117 return "CAST(%s AS TIMESTAMP)" % sql 118 119 def datetime_cast_sql(self): 120 return None 121 122 def drop_sequence_sql(self, table): 123 return "DROP GENERATOR %s;" % self.get_generator_name(table) 124 125 def drop_foreignkey_sql(self): 126 return "DROP CONSTRAINT" 127 128 def limit_offset_sql(self, limit, offset=None): 129 # limits are handled in custom FirebirdQuerySet 130 assert False, 'Limits are handled in a different way in Firebird' 131 return "" 132 133 def random_function_sql(self): 134 return "rand()" 135 136 def pk_default_value(self): 137 """ 138 Returns the value to use during an INSERT statement to specify that 139 the field should use its default value. 140 """ 141 return 'NULL' 142 143 def start_transaction_sql(self): 144 return "" 145 146 def fulltext_search_sql(self, field_name): 147 # We use varchar for TextFields so this is possible 148 # Look at http://www.volny.cz/iprenosil/interbase/ip_ib_strings.htm 149 return '%%s CONTAINING %s' % self.quote_name(field_name) 150 151 ############################################################################ 152 # Advanced SQL ops: 153 def autoinc_sql(self, style, table_name, column_name): 154 """ 155 To simulate auto-incrementing primary keys in Firebird, we have to 156 create a generator and a trigger. 157 158 Create the generators and triggers names based only on table name 159 since django only support one auto field per model 160 """ 161 162 generator_name = self.get_generator_name(table_name) 163 trigger_name = self.get_trigger_name(table_name) 164 column_name = self.quote_name(column_name) 165 table_name = self.quote_name(table_name) 166 167 generator_sql = "%s %s;" % ( style.SQL_KEYWORD('CREATE GENERATOR'), 168 generator_name) 169 trigger_sql = "\n".join([ 170 "%s %s %s %s" % ( \ 171 style.SQL_KEYWORD('CREATE TRIGGER'), trigger_name, style.SQL_KEYWORD('FOR'), 172 style.SQL_TABLE(table_name)), 173 "%s 0 %s" % (style.SQL_KEYWORD('ACTIVE BEFORE INSERT POSITION'), style.SQL_KEYWORD('AS')), 174 style.SQL_KEYWORD('BEGIN'), 175 " %s ((%s.%s %s) %s (%s.%s = 0)) %s" % ( \ 176 style.SQL_KEYWORD('IF'), 177 style.SQL_KEYWORD('NEW'), style.SQL_FIELD(column_name), style.SQL_KEYWORD('IS NULL'), 178 style.SQL_KEYWORD('OR'), style.SQL_KEYWORD('NEW'), style.SQL_FIELD(column_name), 179 style.SQL_KEYWORD('THEN') 180 ), 181 " %s" % style.SQL_KEYWORD('BEGIN'), 182 " %s.%s = %s(%s, 1);" % ( \ 183 style.SQL_KEYWORD('NEW'), style.SQL_FIELD(column_name), 184 style.SQL_KEYWORD('GEN_ID'), generator_name 185 ), 186 " %s" % style.SQL_KEYWORD('END'), 187 "%s;" % style.SQL_KEYWORD('END')]) 188 return (generator_sql, trigger_sql) 189 190 def sequence_reset_sql(self, style, model_list): 191 from django.db import models 192 output = [] 193 sql = ['%s %s %s' % (style.SQL_KEYWORD('CREATE OR ALTER PROCEDURE'), 194 style.SQL_TABLE('"GENERATOR_RESET"'), 195 style.SQL_KEYWORD('AS'))] 196 sql.append('%s %s' % (style.SQL_KEYWORD('DECLARE VARIABLE'), style.SQL_COLTYPE('start_val integer;'))) 197 sql.append('%s %s' % (style.SQL_KEYWORD('DECLARE VARIABLE'), style.SQL_COLTYPE('gen_val integer;'))) 198 sql.append('\t%s' % style.SQL_KEYWORD('BEGIN')) 199 sql.append('\t\t%s %s %s %s %s %s;' % (style.SQL_KEYWORD('SELECT MAX'), style.SQL_FIELD('(%(col)s)'), 200 style.SQL_KEYWORD('FROM'), style.SQL_TABLE('%(table)s'), 201 style.SQL_KEYWORD('INTO'), style.SQL_COLTYPE(':start_val'))) 202 sql.append('\t\t%s (%s %s) %s' % (style.SQL_KEYWORD('IF'), style.SQL_COLTYPE('start_val'), 203 style.SQL_KEYWORD('IS NULL'), style.SQL_KEYWORD('THEN'))) 204 sql.append('\t\t\t%s = %s(%s, 1 - %s(%s, 0));' %\ 205 (style.SQL_COLTYPE('gen_val'), style.SQL_KEYWORD('GEN_ID'), style.SQL_TABLE('%(gen)s'), 206 style.SQL_KEYWORD('GEN_ID'), style.SQL_TABLE('%(gen)s'))) 207 sql.append('\t\t%s' % style.SQL_KEYWORD('ELSE')) 208 sql.append('\t\t\t%s = %s(%s, %s - %s(%s, 0));' %\ 209 (style.SQL_COLTYPE('gen_val'), style.SQL_KEYWORD('GEN_ID'), 210 style.SQL_TABLE('%(gen)s'), style.SQL_COLTYPE('start_val'), style.SQL_KEYWORD('GEN_ID'), 211 style.SQL_TABLE('%(gen)s'))) 212 sql.append('\t\t%s;' % style.SQL_KEYWORD('EXIT')) 213 sql.append('%s;' % style.SQL_KEYWORD('END')) 214 sql ="\n".join(sql) 215 for model in model_list: 216 for f in model._meta.fields: 217 if isinstance(f, models.AutoField): 218 generator_name = self.get_generator_name(model._meta.db_table) 219 column_name = self.quote_name(f.db_column or f.name) 220 table_name = self.quote_name(model._meta.db_table) 221 output.append(sql % {'col' : column_name, 'table' : table_name, 'gen' : generator_name}) 222 output.append('%s %s;' % (style.SQL_KEYWORD('EXECUTE PROCEDURE'), 223 style.SQL_TABLE('"GENERATOR_RESET"'))) 224 break # Only one AutoField is allowed per model, so don't bother continuing. 225 for f in model._meta.many_to_many: 226 generator_name = self.get_generator_name(f.m2m_db_table()) 227 table_name = self.quote_name(f.m2m_db_table()) 228 column_name = '"id"' 229 output.append(sql % {'col' : column_name, 'table' : table_name, 'gen' : generator_name}) 230 output.append('%s %s;' % (style.SQL_KEYWORD('EXECUTE PROCEDURE'), 231 style.SQL_TABLE('"GENERATOR_RESET"'))) 232 return output 233 234 def sql_flush(self, style, tables, sequences): 235 if tables: 236 sql = ['%s %s %s;' % \ 237 (style.SQL_KEYWORD('DELETE'), 238 style.SQL_KEYWORD('FROM'), 239 style.SQL_TABLE(self.quote_name(table)) 240 ) for table in tables] 241 for generator_info in sequences: 242 table_name = generator_info['table'] 243 query = "%s %s %s 0;" % (style.SQL_KEYWORD('SET GENERATOR'), 244 self.get_generator_name(table_name), style.SQL_KEYWORD('TO')) 245 sql.append(query) 246 return sql 247 else: 248 return [] 249 250 ############################################################################ 251 # Custom classes 252 def field_class(this, DefaultField): 253 from django.db import connection 254 from django.db.models.fields import prep_for_like_query 255 class FirebirdField(DefaultField): 256 def get_db_prep_lookup(self, lookup_type, value): 257 "Returns field's value prepared for database lookup." 258 if lookup_type in ('exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 259 'lte', 'month', 'day', 'search', 'icontains', 260 'startswith', 'istartswith'): 261 return [value] 262 elif lookup_type in ('range', 'in'): 263 return value 264 elif lookup_type in ('contains',): 265 return ["%%%s%%" % prep_for_like_query(value)] 266 elif lookup_type == 'iexact': 267 return [prep_for_like_query(value)] 268 elif lookup_type in ('endswith', 'iendswith'): 269 return ["%%%s" % prep_for_like_query(value)] 270 elif lookup_type == 'isnull': 271 return [] 272 elif lookup_type == 'year': 273 try: 274 value = int(value) 275 except ValueError: 276 raise ValueError("The __year lookup type requires an integer argument") 277 return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.999999' % value] 278 raise TypeError("Field has invalid lookup: %s" % lookup_type) 279 return FirebirdField 280 281 def query_set_class(this, DefaultQuerySet): 282 from django.db import connection 283 from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE 284 class FirebirdQuerySet(DefaultQuerySet): 285 def _get_sql_clause(self): 286 from django.db.models.query import SortedDict, handle_legacy_orderlist, orderfield2column, fill_table_cache 287 qn = this.quote_name 288 opts = self.model._meta 289 290 # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. 291 select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields] 292 tables = [qn(t) for t in self._tables] 293 joins = SortedDict() 294 where = self._where[:] 295 params = self._params[:] 296 297 # Convert self._filters into SQL. 298 joins2, where2, params2 = self._filters.get_sql(opts) 299 joins.update(joins2) 300 where.extend(where2) 301 params.extend(params2) 302 303 # Add additional tables and WHERE clauses based on select_related. 304 if self._select_related: 305 fill_table_cache(opts, select, tables, where, 306 old_prefix=opts.db_table, 307 cache_tables_seen=[opts.db_table], 308 max_depth=self._max_related_depth) 309 310 # Add any additional SELECTs. 311 if self._select: 312 select.extend([('(%s AS %s') % (qn(s[1]), qn(s[0])) for s in self._select.items()]) 313 314 # Start composing the body of the SQL statement. 315 sql = [" FROM", qn(opts.db_table)] 316 317 # Compose the join dictionary into SQL describing the joins. 318 if joins: 319 sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition) 320 for (alias, (table, join_type, condition)) in joins.items()])) 321 322 # Compose the tables clause into SQL. 323 if tables: 324 sql.append(", " + ", ".join(tables)) 325 326 # Compose the where clause into SQL. 327 if where: 328 sql.append(where and "WHERE " + " AND ".join(where)) 329 330 # ORDER BY clause 331 order_by = [] 332 if self._order_by is not None: 333 ordering_to_use = self._order_by 334 else: 335 ordering_to_use = opts.ordering 336 for f in handle_legacy_orderlist(ordering_to_use): 337 if f == '?': # Special case. 338 order_by.append(connection.ops.random_function_sql()) 339 else: 340 if f.startswith('-'): 341 col_name = f[1:] 342 order = "DESC" 343 else: 344 col_name = f 345 order = "ASC" 346 if "." in col_name: 347 table_prefix, col_name = col_name.split('.', 1) 348 table_prefix = qn(table_prefix) + '.' 349 else: 350 # Use the database table as a column prefix if it wasn't given, 351 # and if the requested column isn't a custom SELECT. 352 if "." not in col_name and col_name not in (self._select or ()): 353 table_prefix = qn(opts.db_table) + '.' 354 else: 355 table_prefix = '' 356 order_by.append('%s%s %s' % \ 357 (table_prefix, qn(orderfield2column(col_name, opts)), order)) 358 if order_by: 359 sql.append("ORDER BY " + ", ".join(order_by)) 360 361 return select, " ".join(sql), params 362 363 def iterator(self): 364 "Performs the SELECT database lookup of this QuerySet." 365 from django.db.models.query import get_cached_row 366 try: 367 select, sql, params = self._get_sql_clause() 368 except EmptyResultSet: 369 raise StopIteration 370 371 # self._select is a dictionary, and dictionaries' key order is 372 # undefined, so we convert it to a list of tuples. 373 extra_select = self._select.items() 374 375 cursor = connection.cursor() 376 limit_offset_before = "" 377 if self._limit is not None: 378 limit_offset_before += "FIRST %s " % self._limit 379 if self._offset: 380 limit_offset_before += "SKIP %s " % self._offset 381 else: 382 assert self._offset is None, "'offset' is not allowed without 'limit'" 383 cursor.execute("SELECT " + limit_offset_before + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 384 fill_cache = self._select_related 385 fields = self.model._meta.fields 386 index_end = len(fields) 387 while 1: 388 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 389 if not rows: 390 raise StopIteration 391 for row in rows: 392 row = self.resolve_columns(row, fields) 393 if fill_cache: 394 obj, index_end = get_cached_row(klass=self.model, row=row, 395 index_start=0, max_depth=self._max_related_depth) 396 else: 397 obj = self.model(*row[:index_end]) 398 for i, k in enumerate(extra_select): 399 setattr(obj, k[0], row[index_end+i]) 400 yield obj 401 402 def resolve_columns(self, row, fields=()): 403 from django.db.models.fields import DateField, DateTimeField, \ 404 TimeField, BooleanField, NullBooleanField, DecimalField, Field 405 values = [] 406 for value, field in map(None, row, fields): 407 # Convert 1 or 0 to True or False 408 if value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)): 409 value = bool(value) 410 411 values.append(value) 412 return values 413 414 def extra(self, select=None, where=None, params=None, tables=None): 415 assert self._limit is None and self._offset is None, \ 416 "Cannot change a query once a slice has been taken" 417 clone = self._clone() 418 qn = this.quote_name 419 if select: clone._select.update(select) 420 if where: 421 qn_where = [] 422 for where_item in where: 423 try: 424 table, col_exact = where_item.split(".") 425 col, value = col_exact.split("=") 426 where_item = "%s.%s = %s" % (qn(table.strip()), 427 qn(col.strip()), value.strip()) 428 except: 429 try: 430 table, value = where_item.split("=") 431 where_item = "%s = %s" % (qn(table.strip()), qn(value.strip())) 432 except: 433 raise TypeError, "Can't understand extra WHERE clause: %s" % where 434 qn_where.append(where_item) 435 clone._where.extend(qn_where) 436 if params: clone._params.extend(params) 437 if tables: clone._tables.extend(tables) 438 return clone 439 440 return FirebirdQuerySet 441 442 ################################################################################ 443 # Cursor wrapper 444 class FirebirdCursorWrapper(object): 445 """ 446 Django uses "format" ('%s') style placeholders, but firebird uses "qmark" ('?') style. 447 This fixes it -- but note that if you want to use a literal "%s" in a query, 448 you'll need to use "%%s". 449 450 We also do all automatic type conversions here. 451 """ 452 import kinterbasdb.typeconv_datetime_stdlib as tc_dt 453 import kinterbasdb.typeconv_fixed_decimal as tc_fd 454 import kinterbasdb.typeconv_text_unicode as tc_tu 455 import django.utils.encoding as dj_ue 456 457 def ascii_conv_in(self, text): 458 if text is not None: 459 return self.dj_ue.smart_str(text, 'ascii') 460 461 def ascii_conv_out(self, text): 462 if text is not None: 463 return self.dj_ue.smart_unicode(text) 464 465 def blob_conv_in(self, text): 466 return self.tc_tu.unicode_conv_in((self.dj_ue.smart_unicode(text), self.FB_CHARSET_CODE)) 467 468 def blob_conv_out(self, text): 469 return self.tc_tu.unicode_conv_out((text, self.FB_CHARSET_CODE)) 470 471 def fixed_conv_in(self, (val, scale)): 472 if val is not None: 473 if isinstance(val, basestring): 474 val = decimal.Decimal(val) 475 return self.tc_fd.fixed_conv_in_precise((val, scale)) 476 477 def timestamp_conv_in(self, timestamp): 478 if isinstance(timestamp, basestring): 479 #Replaces 6 digits microseconds to 4 digits allowed in Firebird 480 timestamp = timestamp[:24] 481 return self.tc_dt.timestamp_conv_in(timestamp) 482 483 def time_conv_in(self, value): 484 import datetime 485 if isinstance(value, datetime.datetime): 486 value = datetime.time(value.hour, value.minute, value.second, value.microsecond) 487 488 def unicode_conv_in(self, text): 489 if text[0] is not None: 490 return self.tc_tu.unicode_conv_in((self.dj_ue.smart_unicode(text[0]), self.FB_CHARSET_CODE)) 491 492 def __init__(self, cursor, connection): 493 self.cursor = cursor 494 self._connection = connection 495 self._statement = None #prepared statement 496 self.FB_CHARSET_CODE = 3 #UNICODE_FSS 497 if connection.charset == 'UTF8': 498 self.FB_CHARSET_CODE = 4 # UTF-8 with Firebird 2.0+ 499 self.cursor.set_type_trans_in({ 500 'DATE': self.tc_dt.date_conv_in, 501 'TIME': self.time_conv_in, 502 'TIMESTAMP': self.timestamp_conv_in, 503 'FIXED': self.fixed_conv_in, 504 'TEXT': self.ascii_conv_in, 505 'TEXT_UNICODE': self.unicode_conv_in, 506 'BLOB': self.blob_conv_in 507 }) 508 self.cursor.set_type_trans_out({ 509 'DATE': self.tc_dt.date_conv_out, 510 'TIME': self.tc_dt.time_conv_out, 511 'TIMESTAMP': self.tc_dt.timestamp_conv_out, 512 'FIXED': self.tc_fd.fixed_conv_out_precise, 513 'TEXT': self.ascii_conv_out, 514 'TEXT_UNICODE': self.tc_tu.unicode_conv_out, 515 'BLOB': self.blob_conv_out 516 }) 517 518 def execute_immediate(self, query, params=()): 519 query = query % tuple(params) 520 self._connection.execute_immediate(query) 521 522 def prepare(self, query): 523 """ 524 Returns prepared statement for use with execute_prepared 525 http://kinterbasdb.sourceforge.net/dist_docs/usage.html#adv_prepared_statements 526 """ 527 query.replace("%s", "?") 528 return self.cursor.prep(query) 529 530 def execute_prepared(self, statement, params): 531 return self.cursor.execute(statement, params) 532 533 def execute_straight(self, query, params=()): 534 """ 535 Kinterbasdb-style execute with '?' instead of '%s' 536 """ 537 return self.cursor.execute(query, params) 538 539 def execute(self, query, params=()): 540 cquery = self.convert_query(query, len(params)) 541 if self._get_query() != cquery: 542 try: 543 self._statement = self.cursor.prep(cquery) 544 except Database.ProgrammingError, e: 545 output = ["Prepare query error."] 546 output.extend(str(e).split("'")[1].split('\\n')) 547 output.append("Query:") 548 output.append(cquery) 549 raise Database.ProgrammingError, "\n".join(output) 550 try: 551 return self.cursor.execute(self._statement, params) 552 except Database.ProgrammingError, e: 553 err_no = int(str(e).split()[0].strip(',()')) 554 output = ["Execute query error. FB error No. %i" % err_no] 555 output.extend(str(e).split("'")[1].split('\\n')) 556 output.append("Query:") 557 output.append(cquery) 558 output.append("Parameters:") 559 output.append(str(params)) 560 raise Database.ProgrammingError, "\n".join(output) 561 562 def executemany(self, query, param_list): 563 try: 564 cquery = self.convert_query(query, len(param_list[0])) 565 except IndexError: 566 return None 567 if self._get_query() != cquery: 568 self._statement = self.cursor.prep(cquery) 569 return self.cursor.executemany(self._statement, param_list) 570 571 def convert_query(self, query, num_params): 572 try: 573 return query % tuple("?" * num_params) 574 except TypeError, e: 575 print query, num_params 576 raise TypeError, e 577 578 def _get_query(self): 579 if self._statement: 580 return self._statement.sql 581 582 def __getattr__(self, attr): 583 if attr in self.__dict__: 584 return self.__dict__[attr] 585 else: 586 return getattr(self.cursor, attr) 587 588 ################################################################################ 589 # DatabaseWrapper(db.connection) 590 class DatabaseWrapper(BaseDatabaseWrapper): 591 features = DatabaseFeatures() 592 ops = DatabaseOperations() 593 operators = { 594 'exact': '= %s', 595 'iexact': '= UPPER(%s)', 596 'contains': "LIKE %s ESCAPE'\\'", 597 'icontains': 'CONTAINING %s', #case is ignored 598 'gt': '> %s', 599 'gte': '>= %s', 600 'lt': '< %s', 601 'lte': '<= %s', 602 'startswith': 'STARTING WITH %s', #looks to be faster then LIKE 603 'endswith': "LIKE %s ESCAPE'\\'", 604 'istartswith': 'STARTING WITH UPPER(%s)', 605 'iendswith': "LIKE UPPER(%s) ESCAPE'\\'" 606 } 607 608 def __init__(self, **kwargs): 609 from django.conf import settings 610 super(DatabaseWrapper, self).__init__(**kwargs) 611 self. _current_cursor = None 612 self._raw_cursor = None 613 self.charset = 'UNICODE_FSS' 614 self.FB_MAX_VARCHAR = 10921 #32765 MAX /3 615 self.BYTES_PER_DEFAULT_CHAR = 3 616 if hasattr(settings, 'FIREBIRD_CHARSET'): 617 if settings.FIREBIRD_CHARSET == 'UTF8': 618 self.charset = 'UTF8' 619 self.FB_MAX_VARCHAR = 8191 #32765 MAX /4 620 self.BYTES_PER_DEFAULT_CHAR = 4 621 622 def _connect(self, settings): 623 if settings.DATABASE_NAME == '': 624 from django.core.exceptions import ImproperlyConfigured 625 raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file." 626 kwargs = {'charset' : self.charset } 627 if settings.DATABASE_HOST: 628 kwargs['dsn'] = "%s:%s" % (settings.DATABASE_HOST, settings.DATABASE_NAME) 629 else: 630 kwargs['dsn'] = "localhost:%s" % settings.DATABASE_NAME 631 if settings.DATABASE_USER: 632 kwargs['user'] = settings.DATABASE_USER 633 if settings.DATABASE_PASSWORD: 634 kwargs['password'] = settings.DATABASE_PASSWORD 635 self.connection = Database.connect(**kwargs) 636 assert self.connection.charset == self.charset 637 638 def cursor(self): 639 from django.conf import settings 640 cursor = self._cursor(settings) 641 if settings.DEBUG: 642 self._debug_cursor = self.make_debug_cursor(cursor) 643 return self._debug_cursor 644 return cursor 645 646 def _cursor(self, settings): 647 if self.connection is None: 648 self._connect(settings) 649 cursor = self.connection.cursor() 650 self._raw_cursor = cursor 651 cursor = FirebirdCursorWrapper(cursor, self) 652 self._current_cursor = cursor 653 return cursor 654 655 def __getattr__(self, attr): 656 if attr in self.__dict__: 657 return self.__dict__[attr] 658 else: 659 return getattr(self.connection, attr) 660 -
django/db/backends/firebird/client.py
1 from django.conf import settings 2 import os 3 4 def 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
1 from django.db import transaction 2 from django.db.backends.firebird.base import DatabaseOperations 3 4 qn = quote_name = DatabaseOperations().quote_name 5 6 def 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()) for row in cursor.fetchall()] 12 13 def 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_straight(""" 19 SELECT DISTINCT R.RDB$FIELD_NAME AS FNAME, 20 F.RDB$FIELD_TYPE AS FTYPE, 21 F.RDB$CHARACTER_LENGTH AS FCHARLENGTH, 22 F.RDB$FIELD_LENGTH AS FLENGTH, 23 F.RDB$FIELD_PRECISION AS FPRECISION, 24 F.RDB$FIELD_SCALE AS FSCALE, 25 R.RDB$NULL_FLAG AS NULL_FLAG, 26 R.RDB$FIELD_POSITION 27 FROM RDB$RELATION_FIELDS R 28 JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME 29 WHERE F.RDB$SYSTEM_FLAG=0 and R.RDB$RELATION_NAME STARTING WITH ? 30 ORDER BY R.RDB$FIELD_POSITION 31 """, (qn(table_name).strip('"'),)) 32 return [(row[0].rstrip(), row[1], row[2] or 0, row[3], row[4], row[5], row[6] and True or False) for row in cursor.fetchall()] 33 34 35 def get_relations(cursor, table_name): 36 """ 37 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 38 representing all relationships to the given table. Indexes are 0-based. 39 """ 40 cursor.execute_straight(""" 41 SELECT seg.rdb$field_name, seg_ref.rdb$field_name, idx_ref.rdb$relation_name 42 FROM rdb$indices idx 43 INNER JOIN rdb$index_segments seg 44 ON seg.rdb$index_name = idx.rdb$index_name 45 INNER JOIN rdb$indices idx_ref 46 ON idx_ref.rdb$index_name = idx.rdb$foreign_key 47 INNER JOIN rdb$index_segments seg_ref 48 ON seg_ref.rdb$index_name = idx_ref.rdb$index_name 49 WHERE idx.rdb$relation_name STARTING WITH ? 50 AND idx.rdb$foreign_key IS NOT NULL""", [qn(table_name).strip('"')]) 51 52 relations = {} 53 for row in cursor.fetchall(): 54 relations[row[0].rstrip()] = (row[1].strip(), row[2].strip()) 55 return relations 56 57 58 def get_indexes(cursor, table_name): 59 """ 60 Returns a dictionary of fieldname -> infodict for the given table, 61 where each infodict is in the format: 62 {'primary_key': boolean representing whether it's the primary key, 63 'unique': boolean representing whether it's a unique index} 64 """ 65 66 # This query retrieves each field name and index type on the given table. 67 cursor.execute(""" 68 SELECT seg.RDB$FIELD_NAME, const.RDB$CONSTRAINT_TYPE 69 FROM RDB$RELATION_CONSTRAINTS const 70 LEFT JOIN RDB$INDEX_SEGMENTS seg 71 ON seg.RDB$INDEX_NAME = const.RDB$INDEX_NAME 72 WHERE const.RDB$RELATION_NAME STARTING WITH ? 73 ORDER BY seg.RDB$FIELD_POSITION)""", 74 [qn(table_name).strip('"')]) 75 indexes = {} 76 for row in cursor.fetchall(): 77 indexes[row[0]] = {'primary_key': row[1].startswith('PRIMARY'), 78 'unique': row[1].startswith('UNIQUE')} 79 return indexes 80 81 # Maps type codes to Django Field types. 82 DATA_TYPES_REVERSE = { 83 261: 'LargeTextField', 84 14: 'CharField', 85 40: 'CharField', 86 11: 'FloatField', 87 27: 'FloatField', 88 10: 'FloatField', 89 16: 'IntegerField', 90 8: 'IntegerField', 91 9: 'IntegerField', 92 7: 'SmallIntegerField', 93 12: 'DateField', 94 13: 'TimeField', 95 35: 'DateTimeField', 96 37: 'CharField' 97 } -
django/db/backends/firebird/creation.py
1 # This dictionary maps Field objects to their associated Firebird column 2 # types, as strings. Column-type strings can contain format strings; they'll 3 # be interpolated against the values of Field.__dict__ before being output. 4 # If a column type is set to None, it won't be included in the output. 5 6 7 from kinterbasdb import connect, create_database 8 from django.core.management import call_command 9 from django.conf import settings 10 from django.db import connection 11 import sys, os, os.path, codecs 12 try: 13 set 14 except NameError: 15 from sets import Set as set # Python 2.3 fallback 16 17 # Setting TEST_MODE to 1 enables cascading deletes (for table flush) which are dangerous 18 # Setting TEST_MODE to 2 disables strict FK constraints (for forward/post references) 19 # Setting TEST_MODE to 0 is the most secure option (it even fails some official Django tests because of it) 20 TEST_MODE = 0 21 if 'FB_DJANGO_TEST_MODE' in os.environ: 22 TEST_MODE = int(os.environ['FB_DJANGO_TEST_MODE']) 23 24 DATA_TYPES = { 25 'AutoField': '"AutoField"', 26 'BooleanField': '"BooleanField"', 27 'CharField': 'varchar(%(max_length)s)', 28 'CommaSeparatedIntegerField': 'varchar(%(max_length)s) CHARACTER SET ASCII', 29 'DateField': '"DateField"', 30 'DateTimeField': '"DateTimeField"', 31 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 32 'DefaultCharField': '"CharField"', 33 'FileField': 'varchar(%(max_length)s)', 34 'FilePathField': 'varchar(%(max_length)s)', 35 'FloatField': '"FloatField"', 36 'ImageField': '"varchar(%(max_length)s)"', 37 'IntegerField': '"IntegerField"', 38 'IPAddressField': 'varchar(15) CHARACTER SET ASCII', 39 'NullBooleanField': '"NullBooleanField"', 40 'OneToOneField': '"OneToOneField"', 41 'PhoneNumberField': '"PhoneNumberField"', 42 'PositiveIntegerField': '"PositiveIntegerField"', 43 'PositiveSmallIntegerField': '"PositiveSmallIntegerField"', 44 'SlugField': 'varchar(%(max_length)s)', 45 'SmallIntegerField': '"SmallIntegerField"', 46 'LargeTextField': '"LargeTextField"', 47 'TextField': '"TextField"', 48 'TimeField': '"TimeField"', 49 'URLField': 'varchar(%(max_length)s) CHARACTER SET ASCII', 50 'USStateField': '"USStateField"' 51 } 52 53 PYTHON_TO_FB_ENCODING_MAP = { 54 'ascii': 'ASCII', 55 'utf_8': connection.charset, 56 'shift_jis': 'SJIS_0208', 57 'euc_jp': 'EUCJ_0208', 58 'cp737': 'DOS737', 59 'cp437': 'DOS437', 60 'cp850': 'DOS850', 61 'cp865': 'DOS865', 62 'cp860': 'DOS860', 63 'cp863': 'DOS863', 64 'cp775': 'DOS775', 65 'cp862': 'DOS862', 66 'cp864': 'DOS864', 67 'iso8859_1': 'ISO8859_1', 68 'iso8859_2': 'ISO8859_2', 69 'iso8859_3': 'ISO8859_3', 70 'iso8859_4': 'ISO8859_4', 71 'iso8859_5': 'ISO8859_5', 72 'iso8859_6': 'ISO8859_6', 73 'iso8859_7': 'ISO8859_7', 74 'iso8859_8': 'ISO8859_8', 75 'iso8859_9': 'ISO8859_9', 76 'iso8859_13': 'ISO8859_13', 77 'euc_kr': 'KSC_5601', 78 'cp852': 'DOS852', 79 'cp857': 'DOS857', 80 'cp861': 'DOS861', 81 'cp866': 'DOS866', 82 'cp869': 'DOS869', 83 'cp1250': 'WIN1250', 84 'cp1251': 'WIN1251', 85 'cp1252': 'WIN1252', 86 'cp1253': 'WIN1253', 87 'cp1254': 'WIN1254', 88 'big5': 'BIG_5', 89 'gb2312': 'GB_2312', 90 'cp1255': 'WIN1255', 91 'cp1256': 'WIN1256', 92 'cp1257': 'WIN1257', 93 'koi8_r': 'KOI8-R', 94 'koi8_u': 'KOI8-U', 95 'cp1258': 'WIN1258' 96 } 97 98 def get_data_size(data_type, max_length = 100): 99 char_bytes = connection.BYTES_PER_DEFAULT_CHAR 100 size_map = { 101 'AutoField': 8, 102 'BooleanField': 4, 103 'CharField': char_bytes*max_length, 104 'CommaSeparatedIntegerField': max_length, 105 'DateField': 16, 106 'DateTimeField': 16, 107 'DecimalField': 16, 108 'FileField': char_bytes*max_length, 109 'FilePathField': 'varchar(%(max_length)s)', 110 'FloatField': 16, 111 'ImageField': char_bytes*max_length, 112 'IntegerField': 8, 113 'IPAddressField': 15, 114 'NullBooleanField': 4, 115 'OneToOneField': 8, 116 'PhoneNumberField': 20, 117 'PositiveIntegerField': 8, 118 'PositiveSmallIntegerField': 4, 119 'SlugField': char_bytes*max_length, 120 'SmallIntegerField': 4, 121 'TextBlob': 8, 122 'TextField': 32767, 123 'TimeField': 16, 124 'URLField': max_length, 125 'USStateField': char_bytes*2 126 } 127 return size_map[data_type] 128 129 DEFAULT_MAX_LENGTH = 100 130 def sql_model_create(model, style, known_models=set()): 131 """ 132 Returns the SQL required to create a single model, as a tuple of: 133 (list_of_sql, pending_references_dict) 134 """ 135 from django.db import connection, models 136 137 opts = model._meta 138 final_output = [] 139 table_output = [] 140 pending_references = {} 141 qn = connection.ops.quote_name 142 143 # Create domains 144 domains = [ ('AutoField', 'integer'), 145 ('BooleanField', 'smallint CHECK (VALUE IN (0,1))'), 146 ('DateField', 'date'), 147 ('CharField', 'varchar(%i)' % DEFAULT_MAX_LENGTH), 148 ('DateTimeField', 'timestamp'), 149 ('FloatField', 'double precision'), 150 ('IntegerField', 'integer'), 151 ('IPAddressField', 'varchar(15) CHARACTER SET ASCII'), 152 ('NullBooleanField', 'smallint CHECK ((VALUE IN (0,1)) OR (VALUE IS NULL))'), 153 ('OneToOneField', 'integer'), 154 ('PhoneNumberField', 'varchar(20) CHARACTER SET ASCII'), 155 ('PositiveIntegerField', 'integer CHECK ((VALUE >= 0) OR (VALUE IS NULL))'), 156 ('PositiveSmallIntegerField', 'smallint CHECK ((VALUE >= 0) OR (VALUE IS NULL))'), 157 ('SmallIntegerField', 'smallint'), 158 ('TextField', 'varchar(%s)' % connection.FB_MAX_VARCHAR), 159 ('LargeTextField', 'blob sub_type text'), 160 ('TimeField', 'time'), 161 ('USStateField', 'varchar(2) CHARACTER SET ASCII') ] 162 163 connected = True 164 try: 165 cursor = connection.cursor() 166 except: 167 connected = False 168 if connected: 169 cursor.execute("SELECT RDB$FIELD_NAME FROM RDB$FIELDS") 170 existing_domains = set([row[0].strip() for row in cursor.fetchall() if not row[0].startswith('RDB$')]) 171 domains = map(lambda domain: '%s "%s" AS %s;' % ('CREATE DOMAIN', domain[0], domain[1]), 172 filter(lambda x: x[0] not in existing_domains, domains)) 173 final_output.extend(domains) 174 175 # Check that row size is less than 64k and adjust TextFields if needed 176 row_size = 0 177 columns = [(f.db_type().strip('"'), f.get_internal_type(), f) for f in opts.fields] 178 columns_simple = [col[0] for col in columns] 179 text_field_type = '"TextField"' 180 max_alowed_bytes = 32765 181 if 'TextField' in columns_simple: 182 max_length = 100 183 num_text_fields = 0 184 for column in columns: 185 num_text_fields += (column[0] == 'TextField') 186 if column[0].startswith('varchar'): 187 max_length = int(column[0].split('(')[1].split(')')[0]) 188 if column[1] in DATA_TYPES: 189 row_size += get_data_size(column[1], max_length) 190 if row_size > 65536: 191 max_alowed_bytes = int( (max_alowed_bytes/num_text_fields) - (row_size-65536) ) 192 n = max_alowed_bytes / connection.BYTES_PER_DEFAULT_CHAR 193 if n > 512: 194 text_field_type = 'varchar(%s)' % n 195 FB_TEXTFIELD_ALTERED = True 196 print 197 print "WARNING: Maximum number of characters in TextFields has changed to %s." % n 198 print " TextField columns with custom charsets will have %s chars available" % max_alowed_bytes 199 print " The change affects %s table only." % opts.db_table 200 print " TextFields in other tables will have %s characters maximum" % connection.FB_MAX_VARCHAR 201 print " or 32765 characters with custom (non-UTF) encoding." 202 print " If you need more space in those fields try LargeTextFields instead." 203 print 204 else: 205 # Swich to blobs if size is too small (<1024) 206 text_field_type = '"LargeTextField"' 207 208 # Create tables 209 for f in opts.fields: 210 col_type = f.db_type() 211 if col_type.strip('"') == 'TextField': 212 col_type = text_field_type 213 fb_version = "%s.%s" % (connection.ops.firebird_version[0], connection.ops.firebird_version[1]) 214 page_size = connection.ops.page_size 215 #look at: http://www.volny.cz/iprenosil/interbase/ip_ib_indexcalculator.htm 216 if connection.ops.index_limit < 1000: 217 strip2ascii = False 218 custom_charset = False 219 if col_type.startswith('varchar'): 220 if (f.unique or f.primary_key or f.db_index): 221 length = f.max_length 222 if f.encoding: 223 if not f.encoding.upper().startswith('UTF'): 224 custom_charset = True 225 if not custom_charset: 226 try: 227 length = f.max_length * connection.BYTES_PER_DEFAULT_CHAR 228 except TypeError: 229 length = 100*connection.BYTES_PER_DEFAULT_CHAR #Default for CharField 230 if length >= connection.ops.index_limit: 231 strip2ascii = True 232 if len(opts.unique_together) > 0: 233 if f.column in opts.unique_together[0]: 234 num_unique_char_fields = len([ fld for fld in opts.unique_together[0] if opts.get_field(fld).db_type().startswith('varchar') ]) 235 num_unique_fileds = len(opts.unique_together[0]) 236 num_unique_nonchar_fileds = num_unique_fileds - num_unique_char_fields 237 limit = connection.ops.index_limit 238 limit -= ((num_unique_fileds - 1)*64) 239 limit -= 8*num_unique_nonchar_fileds 240 max_length = limit/num_unique_char_fields 241 ascii_length = int(f.max_length) 242 old_length = ascii_length*connection.BYTES_PER_DEFAULT_CHAR 243 244 if (old_length >= max_length) and (ascii_length < max_length): 245 strip2ascii = True 246 elif old_length > max_length: 247 strip2ascii = False #We change it here 248 col_type = "varchar(%i) CHARACTER SET ASCII" % max_length 249 msg = "WARNING: Character set of the '%s' field\n" 250 msg += " (table %s)\n" 251 msg += " has changed to ASCII" 252 msg += " to fit %s-byte limit in FB %s" 253 if not page_size: 254 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version) 255 else: 256 msg += " with page size %s" 257 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version, page_size) 258 print " The maximum length of '%s' is now %s instead of %s"\ 259 % (f.column, max_length, old_length) 260 if strip2ascii: 261 col_type = "%s %s %s" % (col_type, "CHARACTER SET", "ASCII") 262 msg = "WARNING: Character set of the '%s' field\n" 263 msg += " (table %s)\n" 264 msg += " has changed to ASCII" 265 msg += " to fit %s-byte limit in FB %s" 266 if not page_size: 267 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version) 268 else: 269 msg += " with page size %s" 270 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version, page_size) 271 272 if (col_type.startswith('varchar') or col_type.strip('"') == 'TextField') and f.encoding: 273 charset = PYTHON_TO_FB_ENCODING_MAP[codecs.lookup(f.encoding).name] 274 if col_type.strip('"') == 'TextField': 275 col_type = 'varchar(%i)' % max_alowed_bytes 276 col_type = "%s %s %s" % (col_type, "CHARACTER SET", charset) 277 278 if col_type is None: 279 # Skip ManyToManyFields, because they're not represented as 280 # database columns in this table. 281 continue 282 if col_type == 'ComputedField': 283 # Make the definition (e.g. 'foo COMPUTED BY (oldfoo*2)') for this field. 284 field_output = [ style.SQL_FIELD(qn(f.column)), style.SQL_KEYWORD('COMPUTED BY'), 285 '(%s)' % f.expression ] 286 287 else: 288 # Make the definition (e.g. 'foo VARCHAR(30)') for this field. 289 field_output = [style.SQL_FIELD(qn(f.column)), 290 style.SQL_COLTYPE(col_type)] 291 field_output.append(style.SQL_KEYWORD('%s' % (not f.null and 'NOT NULL' or ''))) 292 if f.unique: 293 field_output.append(style.SQL_KEYWORD('UNIQUE')) 294 if f.primary_key: 295 field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 296 if f.rel: 297 # We haven't yet created the table to which this field 298 # is related, so save it for later. 299 pr = pending_references.setdefault(f.rel.to, []).append((model, f)) 300 table_output.append(' '.join(field_output)) 301 for field_constraints in opts.unique_together: 302 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ 303 ", ".join([qn(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints])) 304 305 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' ('] 306 for i, line in enumerate(table_output): # Combine and add commas. 307 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 308 full_statement.append(');') 309 final_output.append('\n'.join(full_statement)) 310 311 if opts.has_auto_field: 312 # Add any extra SQL needed to support auto-incrementing primary keys. 313 auto_column = opts.auto_field.db_column or opts.auto_field.name 314 autoinc_sql = connection.ops.autoinc_sql(style, opts.db_table, auto_column) 315 if autoinc_sql: 316 for stmt in autoinc_sql: 317 final_output.append(stmt) 318 319 # Declare exteral functions 320 if connected: 321 cursor.execute("SELECT RDB$FUNCTION_NAME FROM RDB$FUNCTIONS") 322 existing_functions = set([row[0].strip().upper() for row in cursor.fetchall()]) 323 if 'RAND' not in existing_functions: 324 final_output.append('%s %s\n\t%s %s\n\t%s %s\n\t%s;' % (style.SQL_KEYWORD('DECLARE EXTERNAL FUNCTION'), 325 style.SQL_TABLE('RAND'), style.SQL_KEYWORD('RETURNS'), style.SQL_COLTYPE('DOUBLE PRECISION'), 326 style.SQL_KEYWORD('BY VALUE ENTRY_POINT'), style.SQL_FIELD("'IB_UDF_rand'"), 327 style.SQL_TABLE("MODULE_NAME 'ib_udf'"))) 328 329 # Create stored procedures 330 if hasattr(model, 'procedures'): 331 for proc in model.procedures: 332 final_output.append(proc.create_procedure_sql()) 333 334 return final_output, pending_references 335 336 def many_to_many_sql_for_model(model, style): 337 from django.db import connection, models 338 from django.contrib.contenttypes import generic 339 from django.db.backends.util import truncate_name 340 341 opts = model._meta 342 final_output = [] 343 qn = connection.ops.quote_name 344 for f in opts.many_to_many: 345 if not isinstance(f.rel, generic.GenericRel): 346 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ 347 style.SQL_TABLE(qn(f.m2m_db_table())) + ' ('] 348 table_output.append(' %s %s %s,' % 349 (style.SQL_FIELD(qn('id')), 350 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()), 351 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'))) 352 353 table_output.append(' %s %s %s,' % 354 (style.SQL_FIELD(qn(f.m2m_column_name())), 355 style.SQL_COLTYPE(models.ForeignKey(model).db_type()), 356 style.SQL_KEYWORD('NOT NULL'))) 357 table_output.append(' %s %s %s,' % 358 (style.SQL_FIELD(qn(f.m2m_reverse_name())), 359 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()), 360 style.SQL_KEYWORD('NOT NULL'))) 361 deferred = [ 362 (f.m2m_db_table(), f.m2m_column_name(), opts.db_table, 363 opts.pk.column), 364 ( f.m2m_db_table(), f.m2m_reverse_name(), 365 f.rel.to._meta.db_table, f.rel.to._meta.pk.column) 366 ] 367 368 table_output.append(' %s (%s, %s)' % 369 (style.SQL_KEYWORD('UNIQUE'), 370 style.SQL_FIELD(qn(f.m2m_column_name())), 371 style.SQL_FIELD(qn(f.m2m_reverse_name())))) 372 table_output.append(');') 373 final_output.append('\n'.join(table_output)) 374 375 autoinc_sql = connection.ops.autoinc_sql(style, f.m2m_db_table(), 'id') 376 if autoinc_sql: 377 for stmt in autoinc_sql: 378 final_output.append(stmt) 379 380 if TEST_MODE < 2: 381 for r_table, r_col, table, col in deferred: 382 r_name = '%s_refs_%s_%x' % (r_col, col, 383 abs(hash((r_table, table)))) 384 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 385 (qn(r_table), 386 truncate_name(r_name, connection.ops.max_name_length()), 387 qn(r_col), qn(table), qn(col), 388 'ON DELETE CASCADE ON UPDATE CASCADE')) 389 390 return final_output 391 392 def sql_for_pending_references(model, style, pending_references): 393 """ 394 Returns any ALTER TABLE statements to add constraints after the fact. 395 """ 396 from django.db import connection 397 398 qn = connection.ops.quote_name 399 final_output = [] 400 if TEST_MODE < 2: 401 opts = model._meta 402 if model in pending_references: 403 for rel_class, f in pending_references[model]: 404 rel_opts = rel_class._meta 405 r_table = rel_opts.db_table 406 r_col = f.column 407 table = opts.db_table 408 col = opts.get_field(f.rel.field_name).column 409 r_name = connection.ops.reference_name(r_col, col, r_table, table) 410 if not f.on_update: 411 f.on_update = 'CASCADE' 412 if not f.on_delete: 413 if TEST_MODE > 0: 414 f.on_delete = 'CASCADE' 415 else: 416 f.on_delete = 'SET NULL' 417 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s) ON UPDATE %s ON DELETE %s;' % \ 418 (qn(r_table), r_name, qn(r_col), qn(table), qn(col), 419 f.on_update, f.on_delete)) 420 421 del pending_references[model] 422 return final_output 423 424 425 TEST_DATABASE_PREFIX = 'test_' 426 def create_test_db(settings, connection, verbosity, autoclobber): 427 # KInterbasDB supports dynamic database creation and deletion 428 # via the module-level function create_database and the method Connection.drop_database. 429 430 if settings.TEST_DATABASE_NAME: 431 TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME 432 else: 433 dbnametuple = os.path.split(settings.DATABASE_NAME) 434 TEST_DATABASE_NAME = os.path.join(dbnametuple[0], TEST_DATABASE_PREFIX + dbnametuple[1]) 435 436 dsn = "localhost:%s" % TEST_DATABASE_NAME 437 if settings.DATABASE_HOST: 438 dsn = "%s:%s" % (settings.DATABASE_HOST, TEST_DATABASE_NAME) 439 440 if os.path.isfile(TEST_DATABASE_NAME): 441 sys.stderr.write("Database %s already exists\n" % TEST_DATABASE_NAME) 442 if not autoclobber: 443 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME) 444 if autoclobber or confirm == 'yes': 445 if verbosity >= 1: 446 print "Destroying old test database..." 447 old_connection = connect(dsn=dsn, user=settings.DATABASE_USER, password=settings.DATABASE_PASSWORD) 448 old_connection.drop_database() 449 else: 450 print "Tests cancelled." 451 sys.exit(1) 452 453 if verbosity >= 1: 454 print "Creating test database..." 455 try: 456 charset = 'UNICODE_FSS' 457 if hasattr(settings, 'FIREBIRD_CHARSET'): 458 if settings.FIREBIRD_CHARSET == 'UTF8': 459 charset='UTF8' 460 create_database("create database '%s' user '%s' password '%s' default character set %s" % \ 461 (dsn, settings.DATABASE_USER, settings.DATABASE_PASSWORD, charset)) 462 except Exception, e: 463 sys.stderr.write("Got an error creating the test database: %s\n" % e) 464 sys.exit(2) 465 466 connection.close() 467 settings.DATABASE_NAME = TEST_DATABASE_NAME 468 469 call_command('syncdb', verbosity=verbosity, interactive=False) 470 471 if settings.CACHE_BACKEND.startswith('db://'): 472 cache_name = settings.CACHE_BACKEND[len('db://'):] 473 call_command('createcachetable', cache_name) 474 475 # Get a cursor (even though we don't need one yet). This has 476 # the side effect of initializing the test database. 477 cursor = connection.cursor() 478 479 return TEST_DATABASE_NAME 480 481 def destroy_test_db(settings, connection, old_database_name, verbosity): 482 # KInterbasDB supports dynamic database deletion via the method Connection.drop_database. 483 if verbosity >= 1: 484 print "Destroying test database..." 485 connection.drop_database() 486 487 -
django/core/cache/backends/db.py
47 47 if timeout is None: 48 48 timeout = self.default_timeout 49 49 cursor = connection.cursor() 50 cursor.execute("SELECT COUNT(*) FROM %s" % self._table) 50 qn = connection.ops.quote_name 51 cursor.execute("SELECT COUNT(*) FROM %s" % qn(self._table)) 51 52 num = cursor.fetchone()[0] 52 53 now = datetime.now().replace(microsecond=0) 53 54 exp = datetime.fromtimestamp(time.time() + timeout).replace(microsecond=0) 54 55 if num > self._max_entries: 55 56 self._cull(cursor, now) 56 57 encoded = base64.encodestring(pickle.dumps(value, 2)).strip() 57 cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % self._table, [key])58 cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % qn(self._table), [key]) 58 59 try: 59 60 if mode == 'set' and cursor.fetchone(): 60 cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % self._table, [encoded, str(exp), key])61 cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % qn(self._table), [encoded, str(exp), key]) 61 62 else: 62 cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % self._table, [key, encoded, str(exp)])63 cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % qn(self._table), [key, encoded, str(exp)]) 63 64 except DatabaseError: 64 65 # To be threadsafe, updates/inserts are allowed to fail silently 65 66 pass -
django/core/management/sql.py
1 1 from django.core.management.base import CommandError 2 from django.conf import settings 2 3 import os 3 4 import re 4 5 … … 66 67 67 68 def sql_create(app, style): 68 69 "Returns a list of the CREATE TABLE SQL statements for the given app." 69 from django.db import models 70 from django.db import models, get_creation_module 70 71 from django.conf import settings 71 72 72 73 if settings.DATABASE_ENGINE == 'dummy': … … 97 98 # Create the many-to-many join tables. 98 99 for model in app_models: 99 100 final_output.extend(many_to_many_sql_for_model(model, style)) 100 101 101 102 # Handle references to tables that are from other apps 102 103 # but don't exist physically. 103 104 not_installed_models = set(pending_references.keys()) … … 163 164 col = f.column 164 165 r_table = model._meta.db_table 165 166 r_col = model._meta.get_field(f.rel.field_name).column 166 r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))167 r_name = connection.ops.reference_name(r_col, col, r_table, table) 167 168 output.append('%s %s %s %s;' % \ 168 169 (style.SQL_KEYWORD('ALTER TABLE'), 169 170 style.SQL_TABLE(qn(table)), … … 245 246 Returns the SQL required to create a single model, as a tuple of: 246 247 (list_of_sql, pending_references_dict) 247 248 """ 248 from django.db import connection, models 249 249 from django.db import connection, models, get_creation_module 250 creation_module = get_creation_module() 251 # If the database backend wants to create model itself, let it 252 if hasattr(creation_module, "sql_model_create"): 253 return creation_module.sql_model_create(model, style, known_models) 250 254 opts = model._meta 251 255 final_output = [] 252 256 table_output = [] … … 315 319 """ 316 320 Returns any ALTER TABLE statements to add constraints after the fact. 317 321 """ 318 from django.db import connection 322 from django.db import connection, get_creation_module 319 323 from django.db.backends.util import truncate_name 320 324 325 creation_module = get_creation_module() 326 # If the database backend wants to create many_to_many sql itself, let it 327 if hasattr(creation_module, "sql_for_pending_references"): 328 return creation_module.sql_for_pending_references(model, style, pending_references) 329 321 330 qn = connection.ops.quote_name 322 331 final_output = [] 323 332 if connection.features.supports_constraints: … … 331 340 col = opts.get_field(f.rel.field_name).column 332 341 # For MySQL, r_name must be unique in the first 64 characters. 333 342 # So we are careful with character usage here. 334 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))343 r_name = connection.ops.reference_name(r_col, col, r_table, table) 335 344 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \ 336 345 (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()), 337 346 qn(r_col), qn(table), qn(col), … … 340 349 return final_output 341 350 342 351 def many_to_many_sql_for_model(model, style): 343 from django.db import connection, models 352 from django.db import connection, models, get_creation_module 344 353 from django.contrib.contenttypes import generic 345 354 from django.db.backends.util import truncate_name 346 355 356 creation_module = get_creation_module() 357 # If the database backend wants to create many_to_many sql itself, let it 358 if hasattr(creation_module, "many_to_many_sql_for_model"): 359 return creation_module.many_to_many_sql_for_model(model, style) 360 347 361 opts = model._meta 348 362 final_output = [] 349 363 qn = connection.ops.quote_name … … 406 420 final_output.append('\n'.join(table_output)) 407 421 408 422 for r_table, r_col, table, col in deferred: 409 r_name = '%s_refs_%s_%x' % (r_col, col, 410 abs(hash((r_table, table)))) 423 r_name = connection.ops.reference_name(r_col, col, r_table, table) 411 424 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 412 425 (qn(r_table), 413 426 truncate_name(r_name, connection.ops.max_name_length()), -
tests/modeltests/custom_methods/models.py
27 27 """ 28 28 from django.db import connection 29 29 cursor = connection.cursor() 30 # Some backends really really need quotes! 30 31 cursor.execute(""" 31 SELECT id, headline, pub_date32 FROM custom_methods_article33 WHERE pub_date= %s34 AND id!= %s""", [str(self.pub_date), self.id])32 SELECT "id", "headline", "pub_date" 33 FROM "custom_methods_article" 34 WHERE "pub_date" = %s 35 AND "id" != %s""", [str(self.pub_date), self.id]) 35 36 # The asterisk in "(*row)" tells Python to expand the list into 36 37 # positional arguments to Article(). 37 38 return [self.__class__(*row) for row in cursor.fetchall()] 39 40 class articles_from_same_day_3(models.Procedure): 41 """ 42 Stored procedure version of get_articles_from_same_day_1, which executes 43 a custom stored procedure for the sake of demonstration. 44 """ 45 __params__ = [ ('self_pub_date', 'date'), 46 ('self_id', 'integer') ] 47 __returns__ = [ ('other_id', 'integer'), 48 ('other_headline', 'varchar(100)'), 49 ('other_pub_date', 'date') ] 50 __body__ = \ 51 """FOR SELECT "id", "headline", "pub_date" 52 FROM "custom_methods_article" 53 WHERE "pub_date" = :self_pub_date 54 AND "id" != :self_id 55 INTO :other_id, :other_headline, :other_pub_date 56 DO BEGIN SUSPEND; END""" 57 58 def articles_from_same_day_4(self): 59 # The asterisk in "(*row)" tells Python to expand the list into 60 # positional arguments to Article(). 61 return [self.__class__(*row) for row in self.articles_from_same_day_3(self.pub_date, self.pk) ] 62 63 # Tell the creation module to install the procedure 64 procedures = (articles_from_same_day_3,) 38 65 66 39 67 __test__ = {'API_TESTS':""" 40 68 # Create a couple of Articles. 41 69 >>> from datetime import date … … 51 79 [<Article: Beatles reunite>] 52 80 >>> a.articles_from_same_day_2() 53 81 [<Article: Beatles reunite>] 82 >>> [Article(*row) for row in a.articles_from_same_day_3(a.pub_date, a.pk)] 83 [<Article: Beatles reunite>] 84 >>> a.articles_from_same_day_4() 85 [<Article: Beatles reunite>] 54 86 >>> b.articles_from_same_day_1() 55 87 [<Article: Area man programs in Python>] 56 88 >>> b.articles_from_same_day_2() -
tests/modeltests/lookup/models.py
274 274 >>> a4.save() 275 275 >>> a5 = Article(pub_date=now, headline='hey-Foo') 276 276 >>> a5.save() 277 """} 277 278 279 # Firebird support 'magic values' 280 if settings.DATABASE_ENGINE in ('firebird',): 281 __test__['API_TESTS'] += r""" 282 # and yet more: 283 >>> a10 = Article(pub_date='today', headline='foobar') 284 >>> a10.save() 285 >>> a11 = Article(pub_date='tomorrow', headline='foobaz') 286 >>> a11.save() 287 >>> a12 = Article(pub_date='yesterday', headline='ooF') 288 >>> a12.save() 289 >>> a13 = Article(pub_date='now', headline='foobarbaz') 290 >>> a13.save() 291 >>> a14 = Article(pub_date='today', headline='zoocarfaz') 292 >>> a14.save() 293 >>> a15 = Article(pub_date='today', headline='barfoobaz') 294 >>> a15.save() 295 >>> a16 = Article(pub_date='today', headline='bazbaRFOO') 296 >>> a16.save() 297 >>> Article.objects.filter(pub_date__exact='yesterday') 298 [<Article: ooF>] 299 """ 300 301 302 # Firebird doesn't support regular expression lookups 303 if settings.DATABASE_ENGINE not in ('firebird',): 304 __test__['API_TESTS'] += r""" 278 305 # zero-or-more 279 306 >>> Article.objects.filter(headline__regex=r'fo*') 280 307 [<Article: f>, <Article: fo>, <Article: foo>, <Article: fooo>] … … 348 375 [<Article: barfoobaz>, <Article: baz>, <Article: bazbaRFOO>, <Article: foobarbaz>, <Article: foobaz>] 349 376 >>> Article.objects.filter(headline__iregex=r'b.*ar') 350 377 [<Article: bar>, <Article: barfoobaz>, <Article: bazbaRFOO>, <Article: foobar>, <Article: foobarbaz>] 351 """ }378 """ 352 379 353 380 354 if settings.DATABASE_ENGINE not in ('mysql', 'mysql_old' ):381 if settings.DATABASE_ENGINE not in ('mysql', 'mysql_old', 'firebird'): 355 382 __test__['API_TESTS'] += r""" 356 383 # grouping and backreferences 357 384 >>> Article.objects.filter(headline__regex=r'b(.).*b\1') -
tests/regressiontests/serializers_regress/tests.py
22 22 import decimal 23 23 except ImportError: 24 24 from django.utils import _decimal as decimal 25 try: 26 set 27 except NameError: 28 from sets import Set as set # Python 2.3 fallback 25 29 26 30 # A set of functions that can be used to recreate 27 31 # test data objects of various kinds. … … 83 87 testcase.assertEqual(data, instance.data_id) 84 88 85 89 def m2m_compare(testcase, pk, klass, data): 90 # Use sets to ignore order of data 86 91 instance = klass.objects.get(id=pk) 87 testcase.assertEqual( data, [obj.id for obj in instance.data.all()])92 testcase.assertEqual(set(data), set([obj.id for obj in instance.data.all()])) 88 93 89 94 def o2o_compare(testcase, pk, klass, data): 90 95 instance = klass.objects.get(data=data) -
tests/regressiontests/backends/models.py
22 22 >>> opts = Square._meta 23 23 >>> f1, f2 = opts.get_field('root'), opts.get_field('square') 24 24 >>> query = ('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)' 25 ... % ( t_convert(opts.db_table), qn(f1.column), qn(f2.column)))25 ... % ((qn(t_convert(opts.db_table)), qn(f1.column), qn(f2.column)))) 26 26 >>> cursor.executemany(query, [(i, i**2) for i in range(-5, 6)]) and None or None 27 27 >>> Square.objects.order_by('root') 28 28 [<Square: -5 ** 2 == 25>, <Square: -4 ** 2 == 16>, <Square: -3 ** 2 == 9>, <Square: -2 ** 2 == 4>, <Square: -1 ** 2 == 1>, <Square: 0 ** 2 == 0>, <Square: 1 ** 2 == 1>, <Square: 2 ** 2 == 4>, <Square: 3 ** 2 == 9>, <Square: 4 ** 2 == 16>, <Square: 5 ** 2 == 25>]