Ticket #5461: 5461-r8224.diff
File 5461-r8224.diff, 150.2 KB (added by , 16 years ago) |
---|
-
django/contrib/gis/db/backend/postgis/creation.py
diff -r 187c638a7c24 django/contrib/gis/db/backend/postgis/creation.py
a b 1 1 from django.conf import settings 2 2 from django.core.management import call_command 3 3 from django.db import connection 4 from django. test.utils import _set_autocommit,TEST_DATABASE_PREFIX4 from django.db.backends.creation import TEST_DATABASE_PREFIX 5 5 import os, re, sys 6 6 7 7 def getstatusoutput(cmd): … … 38 38 create_sql = 'CREATE DATABASE %s' % connection.ops.quote_name(db_name) 39 39 if settings.DATABASE_USER: 40 40 create_sql += ' OWNER %s' % settings.DATABASE_USER 41 41 42 42 cursor = connection.cursor() 43 _set_autocommit(connection)43 connection.creation._set_autocommit(connection) 44 44 45 45 try: 46 46 # Trying to create the database first. … … 58 58 else: 59 59 raise Exception('Spatial Database Creation canceled.') 60 60 foo = _create_with_cursor 61 61 62 62 created_regex = re.compile(r'^createdb: database creation failed: ERROR: database ".+" already exists') 63 63 def _create_with_shell(db_name, verbosity=1, autoclobber=False): 64 64 """ 65 If no spatial database already exists, then using a cursor will not work. 66 Thus, a `createdb` command will be issued through the shell to bootstrap 65 If no spatial database already exists, then using a cursor will not work. 66 Thus, a `createdb` command will be issued through the shell to bootstrap 67 67 creation of the spatial database. 68 68 """ 69 69 … … 83 83 if verbosity >= 1: print 'Destroying old spatial database...' 84 84 drop_cmd = 'dropdb %s%s' % (options, db_name) 85 85 status, output = getstatusoutput(drop_cmd) 86 if status != 0: 86 if status != 0: 87 87 raise Exception('Could not drop database %s: %s' % (db_name, output)) 88 88 if verbosity >= 1: print 'Creating new spatial database...' 89 89 status, output = getstatusoutput(create_cmd) … … 102 102 raise Exception('Spatial database creation only supported postgresql_psycopg2 platform.') 103 103 104 104 # Getting the spatial database name 105 if test: 105 if test: 106 106 db_name = get_spatial_db(test=True) 107 107 _create_with_cursor(db_name, verbosity=verbosity, autoclobber=autoclobber) 108 else: 108 else: 109 109 db_name = get_spatial_db() 110 110 _create_with_shell(db_name, verbosity=verbosity, autoclobber=autoclobber) 111 111 … … 125 125 126 126 # Syncing the database 127 127 call_command('syncdb', verbosity=verbosity, interactive=interactive) 128 128 129 129 def drop_db(db_name=False, test=False): 130 130 """ 131 131 Drops the given database (defaults to what is returned from … … 151 151 152 152 def get_spatial_db(test=False): 153 153 """ 154 Returns the name of the spatial database. The 'test' keyword may be set 154 Returns the name of the spatial database. The 'test' keyword may be set 155 155 to return the test spatial database name. 156 156 """ 157 157 if test: … … 167 167 168 168 def load_postgis_sql(db_name, verbosity=1): 169 169 """ 170 This routine loads up the PostGIS SQL files lwpostgis.sql and 170 This routine loads up the PostGIS SQL files lwpostgis.sql and 171 171 spatial_ref_sys.sql. 172 172 """ 173 173 174 174 # Getting the path to the PostGIS SQL 175 175 try: 176 # POSTGIS_SQL_PATH may be placed in settings to tell GeoDjango where the 176 # POSTGIS_SQL_PATH may be placed in settings to tell GeoDjango where the 177 177 # PostGIS SQL files are located. This is especially useful on Win32 178 178 # platforms since the output of pg_config looks like "C:/PROGRA~1/..". 179 179 sql_path = settings.POSTGIS_SQL_PATH … … 193 193 # Getting the psql command-line options, and command format. 194 194 options = get_cmd_options(db_name) 195 195 cmd_fmt = 'psql %s-f "%%s"' % options 196 196 197 197 # Now trying to load up the PostGIS functions 198 198 cmd = cmd_fmt % lwpostgis_file 199 199 if verbosity >= 1: print cmd … … 211 211 # Setting the permissions because on Windows platforms the owner 212 212 # of the spatial_ref_sys and geometry_columns tables is always 213 213 # the postgres user, regardless of how the db is created. 214 if os.name == 'nt': set_permissions(db_name) 215 214 if os.name == 'nt': set_permissions(db_name) 215 216 216 def set_permissions(db_name): 217 217 """ 218 218 Sets the permissions on the given database to that of the user specified -
django/contrib/gis/management/commands/inspectdb.py
diff -r 187c638a7c24 django/contrib/gis/management/commands/inspectdb.py
a b 7 7 from django.contrib.gis.db.backend import SpatialBackend 8 8 9 9 class Command(InspectCommand): 10 10 11 11 # Mapping from lower-case OGC type to the corresponding GeoDjango field. 12 12 geofield_mapping = {'point' : 'PointField', 13 13 'linestring' : 'LineStringField', … … 21 21 22 22 def geometry_columns(self): 23 23 """ 24 Returns a datastructure of metadata information associated with the 24 Returns a datastructure of metadata information associated with the 25 25 `geometry_columns` (or equivalent) table. 26 26 """ 27 27 # The `geo_cols` is a dictionary data structure that holds information 28 # about any geographic columns in the database. 28 # about any geographic columns in the database. 29 29 geo_cols = {} 30 30 def add_col(table, column, coldata): 31 31 if table in geo_cols: … … 47 47 elif SpatialBackend.name == 'mysql': 48 48 # On MySQL have to get all table metadata before hand; this means walking through 49 49 # each table and seeing if any column types are spatial. Can't detect this with 50 # `cursor.description` (what the introspection module does) because all spatial types 50 # `cursor.description` (what the introspection module does) because all spatial types 51 51 # have the same integer type (255 for GEOMETRY). 52 52 from django.db import connection 53 53 cursor = connection.cursor() … … 67 67 68 68 def handle_inspection(self): 69 69 "Overloaded from Django's version to handle geographic database tables." 70 from django.db import connection , get_introspection_module70 from django.db import connection 71 71 import keyword 72 72 73 introspection_module = get_introspection_module()73 geo_cols = self.geometry_columns() 74 74 75 geo_cols = self.geometry_columns()76 77 75 table2model = lambda table_name: table_name.title().replace('_', '') 78 76 79 77 cursor = connection.cursor() … … 88 86 yield '' 89 87 yield 'from django.contrib.gis.db import models' 90 88 yield '' 91 for table_name in introspection_module.get_table_list(cursor):89 for table_name in connection.introspection.get_table_list(cursor): 92 90 # Getting the geographic table dictionary. 93 91 geo_table = geo_cols.get(table_name, {}) 94 92 95 93 yield 'class %s(models.Model):' % table2model(table_name) 96 94 try: 97 relations = introspection_module.get_relations(cursor, table_name)95 relations = connection.introspection.get_relations(cursor, table_name) 98 96 except NotImplementedError: 99 97 relations = {} 100 98 try: 101 indexes = introspection_module.get_indexes(cursor, table_name)99 indexes = connection.introspection.get_indexes(cursor, table_name) 102 100 except NotImplementedError: 103 101 indexes = {} 104 for i, row in enumerate( introspection_module.get_table_description(cursor, table_name)):102 for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)): 105 103 att_name, iatt_name = row[0].lower(), row[0] 106 104 comment_notes = [] # Holds Field notes, to be displayed in a Python comment. 107 105 extra_params = {} # Holds Field parameters such as 'db_column'. … … 133 131 if srid != 4326: extra_params['srid'] = srid 134 132 else: 135 133 try: 136 field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]134 field_type = connection.introspection.data_types_reverse[row[1]] 137 135 except KeyError: 138 136 field_type = 'TextField' 139 137 comment_notes.append('This field type is a guess.') 140 138 141 # This is a hook for DATA_TYPES_REVERSEto return a tuple of139 # This is a hook for data_types_reverse to return a tuple of 142 140 # (field_type, extra_params_dict). 143 141 if type(field_type) is tuple: 144 142 field_type, new_params = field_type -
django/core/management/commands/dbshell.py
diff -r 187c638a7c24 django/core/management/commands/dbshell.py
a b 6 6 requires_model_validation = False 7 7 8 8 def handle_noargs(self, **options): 9 from django.db import runshell10 runshell()9 from django.db import connection 10 connection.client.runshell() -
django/core/management/commands/inspectdb.py
diff -r 187c638a7c24 django/core/management/commands/inspectdb.py
a b 13 13 raise CommandError("Database inspection isn't supported for the currently selected database backend.") 14 14 15 15 def handle_inspection(self): 16 from django.db import connection , get_introspection_module16 from django.db import connection 17 17 import keyword 18 19 introspection_module = get_introspection_module()20 18 21 19 table2model = lambda table_name: table_name.title().replace('_', '') 22 20 … … 32 30 yield '' 33 31 yield 'from django.db import models' 34 32 yield '' 35 for table_name in introspection_module.get_table_list(cursor):33 for table_name in connection.introspection.get_table_list(cursor): 36 34 yield 'class %s(models.Model):' % table2model(table_name) 37 35 try: 38 relations = introspection_module.get_relations(cursor, table_name)36 relations = connection.introspection.get_relations(cursor, table_name) 39 37 except NotImplementedError: 40 38 relations = {} 41 39 try: 42 indexes = introspection_module.get_indexes(cursor, table_name)40 indexes = connection.introspection.get_indexes(cursor, table_name) 43 41 except NotImplementedError: 44 42 indexes = {} 45 for i, row in enumerate( introspection_module.get_table_description(cursor, table_name)):43 for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)): 46 44 att_name = row[0].lower() 47 45 comment_notes = [] # Holds Field notes, to be displayed in a Python comment. 48 46 extra_params = {} # Holds Field parameters such as 'db_column'. … … 65 63 extra_params['db_column'] = att_name 66 64 else: 67 65 try: 68 field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]66 field_type = connection.introspection.data_types_reverse[row[1]] 69 67 except KeyError: 70 68 field_type = 'TextField' 71 69 comment_notes.append('This field type is a guess.') -
django/core/management/commands/syncdb.py
diff -r 187c638a7c24 django/core/management/commands/syncdb.py
a b 21 21 def handle_noargs(self, **options): 22 22 from django.db import connection, transaction, models 23 23 from django.conf import settings 24 from django.core.management.sql import table_names, installed_models, sql_model_create, sql_for_pending_references, many_to_many_sql_for_model, custom_sql_for_model, sql_indexes_for_model, emit_post_sync_signal24 from django.core.management.sql import table_names, installed_models, custom_sql_for_model, emit_post_sync_signal 25 25 26 26 verbosity = int(options.get('verbosity', 1)) 27 27 interactive = options.get('interactive') … … 73 73 print "Processing %s.%s model" % (app_name, model._meta.object_name) 74 74 if table_name_converter(model._meta.db_table) in tables: 75 75 continue 76 sql, references = sql_model_create(model, self.style, seen_models)76 sql, references = connection.creation.sql_create_model(model, self.style, seen_models) 77 77 seen_models.add(model) 78 78 created_models.add(model) 79 79 for refto, refs in references.items(): 80 80 pending_references.setdefault(refto, []).extend(refs) 81 81 if refto in seen_models: 82 sql.extend( sql_for_pending_references(refto, self.style, pending_references))83 sql.extend( sql_for_pending_references(model, self.style, pending_references))82 sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references)) 83 sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references)) 84 84 if verbosity >= 1: 85 85 print "Creating table %s" % model._meta.db_table 86 86 for statement in sql: … … 94 94 model_list = models.get_models(app) 95 95 for model in model_list: 96 96 if model in created_models: 97 sql = many_to_many_sql_for_model(model, self.style)97 sql = connection.creation.many_to_many_sql_for_model(model, self.style) 98 98 if sql: 99 99 if verbosity >= 2: 100 100 print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name) … … 140 140 app_name = app.__name__.split('.')[-2] 141 141 for model in models.get_models(app): 142 142 if model in created_models: 143 index_sql = sql_indexes_for_model(model, self.style)143 index_sql = connection.creation.sql_indexes_for_model(model, self.style) 144 144 if index_sql: 145 145 if verbosity >= 1: 146 146 print "Installing index for %s.%s model" % (app_name, model._meta.object_name) -
django/core/management/commands/testserver.py
diff -r 187c638a7c24 django/core/management/commands/testserver.py
a b 18 18 19 19 def handle(self, *fixture_labels, **options): 20 20 from django.core.management import call_command 21 from django. test.utils import create_test_db21 from django.db import connection 22 22 23 23 verbosity = int(options.get('verbosity', 1)) 24 24 addrport = options.get('addrport') 25 25 26 26 # Create a test database. 27 db_name = c reate_test_db(verbosity=verbosity)27 db_name = connection.creation.create_test_db(verbosity=verbosity) 28 28 29 29 # Import the fixture data into the test database. 30 30 call_command('loaddata', *fixture_labels, **{'verbosity': verbosity}) -
django/core/management/sql.py
diff -r 187c638a7c24 django/core/management/sql.py
a b 9 9 10 10 def table_names(): 11 11 "Returns a list of all table names that exist in the database." 12 from django.db import connection , get_introspection_module12 from django.db import connection 13 13 cursor = connection.cursor() 14 return set( get_introspection_module().get_table_list(cursor))14 return set(connection.introspection.get_table_list(cursor)) 15 15 16 16 def django_table_names(only_existing=False): 17 17 """ … … 65 65 66 66 def sql_create(app, style): 67 67 "Returns a list of the CREATE TABLE SQL statements for the given app." 68 from django.db import models68 from django.db import connection, models 69 69 from django.conf import settings 70 70 71 71 if settings.DATABASE_ENGINE == 'dummy': … … 85 85 pending_references = {} 86 86 87 87 for model in app_models: 88 output, references = sql_model_create(model, style, known_models)88 output, references = connection.creation.sql_create_model(model, style, known_models) 89 89 final_output.extend(output) 90 90 for refto, refs in references.items(): 91 91 pending_references.setdefault(refto, []).extend(refs) 92 92 if refto in known_models: 93 final_output.extend( sql_for_pending_references(refto, style, pending_references))94 final_output.extend( sql_for_pending_references(model, style, pending_references))93 final_output.extend(connection.creation.sql_for_pending_references(refto, style, pending_references)) 94 final_output.extend(connection.creation.sql_for_pending_references(model, style, pending_references)) 95 95 # Keep track of the fact that we've created the table for this model. 96 96 known_models.add(model) 97 97 98 98 # Create the many-to-many join tables. 99 99 for model in app_models: 100 final_output.extend( many_to_many_sql_for_model(model, style))100 final_output.extend(connection.creation.many_to_many_sql_for_model(model, style)) 101 101 102 102 # Handle references to tables that are from other apps 103 103 # but don't exist physically. … … 106 106 alter_sql = [] 107 107 for model in not_installed_models: 108 108 alter_sql.extend(['-- ' + sql for sql in 109 sql_for_pending_references(model, style, pending_references)])109 connection.creation.sql_for_pending_references(model, style, pending_references)]) 110 110 if alter_sql: 111 111 final_output.append('-- The following references should be added but depend on non-existent tables:') 112 112 final_output.extend(alter_sql) … … 115 115 116 116 def sql_delete(app, style): 117 117 "Returns a list of the DROP TABLE SQL statements for the given app." 118 from django.db import connection, models , get_introspection_module118 from django.db import connection, models 119 119 from django.db.backends.util import truncate_name 120 120 from django.contrib.contenttypes import generic 121 introspection = get_introspection_module()122 121 123 122 # This should work even if a connection isn't available 124 123 try: … … 128 127 129 128 # Figure out which tables already exist 130 129 if cursor: 131 table_names = introspection.get_table_list(cursor)130 table_names = connection.introspection.get_table_list(cursor) 132 131 else: 133 132 table_names = [] 134 133 if connection.features.uses_case_insensitive_names: … … 137 136 table_name_converter = lambda x: x 138 137 139 138 output = [] 140 qn = connection.ops.quote_name141 139 142 140 # Output DROP TABLE statements for standard application tables. 143 141 to_delete = set() … … 155 153 to_delete.add(model) 156 154 157 155 for model in app_models: 158 if cursor and table_name_converter(model._meta.db_table) in table_names: 159 # Drop the table now 160 output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'), 161 style.SQL_TABLE(qn(model._meta.db_table)))) 162 if connection.features.supports_constraints and model in references_to_delete: 163 for rel_class, f in references_to_delete[model]: 164 table = rel_class._meta.db_table 165 col = f.column 166 r_table = model._meta.db_table 167 r_col = model._meta.get_field(f.rel.field_name).column 168 r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table)))) 169 output.append('%s %s %s %s;' % \ 170 (style.SQL_KEYWORD('ALTER TABLE'), 171 style.SQL_TABLE(qn(table)), 172 style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()), 173 style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length())))) 174 del references_to_delete[model] 175 if model._meta.has_auto_field: 176 ds = connection.ops.drop_sequence_sql(model._meta.db_table) 177 if ds: 178 output.append(ds) 156 if table_name_converter(model._meta.db_table) in table_names: 157 output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style)) 179 158 180 159 # Output DROP TABLE statements for many-to-many tables. 181 160 for model in app_models: 182 161 opts = model._meta 183 162 for f in opts.local_many_to_many: 184 if not f.creates_table:185 continue186 163 if cursor and table_name_converter(f.m2m_db_table()) in table_names: 187 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'), 188 style.SQL_TABLE(qn(f.m2m_db_table())))) 189 ds = connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column)) 190 if ds: 191 output.append(ds) 164 output.extend(connection.creation.sql_destroy_many_to_many(model, f, style)) 192 165 193 166 app_label = app_models[0]._meta.app_label 194 167 … … 234 207 235 208 def sql_indexes(app, style): 236 209 "Returns a list of the CREATE INDEX SQL statements for all models in the given app." 237 from django.db import models210 from django.db import connection, models 238 211 output = [] 239 212 for model in models.get_models(app): 240 output.extend( sql_indexes_for_model(model, style))213 output.extend(connection.creation.sql_indexes_for_model(model, style)) 241 214 return output 242 215 243 216 def sql_all(app, style): 244 217 "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module." 245 218 return sql_create(app, style) + sql_custom(app, style) + sql_indexes(app, style) 246 247 def sql_model_create(model, style, known_models=set()):248 """249 Returns the SQL required to create a single model, as a tuple of:250 (list_of_sql, pending_references_dict)251 """252 from django.db import connection, models253 254 opts = model._meta255 final_output = []256 table_output = []257 pending_references = {}258 qn = connection.ops.quote_name259 inline_references = connection.features.inline_fk_references260 for f in opts.local_fields:261 col_type = f.db_type()262 tablespace = f.db_tablespace or opts.db_tablespace263 if col_type is None:264 # Skip ManyToManyFields, because they're not represented as265 # database columns in this table.266 continue267 # Make the definition (e.g. 'foo VARCHAR(30)') for this field.268 field_output = [style.SQL_FIELD(qn(f.column)),269 style.SQL_COLTYPE(col_type)]270 field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))271 if f.primary_key:272 field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))273 elif f.unique:274 field_output.append(style.SQL_KEYWORD('UNIQUE'))275 if tablespace and connection.features.supports_tablespaces and f.unique:276 # We must specify the index tablespace inline, because we277 # won't be generating a CREATE INDEX statement for this field.278 field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))279 if f.rel:280 if inline_references and f.rel.to in known_models:281 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \282 style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \283 style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +284 connection.ops.deferrable_sql()285 )286 else:287 # We haven't yet created the table to which this field288 # is related, so save it for later.289 pr = pending_references.setdefault(f.rel.to, []).append((model, f))290 table_output.append(' '.join(field_output))291 if opts.order_with_respect_to:292 table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \293 style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \294 style.SQL_KEYWORD('NULL'))295 for field_constraints in opts.unique_together:296 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \297 ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints]))298 299 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']300 for i, line in enumerate(table_output): # Combine and add commas.301 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))302 full_statement.append(')')303 if opts.db_tablespace and connection.features.supports_tablespaces:304 full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))305 full_statement.append(';')306 final_output.append('\n'.join(full_statement))307 308 if opts.has_auto_field:309 # Add any extra SQL needed to support auto-incrementing primary keys.310 auto_column = opts.auto_field.db_column or opts.auto_field.name311 autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column)312 if autoinc_sql:313 for stmt in autoinc_sql:314 final_output.append(stmt)315 316 return final_output, pending_references317 318 def sql_for_pending_references(model, style, pending_references):319 """320 Returns any ALTER TABLE statements to add constraints after the fact.321 """322 from django.db import connection323 from django.db.backends.util import truncate_name324 325 qn = connection.ops.quote_name326 final_output = []327 if connection.features.supports_constraints:328 opts = model._meta329 if model in pending_references:330 for rel_class, f in pending_references[model]:331 rel_opts = rel_class._meta332 r_table = rel_opts.db_table333 r_col = f.column334 table = opts.db_table335 col = opts.get_field(f.rel.field_name).column336 # For MySQL, r_name must be unique in the first 64 characters.337 # So we are careful with character usage here.338 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))339 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \340 (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),341 qn(r_col), qn(table), qn(col),342 connection.ops.deferrable_sql()))343 del pending_references[model]344 return final_output345 346 def many_to_many_sql_for_model(model, style):347 from django.db import connection, models348 from django.contrib.contenttypes import generic349 from django.db.backends.util import truncate_name350 351 opts = model._meta352 final_output = []353 qn = connection.ops.quote_name354 inline_references = connection.features.inline_fk_references355 for f in opts.local_many_to_many:356 if f.creates_table:357 tablespace = f.db_tablespace or opts.db_tablespace358 if tablespace and connection.features.supports_tablespaces:359 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace, inline=True)360 else:361 tablespace_sql = ''362 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \363 style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']364 table_output.append(' %s %s %s%s,' %365 (style.SQL_FIELD(qn('id')),366 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),367 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),368 tablespace_sql))369 if inline_references:370 deferred = []371 table_output.append(' %s %s %s %s (%s)%s,' %372 (style.SQL_FIELD(qn(f.m2m_column_name())),373 style.SQL_COLTYPE(models.ForeignKey(model).db_type()),374 style.SQL_KEYWORD('NOT NULL REFERENCES'),375 style.SQL_TABLE(qn(opts.db_table)),376 style.SQL_FIELD(qn(opts.pk.column)),377 connection.ops.deferrable_sql()))378 table_output.append(' %s %s %s %s (%s)%s,' %379 (style.SQL_FIELD(qn(f.m2m_reverse_name())),380 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),381 style.SQL_KEYWORD('NOT NULL REFERENCES'),382 style.SQL_TABLE(qn(f.rel.to._meta.db_table)),383 style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),384 connection.ops.deferrable_sql()))385 else:386 table_output.append(' %s %s %s,' %387 (style.SQL_FIELD(qn(f.m2m_column_name())),388 style.SQL_COLTYPE(models.ForeignKey(model).db_type()),389 style.SQL_KEYWORD('NOT NULL')))390 table_output.append(' %s %s %s,' %391 (style.SQL_FIELD(qn(f.m2m_reverse_name())),392 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),393 style.SQL_KEYWORD('NOT NULL')))394 deferred = [395 (f.m2m_db_table(), f.m2m_column_name(), opts.db_table,396 opts.pk.column),397 ( f.m2m_db_table(), f.m2m_reverse_name(),398 f.rel.to._meta.db_table, f.rel.to._meta.pk.column)399 ]400 table_output.append(' %s (%s, %s)%s' %401 (style.SQL_KEYWORD('UNIQUE'),402 style.SQL_FIELD(qn(f.m2m_column_name())),403 style.SQL_FIELD(qn(f.m2m_reverse_name())),404 tablespace_sql))405 table_output.append(')')406 if opts.db_tablespace and connection.features.supports_tablespaces:407 # f.db_tablespace is only for indices, so ignore its value here.408 table_output.append(connection.ops.tablespace_sql(opts.db_tablespace))409 table_output.append(';')410 final_output.append('\n'.join(table_output))411 412 for r_table, r_col, table, col in deferred:413 r_name = '%s_refs_%s_%x' % (r_col, col,414 abs(hash((r_table, table))))415 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' %416 (qn(r_table),417 truncate_name(r_name, connection.ops.max_name_length()),418 qn(r_col), qn(table), qn(col),419 connection.ops.deferrable_sql()))420 421 # Add any extra SQL needed to support auto-incrementing PKs422 autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table(), 'id')423 if autoinc_sql:424 for stmt in autoinc_sql:425 final_output.append(stmt)426 427 return final_output428 219 429 220 def custom_sql_for_model(model, style): 430 221 from django.db import models … … 461 252 462 253 return output 463 254 464 def sql_indexes_for_model(model, style):465 "Returns the CREATE INDEX SQL statements for a single model"466 from django.db import connection467 output = []468 469 qn = connection.ops.quote_name470 for f in model._meta.local_fields:471 if f.db_index and not f.unique:472 tablespace = f.db_tablespace or model._meta.db_tablespace473 if tablespace and connection.features.supports_tablespaces:474 tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)475 else:476 tablespace_sql = ''477 output.append(478 style.SQL_KEYWORD('CREATE INDEX') + ' ' + \479 style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \480 style.SQL_KEYWORD('ON') + ' ' + \481 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \482 "(%s)" % style.SQL_FIELD(qn(f.column)) + \483 "%s;" % tablespace_sql484 )485 return output486 255 487 256 def emit_post_sync_signal(created_models, verbosity, interactive): 488 257 from django.db import models -
django/core/management/validation.py
diff -r 187c638a7c24 django/core/management/validation.py
a b 61 61 if f.db_index not in (None, True, False): 62 62 e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name) 63 63 64 # Check that max_length <= 255 if using older MySQL versions. 65 if settings.DATABASE_ENGINE == 'mysql': 66 db_version = connection.get_server_version() 67 if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255: 68 e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]]))) 64 # Perform any backend-specific field validation. 65 connection.validation.validate_field(e, opts, f) 69 66 70 67 # Check to see if the related field will clash with any existing 71 68 # fields, m2m fields, m2m related objects or related objects -
django/db/__init__.py
diff -r 187c638a7c24 django/db/__init__.py
a b 14 14 # backends that ships with Django, so look there first. 15 15 _import_path = 'django.db.backends.' 16 16 backend = __import__('%s%s.base' % (_import_path, settings.DATABASE_ENGINE), {}, {}, ['']) 17 creation = __import__('%s%s.creation' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])18 17 except ImportError, e: 19 18 # If the import failed, we might be looking for a database backend 20 19 # distributed external to Django. So we'll try that next. 21 20 try: 22 21 _import_path = '' 23 22 backend = __import__('%s.base' % settings.DATABASE_ENGINE, {}, {}, ['']) 24 creation = __import__('%s.creation' % settings.DATABASE_ENGINE, {}, {}, [''])25 23 except ImportError, e_user: 26 24 # The database backend wasn't found. Display a helpful error message 27 25 # listing all possible (built-in) database backends. … … 29 27 available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')] 30 28 available_backends.sort() 31 29 if settings.DATABASE_ENGINE not in available_backends: 32 raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s " % \33 (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends )))30 raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s\nError was: %s" % \ 31 (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends, e_user))) 34 32 else: 35 33 raise # If there's some other error, this must be an error in Django itself. 36 37 def _import_database_module(import_path='', module_name=''):38 """Lazily import a database module when requested."""39 return __import__('%s%s.%s' % (import_path, settings.DATABASE_ENGINE, module_name), {}, {}, [''])40 41 # We don't want to import the introspect module unless someone asks for it, so42 # lazily load it on demmand.43 get_introspection_module = curry(_import_database_module, _import_path, 'introspection')44 45 def get_creation_module():46 return creation47 48 # We want runshell() to work the same way, but we have to treat it a49 # little differently (since it just runs instead of returning a module like50 # the above) and wrap the lazily-loaded runshell() method.51 runshell = lambda: _import_database_module(_import_path, "client").runshell()52 34 53 35 # Convenient aliases for backend bits. 54 36 connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS) -
django/db/backends/__init__.py
diff -r 187c638a7c24 django/db/backends/__init__.py
a b 325 325 """ 326 326 return self.year_lookup_bounds(value) 327 327 328 class BaseDatabaseIntrospection(object): 329 """ 330 This class encapsulates all backend-specific introspection utilities 331 """ 332 data_types_reverse = {} 333 334 class BaseDatabaseClient(object): 335 """ 336 This class encapsualtes all backend-specific methods for opening a 337 client shell 338 """ 339 def runshell(self): 340 raise NotImplementedError() 341 342 class BaseDatabaseValidation(object): 343 """ 344 This class encapsualtes all backend-specific model validation. 345 """ 346 def validate_field(self, errors, opts, f): 347 "By default, there is no backend-specific validation" 348 pass 349 -
django/db/backends/creation.py
diff -r 187c638a7c24 django/db/backends/creation.py
a b 1 class BaseCreation(object): 1 import sys 2 import time 3 4 from django.conf import settings 5 from django.core.management import call_command 6 7 # The prefix to put on the default database name when creating 8 # the test database. 9 TEST_DATABASE_PREFIX = 'test_' 10 11 class BaseDatabaseCreation(object): 2 12 """ 3 13 This class encapsulates all backend-specific differences that pertain to 4 14 database *creation*, such as the column types to use for particular Django 5 15 Fields. 6 16 """ 7 pass 17 data_types = {} 18 19 def __init__(self, ops, features): 20 self.ops = ops 21 self.features = features 22 23 def sql_create_model(self, model, style, known_models=set()): 24 """ 25 Returns the SQL required to create a single model, as a tuple of: 26 (list_of_sql, pending_references_dict) 27 """ 28 from django.db import models 29 30 opts = model._meta 31 final_output = [] 32 table_output = [] 33 pending_references = {} 34 qn = self.ops.quote_name 35 inline_references = self.features.inline_fk_references 36 for f in opts.local_fields: 37 col_type = f.db_type() 38 tablespace = f.db_tablespace or opts.db_tablespace 39 if col_type is None: 40 # Skip ManyToManyFields, because they're not represented as 41 # database columns in this table. 42 continue 43 # Make the definition (e.g. 'foo VARCHAR(30)') for this field. 44 field_output = [style.SQL_FIELD(qn(f.column)), 45 style.SQL_COLTYPE(col_type)] 46 field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or ''))) 47 if f.primary_key: 48 field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 49 elif f.unique: 50 field_output.append(style.SQL_KEYWORD('UNIQUE')) 51 if tablespace and self.features.supports_tablespaces and f.unique: 52 # We must specify the index tablespace inline, because we 53 # won't be generating a CREATE INDEX statement for this field. 54 field_output.append(self.ops.tablespace_sql(tablespace, inline=True)) 55 if f.rel: 56 if inline_references and f.rel.to in known_models: 57 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \ 58 style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \ 59 style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' + 60 self.ops.deferrable_sql() 61 ) 62 else: 63 # We haven't yet created the table to which this field 64 # is related, so save it for later. 65 pr = pending_references.setdefault(f.rel.to, []).append((model, f)) 66 table_output.append(' '.join(field_output)) 67 if opts.order_with_respect_to: 68 table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \ 69 style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \ 70 style.SQL_KEYWORD('NULL')) 71 for field_constraints in opts.unique_together: 72 table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ 73 ", ".join([style.SQL_FIELD(qn(opts.get_field(f).column)) for f in field_constraints])) 74 75 full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' ('] 76 for i, line in enumerate(table_output): # Combine and add commas. 77 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 78 full_statement.append(')') 79 if opts.db_tablespace and self.features.supports_tablespaces: 80 full_statement.append(self.ops.tablespace_sql(opts.db_tablespace)) 81 full_statement.append(';') 82 final_output.append('\n'.join(full_statement)) 83 84 if opts.has_auto_field: 85 # Add any extra SQL needed to support auto-incrementing primary keys. 86 auto_column = opts.auto_field.db_column or opts.auto_field.name 87 autoinc_sql = self.ops.autoinc_sql(opts.db_table, auto_column) 88 if autoinc_sql: 89 for stmt in autoinc_sql: 90 final_output.append(stmt) 91 92 return final_output, pending_references 93 94 def sql_for_pending_references(self, model, style, pending_references): 95 """ 96 Returns any ALTER TABLE statements to add constraints after the fact. 97 """ 98 from django.db.backends.util import truncate_name 99 100 qn = self.ops.quote_name 101 final_output = [] 102 if self.features.supports_constraints: 103 opts = model._meta 104 if model in pending_references: 105 for rel_class, f in pending_references[model]: 106 rel_opts = rel_class._meta 107 r_table = rel_opts.db_table 108 r_col = f.column 109 table = opts.db_table 110 col = opts.get_field(f.rel.field_name).column 111 # For MySQL, r_name must be unique in the first 64 characters. 112 # So we are careful with character usage here. 113 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table)))) 114 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \ 115 (qn(r_table), truncate_name(r_name, self.ops.max_name_length()), 116 qn(r_col), qn(table), qn(col), 117 self.ops.deferrable_sql())) 118 del pending_references[model] 119 return final_output 120 121 def many_to_many_sql_for_model(self, model, style): 122 output = [] 123 for f in model._meta.local_many_to_many: 124 output.extend(self.sql_for_many_to_many_field(model, f, style)) 125 return output 126 127 def sql_for_many_to_many_field(self, model, f, style): 128 "Return the CREATE TABLE statements for a single m2m field" 129 from django.db import models 130 from django.db.backends.util import truncate_name 131 132 output = [] 133 if f.creates_table: 134 opts = model._meta 135 inline_references = self.features.inline_fk_references 136 qn = self.ops.quote_name 137 tablespace = f.db_tablespace or opts.db_tablespace 138 if tablespace and self.features.supports_tablespaces: 139 tablespace_sql = ' ' + self.ops.tablespace_sql(tablespace, inline=True) 140 else: 141 tablespace_sql = '' 142 table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ 143 style.SQL_TABLE(qn(f.m2m_db_table())) + ' ('] 144 table_output.append(' %s %s %s%s,' % 145 (style.SQL_FIELD(qn('id')), 146 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()), 147 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'), 148 tablespace_sql)) 149 if inline_references: 150 deferred = [] 151 table_output.append(' %s %s %s %s (%s)%s,' % 152 (style.SQL_FIELD(qn(f.m2m_column_name())), 153 style.SQL_COLTYPE(models.ForeignKey(model).db_type()), 154 style.SQL_KEYWORD('NOT NULL REFERENCES'), 155 style.SQL_TABLE(qn(opts.db_table)), 156 style.SQL_FIELD(qn(opts.pk.column)), 157 self.ops.deferrable_sql())) 158 table_output.append(' %s %s %s %s (%s)%s,' % 159 (style.SQL_FIELD(qn(f.m2m_reverse_name())), 160 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()), 161 style.SQL_KEYWORD('NOT NULL REFERENCES'), 162 style.SQL_TABLE(qn(f.rel.to._meta.db_table)), 163 style.SQL_FIELD(qn(f.rel.to._meta.pk.column)), 164 self.ops.deferrable_sql())) 165 else: 166 table_output.append(' %s %s %s,' % 167 (style.SQL_FIELD(qn(f.m2m_column_name())), 168 style.SQL_COLTYPE(models.ForeignKey(model).db_type()), 169 style.SQL_KEYWORD('NOT NULL'))) 170 table_output.append(' %s %s %s,' % 171 (style.SQL_FIELD(qn(f.m2m_reverse_name())), 172 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()), 173 style.SQL_KEYWORD('NOT NULL'))) 174 deferred = [ 175 (f.m2m_db_table(), f.m2m_column_name(), opts.db_table, 176 opts.pk.column), 177 ( f.m2m_db_table(), f.m2m_reverse_name(), 178 f.rel.to._meta.db_table, f.rel.to._meta.pk.column) 179 ] 180 table_output.append(' %s (%s, %s)%s' % 181 (style.SQL_KEYWORD('UNIQUE'), 182 style.SQL_FIELD(qn(f.m2m_column_name())), 183 style.SQL_FIELD(qn(f.m2m_reverse_name())), 184 tablespace_sql)) 185 table_output.append(')') 186 if opts.db_tablespace and self.features.supports_tablespaces: 187 # f.db_tablespace is only for indices, so ignore its value here. 188 table_output.append(self.ops.tablespace_sql(opts.db_tablespace)) 189 table_output.append(';') 190 output.append('\n'.join(table_output)) 191 192 for r_table, r_col, table, col in deferred: 193 r_name = '%s_refs_%s_%x' % (r_col, col, 194 abs(hash((r_table, table)))) 195 output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % 196 (qn(r_table), 197 truncate_name(r_name, self.ops.max_name_length()), 198 qn(r_col), qn(table), qn(col), 199 self.ops.deferrable_sql())) 200 201 # Add any extra SQL needed to support auto-incrementing PKs 202 autoinc_sql = self.ops.autoinc_sql(f.m2m_db_table(), 'id') 203 if autoinc_sql: 204 for stmt in autoinc_sql: 205 output.append(stmt) 206 return output 207 208 def sql_indexes_for_model(self, model, style): 209 "Returns the CREATE INDEX SQL statements for a single model" 210 output = [] 211 for f in model._meta.local_fields: 212 output.extend(self.sql_indexes_for_field(model, f, style)) 213 return output 214 215 def sql_indexes_for_field(self, model, f, style): 216 "Return the CREATE INDEX SQL statements for a single model field" 217 if f.db_index and not f.unique: 218 qn = self.ops.quote_name 219 tablespace = f.db_tablespace or model._meta.db_tablespace 220 if tablespace and self.features.supports_tablespaces: 221 tablespace_sql = ' ' + self.ops.tablespace_sql(tablespace) 222 else: 223 tablespace_sql = '' 224 output = [style.SQL_KEYWORD('CREATE INDEX') + ' ' + 225 style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + 226 style.SQL_KEYWORD('ON') + ' ' + 227 style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + 228 "(%s)" % style.SQL_FIELD(qn(f.column)) + 229 "%s;" % tablespace_sql] 230 else: 231 output = [] 232 return output 233 234 def sql_destroy_model(self, model, references_to_delete, style): 235 "Return the DROP TABLE and restraint dropping statements for a single model" 236 # Drop the table now 237 qn = self.ops.quote_name 238 output = ['%s %s;' % (style.SQL_KEYWORD('DROP TABLE'), 239 style.SQL_TABLE(qn(model._meta.db_table)))] 240 if self.features.supports_constraints and model in references_to_delete: 241 for rel_class, f in references_to_delete[model]: 242 table = rel_class._meta.db_table 243 col = f.column 244 r_table = model._meta.db_table 245 r_col = model._meta.get_field(f.rel.field_name).column 246 r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table)))) 247 output.append('%s %s %s %s;' % \ 248 (style.SQL_KEYWORD('ALTER TABLE'), 249 style.SQL_TABLE(qn(table)), 250 style.SQL_KEYWORD(self.ops.drop_foreignkey_sql()), 251 style.SQL_FIELD(truncate_name(r_name, self.ops.max_name_length())))) 252 del references_to_delete[model] 253 if model._meta.has_auto_field: 254 ds = self.ops.drop_sequence_sql(model._meta.db_table) 255 if ds: 256 output.append(ds) 257 return output 258 259 def sql_destroy_many_to_many(self, model, f, style): 260 "Returns the DROP TABLE statements for a single m2m field" 261 qn = self.ops.quote_name 262 output = [] 263 if f.creates_table: 264 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'), 265 style.SQL_TABLE(qn(f.m2m_db_table())))) 266 ds = connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column)) 267 if ds: 268 output.append(ds) 269 return output 270 271 def create_test_db(self, verbosity=1, autoclobber=False): 272 """ 273 Creates a test database, prompting the user for confirmation if the 274 database already exists. Returns the name of the test database created. 275 """ 276 from django.db import connection 277 if verbosity >= 1: 278 print "Creating test database..." 279 280 test_database_name = self._create_test_db(connection, verbosity, autoclobber) 281 282 connection.close() 283 settings.DATABASE_NAME = test_database_name 284 285 call_command('syncdb', verbosity=verbosity, interactive=False) 286 287 if settings.CACHE_BACKEND.startswith('db://'): 288 cache_name = settings.CACHE_BACKEND[len('db://'):] 289 call_command('createcachetable', cache_name) 290 291 # Get a cursor (even though we don't need one yet). This has 292 # the side effect of initializing the test database. 293 cursor = connection.cursor() 294 295 return test_database_name 296 297 def _create_test_db(self, connection, verbosity, autoclobber): 298 suffix = self._creation_suffix() 299 300 if settings.TEST_DATABASE_NAME: 301 test_database_name = settings.TEST_DATABASE_NAME 302 else: 303 test_database_name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 304 305 qn = self.ops.quote_name 306 307 # Create the test database and connect to it. We need to autocommit 308 # if the database supports it because PostgreSQL doesn't allow 309 # CREATE/DROP DATABASE statements within transactions. 310 cursor = connection.cursor() 311 self._set_autocommit(connection) 312 try: 313 cursor.execute("CREATE DATABASE %s %s" % (qn(test_database_name), suffix)) 314 except Exception, e: 315 sys.stderr.write("Got an error creating the test database: %s\n" % e) 316 if not autoclobber: 317 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % test_database_name) 318 if autoclobber or confirm == 'yes': 319 try: 320 if verbosity >= 1: 321 print "Destroying old test database..." 322 cursor.execute("DROP DATABASE %s" % qn(test_database_name)) 323 if verbosity >= 1: 324 print "Creating test database..." 325 cursor.execute("CREATE DATABASE %s %s" % (qn(test_database_name), suffix)) 326 except Exception, e: 327 sys.stderr.write("Got an error recreating the test database: %s\n" % e) 328 sys.exit(2) 329 else: 330 print "Tests cancelled." 331 sys.exit(1) 332 333 return test_database_name 334 335 def destroy_test_db(self, old_database_name, verbosity=1): 336 """ 337 Destroy a test database, prompting the user for confirmation if the 338 database already exists. Returns the name of the test database created. 339 """ 340 from django.db import connection 341 if verbosity >= 1: 342 print "Destroying test database..." 343 connection.close() 344 test_database_name = settings.DATABASE_NAME 345 settings.DATABASE_NAME = old_database_name 346 347 self._destroy_test_db(connection, test_database_name, verbosity) 348 349 def _destroy_test_db(self, connection, test_database_name, verbosity): 350 # Remove the test database to clean up after 351 # ourselves. Connect to the previous database (not the test database) 352 # to do so, because it's not allowed to delete a database while being 353 # connected to it. 354 cursor = connection.cursor() 355 self._set_autocommit(connection) 356 time.sleep(1) # To avoid "database is being accessed by other users" errors. 357 cursor.execute("DROP DATABASE %s" % self.ops.quote_name(test_database_name)) 358 connection.close() 359 360 def _set_autocommit(self, connection): 361 "Make sure a connection is in autocommit mode." 362 if hasattr(connection.connection, "autocommit"): 363 if callable(connection.connection.autocommit): 364 connection.connection.autocommit(True) 365 else: 366 connection.connection.autocommit = True 367 elif hasattr(connection.connection, "set_isolation_level"): 368 connection.connection.set_isolation_level(0) 369 370 def _creation_suffix(self): 371 "SQL to append to the end of the test table creation statements" 372 return '' 373 -
django/db/backends/dummy/base.py
diff -r 187c638a7c24 django/db/backends/dummy/base.py
a b 8 8 """ 9 9 10 10 from django.core.exceptions import ImproperlyConfigured 11 from django.db.backends import BaseDatabaseFeatures, BaseDatabaseOperations 11 from django.db.backends import BaseDatabaseClient 12 from django.db.backends import BaseDatabaseFeatures 13 from django.db.backends import BaseDatabaseIntrospection 14 from django.db.backends import BaseDatabaseOperations 15 from django.db.backends import BaseDatabaseValidation 16 from django.db.backends.creation import BaseDatabaseCreation 12 17 13 18 def complain(*args, **kwargs): 14 19 raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet." … … 25 30 class DatabaseOperations(BaseDatabaseOperations): 26 31 quote_name = complain 27 32 33 class DatabaseClient(BaseDatabaseClient): 34 runshell = complain 35 36 class DatabaseCreation(BaseDatabaseCreation): 37 pass 38 39 class DatabaseIntrospection(BaseDatabaseIntrospection): 40 get_table_list = complain 41 get_table_description = complain 42 get_relations = complain 43 get_indexes = complain 44 45 class DatabaseValidation(BaseDatabaseValidation): 46 pass 47 28 48 class DatabaseWrapper(object): 29 49 features = BaseDatabaseFeatures() 30 50 ops = DatabaseOperations() 51 client = DatabaseClient() 52 creation = DatabaseCreation(ops, features) 53 introspection = DatabaseIntrospection() 54 validation = DatabaseValidation() 55 31 56 operators = {} 32 57 cursor = complain 33 58 _commit = complain -
django/db/backends/dummy/client.py
diff -r 187c638a7c24 django/db/backends/dummy/client.py
a b 1 from django.db.backends.dummy.base import complain2 3 runshell = complain -
django/db/backends/dummy/creation.py
diff -r 187c638a7c24 django/db/backends/dummy/creation.py
a b 1 DATA_TYPES = {} -
django/db/backends/dummy/introspection.py
diff -r 187c638a7c24 django/db/backends/dummy/introspection.py
a b 1 from django.db.backends.dummy.base import complain2 3 get_table_list = complain4 get_table_description = complain5 get_relations = complain6 get_indexes = complain7 8 DATA_TYPES_REVERSE = {} -
django/db/backends/mysql/base.py
diff -r 187c638a7c24 django/db/backends/mysql/base.py
a b 4 4 Requires MySQLdb: http://sourceforge.net/projects/mysql-python 5 5 """ 6 6 7 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 7 from django.db.backends import BaseDatabaseFeatures 8 from django.db.backends import BaseDatabaseOperations 9 from django.db.backends import BaseDatabaseWrapper 10 from django.db.backends import util 11 from django.db.backends.mysql.client import DatabaseClient 12 from django.db.backends.mysql.creation import DatabaseCreation 13 from django.db.backends.mysql.introspection import DatabaseIntrospection 14 from django.db.backends.mysql.validation import DatabaseValidation 15 8 16 try: 9 17 import MySQLdb as Database 10 18 except ImportError, e: … … 144 152 class DatabaseWrapper(BaseDatabaseWrapper): 145 153 features = DatabaseFeatures() 146 154 ops = DatabaseOperations() 155 client = DatabaseClient() 156 creation = DatabaseCreation(ops, features) 157 introspection = DatabaseIntrospection(ops) 158 validation = DatabaseValidation() 159 147 160 operators = { 148 161 'exact': '= BINARY %s', 149 162 'iexact': 'LIKE %s', -
django/db/backends/mysql/client.py
diff -r 187c638a7c24 django/db/backends/mysql/client.py
a b 1 from django.db.backends import BaseDatabaseClient 1 2 from django.conf import settings 2 3 import os 3 4 4 def runshell(): 5 args = [''] 6 db = settings.DATABASE_OPTIONS.get('db', settings.DATABASE_NAME) 7 user = settings.DATABASE_OPTIONS.get('user', settings.DATABASE_USER) 8 passwd = settings.DATABASE_OPTIONS.get('passwd', settings.DATABASE_PASSWORD) 9 host = settings.DATABASE_OPTIONS.get('host', settings.DATABASE_HOST) 10 port = settings.DATABASE_OPTIONS.get('port', settings.DATABASE_PORT) 11 defaults_file = settings.DATABASE_OPTIONS.get('read_default_file') 12 # Seems to be no good way to set sql_mode with CLI 5 class DatabaseClient(BaseDatabaseClient): 6 def runshell(self): 7 args = [''] 8 db = settings.DATABASE_OPTIONS.get('db', settings.DATABASE_NAME) 9 user = settings.DATABASE_OPTIONS.get('user', settings.DATABASE_USER) 10 passwd = settings.DATABASE_OPTIONS.get('passwd', settings.DATABASE_PASSWORD) 11 host = settings.DATABASE_OPTIONS.get('host', settings.DATABASE_HOST) 12 port = settings.DATABASE_OPTIONS.get('port', settings.DATABASE_PORT) 13 defaults_file = settings.DATABASE_OPTIONS.get('read_default_file') 14 # Seems to be no good way to set sql_mode with CLI 13 15 14 if defaults_file:15 args += ["--defaults-file=%s" % defaults_file]16 if user:17 args += ["--user=%s" % user]18 if passwd:19 args += ["--password=%s" % passwd]20 if host:21 args += ["--host=%s" % host]22 if port:23 args += ["--port=%s" % port]24 if db:25 args += [db]16 if defaults_file: 17 args += ["--defaults-file=%s" % defaults_file] 18 if user: 19 args += ["--user=%s" % user] 20 if passwd: 21 args += ["--password=%s" % passwd] 22 if host: 23 args += ["--host=%s" % host] 24 if port: 25 args += ["--port=%s" % port] 26 if db: 27 args += [db] 26 28 27 os.execvp('mysql', args)29 os.execvp('mysql', args) -
django/db/backends/mysql/creation.py
diff -r 187c638a7c24 django/db/backends/mysql/creation.py
a b 1 # This dictionary maps Field objects to their associated MySQL 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 DATA_TYPES = { 6 'AutoField': 'integer AUTO_INCREMENT', 7 'BooleanField': 'bool', 8 'CharField': 'varchar(%(max_length)s)', 9 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 10 'DateField': 'date', 11 'DateTimeField': 'datetime', 12 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 13 'FileField': 'varchar(%(max_length)s)', 14 'FilePathField': 'varchar(%(max_length)s)', 15 'FloatField': 'double precision', 16 'IntegerField': 'integer', 17 'IPAddressField': 'char(15)', 18 'NullBooleanField': 'bool', 19 'OneToOneField': 'integer', 20 'PhoneNumberField': 'varchar(20)', 21 'PositiveIntegerField': 'integer UNSIGNED', 22 'PositiveSmallIntegerField': 'smallint UNSIGNED', 23 'SlugField': 'varchar(%(max_length)s)', 24 'SmallIntegerField': 'smallint', 25 'TextField': 'longtext', 26 'TimeField': 'time', 27 'USStateField': 'varchar(2)', 28 } 1 from django.conf import settings 2 from django.db.backends.creation import BaseDatabaseCreation 3 4 class DatabaseCreation(BaseDatabaseCreation): 5 # This dictionary maps Field objects to their associated MySQL column 6 # types, as strings. Column-type strings can contain format strings; they'll 7 # be interpolated against the values of Field.__dict__ before being output. 8 # If a column type is set to None, it won't be included in the output. 9 data_types = { 10 'AutoField': 'integer AUTO_INCREMENT', 11 'BooleanField': 'bool', 12 'CharField': 'varchar(%(max_length)s)', 13 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 14 'DateField': 'date', 15 'DateTimeField': 'datetime', 16 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 17 'FileField': 'varchar(%(max_length)s)', 18 'FilePathField': 'varchar(%(max_length)s)', 19 'FloatField': 'double precision', 20 'IntegerField': 'integer', 21 'IPAddressField': 'char(15)', 22 'NullBooleanField': 'bool', 23 'OneToOneField': 'integer', 24 'PhoneNumberField': 'varchar(20)', 25 'PositiveIntegerField': 'integer UNSIGNED', 26 'PositiveSmallIntegerField': 'smallint UNSIGNED', 27 'SlugField': 'varchar(%(max_length)s)', 28 'SmallIntegerField': 'smallint', 29 'TextField': 'longtext', 30 'TimeField': 'time', 31 'USStateField': 'varchar(2)', 32 } 33 34 def _creation_suffix(self): 35 suffix = [] 36 if settings.TEST_DATABASE_CHARSET: 37 suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET) 38 if settings.TEST_DATABASE_COLLATION: 39 suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION) 40 return ' '.join(suffix) -
django/db/backends/mysql/introspection.py
diff -r 187c638a7c24 django/db/backends/mysql/introspection.py
a b 1 from django.db.backends .mysql.base import DatabaseOperations1 from django.db.backends import BaseDatabaseIntrospection 2 2 from MySQLdb import ProgrammingError, OperationalError 3 3 from MySQLdb.constants import FIELD_TYPE 4 4 import re 5 5 6 quote_name = DatabaseOperations().quote_name7 6 foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 8 7 9 def get_table_list(cursor): 10 "Returns a list of table names in the current database." 11 cursor.execute("SHOW TABLES") 12 return [row[0] for row in cursor.fetchall()] 8 class DatabaseIntrospection(BaseDatabaseIntrospection): 9 data_types_reverse = { 10 FIELD_TYPE.BLOB: 'TextField', 11 FIELD_TYPE.CHAR: 'CharField', 12 FIELD_TYPE.DECIMAL: 'DecimalField', 13 FIELD_TYPE.DATE: 'DateField', 14 FIELD_TYPE.DATETIME: 'DateTimeField', 15 FIELD_TYPE.DOUBLE: 'FloatField', 16 FIELD_TYPE.FLOAT: 'FloatField', 17 FIELD_TYPE.INT24: 'IntegerField', 18 FIELD_TYPE.LONG: 'IntegerField', 19 FIELD_TYPE.LONGLONG: 'IntegerField', 20 FIELD_TYPE.SHORT: 'IntegerField', 21 FIELD_TYPE.STRING: 'CharField', 22 FIELD_TYPE.TIMESTAMP: 'DateTimeField', 23 FIELD_TYPE.TINY: 'IntegerField', 24 FIELD_TYPE.TINY_BLOB: 'TextField', 25 FIELD_TYPE.MEDIUM_BLOB: 'TextField', 26 FIELD_TYPE.LONG_BLOB: 'TextField', 27 FIELD_TYPE.VAR_STRING: 'CharField', 28 } 13 29 14 def get_table_description(cursor, table_name): 15 "Returns a description of the table, with the DB-API cursor.description interface." 16 cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name)) 17 return cursor.description 30 def __init__(self, ops): 31 self.ops = ops 32 33 def get_table_list(self, cursor): 34 "Returns a list of table names in the current database." 35 cursor.execute("SHOW TABLES") 36 return [row[0] for row in cursor.fetchall()] 18 37 19 def _name_to_index(cursor, table_name): 20 """ 21 Returns a dictionary of {field_name: field_index} for the given table. 22 Indexes are 0-based. 23 """ 24 return dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name))]) 38 def get_table_description(self, cursor, table_name): 39 "Returns a description of the table, with the DB-API cursor.description interface." 40 cursor.execute("SELECT * FROM %s LIMIT 1" % self.ops.quote_name(table_name)) 41 return cursor.description 25 42 26 def get_relations(cursor, table_name): 27 """ 28 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 29 representing all relationships to the given table. Indexes are 0-based. 30 """ 31 my_field_dict = _name_to_index(cursor, table_name) 32 constraints = [] 33 relations = {} 34 try: 35 # This should work for MySQL 5.0. 36 cursor.execute(""" 37 SELECT column_name, referenced_table_name, referenced_column_name 38 FROM information_schema.key_column_usage 39 WHERE table_name = %s 40 AND table_schema = DATABASE() 41 AND referenced_table_name IS NOT NULL 42 AND referenced_column_name IS NOT NULL""", [table_name]) 43 constraints.extend(cursor.fetchall()) 44 except (ProgrammingError, OperationalError): 45 # Fall back to "SHOW CREATE TABLE", for previous MySQL versions. 46 # Go through all constraints and save the equal matches. 47 cursor.execute("SHOW CREATE TABLE %s" % quote_name(table_name)) 43 def _name_to_index(self, cursor, table_name): 44 """ 45 Returns a dictionary of {field_name: field_index} for the given table. 46 Indexes are 0-based. 47 """ 48 return dict([(d[0], i) for i, d in enumerate(self.get_table_description(cursor, table_name))]) 49 50 def get_relations(self, cursor, table_name): 51 """ 52 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 53 representing all relationships to the given table. Indexes are 0-based. 54 """ 55 my_field_dict = self._name_to_index(cursor, table_name) 56 constraints = [] 57 relations = {} 58 try: 59 # This should work for MySQL 5.0. 60 cursor.execute(""" 61 SELECT column_name, referenced_table_name, referenced_column_name 62 FROM information_schema.key_column_usage 63 WHERE table_name = %s 64 AND table_schema = DATABASE() 65 AND referenced_table_name IS NOT NULL 66 AND referenced_column_name IS NOT NULL""", [table_name]) 67 constraints.extend(cursor.fetchall()) 68 except (ProgrammingError, OperationalError): 69 # Fall back to "SHOW CREATE TABLE", for previous MySQL versions. 70 # Go through all constraints and save the equal matches. 71 cursor.execute("SHOW CREATE TABLE %s" % self.ops.quote_name(table_name)) 72 for row in cursor.fetchall(): 73 pos = 0 74 while True: 75 match = foreign_key_re.search(row[1], pos) 76 if match == None: 77 break 78 pos = match.end() 79 constraints.append(match.groups()) 80 81 for my_fieldname, other_table, other_field in constraints: 82 other_field_index = self._name_to_index(cursor, other_table)[other_field] 83 my_field_index = my_field_dict[my_fieldname] 84 relations[my_field_index] = (other_field_index, other_table) 85 86 return relations 87 88 def get_indexes(self, cursor, table_name): 89 """ 90 Returns a dictionary of fieldname -> infodict for the given table, 91 where each infodict is in the format: 92 {'primary_key': boolean representing whether it's the primary key, 93 'unique': boolean representing whether it's a unique index} 94 """ 95 cursor.execute("SHOW INDEX FROM %s" % self.ops.quote_name(table_name)) 96 indexes = {} 48 97 for row in cursor.fetchall(): 49 pos = 0 50 while True: 51 match = foreign_key_re.search(row[1], pos) 52 if match == None: 53 break 54 pos = match.end() 55 constraints.append(match.groups()) 98 indexes[row[4]] = {'primary_key': (row[2] == 'PRIMARY'), 'unique': not bool(row[1])} 99 return indexes 56 100 57 for my_fieldname, other_table, other_field in constraints:58 other_field_index = _name_to_index(cursor, other_table)[other_field]59 my_field_index = my_field_dict[my_fieldname]60 relations[my_field_index] = (other_field_index, other_table)61 62 return relations63 64 def get_indexes(cursor, table_name):65 """66 Returns a dictionary of fieldname -> infodict for the given table,67 where each infodict is in the format:68 {'primary_key': boolean representing whether it's the primary key,69 'unique': boolean representing whether it's a unique index}70 """71 cursor.execute("SHOW INDEX FROM %s" % quote_name(table_name))72 indexes = {}73 for row in cursor.fetchall():74 indexes[row[4]] = {'primary_key': (row[2] == 'PRIMARY'), 'unique': not bool(row[1])}75 return indexes76 77 DATA_TYPES_REVERSE = {78 FIELD_TYPE.BLOB: 'TextField',79 FIELD_TYPE.CHAR: 'CharField',80 FIELD_TYPE.DECIMAL: 'DecimalField',81 FIELD_TYPE.DATE: 'DateField',82 FIELD_TYPE.DATETIME: 'DateTimeField',83 FIELD_TYPE.DOUBLE: 'FloatField',84 FIELD_TYPE.FLOAT: 'FloatField',85 FIELD_TYPE.INT24: 'IntegerField',86 FIELD_TYPE.LONG: 'IntegerField',87 FIELD_TYPE.LONGLONG: 'IntegerField',88 FIELD_TYPE.SHORT: 'IntegerField',89 FIELD_TYPE.STRING: 'CharField',90 FIELD_TYPE.TIMESTAMP: 'DateTimeField',91 FIELD_TYPE.TINY: 'IntegerField',92 FIELD_TYPE.TINY_BLOB: 'TextField',93 FIELD_TYPE.MEDIUM_BLOB: 'TextField',94 FIELD_TYPE.LONG_BLOB: 'TextField',95 FIELD_TYPE.VAR_STRING: 'CharField',96 } -
django/db/backends/oracle/base.py
diff -r 187c638a7c24 django/db/backends/oracle/base.py
a b 8 8 import datetime 9 9 import time 10 10 11 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 11 from django.db.backends import BaseDatabaseFeatures 12 from django.db.backends import BaseDatabaseOperations 13 from django.db.backends import BaseDatabaseWrapper 14 from django.db.backends import BaseDatabaseValidation 15 from django.db.backends import util 12 16 from django.db.backends.oracle import query 17 from django.db.backends.oracle.client import DatabaseClient 18 from django.db.backends.oracle.creation import DatabaseCreation 19 from django.db.backends.oracle.introspection import DatabaseIntrospection 13 20 from django.utils.encoding import smart_str, force_unicode 14 21 15 22 # Oracle takes client-side character set encoding from the environment. … … 194 201 return [first % value, second % value] 195 202 196 203 204 class DatabaseValidation(BaseDatabaseValidation): 205 pass 197 206 198 207 class DatabaseWrapper(BaseDatabaseWrapper): 199 208 features = DatabaseFeatures() 200 209 ops = DatabaseOperations() 210 client = DatabaseClient() 211 creation = DatabaseCreation(ops, features) 212 introspection = DatabaseIntrospection(ops) 213 validation = DatabaseValidation() 214 201 215 operators = { 202 216 'exact': '= %s', 203 217 'iexact': '= UPPER(%s)', -
django/db/backends/oracle/client.py
diff -r 187c638a7c24 django/db/backends/oracle/client.py
a b 1 from django.db.backends import BaseDatabaseClient 1 2 from django.conf import settings 2 3 import os 3 4 4 def runshell(): 5 dsn = settings.DATABASE_USER 6 if settings.DATABASE_PASSWORD: 7 dsn += "/%s" % settings.DATABASE_PASSWORD 8 if settings.DATABASE_NAME: 9 dsn += "@%s" % settings.DATABASE_NAME 10 args = ["sqlplus", "-L", dsn] 11 os.execvp("sqlplus", args) 5 class DatabaseClient(BaseDatabaseClient): 6 def runshell(self): 7 dsn = settings.DATABASE_USER 8 if settings.DATABASE_PASSWORD: 9 dsn += "/%s" % settings.DATABASE_PASSWORD 10 if settings.DATABASE_NAME: 11 dsn += "@%s" % settings.DATABASE_NAME 12 args = ["sqlplus", "-L", dsn] 13 os.execvp("sqlplus", args) -
django/db/backends/oracle/creation.py
diff -r 187c638a7c24 django/db/backends/oracle/creation.py
a b 1 1 import sys, time 2 from django.conf import settings 2 3 from django.core import management 3 4 # This dictionary maps Field objects to their associated Oracle column 5 # types, as strings. Column-type strings can contain format strings; they'll 6 # be interpolated against the values of Field.__dict__ before being output. 7 # If a column type is set to None, it won't be included in the output. 8 # 9 # Any format strings starting with "qn_" are quoted before being used in the 10 # output (the "qn_" prefix is stripped before the lookup is performed. 11 12 DATA_TYPES = { 13 'AutoField': 'NUMBER(11)', 14 'BooleanField': 'NUMBER(1) CHECK (%(qn_column)s IN (0,1))', 15 'CharField': 'NVARCHAR2(%(max_length)s)', 16 'CommaSeparatedIntegerField': 'VARCHAR2(%(max_length)s)', 17 'DateField': 'DATE', 18 'DateTimeField': 'TIMESTAMP', 19 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)', 20 'FileField': 'NVARCHAR2(%(max_length)s)', 21 'FilePathField': 'NVARCHAR2(%(max_length)s)', 22 'FloatField': 'DOUBLE PRECISION', 23 'IntegerField': 'NUMBER(11)', 24 'IPAddressField': 'VARCHAR2(15)', 25 'NullBooleanField': 'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL))', 26 'OneToOneField': 'NUMBER(11)', 27 'PhoneNumberField': 'VARCHAR2(20)', 28 'PositiveIntegerField': 'NUMBER(11) CHECK (%(qn_column)s >= 0)', 29 'PositiveSmallIntegerField': 'NUMBER(11) CHECK (%(qn_column)s >= 0)', 30 'SlugField': 'NVARCHAR2(50)', 31 'SmallIntegerField': 'NUMBER(11)', 32 'TextField': 'NCLOB', 33 'TimeField': 'TIMESTAMP', 34 'URLField': 'VARCHAR2(%(max_length)s)', 35 'USStateField': 'CHAR(2)', 36 } 4 from django.db.backends.creation import BaseDatabaseCreation 37 5 38 6 TEST_DATABASE_PREFIX = 'test_' 39 7 PASSWORD = 'Im_a_lumberjack' 40 REMEMBER = {}41 8 42 def create_test_db(settings, connection, verbosity=1, autoclobber=False): 43 TEST_DATABASE_NAME = _test_database_name(settings) 44 TEST_DATABASE_USER = _test_database_user(settings) 45 TEST_DATABASE_PASSWD = _test_database_passwd(settings) 46 TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings) 47 TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings) 9 class DatabaseCreation(BaseDatabaseCreation): 10 # This dictionary maps Field objects to their associated Oracle column 11 # types, as strings. Column-type strings can contain format strings; they'll 12 # be interpolated against the values of Field.__dict__ before being output. 13 # If a column type is set to None, it won't be included in the output. 14 # 15 # Any format strings starting with "qn_" are quoted before being used in the 16 # output (the "qn_" prefix is stripped before the lookup is performed. 48 17 49 parameters = { 50 'dbname': TEST_DATABASE_NAME, 51 'user': TEST_DATABASE_USER, 52 'password': TEST_DATABASE_PASSWD, 53 'tblspace': TEST_DATABASE_TBLSPACE, 54 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, 55 } 18 data_types = { 19 'AutoField': 'NUMBER(11)', 20 'BooleanField': 'NUMBER(1) CHECK (%(qn_column)s IN (0,1))', 21 'CharField': 'NVARCHAR2(%(max_length)s)', 22 'CommaSeparatedIntegerField': 'VARCHAR2(%(max_length)s)', 23 'DateField': 'DATE', 24 'DateTimeField': 'TIMESTAMP', 25 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)', 26 'FileField': 'NVARCHAR2(%(max_length)s)', 27 'FilePathField': 'NVARCHAR2(%(max_length)s)', 28 'FloatField': 'DOUBLE PRECISION', 29 'IntegerField': 'NUMBER(11)', 30 'IPAddressField': 'VARCHAR2(15)', 31 'NullBooleanField': 'NUMBER(1) CHECK ((%(qn_column)s IN (0,1)) OR (%(qn_column)s IS NULL))', 32 'OneToOneField': 'NUMBER(11)', 33 'PhoneNumberField': 'VARCHAR2(20)', 34 'PositiveIntegerField': 'NUMBER(11) CHECK (%(qn_column)s >= 0)', 35 'PositiveSmallIntegerField': 'NUMBER(11) CHECK (%(qn_column)s >= 0)', 36 'SlugField': 'NVARCHAR2(50)', 37 'SmallIntegerField': 'NUMBER(11)', 38 'TextField': 'NCLOB', 39 'TimeField': 'TIMESTAMP', 40 'URLField': 'VARCHAR2(%(max_length)s)', 41 'USStateField': 'CHAR(2)', 42 } 43 44 def _create_test_db(self, connection, verbosity, autoclobber): 45 TEST_DATABASE_NAME = self._test_database_name(settings) 46 TEST_DATABASE_USER = self._test_database_user(settings) 47 TEST_DATABASE_PASSWD = self._test_database_passwd(settings) 48 TEST_DATABASE_TBLSPACE = self._test_database_tblspace(settings) 49 TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp(settings) 56 50 57 REMEMBER['user'] = settings.DATABASE_USER 58 REMEMBER['passwd'] = settings.DATABASE_PASSWORD 51 parameters = { 52 'dbname': TEST_DATABASE_NAME, 53 'user': TEST_DATABASE_USER, 54 'password': TEST_DATABASE_PASSWD, 55 'tblspace': TEST_DATABASE_TBLSPACE, 56 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, 57 } 59 58 60 cursor = connection.cursor() 61 if _test_database_create(settings): 62 if verbosity >= 1: 63 print 'Creating test database...' 59 self.remember['user'] = settings.DATABASE_USER 60 self.remember['passwd'] = settings.DATABASE_PASSWORD 61 62 cursor = connection.cursor() 63 if self._test_database_create(settings): 64 if verbosity >= 1: 65 print 'Creating test database...' 66 try: 67 self._execute_test_db_creation(cursor, parameters, verbosity) 68 except Exception, e: 69 sys.stderr.write("Got an error creating the test database: %s\n" % e) 70 if not autoclobber: 71 confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) 72 if autoclobber or confirm == 'yes': 73 try: 74 if verbosity >= 1: 75 print "Destroying old test database..." 76 self._execute_test_db_destruction(cursor, parameters, verbosity) 77 if verbosity >= 1: 78 print "Creating test database..." 79 self._execute_test_db_creation(cursor, parameters, verbosity) 80 except Exception, e: 81 sys.stderr.write("Got an error recreating the test database: %s\n" % e) 82 sys.exit(2) 83 else: 84 print "Tests cancelled." 85 sys.exit(1) 86 87 if self._test_user_create(settings): 88 if verbosity >= 1: 89 print "Creating test user..." 90 try: 91 self._create_test_user(cursor, parameters, verbosity) 92 except Exception, e: 93 sys.stderr.write("Got an error creating the test user: %s\n" % e) 94 if not autoclobber: 95 confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER) 96 if autoclobber or confirm == 'yes': 97 try: 98 if verbosity >= 1: 99 print "Destroying old test user..." 100 self._destroy_test_user(cursor, parameters, verbosity) 101 if verbosity >= 1: 102 print "Creating test user..." 103 self._create_test_user(cursor, parameters, verbosity) 104 except Exception, e: 105 sys.stderr.write("Got an error recreating the test user: %s\n" % e) 106 sys.exit(2) 107 else: 108 print "Tests cancelled." 109 sys.exit(1) 110 111 settings.DATABASE_USER = TEST_DATABASE_USER 112 settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD 113 114 return TEST_DATABASE_NAME 115 116 def _destroy_test_db(self, connection, test_database_name, verbosity=1): 117 """ 118 Destroy a test database, prompting the user for confirmation if the 119 database already exists. Returns the name of the test database created. 120 """ 121 TEST_DATABASE_NAME = self._test_database_name(settings) 122 TEST_DATABASE_USER = self._test_database_user(settings) 123 TEST_DATABASE_PASSWD = self._test_database_passwd(settings) 124 TEST_DATABASE_TBLSPACE = self._test_database_tblspace(settings) 125 TEST_DATABASE_TBLSPACE_TMP = self._test_database_tblspace_tmp(settings) 126 127 settings.DATABASE_USER = self.remember['user'] 128 settings.DATABASE_PASSWORD = self.remember['passwd'] 129 130 parameters = { 131 'dbname': TEST_DATABASE_NAME, 132 'user': TEST_DATABASE_USER, 133 'password': TEST_DATABASE_PASSWD, 134 'tblspace': TEST_DATABASE_TBLSPACE, 135 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, 136 } 137 138 self.remember['user'] = settings.DATABASE_USER 139 self.remember['passwd'] = settings.DATABASE_PASSWORD 140 141 cursor = connection.cursor() 142 time.sleep(1) # To avoid "database is being accessed by other users" errors. 143 if self._test_user_create(settings): 144 if verbosity >= 1: 145 print 'Destroying test user...' 146 self._destroy_test_user(cursor, parameters, verbosity) 147 if self._test_database_create(settings): 148 if verbosity >= 1: 149 print 'Destroying test database tables...' 150 self._execute_test_db_destruction(cursor, parameters, verbosity) 151 connection.close() 152 153 def _execute_test_db_creation(cursor, parameters, verbosity): 154 if verbosity >= 2: 155 print "_create_test_db(): dbname = %s" % parameters['dbname'] 156 statements = [ 157 """CREATE TABLESPACE %(tblspace)s 158 DATAFILE '%(tblspace)s.dbf' SIZE 20M 159 REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M 160 """, 161 """CREATE TEMPORARY TABLESPACE %(tblspace_temp)s 162 TEMPFILE '%(tblspace_temp)s.dbf' SIZE 20M 163 REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M 164 """, 165 ] 166 _execute_statements(cursor, statements, parameters, verbosity) 167 168 def _create_test_user(cursor, parameters, verbosity): 169 if verbosity >= 2: 170 print "_create_test_user(): username = %s" % parameters['user'] 171 statements = [ 172 """CREATE USER %(user)s 173 IDENTIFIED BY %(password)s 174 DEFAULT TABLESPACE %(tblspace)s 175 TEMPORARY TABLESPACE %(tblspace_temp)s 176 """, 177 """GRANT CONNECT, RESOURCE TO %(user)s""", 178 ] 179 _execute_statements(cursor, statements, parameters, verbosity) 180 181 def _execute_test_db_destruction(cursor, parameters, verbosity): 182 if verbosity >= 2: 183 print "_execute_test_db_destruction(): dbname=%s" % parameters['dbname'] 184 statements = [ 185 'DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 186 'DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 187 ] 188 _execute_statements(cursor, statements, parameters, verbosity) 189 190 def _destroy_test_user(cursor, parameters, verbosity): 191 if verbosity >= 2: 192 print "_destroy_test_user(): user=%s" % parameters['user'] 193 print "Be patient. This can take some time..." 194 statements = [ 195 'DROP USER %(user)s CASCADE', 196 ] 197 _execute_statements(cursor, statements, parameters, verbosity) 198 199 def _execute_statements(cursor, statements, parameters, verbosity): 200 for template in statements: 201 stmt = template % parameters 202 if verbosity >= 2: 203 print stmt 204 try: 205 cursor.execute(stmt) 206 except Exception, err: 207 sys.stderr.write("Failed (%s)\n" % (err)) 208 raise 209 210 def _test_database_name(settings): 211 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 64 212 try: 65 _create_test_db(cursor, parameters, verbosity) 66 except Exception, e: 67 sys.stderr.write("Got an error creating the test database: %s\n" % e) 68 if not autoclobber: 69 confirm = raw_input("It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_NAME) 70 if autoclobber or confirm == 'yes': 71 try: 72 if verbosity >= 1: 73 print "Destroying old test database..." 74 _destroy_test_db(cursor, parameters, verbosity) 75 if verbosity >= 1: 76 print "Creating test database..." 77 _create_test_db(cursor, parameters, verbosity) 78 except Exception, e: 79 sys.stderr.write("Got an error recreating the test database: %s\n" % e) 80 sys.exit(2) 213 if settings.TEST_DATABASE_NAME: 214 name = settings.TEST_DATABASE_NAME 215 except AttributeError: 216 pass 217 except: 218 raise 219 return name 220 221 def _test_database_create(settings): 222 name = True 223 try: 224 if settings.TEST_DATABASE_CREATE: 225 name = True 81 226 else: 82 print "Tests cancelled." 83 sys.exit(1) 227 name = False 228 except AttributeError: 229 pass 230 except: 231 raise 232 return name 84 233 85 if _test_user_create(settings): 86 if verbosity >= 1: 87 print "Creating test user..." 234 def _test_user_create(settings): 235 name = True 88 236 try: 89 _create_test_user(cursor, parameters, verbosity) 90 except Exception, e: 91 sys.stderr.write("Got an error creating the test user: %s\n" % e) 92 if not autoclobber: 93 confirm = raw_input("It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_DATABASE_USER) 94 if autoclobber or confirm == 'yes': 95 try: 96 if verbosity >= 1: 97 print "Destroying old test user..." 98 _destroy_test_user(cursor, parameters, verbosity) 99 if verbosity >= 1: 100 print "Creating test user..." 101 _create_test_user(cursor, parameters, verbosity) 102 except Exception, e: 103 sys.stderr.write("Got an error recreating the test user: %s\n" % e) 104 sys.exit(2) 237 if settings.TEST_USER_CREATE: 238 name = True 105 239 else: 106 print "Tests cancelled." 107 sys.exit(1) 240 name = False 241 except AttributeError: 242 pass 243 except: 244 raise 245 return name 108 246 109 connection.close() 110 settings.DATABASE_USER = TEST_DATABASE_USER 111 settings.DATABASE_PASSWORD = TEST_DATABASE_PASSWD 247 def _test_database_user(settings): 248 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 249 try: 250 if settings.TEST_DATABASE_USER: 251 name = settings.TEST_DATABASE_USER 252 except AttributeError: 253 pass 254 except: 255 raise 256 return name 112 257 113 management.call_command('syncdb', verbosity=verbosity, interactive=False) 258 def _test_database_passwd(settings): 259 name = PASSWORD 260 try: 261 if settings.TEST_DATABASE_PASSWD: 262 name = settings.TEST_DATABASE_PASSWD 263 except AttributeError: 264 pass 265 except: 266 raise 267 return name 114 268 115 # Get a cursor (even though we don't need one yet). This has 116 # the side effect of initializing the test database. 117 cursor = connection.cursor() 269 def _test_database_tblspace(settings): 270 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 271 try: 272 if settings.TEST_DATABASE_TBLSPACE: 273 name = settings.TEST_DATABASE_TBLSPACE 274 except AttributeError: 275 pass 276 except: 277 raise 278 return name 118 279 119 def destroy_test_db(settings, connection, old_database_name, verbosity=1): 120 connection.close() 121 122 TEST_DATABASE_NAME = _test_database_name(settings) 123 TEST_DATABASE_USER = _test_database_user(settings) 124 TEST_DATABASE_PASSWD = _test_database_passwd(settings) 125 TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings) 126 TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings) 127 128 settings.DATABASE_NAME = old_database_name 129 settings.DATABASE_USER = REMEMBER['user'] 130 settings.DATABASE_PASSWORD = REMEMBER['passwd'] 131 132 parameters = { 133 'dbname': TEST_DATABASE_NAME, 134 'user': TEST_DATABASE_USER, 135 'password': TEST_DATABASE_PASSWD, 136 'tblspace': TEST_DATABASE_TBLSPACE, 137 'tblspace_temp': TEST_DATABASE_TBLSPACE_TMP, 138 } 139 140 REMEMBER['user'] = settings.DATABASE_USER 141 REMEMBER['passwd'] = settings.DATABASE_PASSWORD 142 143 cursor = connection.cursor() 144 time.sleep(1) # To avoid "database is being accessed by other users" errors. 145 if _test_user_create(settings): 146 if verbosity >= 1: 147 print 'Destroying test user...' 148 _destroy_test_user(cursor, parameters, verbosity) 149 if _test_database_create(settings): 150 if verbosity >= 1: 151 print 'Destroying test database...' 152 _destroy_test_db(cursor, parameters, verbosity) 153 connection.close() 154 155 def _create_test_db(cursor, parameters, verbosity): 156 if verbosity >= 2: 157 print "_create_test_db(): dbname = %s" % parameters['dbname'] 158 statements = [ 159 """CREATE TABLESPACE %(tblspace)s 160 DATAFILE '%(tblspace)s.dbf' SIZE 20M 161 REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M 162 """, 163 """CREATE TEMPORARY TABLESPACE %(tblspace_temp)s 164 TEMPFILE '%(tblspace_temp)s.dbf' SIZE 20M 165 REUSE AUTOEXTEND ON NEXT 10M MAXSIZE 100M 166 """, 167 ] 168 _execute_statements(cursor, statements, parameters, verbosity) 169 170 def _create_test_user(cursor, parameters, verbosity): 171 if verbosity >= 2: 172 print "_create_test_user(): username = %s" % parameters['user'] 173 statements = [ 174 """CREATE USER %(user)s 175 IDENTIFIED BY %(password)s 176 DEFAULT TABLESPACE %(tblspace)s 177 TEMPORARY TABLESPACE %(tblspace_temp)s 178 """, 179 """GRANT CONNECT, RESOURCE TO %(user)s""", 180 ] 181 _execute_statements(cursor, statements, parameters, verbosity) 182 183 def _destroy_test_db(cursor, parameters, verbosity): 184 if verbosity >= 2: 185 print "_destroy_test_db(): dbname=%s" % parameters['dbname'] 186 statements = [ 187 'DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 188 'DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS', 189 ] 190 _execute_statements(cursor, statements, parameters, verbosity) 191 192 def _destroy_test_user(cursor, parameters, verbosity): 193 if verbosity >= 2: 194 print "_destroy_test_user(): user=%s" % parameters['user'] 195 print "Be patient. This can take some time..." 196 statements = [ 197 'DROP USER %(user)s CASCADE', 198 ] 199 _execute_statements(cursor, statements, parameters, verbosity) 200 201 def _execute_statements(cursor, statements, parameters, verbosity): 202 for template in statements: 203 stmt = template % parameters 204 if verbosity >= 2: 205 print stmt 280 def _test_database_tblspace_tmp(settings): 281 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp' 206 282 try: 207 cursor.execute(stmt) 208 except Exception, err: 209 sys.stderr.write("Failed (%s)\n" % (err)) 283 if settings.TEST_DATABASE_TBLSPACE_TMP: 284 name = settings.TEST_DATABASE_TBLSPACE_TMP 285 except AttributeError: 286 pass 287 except: 210 288 raise 211 212 def _test_database_name(settings): 213 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 214 try: 215 if settings.TEST_DATABASE_NAME: 216 name = settings.TEST_DATABASE_NAME 217 except AttributeError: 218 pass 219 except: 220 raise 221 return name 222 223 def _test_database_create(settings): 224 name = True 225 try: 226 if settings.TEST_DATABASE_CREATE: 227 name = True 228 else: 229 name = False 230 except AttributeError: 231 pass 232 except: 233 raise 234 return name 235 236 def _test_user_create(settings): 237 name = True 238 try: 239 if settings.TEST_USER_CREATE: 240 name = True 241 else: 242 name = False 243 except AttributeError: 244 pass 245 except: 246 raise 247 return name 248 249 def _test_database_user(settings): 250 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 251 try: 252 if settings.TEST_DATABASE_USER: 253 name = settings.TEST_DATABASE_USER 254 except AttributeError: 255 pass 256 except: 257 raise 258 return name 259 260 def _test_database_passwd(settings): 261 name = PASSWORD 262 try: 263 if settings.TEST_DATABASE_PASSWD: 264 name = settings.TEST_DATABASE_PASSWD 265 except AttributeError: 266 pass 267 except: 268 raise 269 return name 270 271 def _test_database_tblspace(settings): 272 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 273 try: 274 if settings.TEST_DATABASE_TBLSPACE: 275 name = settings.TEST_DATABASE_TBLSPACE 276 except AttributeError: 277 pass 278 except: 279 raise 280 return name 281 282 def _test_database_tblspace_tmp(settings): 283 name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME + '_temp' 284 try: 285 if settings.TEST_DATABASE_TBLSPACE_TMP: 286 name = settings.TEST_DATABASE_TBLSPACE_TMP 287 except AttributeError: 288 pass 289 except: 290 raise 291 return name 289 return name -
django/db/backends/oracle/introspection.py
diff -r 187c638a7c24 django/db/backends/oracle/introspection.py
a b 1 from django.db.backends.oracle.base import DatabaseOperations 1 from django.db.backends import BaseDatabaseIntrospection 2 import cx_Oracle 2 3 import re 3 import cx_Oracle4 4 5 quote_name = DatabaseOperations().quote_name6 5 foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 7 6 8 def get_table_list(cursor): 9 "Returns a list of table names in the current database." 10 cursor.execute("SELECT TABLE_NAME FROM USER_TABLES") 11 return [row[0].upper() for row in cursor.fetchall()] 7 class DatabaseIntrospection(BaseDatabaseIntrospection): 8 # Maps type objects to Django Field types. 9 data_types_reverse = { 10 cx_Oracle.CLOB: 'TextField', 11 cx_Oracle.DATETIME: 'DateTimeField', 12 cx_Oracle.FIXED_CHAR: 'CharField', 13 cx_Oracle.NCLOB: 'TextField', 14 cx_Oracle.NUMBER: 'DecimalField', 15 cx_Oracle.STRING: 'CharField', 16 cx_Oracle.TIMESTAMP: 'DateTimeField', 17 } 12 18 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 * FROM %s WHERE ROWNUM < 2" % quote_name(table_name)) 16 return cursor.description 19 def __init__(self, ops): 20 self.ops = ops 21 22 def get_table_list(self, cursor): 23 "Returns a list of table names in the current database." 24 cursor.execute("SELECT TABLE_NAME FROM USER_TABLES") 25 return [row[0].upper() for row in cursor.fetchall()] 17 26 18 def _name_to_index(cursor, table_name): 19 """ 20 Returns a dictionary of {field_name: field_index} for the given table. 21 Indexes are 0-based. 22 """ 23 return dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name))]) 27 def get_table_description(self, cursor, table_name): 28 "Returns a description of the table, with the DB-API cursor.description interface." 29 cursor.execute("SELECT * FROM %s WHERE ROWNUM < 2" % self.ops.quote_name(table_name)) 30 return cursor.description 24 31 25 def get_relations(cursor, table_name): 26 """ 27 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 28 representing all relationships to the given table. Indexes are 0-based. 29 """ 30 cursor.execute(""" 31 SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1 32 FROM user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb, 33 user_tab_cols ta, user_tab_cols tb 34 WHERE user_constraints.table_name = %s AND 35 ta.table_name = %s AND 36 ta.column_name = ca.column_name AND 37 ca.table_name = %s AND 38 user_constraints.constraint_name = ca.constraint_name AND 39 user_constraints.r_constraint_name = cb.constraint_name AND 40 cb.table_name = tb.table_name AND 41 cb.column_name = tb.column_name AND 42 ca.position = cb.position""", [table_name, table_name, table_name]) 32 def _name_to_index(self, cursor, table_name): 33 """ 34 Returns a dictionary of {field_name: field_index} for the given table. 35 Indexes are 0-based. 36 """ 37 return dict([(d[0], i) for i, d in enumerate(self.get_table_description(cursor, table_name))]) 43 38 44 relations = {} 45 for row in cursor.fetchall(): 46 relations[row[0]] = (row[2], row[1]) 47 return relations 39 def get_relations(self, cursor, table_name): 40 """ 41 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 42 representing all relationships to the given table. Indexes are 0-based. 43 """ 44 cursor.execute(""" 45 SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1 46 FROM user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb, 47 user_tab_cols ta, user_tab_cols tb 48 WHERE user_constraints.table_name = %s AND 49 ta.table_name = %s AND 50 ta.column_name = ca.column_name AND 51 ca.table_name = %s AND 52 user_constraints.constraint_name = ca.constraint_name AND 53 user_constraints.r_constraint_name = cb.constraint_name AND 54 cb.table_name = tb.table_name AND 55 cb.column_name = tb.column_name AND 56 ca.position = cb.position""", [table_name, table_name, table_name]) 48 57 49 def get_indexes(cursor, table_name): 50 """ 51 Returns a dictionary of fieldname -> infodict for the given table, 52 where each infodict is in the format: 53 {'primary_key': boolean representing whether it's the primary key, 54 'unique': boolean representing whether it's a unique index} 55 """ 56 # This query retrieves each index on the given table, including the 57 # first associated field name 58 # "We were in the nick of time; you were in great peril!" 59 sql = """ 60 WITH primarycols AS ( 61 SELECT user_cons_columns.table_name, user_cons_columns.column_name, 1 AS PRIMARYCOL 62 FROM user_cons_columns, user_constraints 63 WHERE user_cons_columns.constraint_name = user_constraints.constraint_name AND 64 user_constraints.constraint_type = 'P' AND 65 user_cons_columns.table_name = %s), 66 uniquecols AS ( 67 SELECT user_ind_columns.table_name, user_ind_columns.column_name, 1 AS UNIQUECOL 68 FROM user_indexes, user_ind_columns 69 WHERE uniqueness = 'UNIQUE' AND 70 user_indexes.index_name = user_ind_columns.index_name AND 71 user_ind_columns.table_name = %s) 72 SELECT allcols.column_name, primarycols.primarycol, uniquecols.UNIQUECOL 73 FROM (SELECT column_name FROM primarycols UNION SELECT column_name FROM 74 uniquecols) allcols, 75 primarycols, uniquecols 76 WHERE allcols.column_name = primarycols.column_name (+) AND 77 allcols.column_name = uniquecols.column_name (+) 78 """ 79 cursor.execute(sql, [table_name, table_name]) 80 indexes = {} 81 for row in cursor.fetchall(): 82 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 83 # a string of space-separated integers. This designates the field 84 # indexes (1-based) of the fields that have indexes on the table. 85 # Here, we skip any indexes across multiple fields. 86 indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]} 87 return indexes 58 relations = {} 59 for row in cursor.fetchall(): 60 relations[row[0]] = (row[2], row[1]) 61 return relations 88 62 89 # Maps type objects to Django Field types. 90 DATA_TYPES_REVERSE = { 91 cx_Oracle.CLOB: 'TextField', 92 cx_Oracle.DATETIME: 'DateTimeField', 93 cx_Oracle.FIXED_CHAR: 'CharField', 94 cx_Oracle.NCLOB: 'TextField', 95 cx_Oracle.NUMBER: 'DecimalField', 96 cx_Oracle.STRING: 'CharField', 97 cx_Oracle.TIMESTAMP: 'DateTimeField', 98 } 63 def get_indexes(self, cursor, table_name): 64 """ 65 Returns a dictionary of fieldname -> infodict for the given table, 66 where each infodict is in the format: 67 {'primary_key': boolean representing whether it's the primary key, 68 'unique': boolean representing whether it's a unique index} 69 """ 70 # This query retrieves each index on the given table, including the 71 # first associated field name 72 # "We were in the nick of time; you were in great peril!" 73 sql = """ 74 WITH primarycols AS ( 75 SELECT user_cons_columns.table_name, user_cons_columns.column_name, 1 AS PRIMARYCOL 76 FROM user_cons_columns, user_constraints 77 WHERE user_cons_columns.constraint_name = user_constraints.constraint_name AND 78 user_constraints.constraint_type = 'P' AND 79 user_cons_columns.table_name = %s), 80 uniquecols AS ( 81 SELECT user_ind_columns.table_name, user_ind_columns.column_name, 1 AS UNIQUECOL 82 FROM user_indexes, user_ind_columns 83 WHERE uniqueness = 'UNIQUE' AND 84 user_indexes.index_name = user_ind_columns.index_name AND 85 user_ind_columns.table_name = %s) 86 SELECT allcols.column_name, primarycols.primarycol, uniquecols.UNIQUECOL 87 FROM (SELECT column_name FROM primarycols UNION SELECT column_name FROM 88 uniquecols) allcols, 89 primarycols, uniquecols 90 WHERE allcols.column_name = primarycols.column_name (+) AND 91 allcols.column_name = uniquecols.column_name (+) 92 """ 93 cursor.execute(sql, [table_name, table_name]) 94 indexes = {} 95 for row in cursor.fetchall(): 96 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 97 # a string of space-separated integers. This designates the field 98 # indexes (1-based) of the fields that have indexes on the table. 99 # Here, we skip any indexes across multiple fields. 100 indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]} 101 return indexes 102 -
django/db/backends/postgresql/base.py
diff -r 187c638a7c24 django/db/backends/postgresql/base.py
a b 4 4 Requires psycopg 1: http://initd.org/projects/psycopg1 5 5 """ 6 6 7 from django.db.backends import BaseDatabaseFeatures 8 from django.db.backends import BaseDatabaseValidation 9 from django.db.backends import BaseDatabaseWrapper 10 from django.db.backends import util 11 from django.db.backends.postgresql.client import DatabaseClient 12 from django.db.backends.postgresql.creation import DatabaseCreation 13 from django.db.backends.postgresql.introspection import DatabaseIntrospection 14 from django.db.backends.postgresql.operations import DatabaseOperations 7 15 from django.utils.encoding import smart_str, smart_unicode 8 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, util 9 from django.db.backends.postgresql.operations import DatabaseOperations 16 10 17 try: 11 18 import psycopg as Database 12 19 except ImportError, e: … … 62 69 class DatabaseFeatures(BaseDatabaseFeatures): 63 70 pass # This backend uses all the defaults. 64 71 72 class DatabaseValidation(BaseDatabaseValidation): 73 pass 74 65 75 class DatabaseWrapper(BaseDatabaseWrapper): 66 76 features = DatabaseFeatures() 67 77 ops = DatabaseOperations() 78 client = DatabaseClient() 79 creation = DatabaseCreation(ops, features) 80 introspection = DatabaseIntrospection(ops) 81 validation = DatabaseValidation() 82 68 83 operators = { 69 84 'exact': '= %s', 70 85 'iexact': 'ILIKE %s', -
django/db/backends/postgresql/client.py
diff -r 187c638a7c24 django/db/backends/postgresql/client.py
a b 1 from django.db.backends import BaseDatabaseClient 1 2 from django.conf import settings 2 3 import os 3 4 4 def runshell(): 5 args = ['psql'] 6 if settings.DATABASE_USER: 7 args += ["-U", settings.DATABASE_USER] 8 if settings.DATABASE_PASSWORD: 9 args += ["-W"] 10 if settings.DATABASE_HOST: 11 args.extend(["-h", settings.DATABASE_HOST]) 12 if settings.DATABASE_PORT: 13 args.extend(["-p", str(settings.DATABASE_PORT)]) 14 args += [settings.DATABASE_NAME] 15 os.execvp('psql', args) 5 class DatabaseClient(BaseDatabaseClient): 6 def runshell(self): 7 args = ['psql'] 8 if settings.DATABASE_USER: 9 args += ["-U", settings.DATABASE_USER] 10 if settings.DATABASE_PASSWORD: 11 args += ["-W"] 12 if settings.DATABASE_HOST: 13 args.extend(["-h", settings.DATABASE_HOST]) 14 if settings.DATABASE_PORT: 15 args.extend(["-p", str(settings.DATABASE_PORT)]) 16 args += [settings.DATABASE_NAME] 17 os.execvp('psql', args) -
django/db/backends/postgresql/creation.py
diff -r 187c638a7c24 django/db/backends/postgresql/creation.py
a b 1 # This dictionary maps Field objects to their associated PostgreSQL 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 DATA_TYPES = { 6 'AutoField': 'serial', 7 'BooleanField': 'boolean', 8 'CharField': 'varchar(%(max_length)s)', 9 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 10 'DateField': 'date', 11 'DateTimeField': 'timestamp with time zone', 12 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 13 'FileField': 'varchar(%(max_length)s)', 14 'FilePathField': 'varchar(%(max_length)s)', 15 'FloatField': 'double precision', 16 'IntegerField': 'integer', 17 'IPAddressField': 'inet', 18 'NullBooleanField': 'boolean', 19 'OneToOneField': 'integer', 20 'PhoneNumberField': 'varchar(20)', 21 'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)', 22 'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)', 23 'SlugField': 'varchar(%(max_length)s)', 24 'SmallIntegerField': 'smallint', 25 'TextField': 'text', 26 'TimeField': 'time', 27 'USStateField': 'varchar(2)', 28 } 1 from django.conf import settings 2 from django.db.backends.creation import BaseDatabaseCreation 3 4 class DatabaseCreation(BaseDatabaseCreation): 5 # This dictionary maps Field objects to their associated PostgreSQL column 6 # types, as strings. Column-type strings can contain format strings; they'll 7 # be interpolated against the values of Field.__dict__ before being output. 8 # If a column type is set to None, it won't be included in the output. 9 data_types = { 10 'AutoField': 'serial', 11 'BooleanField': 'boolean', 12 'CharField': 'varchar(%(max_length)s)', 13 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 14 'DateField': 'date', 15 'DateTimeField': 'timestamp with time zone', 16 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 17 'FileField': 'varchar(%(max_length)s)', 18 'FilePathField': 'varchar(%(max_length)s)', 19 'FloatField': 'double precision', 20 'IntegerField': 'integer', 21 'IPAddressField': 'inet', 22 'NullBooleanField': 'boolean', 23 'OneToOneField': 'integer', 24 'PhoneNumberField': 'varchar(20)', 25 'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)', 26 'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)', 27 'SlugField': 'varchar(%(max_length)s)', 28 'SmallIntegerField': 'smallint', 29 'TextField': 'text', 30 'TimeField': 'time', 31 'USStateField': 'varchar(2)', 32 } 33 34 def _creation_suffix(self): 35 assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time." 36 if settings.TEST_DATABASE_CHARSET: 37 return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET 38 return '' -
django/db/backends/postgresql/introspection.py
diff -r 187c638a7c24 django/db/backends/postgresql/introspection.py
a b 1 from django.db.backends .postgresql.base import DatabaseOperations1 from django.db.backends import BaseDatabaseIntrospection 2 2 3 quote_name = DatabaseOperations().quote_name 3 class DatabaseIntrospection(BaseDatabaseIntrospection): 4 # Maps type codes to Django Field types. 5 data_types_reverse = { 6 16: 'BooleanField', 7 21: 'SmallIntegerField', 8 23: 'IntegerField', 9 25: 'TextField', 10 701: 'FloatField', 11 869: 'IPAddressField', 12 1043: 'CharField', 13 1082: 'DateField', 14 1083: 'TimeField', 15 1114: 'DateTimeField', 16 1184: 'DateTimeField', 17 1266: 'TimeField', 18 1700: 'DecimalField', 19 } 20 21 def __init__(self, ops): 22 self.ops = ops 23 24 def get_table_list(self, cursor): 25 "Returns a list of table names in the current database." 26 cursor.execute(""" 27 SELECT c.relname 28 FROM pg_catalog.pg_class c 29 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 30 WHERE c.relkind IN ('r', 'v', '') 31 AND n.nspname NOT IN ('pg_catalog', 'pg_toast') 32 AND pg_catalog.pg_table_is_visible(c.oid)""") 33 return [row[0] for row in cursor.fetchall()] 4 34 5 def get_table_list(cursor): 6 "Returns a list of table names in the current database." 7 cursor.execute(""" 8 SELECT c.relname 9 FROM pg_catalog.pg_class c 10 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 11 WHERE c.relkind IN ('r', 'v', '') 12 AND n.nspname NOT IN ('pg_catalog', 'pg_toast') 13 AND pg_catalog.pg_table_is_visible(c.oid)""") 14 return [row[0] for row in cursor.fetchall()] 35 def get_table_description(self, cursor, table_name): 36 "Returns a description of the table, with the DB-API cursor.description interface." 37 cursor.execute("SELECT * FROM %s LIMIT 1" % self.ops.quote_name(table_name)) 38 return cursor.description 15 39 16 def get_table_description(cursor, table_name): 17 "Returns a description of the table, with the DB-API cursor.description interface." 18 cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name)) 19 return cursor.description 40 def get_relations(self, cursor, table_name): 41 """ 42 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 43 representing all relationships to the given table. Indexes are 0-based. 44 """ 45 cursor.execute(""" 46 SELECT con.conkey, con.confkey, c2.relname 47 FROM pg_constraint con, pg_class c1, pg_class c2 48 WHERE c1.oid = con.conrelid 49 AND c2.oid = con.confrelid 50 AND c1.relname = %s 51 AND con.contype = 'f'""", [table_name]) 52 relations = {} 53 for row in cursor.fetchall(): 54 try: 55 # row[0] and row[1] are like "{2}", so strip the curly braces. 56 relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2]) 57 except ValueError: 58 continue 59 return relations 20 60 21 def get_relations(cursor, table_name): 22 """ 23 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 24 representing all relationships to the given table. Indexes are 0-based. 25 """ 26 cursor.execute(""" 27 SELECT con.conkey, con.confkey, c2.relname 28 FROM pg_constraint con, pg_class c1, pg_class c2 29 WHERE c1.oid = con.conrelid 30 AND c2.oid = con.confrelid 31 AND c1.relname = %s 32 AND con.contype = 'f'""", [table_name]) 33 relations = {} 34 for row in cursor.fetchall(): 35 try: 36 # row[0] and row[1] are like "{2}", so strip the curly braces. 37 relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2]) 38 except ValueError: 39 continue 40 return relations 61 def get_indexes(self, cursor, table_name): 62 """ 63 Returns a dictionary of fieldname -> infodict for the given table, 64 where each infodict is in the format: 65 {'primary_key': boolean representing whether it's the primary key, 66 'unique': boolean representing whether it's a unique index} 67 """ 68 # This query retrieves each index on the given table, including the 69 # first associated field name 70 cursor.execute(""" 71 SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary 72 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, 73 pg_catalog.pg_index idx, pg_catalog.pg_attribute attr 74 WHERE c.oid = idx.indrelid 75 AND idx.indexrelid = c2.oid 76 AND attr.attrelid = c.oid 77 AND attr.attnum = idx.indkey[0] 78 AND c.relname = %s""", [table_name]) 79 indexes = {} 80 for row in cursor.fetchall(): 81 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 82 # a string of space-separated integers. This designates the field 83 # indexes (1-based) of the fields that have indexes on the table. 84 # Here, we skip any indexes across multiple fields. 85 if ' ' in row[1]: 86 continue 87 indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]} 88 return indexes 41 89 42 def get_indexes(cursor, table_name):43 """44 Returns a dictionary of fieldname -> infodict for the given table,45 where each infodict is in the format:46 {'primary_key': boolean representing whether it's the primary key,47 'unique': boolean representing whether it's a unique index}48 """49 # This query retrieves each index on the given table, including the50 # first associated field name51 cursor.execute("""52 SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary53 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,54 pg_catalog.pg_index idx, pg_catalog.pg_attribute attr55 WHERE c.oid = idx.indrelid56 AND idx.indexrelid = c2.oid57 AND attr.attrelid = c.oid58 AND attr.attnum = idx.indkey[0]59 AND c.relname = %s""", [table_name])60 indexes = {}61 for row in cursor.fetchall():62 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as63 # a string of space-separated integers. This designates the field64 # indexes (1-based) of the fields that have indexes on the table.65 # Here, we skip any indexes across multiple fields.66 if ' ' in row[1]:67 continue68 indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}69 return indexes70 71 # Maps type codes to Django Field types.72 DATA_TYPES_REVERSE = {73 16: 'BooleanField',74 21: 'SmallIntegerField',75 23: 'IntegerField',76 25: 'TextField',77 701: 'FloatField',78 869: 'IPAddressField',79 1043: 'CharField',80 1082: 'DateField',81 1083: 'TimeField',82 1114: 'DateTimeField',83 1184: 'DateTimeField',84 1266: 'TimeField',85 1700: 'DecimalField',86 } -
django/db/backends/postgresql_psycopg2/base.py
diff -r 187c638a7c24 django/db/backends/postgresql_psycopg2/base.py
a b 4 4 Requires psycopg 2: http://initd.org/projects/psycopg2 5 5 """ 6 6 7 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures 7 from django.db.backends import BaseDatabaseFeatures 8 from django.db.backends import BaseDatabaseValidation 9 from django.db.backends import BaseDatabaseWrapper 8 10 from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations 11 from django.db.backends.postgresql.client import DatabaseClient 12 from django.db.backends.postgresql.creation import DatabaseCreation 13 from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection 14 9 15 from django.utils.safestring import SafeUnicode 10 16 try: 11 17 import psycopg2 as Database … … 30 36 # http://www.initd.org/tracker/psycopg/wiki/psycopg2_documentation#postgresql-status-message-and-executed-query 31 37 return cursor.query 32 38 39 class DatabaseValidation(BaseDatabaseValidation): 40 pass 41 33 42 class DatabaseWrapper(BaseDatabaseWrapper): 34 43 features = DatabaseFeatures() 35 44 ops = DatabaseOperations() 45 client = DatabaseClient() 46 creation = DatabaseCreation(ops, features) 47 introspection = DatabaseIntrospection(ops) 48 validation = DatabaseValidation() 49 36 50 operators = { 37 51 'exact': '= %s', 38 52 'iexact': 'ILIKE %s', -
django/db/backends/postgresql_psycopg2/client.py
diff -r 187c638a7c24 django/db/backends/postgresql_psycopg2/client.py
a b 1 from django.db.backends.postgresql.client import * -
django/db/backends/postgresql_psycopg2/creation.py
diff -r 187c638a7c24 django/db/backends/postgresql_psycopg2/creation.py
a b 1 from django.db.backends.postgresql.creation import * -
django/db/backends/postgresql_psycopg2/introspection.py
diff -r 187c638a7c24 django/db/backends/postgresql_psycopg2/introspection.py
a b 1 from django.db.backends.postgresql _psycopg2.base import DatabaseOperations1 from django.db.backends.postgresql.introspection import DatabaseIntrospection as PostgresDatabaseIntrospection 2 2 3 quote_name = DatabaseOperations().quote_name 3 class DatabaseIntrospection(PostgresDatabaseIntrospection): 4 4 5 def get_table_list(cursor): 6 "Returns a list of table names in the current database." 7 cursor.execute(""" 8 SELECT c.relname 9 FROM pg_catalog.pg_class c 10 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace 11 WHERE c.relkind IN ('r', 'v', '') 12 AND n.nspname NOT IN ('pg_catalog', 'pg_toast') 13 AND pg_catalog.pg_table_is_visible(c.oid)""") 14 return [row[0] for row in cursor.fetchall()] 15 16 def get_table_description(cursor, table_name): 17 "Returns a description of the table, with the DB-API cursor.description interface." 18 cursor.execute("SELECT * FROM %s LIMIT 1" % quote_name(table_name)) 19 return cursor.description 20 21 def get_relations(cursor, table_name): 22 """ 23 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 24 representing all relationships to the given table. Indexes are 0-based. 25 """ 26 cursor.execute(""" 27 SELECT con.conkey, con.confkey, c2.relname 28 FROM pg_constraint con, pg_class c1, pg_class c2 29 WHERE c1.oid = con.conrelid 30 AND c2.oid = con.confrelid 31 AND c1.relname = %s 32 AND con.contype = 'f'""", [table_name]) 33 relations = {} 34 for row in cursor.fetchall(): 35 # row[0] and row[1] are single-item lists, so grab the single item. 36 relations[row[0][0] - 1] = (row[1][0] - 1, row[2]) 37 return relations 38 39 def get_indexes(cursor, table_name): 40 """ 41 Returns a dictionary of fieldname -> infodict for the given table, 42 where each infodict is in the format: 43 {'primary_key': boolean representing whether it's the primary key, 44 'unique': boolean representing whether it's a unique index} 45 """ 46 # This query retrieves each index on the given table, including the 47 # first associated field name 48 cursor.execute(""" 49 SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary 50 FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, 51 pg_catalog.pg_index idx, pg_catalog.pg_attribute attr 52 WHERE c.oid = idx.indrelid 53 AND idx.indexrelid = c2.oid 54 AND attr.attrelid = c.oid 55 AND attr.attnum = idx.indkey[0] 56 AND c.relname = %s""", [table_name]) 57 indexes = {} 58 for row in cursor.fetchall(): 59 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 60 # a string of space-separated integers. This designates the field 61 # indexes (1-based) of the fields that have indexes on the table. 62 # Here, we skip any indexes across multiple fields. 63 if ' ' in row[1]: 64 continue 65 indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]} 66 return indexes 67 68 # Maps type codes to Django Field types. 69 DATA_TYPES_REVERSE = { 70 16: 'BooleanField', 71 21: 'SmallIntegerField', 72 23: 'IntegerField', 73 25: 'TextField', 74 701: 'FloatField', 75 869: 'IPAddressField', 76 1043: 'CharField', 77 1082: 'DateField', 78 1083: 'TimeField', 79 1114: 'DateTimeField', 80 1184: 'DateTimeField', 81 1266: 'TimeField', 82 1700: 'DecimalField', 83 } 5 def get_relations(self, cursor, table_name): 6 """ 7 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 8 representing all relationships to the given table. Indexes are 0-based. 9 """ 10 cursor.execute(""" 11 SELECT con.conkey, con.confkey, c2.relname 12 FROM pg_constraint con, pg_class c1, pg_class c2 13 WHERE c1.oid = con.conrelid 14 AND c2.oid = con.confrelid 15 AND c1.relname = %s 16 AND con.contype = 'f'""", [table_name]) 17 relations = {} 18 for row in cursor.fetchall(): 19 # row[0] and row[1] are single-item lists, so grab the single item. 20 relations[row[0][0] - 1] = (row[1][0] - 1, row[2]) 21 return relations -
django/db/backends/sqlite3/base.py
diff -r 187c638a7c24 django/db/backends/sqlite3/base.py
a b 6 6 Python 2.5 and later use the sqlite3 module in the standard library. 7 7 """ 8 8 9 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 9 from django.db.backends import BaseDatabaseWrapper 10 from django.db.backends import BaseDatabaseFeatures 11 from django.db.backends import BaseDatabaseOperations 12 from django.db.backends import BaseDatabaseValidation 13 from django.db.backends import util 14 from django.db.backends.sqlite3.client import DatabaseClient 15 from django.db.backends.sqlite3.creation import DatabaseCreation 16 from django.db.backends.sqlite3.introspection import DatabaseIntrospection 17 10 18 try: 11 19 try: 12 20 from sqlite3 import dbapi2 as Database … … 89 97 second = '%s-12-31 23:59:59.999999' 90 98 return [first % value, second % value] 91 99 100 class DatabaseValidation(BaseDatabaseValidation): 101 pass 92 102 93 103 class DatabaseWrapper(BaseDatabaseWrapper): 94 104 features = DatabaseFeatures() 95 105 ops = DatabaseOperations() 96 106 client = DatabaseClient() 107 creation = DatabaseCreation(ops, features) 108 introspection = DatabaseIntrospection(ops) 109 validation = DatabaseValidation() 110 97 111 # SQLite requires LIKE statements to include an ESCAPE clause if the value 98 112 # being escaped has a percent or underscore in it. 99 113 # See http://www.sqlite.org/lang_expr.html for an explanation. -
django/db/backends/sqlite3/client.py
diff -r 187c638a7c24 django/db/backends/sqlite3/client.py
a b 1 from django.db.backends import BaseDatabaseClient 1 2 from django.conf import settings 2 3 import os 3 4 4 def runshell(): 5 args = ['', settings.DATABASE_NAME] 6 os.execvp('sqlite3', args) 5 class DatabaseClient(BaseDatabaseClient): 6 def runshell(self): 7 args = ['', settings.DATABASE_NAME] 8 os.execvp('sqlite3', args) -
django/db/backends/sqlite3/creation.py
diff -r 187c638a7c24 django/db/backends/sqlite3/creation.py
a b 1 # SQLite doesn't actually support most of these types, but it "does the right 2 # thing" given more verbose field definitions, so leave them as is so that 3 # schema inspection is more useful. 4 DATA_TYPES = { 5 'AutoField': 'integer', 6 'BooleanField': 'bool', 7 'CharField': 'varchar(%(max_length)s)', 8 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 9 'DateField': 'date', 10 'DateTimeField': 'datetime', 11 'DecimalField': 'decimal', 12 'FileField': 'varchar(%(max_length)s)', 13 'FilePathField': 'varchar(%(max_length)s)', 14 'FloatField': 'real', 15 'IntegerField': 'integer', 16 'IPAddressField': 'char(15)', 17 'NullBooleanField': 'bool', 18 'OneToOneField': 'integer', 19 'PhoneNumberField': 'varchar(20)', 20 'PositiveIntegerField': 'integer unsigned', 21 'PositiveSmallIntegerField': 'smallint unsigned', 22 'SlugField': 'varchar(%(max_length)s)', 23 'SmallIntegerField': 'smallint', 24 'TextField': 'text', 25 'TimeField': 'time', 26 'USStateField': 'varchar(2)', 27 } 1 import os 2 import sys 3 from django.conf import settings 4 from django.db.backends.creation import BaseDatabaseCreation 5 6 class DatabaseCreation(BaseDatabaseCreation): 7 # SQLite doesn't actually support most of these types, but it "does the right 8 # thing" given more verbose field definitions, so leave them as is so that 9 # schema inspection is more useful. 10 data_types = { 11 'AutoField': 'integer', 12 'BooleanField': 'bool', 13 'CharField': 'varchar(%(max_length)s)', 14 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 15 'DateField': 'date', 16 'DateTimeField': 'datetime', 17 'DecimalField': 'decimal', 18 'FileField': 'varchar(%(max_length)s)', 19 'FilePathField': 'varchar(%(max_length)s)', 20 'FloatField': 'real', 21 'IntegerField': 'integer', 22 'IPAddressField': 'char(15)', 23 'NullBooleanField': 'bool', 24 'OneToOneField': 'integer', 25 'PhoneNumberField': 'varchar(20)', 26 'PositiveIntegerField': 'integer unsigned', 27 'PositiveSmallIntegerField': 'smallint unsigned', 28 'SlugField': 'varchar(%(max_length)s)', 29 'SmallIntegerField': 'smallint', 30 'TextField': 'text', 31 'TimeField': 'time', 32 'USStateField': 'varchar(2)', 33 } 34 35 def _create_test_db(self, connection, verbosity, autoclobber): 36 if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:": 37 test_database_name = settings.TEST_DATABASE_NAME 38 # Erase the old test database 39 if verbosity >= 1: 40 print "Destroying old test database..." 41 if os.access(test_database_name, os.F_OK): 42 if not autoclobber: 43 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % test_database_name) 44 if autoclobber or confirm == 'yes': 45 try: 46 if verbosity >= 1: 47 print "Destroying old test database..." 48 os.remove(test_database_name) 49 except Exception, e: 50 sys.stderr.write("Got an error deleting the old test database: %s\n" % e) 51 sys.exit(2) 52 else: 53 print "Tests cancelled." 54 sys.exit(1) 55 if verbosity >= 1: 56 print "Creating test database..." 57 else: 58 test_database_name = ":memory:" 59 return test_database_name 60 61 def _destroy_test_db(self, connection, test_database_name, verbosity): 62 if test_database_name and test_database_name != ":memory:": 63 # Remove the SQLite database file 64 os.remove(test_database_name) 65 66 No newline at end of file -
django/db/backends/sqlite3/introspection.py
diff -r 187c638a7c24 django/db/backends/sqlite3/introspection.py
a b 1 from django.db.backends.sqlite3.base import DatabaseOperations 2 3 quote_name = DatabaseOperations().quote_name 4 5 def get_table_list(cursor): 6 "Returns a list of table names in the current database." 7 # Skip the sqlite_sequence system table used for autoincrement key 8 # generation. 9 cursor.execute(""" 10 SELECT name FROM sqlite_master 11 WHERE type='table' AND NOT name='sqlite_sequence' 12 ORDER BY name""") 13 return [row[0] for row in cursor.fetchall()] 14 15 def get_table_description(cursor, table_name): 16 "Returns a description of the table, with the DB-API cursor.description interface." 17 return [(info['name'], info['type'], None, None, None, None, 18 info['null_ok']) for info in _table_info(cursor, table_name)] 19 20 def get_relations(cursor, table_name): 21 raise NotImplementedError 22 23 def get_indexes(cursor, table_name): 24 """ 25 Returns a dictionary of fieldname -> infodict for the given table, 26 where each infodict is in the format: 27 {'primary_key': boolean representing whether it's the primary key, 28 'unique': boolean representing whether it's a unique index} 29 """ 30 indexes = {} 31 for info in _table_info(cursor, table_name): 32 indexes[info['name']] = {'primary_key': info['pk'] != 0, 33 'unique': False} 34 cursor.execute('PRAGMA index_list(%s)' % quote_name(table_name)) 35 # seq, name, unique 36 for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]: 37 if not unique: 38 continue 39 cursor.execute('PRAGMA index_info(%s)' % quote_name(index)) 40 info = cursor.fetchall() 41 # Skip indexes across multiple fields 42 if len(info) != 1: 43 continue 44 name = info[0][2] # seqno, cid, name 45 indexes[name]['unique'] = True 46 return indexes 47 48 def _table_info(cursor, name): 49 cursor.execute('PRAGMA table_info(%s)' % quote_name(name)) 50 # cid, name, type, notnull, dflt_value, pk 51 return [{'name': field[1], 52 'type': field[2], 53 'null_ok': not field[3], 54 'pk': field[5] # undocumented 55 } for field in cursor.fetchall()] 56 57 # Maps SQL types to Django Field types. Some of the SQL types have multiple 58 # entries here because SQLite allows for anything and doesn't normalize the 59 # field type; it uses whatever was given. 60 BASE_DATA_TYPES_REVERSE = { 61 'bool': 'BooleanField', 62 'boolean': 'BooleanField', 63 'smallint': 'SmallIntegerField', 64 'smallinteger': 'SmallIntegerField', 65 'int': 'IntegerField', 66 'integer': 'IntegerField', 67 'text': 'TextField', 68 'char': 'CharField', 69 'date': 'DateField', 70 'datetime': 'DateTimeField', 71 'time': 'TimeField', 72 } 1 from django.db.backends import BaseDatabaseIntrospection 73 2 74 3 # This light wrapper "fakes" a dictionary interface, because some SQLite data 75 4 # types include variables in them -- e.g. "varchar(30)" -- and can't be matched 76 5 # as a simple dictionary lookup. 77 6 class FlexibleFieldLookupDict: 7 # Maps SQL types to Django Field types. Some of the SQL types have multiple 8 # entries here because SQLite allows for anything and doesn't normalize the 9 # field type; it uses whatever was given. 10 base_data_types_reverse = { 11 'bool': 'BooleanField', 12 'boolean': 'BooleanField', 13 'smallint': 'SmallIntegerField', 14 'smallinteger': 'SmallIntegerField', 15 'int': 'IntegerField', 16 'integer': 'IntegerField', 17 'text': 'TextField', 18 'char': 'CharField', 19 'date': 'DateField', 20 'datetime': 'DateTimeField', 21 'time': 'TimeField', 22 } 23 78 24 def __getitem__(self, key): 79 25 key = key.lower() 80 26 try: 81 return BASE_DATA_TYPES_REVERSE[key]27 return self.base_data_types_reverse[key] 82 28 except KeyError: 83 29 import re 84 30 m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key) … … 86 32 return ('CharField', {'max_length': int(m.group(1))}) 87 33 raise KeyError 88 34 89 DATA_TYPES_REVERSE = FlexibleFieldLookupDict() 35 class DatabaseIntrospection(BaseDatabaseIntrospection): 36 data_types_reverse = FlexibleFieldLookupDict() 37 38 def __init__(self, ops): 39 self.ops = ops 40 41 def get_table_list(self, cursor): 42 "Returns a list of table names in the current database." 43 # Skip the sqlite_sequence system table used for autoincrement key 44 # generation. 45 cursor.execute(""" 46 SELECT name FROM sqlite_master 47 WHERE type='table' AND NOT name='sqlite_sequence' 48 ORDER BY name""") 49 return [row[0] for row in cursor.fetchall()] 50 51 def get_table_description(self, cursor, table_name): 52 "Returns a description of the table, with the DB-API cursor.description interface." 53 return [(info['name'], info['type'], None, None, None, None, 54 info['null_ok']) for info in self._table_info(cursor, table_name)] 55 56 def get_relations(self, cursor, table_name): 57 raise NotImplementedError 58 59 def get_indexes(self, cursor, table_name): 60 """ 61 Returns a dictionary of fieldname -> infodict for the given table, 62 where each infodict is in the format: 63 {'primary_key': boolean representing whether it's the primary key, 64 'unique': boolean representing whether it's a unique index} 65 """ 66 indexes = {} 67 for info in self._table_info(cursor, table_name): 68 indexes[info['name']] = {'primary_key': info['pk'] != 0, 69 'unique': False} 70 cursor.execute('PRAGMA index_list(%s)' % self.ops.quote_name(table_name)) 71 # seq, name, unique 72 for index, unique in [(field[1], field[2]) for field in cursor.fetchall()]: 73 if not unique: 74 continue 75 cursor.execute('PRAGMA index_info(%s)' % self.ops.quote_name(index)) 76 info = cursor.fetchall() 77 # Skip indexes across multiple fields 78 if len(info) != 1: 79 continue 80 name = info[0][2] # seqno, cid, name 81 indexes[name]['unique'] = True 82 return indexes 83 84 def _table_info(self, cursor, name): 85 cursor.execute('PRAGMA table_info(%s)' % self.ops.quote_name(name)) 86 # cid, name, type, notnull, dflt_value, pk 87 return [{'name': field[1], 88 'type': field[2], 89 'null_ok': not field[3], 90 'pk': field[5] # undocumented 91 } for field in cursor.fetchall()] 92 -
django/db/models/fields/__init__.py
diff -r 187c638a7c24 django/db/models/fields/__init__.py
a b 7 7 except ImportError: 8 8 from django.utils import _decimal as decimal # for Python 2.3 9 9 10 from django.db import connection , get_creation_module10 from django.db import connection 11 11 from django.db.models import signals 12 12 from django.db.models.query_utils import QueryWrapper 13 13 from django.conf import settings … … 144 144 # as the TextField Django field type, which means XMLField's 145 145 # get_internal_type() returns 'TextField'. 146 146 # 147 # But the limitation of the get_internal_type() / DATA_TYPESapproach147 # But the limitation of the get_internal_type() / data_types approach 148 148 # is that it cannot handle database column types that aren't already 149 149 # mapped to one of the built-in Django field types. In this case, you 150 150 # can implement db_type() instead of get_internal_type() to specify 151 151 # exactly which wacky database column type you want to use. 152 152 data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_") 153 153 try: 154 return get_creation_module().DATA_TYPES[self.get_internal_type()] % data154 return connection.creation.data_types[self.get_internal_type()] % data 155 155 except KeyError: 156 156 return None 157 157 -
django/test/simple.py
diff -r 187c638a7c24 django/test/simple.py
a b 3 3 from django.db.models import get_app, get_apps 4 4 from django.test import _doctest as doctest 5 5 from django.test.utils import setup_test_environment, teardown_test_environment 6 from django.test.utils import create_test_db, destroy_test_db7 6 from django.test.testcases import OutputChecker, DocTestRunner 8 7 9 8 # The module name for tests outside models.py … … 139 138 suite.addTest(test) 140 139 141 140 old_name = settings.DATABASE_NAME 142 create_test_db(verbosity, autoclobber=not interactive) 141 from django.db import connection 142 connection.creation.create_test_db(verbosity, autoclobber=not interactive) 143 143 result = unittest.TextTestRunner(verbosity=verbosity).run(suite) 144 destroy_test_db(old_name, verbosity)144 connection.creation.destroy_test_db(old_name, verbosity) 145 145 146 146 teardown_test_environment() 147 147 -
django/test/utils.py
diff -r 187c638a7c24 django/test/utils.py
a b 1 1 import sys, time, os 2 2 from django.conf import settings 3 from django.db import connection , get_creation_module3 from django.db import connection 4 4 from django.core import mail 5 from django.core.management import call_command6 5 from django.test import signals 7 6 from django.template import Template 8 7 from django.utils.translation import deactivate 9 10 # The prefix to put on the default database name when creating11 # the test database.12 TEST_DATABASE_PREFIX = 'test_'13 8 14 9 def instrumented_test_render(self, context): 15 10 """ … … 70 65 71 66 del mail.outbox 72 67 73 def _set_autocommit(connection):74 "Make sure a connection is in autocommit mode."75 if hasattr(connection.connection, "autocommit"):76 if callable(connection.connection.autocommit):77 connection.connection.autocommit(True)78 else:79 connection.connection.autocommit = True80 elif hasattr(connection.connection, "set_isolation_level"):81 connection.connection.set_isolation_level(0)82 83 def get_mysql_create_suffix():84 suffix = []85 if settings.TEST_DATABASE_CHARSET:86 suffix.append('CHARACTER SET %s' % settings.TEST_DATABASE_CHARSET)87 if settings.TEST_DATABASE_COLLATION:88 suffix.append('COLLATE %s' % settings.TEST_DATABASE_COLLATION)89 return ' '.join(suffix)90 91 def get_postgresql_create_suffix():92 assert settings.TEST_DATABASE_COLLATION is None, "PostgreSQL does not support collation setting at database creation time."93 if settings.TEST_DATABASE_CHARSET:94 return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET95 return ''96 97 def create_test_db(verbosity=1, autoclobber=False):98 """99 Creates a test database, prompting the user for confirmation if the100 database already exists. Returns the name of the test database created.101 """102 # If the database backend wants to create the test DB itself, let it103 creation_module = get_creation_module()104 if hasattr(creation_module, "create_test_db"):105 creation_module.create_test_db(settings, connection, verbosity, autoclobber)106 return107 108 if verbosity >= 1:109 print "Creating test database..."110 # If we're using SQLite, it's more convenient to test against an111 # in-memory database. Using the TEST_DATABASE_NAME setting you can still choose112 # to run on a physical database.113 if settings.DATABASE_ENGINE == "sqlite3":114 if settings.TEST_DATABASE_NAME and settings.TEST_DATABASE_NAME != ":memory:":115 TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME116 # Erase the old test database117 if verbosity >= 1:118 print "Destroying old test database..."119 if os.access(TEST_DATABASE_NAME, os.F_OK):120 if not autoclobber:121 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)122 if autoclobber or confirm == 'yes':123 try:124 if verbosity >= 1:125 print "Destroying old test database..."126 os.remove(TEST_DATABASE_NAME)127 except Exception, e:128 sys.stderr.write("Got an error deleting the old test database: %s\n" % e)129 sys.exit(2)130 else:131 print "Tests cancelled."132 sys.exit(1)133 if verbosity >= 1:134 print "Creating test database..."135 else:136 TEST_DATABASE_NAME = ":memory:"137 else:138 suffix = {139 'postgresql': get_postgresql_create_suffix,140 'postgresql_psycopg2': get_postgresql_create_suffix,141 'mysql': get_mysql_create_suffix,142 }.get(settings.DATABASE_ENGINE, lambda: '')()143 if settings.TEST_DATABASE_NAME:144 TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME145 else:146 TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME147 148 qn = connection.ops.quote_name149 150 # Create the test database and connect to it. We need to autocommit151 # if the database supports it because PostgreSQL doesn't allow152 # CREATE/DROP DATABASE statements within transactions.153 cursor = connection.cursor()154 _set_autocommit(connection)155 try:156 cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))157 except Exception, e:158 sys.stderr.write("Got an error creating the test database: %s\n" % e)159 if not autoclobber:160 confirm = raw_input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % TEST_DATABASE_NAME)161 if autoclobber or confirm == 'yes':162 try:163 if verbosity >= 1:164 print "Destroying old test database..."165 cursor.execute("DROP DATABASE %s" % qn(TEST_DATABASE_NAME))166 if verbosity >= 1:167 print "Creating test database..."168 cursor.execute("CREATE DATABASE %s %s" % (qn(TEST_DATABASE_NAME), suffix))169 except Exception, e:170 sys.stderr.write("Got an error recreating the test database: %s\n" % e)171 sys.exit(2)172 else:173 print "Tests cancelled."174 sys.exit(1)175 176 connection.close()177 settings.DATABASE_NAME = TEST_DATABASE_NAME178 179 call_command('syncdb', verbosity=verbosity, interactive=False)180 181 if settings.CACHE_BACKEND.startswith('db://'):182 cache_name = settings.CACHE_BACKEND[len('db://'):]183 call_command('createcachetable', cache_name)184 185 # Get a cursor (even though we don't need one yet). This has186 # the side effect of initializing the test database.187 cursor = connection.cursor()188 189 return TEST_DATABASE_NAME190 191 def destroy_test_db(old_database_name, verbosity=1):192 # If the database wants to drop the test DB itself, let it193 creation_module = get_creation_module()194 if hasattr(creation_module, "destroy_test_db"):195 creation_module.destroy_test_db(settings, connection, old_database_name, verbosity)196 return197 198 if verbosity >= 1:199 print "Destroying test database..."200 connection.close()201 TEST_DATABASE_NAME = settings.DATABASE_NAME202 settings.DATABASE_NAME = old_database_name203 if settings.DATABASE_ENGINE == "sqlite3":204 if TEST_DATABASE_NAME and TEST_DATABASE_NAME != ":memory:":205 # Remove the SQLite database file206 os.remove(TEST_DATABASE_NAME)207 else:208 # Remove the test database to clean up after209 # ourselves. Connect to the previous database (not the test database)210 # to do so, because it's not allowed to delete a database while being211 # connected to it.212 cursor = connection.cursor()213 _set_autocommit(connection)214 time.sleep(1) # To avoid "database is being accessed by other users" errors.215 cursor.execute("DROP DATABASE %s" % connection.ops.quote_name(TEST_DATABASE_NAME))216 connection.close() -
docs/testing.txt
diff -r 187c638a7c24 docs/testing.txt
a b 1026 1026 black magic hooks into the template system and restoring normal e-mail 1027 1027 services. 1028 1028 1029 The creation module of the database backend (``connection.creation``) also 1030 provides some utilities that can be useful during testing. 1031 1029 1032 ``create_test_db(verbosity=1, autoclobber=False)`` 1030 1033 Creates a new test database and runs ``syncdb`` against it. 1031 1034