Ticket #1261: firebird-6668.diff
File firebird-6668.diff, 74.8 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 self.cursor.set_type_trans_in({ 490 'DATE': self.tc_dt.date_conv_in, 491 'TIME': self.time_conv_in, 492 'TIMESTAMP': self.timestamp_conv_in, 493 'FIXED': self.fixed_conv_in, 494 'TEXT': self.ascii_conv_in, 495 'TEXT_UNICODE': self.unicode_conv_in, 496 'BLOB': self.blob_conv_in 497 }) 498 self.cursor.set_type_trans_out({ 499 'DATE': self.tc_dt.date_conv_out, 500 'TIME': self.tc_dt.time_conv_out, 501 'TIMESTAMP': self.tc_dt.timestamp_conv_out, 502 'FIXED': self.tc_fd.fixed_conv_out_precise, 503 'TEXT': self.ascii_conv_out, 504 'TEXT_UNICODE': self.tc_tu.unicode_conv_out, 505 'BLOB': self.blob_conv_out 506 }) 507 508 def execute_immediate(self, query, params=()): 509 query = query % tuple(params) 510 self._connection.execute_immediate(query) 511 512 # Prepared Statement 513 # http://kinterbasdb.sourceforge.net/dist_docs/usage.html#adv_prepared_statements 514 def prepare(self, query): 515 query.replace("%s", "?") 516 return self.cursor.prep(query) 517 518 def execute_prepared(self, statement, params): 519 return self.cursor.execute(statement, params) 520 521 def execute_straight(self, query, params=()): 522 # Use kinterbasdb style with '?' instead of '%s' 523 return self.cursor.execute(query, params) 524 525 def execute(self, query, params=()): 526 cquery = self.convert_query(query, len(params)) 527 if self._get_query() != cquery: 528 try: 529 self._statement = self.cursor.prep(cquery) 530 except Database.ProgrammingError, e: 531 output = ["Prepare query error."] 532 output.extend(str(e).split("'")[1].split('\\n')) 533 output.append("Query:") 534 output.append(cquery) 535 raise Database.ProgrammingError, "\n".join(output) 536 try: 537 return self.cursor.execute(self._statement, params) 538 except Database.ProgrammingError, e: 539 err_no = int(str(e).split()[0].strip(',()')) 540 output = ["Execute query error. FB error No. %i" % err_no] 541 output.extend(str(e).split("'")[1].split('\\n')) 542 output.append("Query:") 543 output.append(cquery) 544 output.append("Parameters:") 545 output.append(str(params)) 546 raise Database.ProgrammingError, "\n".join(output) 547 548 def executemany(self, query, param_list): 549 try: 550 cquery = self.convert_query(query, len(param_list[0])) 551 except IndexError: 552 return None 553 if self._get_query() != cquery: 554 self._statement = self.cursor.prep(cquery) 555 return self.cursor.executemany(self._statement, param_list) 556 557 def convert_query(self, query, num_params): 558 try: 559 return query % tuple("?" * num_params) 560 except TypeError, e: 561 print query, num_params 562 raise TypeError, e 563 564 def _get_query(self): 565 if self._statement: 566 return self._statement.sql 567 568 def __getattr__(self, attr): 569 if attr in self.__dict__: 570 return self.__dict__[attr] 571 else: 572 return getattr(self.cursor, attr) 573 574 class DatabaseWrapper(BaseDatabaseWrapper): 575 features = DatabaseFeatures() 576 ops = DatabaseOperations() 577 operators = { 578 'exact': '= %s', 579 'iexact': '= UPPER(%s)', 580 'contains': "LIKE %s ESCAPE'\\'", 581 'icontains': 'CONTAINING %s', #case is ignored 582 'gt': '> %s', 583 'gte': '>= %s', 584 'lt': '< %s', 585 'lte': '<= %s', 586 'startswith': 'STARTING WITH %s', #looks to be faster then LIKE 587 'endswith': "LIKE %s ESCAPE'\\'", 588 'istartswith': 'STARTING WITH UPPER(%s)', 589 'iendswith': "LIKE UPPER(%s) ESCAPE'\\'" 590 } 591 592 def __init__(self, **kwargs): 593 from django.conf import settings 594 super(DatabaseWrapper, self).__init__(**kwargs) 595 self. _current_cursor = None 596 self._raw_cursor = None 597 self.charset = 'UNICODE_FSS' 598 self.FB_MAX_VARCHAR = 10921 #32765 MAX /3 599 self.BYTES_PER_DEFAULT_CHAR = 3 600 if hasattr(settings, 'FIREBIRD_CHARSET'): 601 if settings.FIREBIRD_CHARSET == 'UTF8': 602 self.charset = 'UTF8' 603 self.FB_MAX_VARCHAR = 8191 #32765 MAX /4 604 self.BYTES_PER_DEFAULT_CHAR = 4 605 606 def _connect(self, settings): 607 if settings.DATABASE_NAME == '': 608 from django.core.exceptions import ImproperlyConfigured 609 raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file." 610 kwargs = {'charset' : self.charset } 611 if settings.DATABASE_HOST: 612 kwargs['dsn'] = "%s:%s" % (settings.DATABASE_HOST, settings.DATABASE_NAME) 613 else: 614 kwargs['dsn'] = "localhost:%s" % settings.DATABASE_NAME 615 if settings.DATABASE_USER: 616 kwargs['user'] = settings.DATABASE_USER 617 if settings.DATABASE_PASSWORD: 618 kwargs['password'] = settings.DATABASE_PASSWORD 619 self.connection = Database.connect(**kwargs) 620 assert self.connection.charset == self.charset 621 622 def cursor(self): 623 from django.conf import settings 624 cursor = self._cursor(settings) 625 if settings.DEBUG: 626 self._debug_cursor = self.make_debug_cursor(cursor) 627 return self._debug_cursor 628 return cursor 629 630 def _cursor(self, settings): 631 if self.connection is None: 632 self._connect(settings) 633 cursor = self.connection.cursor() 634 self._raw_cursor = cursor 635 cursor = FirebirdCursorWrapper(cursor, self) 636 self._current_cursor = cursor 637 return cursor 638 639 def __getattr__(self, attr): 640 if attr in self.__dict__: 641 return self.__dict__[attr] 642 else: 643 return getattr(self.connection, attr) 644 -
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 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.path, codecs 12 try: 13 set 14 except NameError: 15 from sets import Set as set # Python 2.3 fallback 16 17 18 DATA_TYPES = { 19 'AutoField': '"AutoField"', 20 'BooleanField': '"BooleanField"', 21 'CharField': 'varchar(%(max_length)s)', 22 'CommaSeparatedIntegerField': 'varchar(%(max_length)s) CHARACTER SET ASCII', 23 'DateField': '"DateField"', 24 'DateTimeField': '"DateTimeField"', 25 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 26 'DefaultCharField': '"CharField"', 27 'FileField': 'varchar(%(max_length)s)', 28 'FilePathField': 'varchar(%(max_length)s)', 29 'FloatField': '"FloatField"', 30 'ImageField': '"varchar(%(max_length)s)"', 31 'IntegerField': '"IntegerField"', 32 'IPAddressField': 'varchar(15) CHARACTER SET ASCII', 33 'NullBooleanField': '"NullBooleanField"', 34 'OneToOneField': '"OneToOneField"', 35 'PhoneNumberField': '"PhoneNumberField"', 36 'PositiveIntegerField': '"PositiveIntegerField"', 37 'PositiveSmallIntegerField': '"PositiveSmallIntegerField"', 38 'SlugField': 'varchar(%(max_length)s)', 39 'SmallIntegerField': '"SmallIntegerField"', 40 'LargeTextField': '"LargeTextField"', 41 'TextField': '"TextField"', 42 'TimeField': '"TimeField"', 43 'URLField': 'varchar(%(max_length)s) CHARACTER SET ASCII', 44 'USStateField': '"USStateField"' 45 } 46 47 PYTHON_TO_FB_ENCODING_MAP = { 48 'ascii': 'ASCII', 49 'utf_8': connection.charset, 50 'shift_jis': 'SJIS_0208', 51 'euc_jp': 'EUCJ_0208', 52 'cp737': 'DOS737', 53 'cp437': 'DOS437', 54 'cp850': 'DOS850', 55 'cp865': 'DOS865', 56 'cp860': 'DOS860', 57 'cp863': 'DOS863', 58 'cp775': 'DOS775', 59 'cp862': 'DOS862', 60 'cp864': 'DOS864', 61 'iso8859_1': 'ISO8859_1', 62 'iso8859_2': 'ISO8859_2', 63 'iso8859_3': 'ISO8859_3', 64 'iso8859_4': 'ISO8859_4', 65 'iso8859_5': 'ISO8859_5', 66 'iso8859_6': 'ISO8859_6', 67 'iso8859_7': 'ISO8859_7', 68 'iso8859_8': 'ISO8859_8', 69 'iso8859_9': 'ISO8859_9', 70 'iso8859_13': 'ISO8859_13', 71 'euc_kr': 'KSC_5601', 72 'cp852': 'DOS852', 73 'cp857': 'DOS857', 74 'cp861': 'DOS861', 75 'cp866': 'DOS866', 76 'cp869': 'DOS869', 77 'cp1250': 'WIN1250', 78 'cp1251': 'WIN1251', 79 'cp1252': 'WIN1252', 80 'cp1253': 'WIN1253', 81 'cp1254': 'WIN1254', 82 'big5': 'BIG_5', 83 'gb2312': 'GB_2312', 84 'cp1255': 'WIN1255', 85 'cp1256': 'WIN1256', 86 'cp1257': 'WIN1257', 87 'koi8_r': 'KOI8-R', 88 'koi8_u': 'KOI8-U', 89 'cp1258': 'WIN1258' 90 } 91 92 def get_data_size(data_type, max_length = 100): 93 char_bytes = connection.BYTES_PER_DEFAULT_CHAR 94 size_map = { 95 'AutoField': 8, 96 'BooleanField': 4, 97 'CharField': char_bytes*max_length, 98 'CommaSeparatedIntegerField': max_length, 99 'DateField': 16, 100 'DateTimeField': 16, 101 'DecimalField': 16, 102 'FileField': char_bytes*max_length, 103 'FilePathField': 'varchar(%(max_length)s)', 104 'FloatField': 16, 105 'ImageField': char_bytes*max_length, 106 'IntegerField': 8, 107 'IPAddressField': 15, 108 'NullBooleanField': 4, 109 'OneToOneField': 8, 110 'PhoneNumberField': 20, 111 'PositiveIntegerField': 8, 112 'PositiveSmallIntegerField': 4, 113 'SlugField': char_bytes*max_length, 114 'SmallIntegerField': 4, 115 'TextBlob': 8, 116 'TextField': 32767, 117 'TimeField': 16, 118 'URLField': max_length, 119 'USStateField': char_bytes*2 120 } 121 return size_map[data_type] 122 123 DEFAULT_MAX_LENGTH = 100 124 def sql_model_create(model, style, known_models=set()): 125 """ 126 Returns the SQL required to create a single model, as a tuple of: 127 (list_of_sql, pending_references_dict) 128 """ 129 from django.db import connection, models 130 131 opts = model._meta 132 final_output = [] 133 table_output = [] 134 pending_references = {} 135 qn = connection.ops.quote_name 136 137 # Create domains 138 domains = [ ('AutoField', 'integer'), 139 ('BooleanField', 'smallint CHECK (VALUE IN (0,1))'), 140 ('DateField', 'date'), 141 ('CharField', 'varchar(%i)' % DEFAULT_MAX_LENGTH), 142 ('DateTimeField', 'timestamp'), 143 ('FloatField', 'double precision'), 144 ('IntegerField', 'integer'), 145 ('IPAddressField', 'varchar(15) CHARACTER SET ASCII'), 146 ('NullBooleanField', 'smallint CHECK ((VALUE IN (0,1)) OR (VALUE IS NULL))'), 147 ('OneToOneField', 'integer'), 148 ('PhoneNumberField', 'varchar(20) CHARACTER SET ASCII'), 149 ('PositiveIntegerField', 'integer CHECK ((VALUE >= 0) OR (VALUE IS NULL))'), 150 ('PositiveSmallIntegerField', 'smallint CHECK ((VALUE >= 0) OR (VALUE IS NULL))'), 151 ('SmallIntegerField', 'smallint'), 152 ('TextField', 'varchar(%s)' % connection.FB_MAX_VARCHAR), 153 ('LargeTextField', 'blob sub_type text'), 154 ('TimeField', 'time'), 155 ('USStateField', 'varchar(2) CHARACTER SET ASCII') ] 156 157 cursor = connection.cursor() 158 cursor.execute("SELECT RDB$FIELD_NAME FROM RDB$FIELDS") 159 existing_domains = set([row[0].strip() for row in cursor.fetchall() if not row[0].startswith('RDB$')]) 160 domains = map(lambda domain: '%s "%s" AS %s;' % ('CREATE DOMAIN', domain[0], domain[1]), 161 filter(lambda x: x[0] not in existing_domains, domains)) 162 final_output.extend(domains) 163 164 # Check that row size is less than 64k and adjust TextFields if needed 165 row_size = 0 166 columns = [(f.db_type().strip('"'), f.get_internal_type(), f) for f in opts.fields] 167 columns_simple = [col[0] for col in columns] 168 text_field_type = '"TextField"' 169 max_alowed_bytes = 32765 170 if 'TextField' in columns_simple: 171 max_length = 100 172 num_text_fields = 0 173 for column in columns: 174 num_text_fields += (column[0] == 'TextField') 175 if column[0].startswith('varchar'): 176 max_length = int(column[0].split('(')[1].split(')')[0]) 177 if column[1] in DATA_TYPES: 178 row_size += get_data_size(column[1], max_length) 179 if row_size > 65536: 180 max_alowed_bytes = int( (max_alowed_bytes/num_text_fields) - (row_size-65536) ) 181 n = max_alowed_bytes / connection.BYTES_PER_DEFAULT_CHAR 182 if n > 512: 183 text_field_type = 'varchar(%s)' % n 184 FB_TEXTFIELD_ALTERED = True 185 print 186 print "WARNING: Maximum number of characters in TextFields has changed to %s." % n 187 print " TextField columns with custom charsets will have %s chars available" % max_alowed_bytes 188 print " The change affects %s table only." % opts.db_table 189 print " TextFields in other tables will have %s characters maximum" % connection.FB_MAX_VARCHAR 190 print " or 32765 characters with custom (non-UTF) encoding." 191 print " If you need more space in those fields try LargeTextFields instead." 192 print 193 else: 194 # Swich to blobs if size is too small (<1024) 195 text_field_type = '"LargeTextField"' 196 197 # Create tables 198 for f in opts.fields: 199 col_type = f.db_type() 200 if col_type.strip('"') == 'TextField': 201 col_type = text_field_type 202 fb_version = "%s.%s" % (connection.ops.firebird_version[0], connection.ops.firebird_version[1]) 203 page_size = connection.ops.page_size 204 #look at: http://www.volny.cz/iprenosil/interbase/ip_ib_indexcalculator.htm 205 if connection.ops.index_limit < 1000: 206 strip2ascii = False 207 custom_charset = False 208 if col_type.startswith('varchar'): 209 if (f.unique or f.primary_key or f.db_index): 210 length = f.max_length 211 if f.encoding: 212 if not f.encoding.upper().startswith('UTF'): 213 custom_charset = True 214 if not custom_charset: 215 try: 216 length = f.max_length * connection.BYTES_PER_DEFAULT_CHAR 217 except TypeError: 218 length = 100*connection.BYTES_PER_DEFAULT_CHAR #Default for CharField 219 if length >= connection.ops.index_limit: 220 strip2ascii = True 221 if len(opts.unique_together) > 0: 222 if f.column in opts.unique_together[0]: 223 num_unique_char_fields = len([ fld for fld in opts.unique_together[0] if opts.get_field(fld).db_type().startswith('varchar') ]) 224 num_unique_fileds = len(opts.unique_together[0]) 225 num_unique_nonchar_fileds = num_unique_fileds - num_unique_char_fields 226 limit = connection.ops.index_limit 227 limit -= ((num_unique_fileds - 1)*64) 228 limit -= 8*num_unique_nonchar_fileds 229 max_length = limit/num_unique_char_fields 230 ascii_length = int(f.max_length) 231 old_length = ascii_length*connection.BYTES_PER_DEFAULT_CHAR 232 233 if (old_length >= max_length) and (ascii_length < max_length): 234 strip2ascii = True 235 elif old_length > max_length: 236 strip2ascii = False #We change it here 237 col_type = "varchar(%i) CHARACTER SET ASCII" % max_length 238 msg = "WARNING: Character set of the '%s' field\n" 239 msg += " (table %s)\n" 240 msg += " has changed to ASCII" 241 msg += " to fit %s-byte limit in FB %s" 242 if not page_size: 243 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version) 244 else: 245 msg += " with page size %s" 246 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version, page_size) 247 print " The maximum length of '%s' is now %s instead of %s"\ 248 % (f.column, max_length, old_length) 249 if strip2ascii: 250 col_type = "%s %s %s" % (col_type, "CHARACTER SET", "ASCII") 251 msg = "WARNING: Character set of the '%s' field\n" 252 msg += " (table %s)\n" 253 msg += " has changed to ASCII" 254 msg += " to fit %s-byte limit in FB %s" 255 if not page_size: 256 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version) 257 else: 258 msg += " with page size %s" 259 print msg % (f.column, opts.db_table, connection.ops.index_limit, fb_version, page_size) 260 261 if (col_type.startswith('varchar') or col_type.strip('"') == 'TextField') and f.encoding: 262 charset = PYTHON_TO_FB_ENCODING_MAP[codecs.lookup(f.encoding).name] 263 if col_type.strip('"') == 'TextField': 264 col_type = 'varchar(%i)' % max_alowed_bytes 265 col_type = "%s %s %s" % (col_type, "CHARACTER SET", charset) 266 267 268 if col_type is None: 269 # Skip ManyToManyFields, because they're not represented as 270 # database columns in this table. 271 continue 272 # Make the definition (e.g. 'foo VARCHAR(30)') for this field. 273 field_output = [style.SQL_FIELD(qn(f.column)), 274 style.SQL_COLTYPE(col_type)] 275 field_output.append(style.SQL_KEYWORD('%s' % (not f.null and 'NOT NULL' or 'DEFAULT NULL'))) 276 if f.unique: 277 field_output.append(style.SQL_KEYWORD('UNIQUE')) 278 if f.primary_key: 279 field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 280 if f.rel: 281 # We haven't yet created the table to which this field 282 # is related, so save it for later. 283 pr = pending_references.setdefault(f.rel.to, []).append((model, f)) 284 table_output.append(' '.join(field_output)) 285 if opts.order_with_respect_to: 286 table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \ 287 style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \ 288 style.SQL_KEYWORD('NULL')) 289 for field_constraints in opts.unique_together: 290 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ 291 ", ".join([qn(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints])) 292 293 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' ('] 294 for i, line in enumerate(table_output): # Combine and add commas. 295 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 296 full_statement.append(');') 297 final_output.append('\n'.join(full_statement)) 298 299 if opts.has_auto_field: 300 # Add any extra SQL needed to support auto-incrementing primary keys. 301 auto_column = opts.auto_field.db_column or opts.auto_field.name 302 autoinc_sql = connection.ops.autoinc_sql(style, opts.db_table, auto_column) 303 if autoinc_sql: 304 for stmt in autoinc_sql: 305 final_output.append(stmt) 306 307 # Declare exteral functions 308 cursor.execute("SELECT RDB$FUNCTION_NAME FROM RDB$FUNCTIONS") 309 existing_functions = set([row[0].strip().upper() for row in cursor.fetchall()]) 310 if 'RAND' not in existing_functions: 311 final_output.append('%s %s\n\t%s %s\n\t%s %s\n\t%s;' % (style.SQL_KEYWORD('DECLARE EXTERNAL FUNCTION'), 312 style.SQL_TABLE('RAND'), style.SQL_KEYWORD('RETURNS'), style.SQL_COLTYPE('DOUBLE PRECISION'), 313 style.SQL_KEYWORD('BY VALUE ENTRY_POINT'), style.SQL_FIELD("'IB_UDF_rand'"), 314 style.SQL_TABLE("MODULE_NAME 'ib_udf'"))) 315 316 return final_output, pending_references 317 318 def many_to_many_sql_for_model(model, style): 319 from django.db import connection, models 320 from django.contrib.contenttypes import generic 321 from django.db.backends.util import truncate_name 322 323 opts = model._meta 324 final_output = [] 325 qn = connection.ops.quote_name 326 for f in opts.many_to_many: 327 if not isinstance(f.rel, generic.GenericRel): 328 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ 329 style.SQL_TABLE(qn(f.m2m_db_table())) + ' ('] 330 table_output.append(' %s %s %s,' % 331 (style.SQL_FIELD(qn('id')), 332 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()), 333 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'))) 334 335 table_output.append(' %s %s %s,' % 336 (style.SQL_FIELD(qn(f.m2m_column_name())), 337 style.SQL_COLTYPE(models.ForeignKey(model).db_type()), 338 style.SQL_KEYWORD('NOT NULL'))) 339 table_output.append(' %s %s %s,' % 340 (style.SQL_FIELD(qn(f.m2m_reverse_name())), 341 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()), 342 style.SQL_KEYWORD('NOT NULL'))) 343 deferred = [ 344 (f.m2m_db_table(), f.m2m_column_name(), opts.db_table, 345 opts.pk.column), 346 ( f.m2m_db_table(), f.m2m_reverse_name(), 347 f.rel.to._meta.db_table, f.rel.to._meta.pk.column) 348 ] 349 350 table_output.append(' %s (%s, %s)' % 351 (style.SQL_KEYWORD('UNIQUE'), 352 style.SQL_FIELD(qn(f.m2m_column_name())), 353 style.SQL_FIELD(qn(f.m2m_reverse_name())))) 354 table_output.append(');') 355 final_output.append('\n'.join(table_output)) 356 357 autoinc_sql = connection.ops.autoinc_sql(style, f.m2m_db_table(), 'id') 358 if autoinc_sql: 359 for stmt in autoinc_sql: 360 final_output.append(stmt) 361 362 if connection.features.supports_constraints: 363 for r_table, r_col, table, col in deferred: 364 r_name = '%s_%s_%x' % (r_col, col, 365 abs(hash((r_table, table)))) 366 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 367 (qn(r_table), 368 truncate_name(r_name, connection.ops.max_name_length()), 369 qn(r_col), qn(table), qn(col), 370 'ON DELETE CASCADE ON UPDATE CASCADE')) 371 372 return final_output 373 374 TEST_DATABASE_PREFIX = 'test_' 375 def create_test_db(settings, connection, verbosity, autoclobber): 376 # KInterbasDB supports dynamic database creation and deletion 377 # via the module-level function create_database and the method Connection.drop_database. 378 379 if settings.TEST_DATABASE_NAME: 380 TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME 381 else: 382 dbnametuple = os.path.split(settings.DATABASE_NAME) 383 TEST_DATABASE_NAME = os.path.join(dbnametuple[0], TEST_DATABASE_PREFIX + dbnametuple[1]) 384 385 dsn = "localhost:%s" % TEST_DATABASE_NAME 386 if settings.DATABASE_HOST: 387 dsn = "%s:%s" % (settings.DATABASE_HOST, TEST_DATABASE_NAME) 388 389 if os.path.isfile(TEST_DATABASE_NAME): 390 sys.stderr.write("Database %s already exists\n" % TEST_DATABASE_NAME) 391 if not autoclobber: 392 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME) 393 if autoclobber or confirm == 'yes': 394 if verbosity >= 1: 395 print "Destroying old test database..." 396 old_connection = connect(dsn=dsn, user=settings.DATABASE_USER, password=settings.DATABASE_PASSWORD) 397 old_connection.drop_database() 398 else: 399 print "Tests cancelled." 400 sys.exit(1) 401 402 if verbosity >= 1: 403 print "Creating test database..." 404 try: 405 charset = 'UNICODE_FSS' 406 if hasattr(settings, 'FIREBIRD_CHARSET'): 407 if settings.FIREBIRD_CHARSET == 'UTF8': 408 charset='UTF8' 409 create_database("create database '%s' user '%s' password '%s' default character set %s" % \ 410 (dsn, settings.DATABASE_USER, settings.DATABASE_PASSWORD, charset)) 411 except Exception, e: 412 sys.stderr.write("Got an error creating the test database: %s\n" % e) 413 sys.exit(2) 414 415 connection.close() 416 settings.DATABASE_NAME = TEST_DATABASE_NAME 417 418 call_command('syncdb', verbosity=verbosity, interactive=False) 419 420 if settings.CACHE_BACKEND.startswith('db://'): 421 cache_name = settings.CACHE_BACKEND[len('db://'):] 422 call_command('createcachetable', cache_name) 423 424 # Get a cursor (even though we don't need one yet). This has 425 # the side effect of initializing the test database. 426 cursor = connection.cursor() 427 428 return TEST_DATABASE_NAME 429 430 def destroy_test_db(settings, connection, old_database_name, verbosity): 431 # KInterbasDB supports dynamic database deletion via the method Connection.drop_database. 432 if verbosity >= 1: 433 print "Destroying test database..." 434 connection.drop_database() 435 436 -
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()) … … 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>]