Ticket #1261: firebird-6660.diff
File firebird-6660.diff, 74.9 KB (added by , 17 years ago) |
---|
-
django/db/models/base.py
241 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)] 242 242 # If the PK has been manually set, respect that. 243 243 if pk_set: 244 field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)] 244 if connection.features.quote_autofields: 245 field_names += [qn(f.column) for f in self._meta.fields if isinstance(f, AutoField)] 246 else: 247 field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)] 245 248 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 249 placeholders = ['%s'] * len(field_names) 247 250 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 87 self.name = name 88 88 self.verbose_name = verbose_name 89 89 self.primary_key = primary_key 90 90 self.max_length, self.unique = max_length, unique 91 self.encoding = encoding 91 92 self.blank, self.null = blank, null 92 93 # Oracle treats the empty string ('') as null, so coerce the null 93 94 # option whenever '' is a possible value. … … 148 149 data_types = get_creation_module().DATA_TYPES 149 150 internal_type = self.get_internal_type() 150 151 if internal_type not in data_types: 151 return None 152 return None 152 153 return data_types[internal_type] % self.__dict__ 153 154 154 155 def validate_full(self, field_data, all_data): … … 402 403 "Returns the value of this field in the given model instance." 403 404 return getattr(obj, self.attname) 404 405 406 # Use the backend's Field class if it defines one. Otherwise, use _Field. 407 if connection.features.uses_custom_field: 408 Field = connection.ops.field_class(_Field) 409 else: 410 Field = _Field 411 405 412 class AutoField(Field): 406 413 empty_strings_allowed = False 407 414 def __init__(self, *args, **kwargs): … … 688 695 defaults.update(kwargs) 689 696 return super(DecimalField, self).formfield(**defaults) 690 697 698 class DefaultCharField(CharField): 699 def __init__(self, *args, **kwargs): 700 DEFAULT_MAX_LENGTH = 100 701 if hasattr(settings, 'DEFAULT_MAX_LENGTH'): 702 DEFAULT_MAX_LENGTH = settings.DEFAULT_MAX_LENGT 703 kwargs['max_length'] = kwargs.get('max_length', DEFAULT_MAX_LENGTH) 704 CharField.__init__(self, *args, **kwargs) 705 691 706 class EmailField(CharField): 692 707 def __init__(self, *args, **kwargs): 693 708 kwargs['max_length'] = kwargs.get('max_length', 75) … … 890 905 defaults.update(kwargs) 891 906 return super(IPAddressField, self).formfield(**defaults) 892 907 908 class LargeTextField(Field): 909 def get_manipulator_field_objs(self): 910 return [oldforms.LargeTextField] 911 912 def formfield(self, **kwargs): 913 defaults = {'widget': forms.Textarea} 914 defaults.update(kwargs) 915 return super(LargeTextField, self).formfield(**defaults) 916 893 917 class NullBooleanField(Field): 894 918 empty_strings_allowed = False 895 919 def __init__(self, *args, **kwargs): … … 997 1021 # doesn't support microseconds. 998 1022 if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): 999 1023 value = value.replace(microsecond=0) 1000 if settings.DATABASE_ENGINE == 'oracle':1001 # cx_Oracle expectsa datetime.datetime to persist into TIMESTAMP field.1024 if settings.DATABASE_ENGINE in ('oracle', 'firebird'): 1025 # cx_Oracle and kinterbasdb expect a datetime.datetime to persist into TIMESTAMP field. 1002 1026 if isinstance(value, datetime.time): 1003 1027 value = datetime.datetime(1900, 1, 1, value.hour, value.minute, 1004 1028 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/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): … … 65 67 This SQL is executed when a table is created. 66 68 """ 67 69 return None 68 70 71 def cascade_delete_update_sql(self): 72 """ 73 Returns the SQL necessary to make a cascading deletes and updates 74 of foreign key references during a CREATE TABLE statement. 75 """ 76 return '' 77 69 78 def date_extract_sql(self, lookup_type, field_name): 70 79 """ 71 80 Given a lookup_type of 'year', 'month' or 'day', returns the SQL that … … 127 136 contain a '%s' placeholder for the value being searched against. 128 137 """ 129 138 raise NotImplementedError('Full-text search is not implemented for this database backend') 130 139 131 140 def last_executed_query(self, cursor, sql, params): 132 141 """ 133 142 Returns a string of the query last executed by the given cursor, with … … 175 184 is no limit. 176 185 """ 177 186 return None 178 187 179 188 def pk_default_value(self): 180 189 """ 181 190 Returns the value to use during an INSERT statement to specify that -
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 supports_constraints = True #turn this off to pass the tests with forward/post references 34 uses_custom_field = True 35 uses_custom_queryset = True 36 37 class DatabaseOperations(BaseDatabaseOperations): 38 _max_name_length = 31 39 def __init__(self): 40 self._firebird_version = None 41 self._page_size = None 42 43 def get_generator_name(self, name): 44 return '%s_G' % util.truncate_name(name.strip('"'), self._max_name_length-2).upper() 45 46 def get_trigger_name(self, name): 47 return '%s_T' % util.truncate_name(name.strip('"'), self._max_name_length-2).upper() 48 49 def _get_firebird_version(self): 50 if self._firebird_version is None: 51 from django.db import connection 52 self._firebird_version = [int(val) for val in connection.server_version.split()[-1].split('.')] 53 return self._firebird_version 54 firebird_version = property(_get_firebird_version) 55 56 def _get_page_size(self): 57 if self._page_size is None: 58 from django.db import connection 59 self._page_size = connection.database_info(Database.isc_info_page_size, 'i') 60 return self._page_size 61 page_size = property(_get_page_size) 62 63 def _get_index_limit(self): 64 if self.firebird_version[0] < 2: 65 self._index_limit = 252 66 else: 67 page_size = self._get_page_size() 68 self._index_limit = page_size/4 69 return self._index_limit 70 index_limit = property(_get_index_limit) 71 72 def autoinc_sql(self, style, table_name, column_name): 73 """ 74 To simulate auto-incrementing primary keys in Firebird, we have to 75 create a generator and a trigger. 76 77 Create the generators and triggers names based only on table name 78 since django only support one auto field per model 79 """ 80 81 generator_name = self.get_generator_name(table_name) 82 trigger_name = self.get_trigger_name(table_name) 83 column_name = self.quote_name(column_name) 84 table_name = self.quote_name(table_name) 85 86 generator_sql = "%s %s;" % ( style.SQL_KEYWORD('CREATE GENERATOR'), 87 style.SQL_TABLE(generator_name)) 88 trigger_sql = "\n".join([ 89 "%s %s %s %s" % ( \ 90 style.SQL_KEYWORD('CREATE TRIGGER'), style.SQL_TABLE(trigger_name), style.SQL_KEYWORD('FOR'), 91 style.SQL_TABLE(table_name)), 92 "%s 0 %s" % (style.SQL_KEYWORD('ACTIVE BEFORE INSERT POSITION'), style.SQL_KEYWORD('AS')), 93 style.SQL_KEYWORD('BEGIN'), 94 " %s ((%s.%s %s) %s (%s.%s = 0)) %s" % ( \ 95 style.SQL_KEYWORD('IF'), 96 style.SQL_KEYWORD('NEW'), style.SQL_FIELD(column_name), style.SQL_KEYWORD('IS NULL'), 97 style.SQL_KEYWORD('OR'), style.SQL_KEYWORD('NEW'), style.SQL_FIELD(column_name), 98 style.SQL_KEYWORD('THEN') 99 ), 100 " %s" % style.SQL_KEYWORD('BEGIN'), 101 " %s.%s = %s(%s, 1);" % ( \ 102 style.SQL_KEYWORD('NEW'), style.SQL_FIELD(column_name), 103 style.SQL_KEYWORD('GEN_ID'), style.SQL_TABLE(generator_name) 104 ), 105 " %s" % style.SQL_KEYWORD('END'), 106 style.SQL_KEYWORD('END') 107 ]) 108 return (generator_sql, trigger_sql) 109 110 def max_name_length(self): 111 return self._max_name_length 112 113 def field_class(this, DefaultField): 114 from django.db import connection 115 from django.db.models.fields import prep_for_like_query 116 class FirebirdField(DefaultField): 117 def get_db_prep_lookup(self, lookup_type, value): 118 "Returns field's value prepared for database lookup." 119 if lookup_type in ('exact', 'regex', 'iregex', 'gt', 'gte', 'lt', 120 'lte', 'month', 'day', 'search', 'icontains', 121 'startswith', 'istartswith'): 122 return [value] 123 elif lookup_type in ('range', 'in'): 124 return value 125 elif lookup_type in ('contains',): 126 return ["%%%s%%" % prep_for_like_query(value)] 127 elif lookup_type == 'iexact': 128 return [prep_for_like_query(value)] 129 elif lookup_type in ('endswith', 'iendswith'): 130 return ["%%%s" % prep_for_like_query(value)] 131 elif lookup_type == 'isnull': 132 return [] 133 elif lookup_type == 'year': 134 try: 135 value = int(value) 136 except ValueError: 137 raise ValueError("The __year lookup type requires an integer argument") 138 return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.999999' % value] 139 raise TypeError("Field has invalid lookup: %s" % lookup_type) 140 return FirebirdField 141 142 def query_set_class(this, DefaultQuerySet): 143 from django.db import connection 144 from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE 145 class FirebirdQuerySet(DefaultQuerySet): 146 def _get_sql_clause(self): 147 from django.db.models.query import SortedDict, handle_legacy_orderlist, orderfield2column, fill_table_cache 148 qn = this.quote_name 149 opts = self.model._meta 150 151 # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. 152 select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields] 153 tables = [qn(t) for t in self._tables] 154 joins = SortedDict() 155 where = self._where[:] 156 params = self._params[:] 157 158 # Convert self._filters into SQL. 159 joins2, where2, params2 = self._filters.get_sql(opts) 160 joins.update(joins2) 161 where.extend(where2) 162 params.extend(params2) 163 164 # Add additional tables and WHERE clauses based on select_related. 165 if self._select_related: 166 fill_table_cache(opts, select, tables, where, 167 old_prefix=opts.db_table, 168 cache_tables_seen=[opts.db_table], 169 max_depth=self._max_related_depth) 170 171 # Add any additional SELECTs. 172 if self._select: 173 select.extend([('(%s AS %s') % (qn(s[1]), qn(s[0])) for s in self._select.items()]) 174 175 # Start composing the body of the SQL statement. 176 sql = [" FROM", qn(opts.db_table)] 177 178 # Compose the join dictionary into SQL describing the joins. 179 if joins: 180 sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition) 181 for (alias, (table, join_type, condition)) in joins.items()])) 182 183 # Compose the tables clause into SQL. 184 if tables: 185 sql.append(", " + ", ".join(tables)) 186 187 # Compose the where clause into SQL. 188 if where: 189 sql.append(where and "WHERE " + " AND ".join(where)) 190 191 # ORDER BY clause 192 order_by = [] 193 if self._order_by is not None: 194 ordering_to_use = self._order_by 195 else: 196 ordering_to_use = opts.ordering 197 for f in handle_legacy_orderlist(ordering_to_use): 198 if f == '?': # Special case. 199 order_by.append(connection.ops.random_function_sql()) 200 else: 201 if f.startswith('-'): 202 col_name = f[1:] 203 order = "DESC" 204 else: 205 col_name = f 206 order = "ASC" 207 if "." in col_name: 208 table_prefix, col_name = col_name.split('.', 1) 209 table_prefix = qn(table_prefix) + '.' 210 else: 211 # Use the database table as a column prefix if it wasn't given, 212 # and if the requested column isn't a custom SELECT. 213 if "." not in col_name and col_name not in (self._select or ()): 214 table_prefix = qn(opts.db_table) + '.' 215 else: 216 table_prefix = '' 217 order_by.append('%s%s %s' % \ 218 (table_prefix, qn(orderfield2column(col_name, opts)), order)) 219 if order_by: 220 sql.append("ORDER BY " + ", ".join(order_by)) 221 222 return select, " ".join(sql), params 223 224 def iterator(self): 225 "Performs the SELECT database lookup of this QuerySet." 226 from django.db.models.query import get_cached_row 227 try: 228 select, sql, params = self._get_sql_clause() 229 except EmptyResultSet: 230 raise StopIteration 231 232 # self._select is a dictionary, and dictionaries' key order is 233 # undefined, so we convert it to a list of tuples. 234 extra_select = self._select.items() 235 236 cursor = connection.cursor() 237 limit_offset_before = "" 238 if self._limit is not None: 239 limit_offset_before += "FIRST %s " % self._limit 240 if self._offset: 241 limit_offset_before += "SKIP %s " % self._offset 242 else: 243 assert self._offset is None, "'offset' is not allowed without 'limit'" 244 cursor.execute("SELECT " + limit_offset_before + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 245 fill_cache = self._select_related 246 fields = self.model._meta.fields 247 index_end = len(fields) 248 while 1: 249 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 250 if not rows: 251 raise StopIteration 252 for row in rows: 253 row = self.resolve_columns(row, fields) 254 if fill_cache: 255 obj, index_end = get_cached_row(klass=self.model, row=row, 256 index_start=0, max_depth=self._max_related_depth) 257 else: 258 obj = self.model(*row[:index_end]) 259 for i, k in enumerate(extra_select): 260 setattr(obj, k[0], row[index_end+i]) 261 yield obj 262 263 def resolve_columns(self, row, fields=()): 264 from django.db.models.fields import DateField, DateTimeField, \ 265 TimeField, BooleanField, NullBooleanField, DecimalField, Field 266 values = [] 267 for value, field in map(None, row, fields): 268 #if value is None and isinstance(field, Field) and field.empty_strings_allowed: 269 # value = u'' 270 # Convert 1 or 0 to True or False 271 if value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)): 272 value = bool(value) 273 274 values.append(value) 275 return values 276 277 def extra(self, select=None, where=None, params=None, tables=None): 278 assert self._limit is None and self._offset is None, \ 279 "Cannot change a query once a slice has been taken" 280 clone = self._clone() 281 qn = this.quote_name 282 if select: clone._select.update(select) 283 if where: 284 qn_where = [] 285 for where_item in where: 286 try: 287 table, col_exact = where_item.split(".") 288 col, value = col_exact.split("=") 289 where_item = "%s.%s = %s" % (qn(table.strip()), 290 qn(col.strip()), value.strip()) 291 except: 292 try: 293 table, value = where_item.split("=") 294 where_item = "%s = %s" % (qn(table.strip()), qn(value.strip())) 295 except: 296 raise TypeError, "Can't understand extra WHERE clause: %s" % where 297 qn_where.append(where_item) 298 clone._where.extend(qn_where) 299 if params: clone._params.extend(params) 300 if tables: clone._tables.extend(tables) 301 return clone 302 303 return FirebirdQuerySet 304 305 def quote_name(self, name): 306 name = '"%s"' % util.truncate_name(name.strip('"'), self._max_name_length) 307 return name 308 309 def quote_id_plus_number(self, name): 310 try: 311 return '"%s" + %s' % tuple(s.strip() for s in name.strip('"').split('+')) 312 except: 313 return self.quote_name(name) 314 315 def pk_default_value(self): 316 """ 317 Returns the value to use during an INSERT statement to specify that 318 the field should use its default value. 319 """ 320 return 'NULL' 321 322 def field_cast_sql(self, db_type): 323 return '%s' 324 325 def last_insert_id(self, cursor, table_name, pk_name=None): 326 generator_name = self.get_generator_name(table_name) 327 cursor.execute('SELECT GEN_ID(%s, 0) from RDB$DATABASE' % generator_name) 328 return cursor.fetchone()[0] 329 330 def date_extract_sql(self, lookup_type, column_name): 331 # lookup_type is 'year', 'month', 'day' 332 return "EXTRACT(%s FROM %s)" % (lookup_type, column_name) 333 334 def date_trunc_sql(self, lookup_type, column_name): 335 if lookup_type == 'year': 336 sql = "EXTRACT(year FROM %s)||'-01-01 00:00:00'" % column_name 337 elif lookup_type == 'month': 338 sql = "EXTRACT(year FROM %s)||'-'||EXTRACT(month FROM %s)||'-01 00:00:00'" % (column_name, column_name) 339 elif lookup_type == 'day': 340 sql = "EXTRACT(year FROM %s)||'-'||EXTRACT(month FROM %s)||'-'||EXTRACT(day FROM %s)||' 00:00:00'" % (column_name, column_name, column_name) 341 return "CAST(%s AS TIMESTAMP)" % sql 342 343 def cascade_delete_update_sql(self): 344 #TODO: Use ON DELETE CASCADE only on M2M tables by default 345 return " ON DELETE CASCADE ON UPDATE CASCADE" 346 347 def datetime_cast_sql(self): 348 return None 349 350 def limit_offset_sql(self, limit, offset=None): 351 # limits are handled in custom FirebirdQuerySet 352 assert False, 'Limits are handled in a different way in Firebird' 353 return "" 354 355 def random_function_sql(self): 356 return "rand()" 357 358 def start_transaction_sql(self): 359 return "" 360 361 def sequence_reset_sql(self, style, model_list): 362 from django.db import models 363 output = [] 364 sql = ['%s %s %s' % (style.SQL_KEYWORD('CREATE OR ALTER PROCEDURE'), 365 style.SQL_TABLE('"GENERATOR_RESET"'), 366 style.SQL_KEYWORD('AS'))] 367 sql.append('%s %s' % (style.SQL_KEYWORD('DECLARE VARIABLE'), style.SQL_COLTYPE('start_val integer;'))) 368 sql.append('%s %s' % (style.SQL_KEYWORD('DECLARE VARIABLE'), style.SQL_COLTYPE('gen_val integer;'))) 369 sql.append('\t%s' % style.SQL_KEYWORD('BEGIN')) 370 sql.append('\t\t%s %s %s %s %s %s;' % (style.SQL_KEYWORD('SELECT MAX'), style.SQL_FIELD('(%(col)s)'), 371 style.SQL_KEYWORD('FROM'), style.SQL_TABLE('%(table)s'), 372 style.SQL_KEYWORD('INTO'), style.SQL_COLTYPE(':start_val'))) 373 sql.append('\t\t%s (%s %s) %s' % (style.SQL_KEYWORD('IF'), style.SQL_COLTYPE('start_val'), 374 style.SQL_KEYWORD('IS NULL'), style.SQL_KEYWORD('THEN'))) 375 sql.append('\t\t\t%s = %s(%s, 1 - %s(%s, 0));' %\ 376 (style.SQL_COLTYPE('gen_val'), style.SQL_KEYWORD('GEN_ID'), style.SQL_TABLE('%(gen)s'), 377 style.SQL_KEYWORD('GEN_ID'), style.SQL_TABLE('%(gen)s'))) 378 sql.append('\t\t%s' % style.SQL_KEYWORD('ELSE')) 379 sql.append('\t\t\t%s = %s(%s, %s - %s(%s, 0));' %\ 380 (style.SQL_COLTYPE('gen_val'), style.SQL_KEYWORD('GEN_ID'), 381 style.SQL_TABLE('%(gen)s'), style.SQL_COLTYPE('start_val'), style.SQL_KEYWORD('GEN_ID'), 382 style.SQL_TABLE('%(gen)s'))) 383 sql.append('\t\t%s;' % style.SQL_KEYWORD('EXIT')) 384 sql.append('%s;' % style.SQL_KEYWORD('END')) 385 sql ="\n".join(sql) 386 for model in model_list: 387 for f in model._meta.fields: 388 if isinstance(f, models.AutoField): 389 generator_name = self.get_generator_name(model._meta.db_table) 390 column_name = self.quote_name(f.db_column or f.name) 391 table_name = self.quote_name(model._meta.db_table) 392 output.append(sql % {'col' : column_name, 'table' : table_name, 'gen' : generator_name}) 393 output.append('%s %s;' % (style.SQL_KEYWORD('EXECUTE PROCEDURE'), 394 style.SQL_TABLE('"GENERATOR_RESET"'))) 395 break # Only one AutoField is allowed per model, so don't bother continuing. 396 for f in model._meta.many_to_many: 397 generator_name = self.get_generator_name(f.m2m_db_table()) 398 table_name = self.quote_name(f.m2m_db_table()) 399 column_name = '"id"' 400 output.append(sql % {'col' : column_name, 'table' : table_name, 'gen' : generator_name}) 401 output.append('%s %s;' % (style.SQL_KEYWORD('EXECUTE PROCEDURE'), 402 style.SQL_TABLE('"GENERATOR_RESET"'))) 403 return output 404 405 def sql_flush(self, style, tables, sequences): 406 if tables: 407 #TODO: Alter all tables witk FKs without ON DELETE CASCADE to set it 408 # Them reset to previous state when all are deleted 409 # Becasue we may not want to have ON DELETE CASCADE by default on all FK fields 410 sql = ['%s %s %s;' % \ 411 (style.SQL_KEYWORD('DELETE'), 412 style.SQL_KEYWORD('FROM'), 413 style.SQL_FIELD(self.quote_name(table)) 414 ) for table in tables] 415 for generator_info in sequences: 416 table_name = generator_info['table'] 417 query = "%s %s %s 0;" % (style.SQL_KEYWORD('SET GENERATOR'), 418 style.SQL_TABLE(self.get_generator_name(table_name)), style.SQL_KEYWORD('TO')) 419 sql.append(query) 420 return sql 421 else: 422 return [] 423 424 def fulltext_search_sql(self, field_name): 425 # We use varchar for TextFields so this is possible 426 # Look at http://www.volny.cz/iprenosil/interbase/ip_ib_strings.htm 427 return '%%s CONTAINING %s' % self.quote_name(field_name) 428 429 def drop_sequence_sql(self, table): 430 return "DROP GENERATOR %s;" % self.get_generator_name(table) 431 432 class FirebirdCursorWrapper(object): 433 """ 434 Django uses "format" ('%s') style placeholders, but firebird uses "qmark" ('?') style. 435 This fixes it -- but note that if you want to use a literal "%s" in a query, 436 you'll need to use "%%s". 437 438 We also do all automatic type conversions here. 439 """ 440 import kinterbasdb.typeconv_datetime_stdlib as tc_dt 441 import kinterbasdb.typeconv_fixed_decimal as tc_fd 442 import kinterbasdb.typeconv_text_unicode as tc_tu 443 import django.utils.encoding as dj_ue 444 445 446 def timestamp_conv_in(self, timestamp): 447 if isinstance(timestamp, basestring): 448 #Replaces 6 digits microseconds to 4 digits allowed in Firebird 449 timestamp = timestamp[:24] 450 return self.tc_dt.timestamp_conv_in(timestamp) 451 452 def time_conv_in(self, value): 453 import datetime 454 if isinstance(value, datetime.datetime): 455 value = datetime.time(value.hour, value.minute, value.second, value.microsecond) 456 return self.tc_dt.time_conv_in(value) 457 458 def ascii_conv_in(self, text): 459 if text is not None: 460 return self.dj_ue.smart_str(text, 'ascii') 461 462 def ascii_conv_out(self, text): 463 if text is not None: 464 return self.dj_ue.smart_unicode(text) 465 466 def fixed_conv_in(self, (val, scale)): 467 if val is not None: 468 if isinstance(val, basestring): 469 val = decimal.Decimal(val) 470 return self.tc_fd.fixed_conv_in_precise((val, scale)) 471 472 def unicode_conv_in(self, text): 473 if text[0] is not None: 474 return self.tc_tu.unicode_conv_in((self.dj_ue.smart_unicode(text[0]), self.FB_CHARSET_CODE)) 475 476 def blob_conv_in(self, text): 477 return self.tc_tu.unicode_conv_in((self.dj_ue.smart_unicode(text), self.FB_CHARSET_CODE)) 478 479 def blob_conv_out(self, text): 480 return self.tc_tu.unicode_conv_out((text, self.FB_CHARSET_CODE)) 481 482 def __init__(self, cursor, connection): 483 self.cursor = cursor 484 self._connection = connection 485 self._statement = None #prepared statement 486 self.FB_CHARSET_CODE = 3 #UNICODE_FSS 487 if connection.charset == 'UTF8': 488 self.FB_CHARSET_CODE = 4 # UTF-8 with Firebird 2.0+ 489 DEFAULT_MAX_LENGTH = connection.DEFAULT_MAX_LENGTH 490 self.cursor.set_type_trans_in({ 491 'DATE': self.tc_dt.date_conv_in, 492 'TIME': self.time_conv_in, 493 'TIMESTAMP': self.timestamp_conv_in, 494 'FIXED': self.fixed_conv_in, 495 'TEXT': self.ascii_conv_in, 496 'TEXT_UNICODE': self.unicode_conv_in, 497 'BLOB': self.blob_conv_in 498 }) 499 self.cursor.set_type_trans_out({ 500 'DATE': self.tc_dt.date_conv_out, 501 'TIME': self.tc_dt.time_conv_out, 502 'TIMESTAMP': self.tc_dt.timestamp_conv_out, 503 'FIXED': self.tc_fd.fixed_conv_out_precise, 504 'TEXT': self.ascii_conv_out, 505 'TEXT_UNICODE': self.tc_tu.unicode_conv_out, 506 'BLOB': self.blob_conv_out 507 }) 508 # Create DOMAINS 509 domains = [ ('AutoField', 'integer'), 510 ('BooleanField', 'smallint CHECK (VALUE IN (0,1))'), 511 ('DateField', 'date'), 512 ('CharField', 'varchar(%i)' % DEFAULT_MAX_LENGTH), 513 ('DateTimeField', 'timestamp'), 514 ('FloatField', 'double precision'), 515 ('IntegerField', 'integer'), 516 ('IPAddressField', 'varchar(15) CHARACTER SET ASCII'), 517 ('NullBooleanField', 'smallint CHECK ((VALUE IN (0,1)) OR (VALUE IS NULL))'), 518 ('OneToOneField', 'integer'), 519 ('PhoneNumberField', 'varchar(20) CHARACTER SET ASCII'), 520 ('PositiveIntegerField', 'integer CHECK ((VALUE >= 0) OR (VALUE IS NULL))'), 521 ('PositiveSmallIntegerField', 'smallint CHECK ((VALUE >= 0) OR (VALUE IS NULL))'), 522 ('SmallIntegerField', 'smallint'), 523 ('TextField', 'varchar(%s)' % connection.FB_MAX_VARCHAR), 524 ('LargeTextField', 'blob sub_type text'), 525 ('TimeField', 'time'), 526 ('USStateField', 'varchar(2) CHARACTER SET ASCII') ] 527 # Create domains only if they do not exist already 528 cursor.execute("SELECT RDB$FIELD_NAME FROM RDB$FIELDS") 529 existing_domains = set([row[0].strip() for row in cursor.fetchall() if not row[0].startswith('RDB$')]) 530 domains = map(lambda domain: '%s "%s" AS %s;' % ('CREATE DOMAIN', domain[0], domain[1]), 531 filter(lambda x: x[0] not in existing_domains, domains)) 532 for domain in domains: 533 connection.execute_immediate(domain) 534 # But alter CharField to sync with any changes in settings for use with DefaultCharField object 535 connection.execute_immediate('ALTER DOMAIN "CharField" TYPE varchar(%i)' % DEFAULT_MAX_LENGTH) 536 537 # Declare FUNCTIONS 538 cursor.execute("SELECT RDB$FUNCTION_NAME FROM RDB$FUNCTIONS") 539 existing_functions = set([row[0].strip().upper() for row in cursor.fetchall()]) 540 if 'RAND' not in existing_functions: 541 connection.execute_immediate(""" 542 DECLARE EXTERNAL FUNCTION RAND 543 RETURNS DOUBLE PRECISION 544 BY VALUE ENTRY_POINT 'IB_UDF_rand' MODULE_NAME 'ib_udf'; 545 """) 546 547 def _get_query(self): 548 if self._statement: 549 return self._statement.sql 550 def _get_statement(self): 551 if self._statement: 552 return self._statement 553 query = property(_get_query) 554 statement = property(_get_statement) 555 556 def execute_immediate(self, query, params=()): 557 query = query % tuple(params) 558 self._connection.execute_immediate(query) 559 560 # Prepared Statement 561 # http://kinterbasdb.sourceforge.net/dist_docs/usage.html#adv_prepared_statements 562 def prepare(self, query): 563 query.replace("%s", "?") 564 return self.cursor.prep(query) 565 566 def execute_prepared(self, statement, params): 567 return self.cursor.execute(statement, params) 568 569 def execute_straight(self, query, params=()): 570 # Use kinterbasdb style with '?' instead of '%s' 571 return self.cursor.execute(query, params) 572 573 def execute(self, query, params=()): 574 cquery = self.convert_query(query, len(params)) 575 if self._get_query() != cquery: 576 try: 577 self._statement = self.cursor.prep(cquery) 578 except Database.ProgrammingError, e: 579 output = ["Prepare query error."] 580 output.extend(str(e).split("'")[1].split('\\n')) 581 output.append("Query:") 582 output.append(cquery) 583 raise Database.ProgrammingError, "\n".join(output) 584 try: 585 return self.cursor.execute(self._statement, params) 586 except Database.ProgrammingError, e: 587 err_no = int(str(e).split()[0].strip(',()')) 588 output = ["Execute query error. FB error No. %i" % err_no] 589 output.extend(str(e).split("'")[1].split('\\n')) 590 output.append("Query:") 591 output.append(cquery) 592 output.append("Parameters:") 593 output.append(str(params)) 594 raise Database.ProgrammingError, "\n".join(output) 595 596 def executemany(self, query, param_list): 597 try: 598 cquery = self.convert_query(query, len(param_list[0])) 599 except IndexError: 600 return None 601 if self._get_query() != cquery: 602 self._statement = self.cursor.prep(cquery) 603 return self.cursor.executemany(self._statement, param_list) 604 605 def convert_query(self, query, num_params): 606 try: 607 return query % tuple("?" * num_params) 608 except TypeError, e: 609 print query, num_params 610 raise TypeError, e 611 612 def __getattr__(self, attr): 613 if attr in self.__dict__: 614 return self.__dict__[attr] 615 else: 616 return getattr(self.cursor, attr) 617 618 class DatabaseWrapper(BaseDatabaseWrapper): 619 features = DatabaseFeatures() 620 ops = DatabaseOperations() 621 operators = { 622 'exact': '= %s', 623 'iexact': '= UPPER(%s)', 624 'contains': "LIKE %s ESCAPE'\\'", 625 'icontains': 'CONTAINING %s', #case is ignored 626 'gt': '> %s', 627 'gte': '>= %s', 628 'lt': '< %s', 629 'lte': '<= %s', 630 'startswith': 'STARTING WITH %s', #looks to be faster then LIKE 631 'endswith': "LIKE %s ESCAPE'\\'", 632 'istartswith': 'STARTING WITH UPPER(%s)', 633 'iendswith': "LIKE UPPER(%s) ESCAPE'\\'" 634 } 635 636 def __init__(self, **kwargs): 637 from django.conf import settings 638 super(DatabaseWrapper, self).__init__(**kwargs) 639 self. _current_cursor = None 640 self._raw_cursor = None 641 self.charset = 'UNICODE_FSS' 642 self.FB_MAX_VARCHAR = 10921 #32765 MAX /3 643 self.BYTES_PER_DEFAULT_CHAR = 3 644 if hasattr(settings, 'FIREBIRD_CHARSET'): 645 if settings.FIREBIRD_CHARSET == 'UTF8': 646 self.charset = 'UTF8' 647 self.FB_MAX_VARCHAR = 8191 #32765 MAX /4 648 self.BYTES_PER_DEFAULT_CHAR = 4 649 self.DEFAULT_MAX_LENGTH = 100 650 if hasattr(settings, 'DEFAULT_MAX_LENGTH'): 651 # You can set DEFAULT_MAX_LENGTH in settings.py and all 652 # DefaultCharField objects will have this value automaticaly 653 # with a little help from Firebird's domains 654 self.DEFAULT_MAX_LENGTH = settings.DEFAULT_MAX_LENGTH 655 656 657 def _connect(self, settings): 658 if settings.DATABASE_NAME == '': 659 from django.core.exceptions import ImproperlyConfigured 660 raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file." 661 kwargs = {'charset' : self.charset } 662 if settings.DATABASE_HOST: 663 kwargs['dsn'] = "%s:%s" % (settings.DATABASE_HOST, settings.DATABASE_NAME) 664 else: 665 kwargs['dsn'] = "localhost:%s" % settings.DATABASE_NAME 666 if settings.DATABASE_USER: 667 kwargs['user'] = settings.DATABASE_USER 668 if settings.DATABASE_PASSWORD: 669 kwargs['password'] = settings.DATABASE_PASSWORD 670 self.connection = Database.connect(**kwargs) 671 assert self.connection.charset == self.charset 672 673 def cursor(self): 674 from django.conf import settings 675 cursor = self._cursor(settings) 676 if settings.DEBUG: 677 self._debug_cursor = self.make_debug_cursor(cursor) 678 return self._debug_cursor 679 return cursor 680 681 def _cursor(self, settings): 682 if self.connection is None: 683 self._connect(settings) 684 cursor = self.connection.cursor() 685 self._raw_cursor = cursor 686 cursor = FirebirdCursorWrapper(cursor, self) 687 self._current_cursor = cursor 688 return cursor 689 690 def __getattr__(self, attr): 691 if attr in self.__dict__: 692 return self.__dict__[attr] 693 else: 694 return getattr(self.connection, attr) 695 -
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 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().lower()) 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(""" 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 34 def 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 56 def 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 82 DATA_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
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 import sys, os.path, codecs 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 12 13 14 DATA_TYPES = { 15 'AutoField': '"AutoField"', 16 'BooleanField': '"BooleanField"', 17 'CharField': 'varchar(%(max_length)s)', 18 'CommaSeparatedIntegerField': 'varchar(%(max_length)s) CHARACTER SET ASCII', 19 'DateField': '"DateField"', 20 'DateTimeField': '"DateTimeField"', 21 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 22 'DefaultCharField': '"CharField"', 23 'FileField': 'varchar(%(max_length)s)', 24 'FilePathField': 'varchar(%(max_length)s)', 25 'FloatField': '"FloatField"', 26 'ImageField': '"varchar(%(max_length)s)"', 27 'IntegerField': '"IntegerField"', 28 'IPAddressField': 'varchar(15) CHARACTER SET ASCII', 29 'NullBooleanField': '"NullBooleanField"', 30 'OneToOneField': '"OneToOneField"', 31 'PhoneNumberField': '"PhoneNumberField"', 32 'PositiveIntegerField': '"PositiveIntegerField"', 33 'PositiveSmallIntegerField': '"PositiveSmallIntegerField"', 34 'SlugField': 'varchar(%(max_length)s)', 35 'SmallIntegerField': '"SmallIntegerField"', 36 'LargeTextField': '"LargeTextField"', 37 'TextField': '"TextField"', 38 'TimeField': '"TimeField"', 39 'URLField': 'varchar(%(max_length)s) CHARACTER SET ASCII', 40 'USStateField': '"USStateField"' 41 } 42 43 PYTHON_TO_FB_ENCODING_MAP = { 44 'ascii': 'ASCII', 45 'utf_8': connection.charset, 46 'shift_jis': 'SJIS_0208', 47 'euc_jp': 'EUCJ_0208', 48 'cp737': 'DOS737', 49 'cp437': 'DOS437', 50 'cp850': 'DOS850', 51 'cp865': 'DOS865', 52 'cp860': 'DOS860', 53 'cp863': 'DOS863', 54 'cp775': 'DOS775', 55 'cp862': 'DOS862', 56 'cp864': 'DOS864', 57 'iso8859_1': 'ISO8859_1', 58 'iso8859_2': 'ISO8859_2', 59 'iso8859_3': 'ISO8859_3', 60 'iso8859_4': 'ISO8859_4', 61 'iso8859_5': 'ISO8859_5', 62 'iso8859_6': 'ISO8859_6', 63 'iso8859_7': 'ISO8859_7', 64 'iso8859_8': 'ISO8859_8', 65 'iso8859_9': 'ISO8859_9', 66 'iso8859_13': 'ISO8859_13', 67 'euc_kr': 'KSC_5601', 68 'cp852': 'DOS852', 69 'cp857': 'DOS857', 70 'cp861': 'DOS861', 71 'cp866': 'DOS866', 72 'cp869': 'DOS869', 73 'cp1250': 'WIN1250', 74 'cp1251': 'WIN1251', 75 'cp1252': 'WIN1252', 76 'cp1253': 'WIN1253', 77 'cp1254': 'WIN1254', 78 'big5': 'BIG_5', 79 'gb2312': 'GB_2312', 80 'cp1255': 'WIN1255', 81 'cp1256': 'WIN1256', 82 'cp1257': 'WIN1257', 83 'koi8_r': 'KOI8-R', 84 'koi8_u': 'KOI8-U', 85 'cp1258': 'WIN1258' 86 } 87 88 def get_data_size(data_type, max_length = 100): 89 char_bytes = connection.BYTES_PER_DEFAULT_CHAR 90 size_map = { 91 'AutoField': 8, 92 'BooleanField': 4, 93 'CharField': char_bytes*max_length, 94 'CommaSeparatedIntegerField': max_length, 95 'DateField': 16, 96 'DateTimeField': 16, 97 'DecimalField': 16, 98 'FileField': char_bytes*max_length, 99 'FilePathField': 'varchar(%(max_length)s)', 100 'FloatField': 16, 101 'ImageField': char_bytes*max_length, 102 'IntegerField': 8, 103 'IPAddressField': 15, 104 'NullBooleanField': 4, 105 'OneToOneField': 8, 106 'PhoneNumberField': 20, 107 'PositiveIntegerField': 8, 108 'PositiveSmallIntegerField': 4, 109 'SlugField': char_bytes*max_length, 110 'SmallIntegerField': 4, 111 'TextBlob': 8, 112 'TextField': 32767, 113 'TimeField': 16, 114 'URLField': max_length, 115 'USStateField': char_bytes*2 116 } 117 return size_map[data_type] 118 119 def sql_model_create(model, style, known_models=set()): 120 """ 121 Returns the SQL required to create a single model, as a tuple of: 122 (list_of_sql, pending_references_dict) 123 """ 124 from django.db import connection, models 125 126 opts = model._meta 127 final_output = [] 128 table_output = [] 129 pending_references = {} 130 qn = connection.ops.quote_name 131 inline_references = connection.features.inline_fk_references 132 # Check that row size is less than 64k and adjust TextFields if needed 133 row_size = 0 134 columns = [(f.db_type().strip('"'), f.get_internal_type(), f) for f in opts.fields] 135 columns_simple = [col[0] for col in columns] 136 text_field_type = '"TextField"' 137 max_alowed_bytes = 32765 138 if 'TextField' in columns_simple: 139 max_length = 100 140 num_text_fields = 0 141 for column in columns: 142 num_text_fields += (column[0] == 'TextField') 143 if column[0].startswith('varchar'): 144 max_length = int(column[0].split('(')[1].split(')')[0]) 145 if column[1] in DATA_TYPES: 146 row_size += get_data_size(column[1], max_length) 147 if row_size > 65536: 148 max_alowed_bytes = int( (max_alowed_bytes/num_text_fields) - (row_size-65536) ) 149 n = max_alowed_bytes / connection.BYTES_PER_DEFAULT_CHAR 150 if n > 512: 151 text_field_type = 'varchar(%s)' % n 152 FB_TEXTFIELD_ALTERED = True 153 print 154 print "WARNING: Maximum number of characters in TextFields has changed to %s." % n 155 print " TextField columns with custom charsets will have %s chars available" % max_alowed_bytes 156 print " The change affects %s table only." % opts.db_table 157 print " TextFields in other tables will have %s characters maximum" % connection.FB_MAX_VARCHAR 158 print " or 32765 characters with custom (non-UTF) encoding." 159 print " If you need more space in those fields try LargeTextFields instead." 160 print 161 else: 162 # Swich to blobs if size is too small (<1024) 163 text_field_type = '"LargeTextField"' 164 for f in opts.fields: 165 col_type = f.db_type() 166 167 if col_type.strip('"') == 'TextField': 168 col_type = text_field_type 169 fb_version = "%s.%s" % (connection.ops.firebird_version[0], connection.ops.firebird_version[1]) 170 page_size = connection.ops.page_size 171 #look at: http://www.volny.cz/iprenosil/interbase/ip_ib_indexcalculator.htm 172 if connection.ops.index_limit < 1000: 173 strip2ascii = False 174 custom_charset = False 175 if col_type.startswith('varchar'): 176 if (f.unique or f.primary_key or f.db_index): 177 length = f.max_length 178 if f.encoding: 179 if not f.encoding.upper().startswith('UTF'): 180 custom_charset = True 181 if not custom_charset: 182 try: 183 length = f.max_length * connection.BYTES_PER_DEFAULT_CHAR 184 except TypeError: 185 length = 100*connection.BYTES_PER_DEFAULT_CHAR #Default for CharField 186 if length >= connection.ops.index_limit: 187 strip2ascii = True 188 if len(opts.unique_together) > 0: 189 if f.column in opts.unique_together[0]: 190 num_unique_char_fields = len([ fld for fld in opts.unique_together[0] if opts.get_field(fld).db_type().startswith('varchar') ]) 191 num_unique_fileds = len(opts.unique_together[0]) 192 num_unique_nonchar_fileds = num_unique_fileds - num_unique_char_fields 193 limit = connection.ops.index_limit 194 limit -= ((num_unique_fileds - 1)*64) 195 limit -= 8*num_unique_nonchar_fileds 196 max_length = limit/num_unique_char_fields 197 ascii_length = int(f.max_length) 198 old_length = ascii_length*connection.BYTES_PER_DEFAULT_CHAR 199 200 if (old_length >= max_length) and (ascii_length < max_length): 201 strip2ascii = True 202 elif old_length > max_length: 203 strip2ascii = False #We change it here 204 col_type = "varchar(%i) CHARACTER SET ASCII" % max_length 205 msg = "WARNING: Character set of the '%s' field\n" 206 msg += " (table %s)\n" 207 msg += " has changed to ASCII" 208 msg += " to fit %s-byte limit in FB %s" 209 if not page_size: 210 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version) 211 else: 212 msg += " with page size %s" 213 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version, page_size) 214 print " The maximum length of '%s' is now %s instead of %s"\ 215 % (f.column, max_length, old_length) 216 if strip2ascii: 217 col_type = "%s %s %s" % (col_type, "CHARACTER SET", "ASCII") 218 msg = "WARNING: Character set of the '%s' field\n" 219 msg += " (table %s)\n" 220 msg += " has changed to ASCII" 221 msg += " to fit %s-byte limit in FB %s" 222 if not page_size: 223 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version) 224 else: 225 msg += " with page size %s" 226 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version, page_size) 227 228 if (col_type.startswith('varchar') or col_type.strip('"') == 'TextField') and f.encoding: 229 charset = PYTHON_TO_FB_ENCODING_MAP[codecs.lookup(f.encoding).name] 230 if col_type.strip('"') == 'TextField': 231 col_type = 'varchar(%i)' % max_alowed_bytes 232 col_type = "%s %s %s" % (col_type, "CHARACTER SET", charset) 233 234 235 if col_type is None: 236 # Skip ManyToManyFields, because they're not represented as 237 # database columns in this table. 238 continue 239 # Make the definition (e.g. 'foo VARCHAR(30)') for this field. 240 field_output = [style.SQL_FIELD(qn(f.column)), 241 style.SQL_COLTYPE(col_type)] 242 field_output.append(style.SQL_KEYWORD('%s' % (not f.null and 'NOT NULL' or 'DEFAULT NULL'))) 243 if f.unique: 244 field_output.append(style.SQL_KEYWORD('UNIQUE')) 245 if f.primary_key: 246 field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 247 if f.rel: 248 # We haven't yet created the table to which this field 249 # is related, so save it for later. 250 pr = pending_references.setdefault(f.rel.to, []).append((model, f)) 251 table_output.append(' '.join(field_output)) 252 if opts.order_with_respect_to: 253 table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \ 254 style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \ 255 style.SQL_KEYWORD('NULL')) 256 for field_constraints in opts.unique_together: 257 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ 258 ", ".join([qn(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints])) 259 260 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' ('] 261 for i, line in enumerate(table_output): # Combine and add commas. 262 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 263 full_statement.append(');') 264 final_output.append('\n'.join(full_statement)) 265 266 if opts.has_auto_field: 267 # Add any extra SQL needed to support auto-incrementing primary keys. 268 auto_column = opts.auto_field.db_column or opts.auto_field.name 269 autoinc_sql = connection.ops.autoinc_sql(style, opts.db_table, auto_column) 270 if autoinc_sql: 271 for stmt in autoinc_sql: 272 final_output.append(stmt) 273 274 return final_output, pending_references 275 276 def many_to_many_sql_for_model(model, style): 277 from django.db import connection, models 278 from django.contrib.contenttypes import generic 279 from django.db.backends.util import truncate_name 280 281 opts = model._meta 282 final_output = [] 283 qn = connection.ops.quote_name 284 for f in opts.many_to_many: 285 if not isinstance(f.rel, generic.GenericRel): 286 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ 287 style.SQL_TABLE(qn(f.m2m_db_table())) + ' ('] 288 table_output.append(' %s %s %s,' % 289 (style.SQL_FIELD(qn('id')), 290 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()), 291 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'))) 292 293 table_output.append(' %s %s %s,' % 294 (style.SQL_FIELD(qn(f.m2m_column_name())), 295 style.SQL_COLTYPE(models.ForeignKey(model).db_type()), 296 style.SQL_KEYWORD('NOT NULL'))) 297 table_output.append(' %s %s %s,' % 298 (style.SQL_FIELD(qn(f.m2m_reverse_name())), 299 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()), 300 style.SQL_KEYWORD('NOT NULL'))) 301 deferred = [ 302 (f.m2m_db_table(), f.m2m_column_name(), opts.db_table, 303 opts.pk.column), 304 ( f.m2m_db_table(), f.m2m_reverse_name(), 305 f.rel.to._meta.db_table, f.rel.to._meta.pk.column) 306 ] 307 308 table_output.append(' %s (%s, %s)' % 309 (style.SQL_KEYWORD('UNIQUE'), 310 style.SQL_FIELD(qn(f.m2m_column_name())), 311 style.SQL_FIELD(qn(f.m2m_reverse_name())))) 312 table_output.append(');') 313 final_output.append('\n'.join(table_output)) 314 315 autoinc_sql = connection.ops.autoinc_sql(style, f.m2m_db_table(), 'id') 316 if autoinc_sql: 317 for stmt in autoinc_sql: 318 final_output.append(stmt) 319 320 if connection.features.supports_constraints: 321 for r_table, r_col, table, col in deferred: 322 r_name = '%s_%s_%x' % (r_col, col, 323 abs(hash((r_table, table)))) 324 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 325 (qn(r_table), 326 truncate_name(r_name, connection.ops.max_name_length()), 327 qn(r_col), qn(table), qn(col), 328 'ON DELETE CASCADE ON UPDATE CASCADE')) 329 330 return final_output 331 332 TEST_DATABASE_PREFIX = 'test_' 333 def create_test_db(settings, connection, verbosity, autoclobber): 334 # KInterbasDB supports dynamic database creation and deletion 335 # via the module-level function create_database and the method Connection.drop_database. 336 337 if settings.TEST_DATABASE_NAME: 338 TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME 339 else: 340 dbnametuple = os.path.split(settings.DATABASE_NAME) 341 TEST_DATABASE_NAME = os.path.join(dbnametuple[0], TEST_DATABASE_PREFIX + dbnametuple[1]) 342 343 dsn = "localhost:%s" % TEST_DATABASE_NAME 344 if settings.DATABASE_HOST: 345 dsn = "%s:%s" % (settings.DATABASE_HOST, TEST_DATABASE_NAME) 346 347 if os.path.isfile(TEST_DATABASE_NAME): 348 sys.stderr.write("Database %s already exists\n" % TEST_DATABASE_NAME) 349 if not autoclobber: 350 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME) 351 if autoclobber or confirm == 'yes': 352 if verbosity >= 1: 353 print "Destroying old test database..." 354 old_connection = connect(dsn=dsn, user=settings.DATABASE_USER, password=settings.DATABASE_PASSWORD) 355 old_connection.drop_database() 356 else: 357 print "Tests cancelled." 358 sys.exit(1) 359 360 if verbosity >= 1: 361 print "Creating test database..." 362 try: 363 charset = 'UNICODE_FSS' 364 if hasattr(settings, 'FIREBIRD_CHARSET'): 365 if settings.FIREBIRD_CHARSET == 'UTF8': 366 charset='UTF8' 367 create_database("create database '%s' user '%s' password '%s' default character set %s" % \ 368 (dsn, settings.DATABASE_USER, settings.DATABASE_PASSWORD, charset)) 369 except Exception, e: 370 sys.stderr.write("Got an error creating the test database: %s\n" % e) 371 sys.exit(2) 372 373 connection.close() 374 settings.DATABASE_NAME = TEST_DATABASE_NAME 375 376 call_command('syncdb', verbosity=verbosity, interactive=False) 377 378 if settings.CACHE_BACKEND.startswith('db://'): 379 cache_name = settings.CACHE_BACKEND[len('db://'):] 380 call_command('createcachetable', cache_name) 381 382 # Get a cursor (even though we don't need one yet). This has 383 # the side effect of initializing the test database. 384 cursor = connection.cursor() 385 386 return TEST_DATABASE_NAME 387 388 def destroy_test_db(settings, connection, old_database_name, verbosity): 389 # KInterbasDB supports dynamic database deletion via the method Connection.drop_database. 390 if verbosity >= 1: 391 print "Destroying test database..." 392 connection.drop_database() 393 394 -
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 … … 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 = [] … … 332 336 # For MySQL, r_name must be unique in the first 64 characters. 333 337 # So we are careful with character usage here. 334 338 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table)))) 335 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s ;' % \339 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s%s;' % \ 336 340 (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()), 337 341 qn(r_col), qn(table), qn(col), 342 connection.ops.cascade_delete_update_sql(), 338 343 connection.ops.deferrable_sql())) 339 344 del pending_references[model] 340 345 return final_output 341 346 342 347 def many_to_many_sql_for_model(model, style): 343 from django.db import connection, models 348 from django.db import connection, models, get_creation_module 344 349 from django.contrib.contenttypes import generic 345 350 from django.db.backends.util import truncate_name 346 351 352 creation_module = get_creation_module() 353 # If the database backend wants to create many_to_many sql itself, let it 354 if hasattr(creation_module, "many_to_many_sql_for_model"): 355 return creation_module.many_to_many_sql_for_model(model, style) 356 347 357 opts = model._meta 348 358 final_output = [] 349 359 qn = connection.ops.quote_name -
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()] 38 39 39 40 __test__ = {'API_TESTS':""" 40 41 # Create a couple of Articles. 41 42 >>> from datetime import date -
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>]