diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py
a
|
b
|
|
133 | 133 | truncate_params = {'relate' : None} |
134 | 134 | |
135 | 135 | def __init__(self, connection): |
136 | | super(OracleOperations, self).__init__() |
137 | | self.connection = connection |
| 136 | super(OracleOperations, self).__init__(connection) |
138 | 137 | |
139 | 138 | def convert_extent(self, clob): |
140 | 139 | if clob: |
diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py
a
|
b
|
|
110 | 110 | geometry_functions.update(distance_functions) |
111 | 111 | |
112 | 112 | def __init__(self, connection): |
113 | | super(DatabaseOperations, self).__init__() |
114 | | self.connection = connection |
| 113 | super(DatabaseOperations, self).__init__(connection) |
115 | 114 | |
116 | 115 | # Determine the version of the SpatiaLite library. |
117 | 116 | try: |
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
a
|
b
|
|
388 | 388 | """ |
389 | 389 | compiler_module = "django.db.models.sql.compiler" |
390 | 390 | |
391 | | def __init__(self): |
| 391 | def __init__(self, connection): |
| 392 | self.connection = connection |
392 | 393 | self._cache = None |
393 | 394 | |
394 | 395 | def autoinc_sql(self, table, column): |
diff --git a/django/db/backends/dummy/base.py b/django/db/backends/dummy/base.py
a
|
b
|
|
59 | 59 | super(DatabaseWrapper, self).__init__(*args, **kwargs) |
60 | 60 | |
61 | 61 | self.features = BaseDatabaseFeatures(self) |
62 | | self.ops = DatabaseOperations() |
| 62 | self.ops = DatabaseOperations(self) |
63 | 63 | self.client = DatabaseClient(self) |
64 | 64 | self.creation = BaseDatabaseCreation(self) |
65 | 65 | self.introspection = DatabaseIntrospection(self) |
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
a
|
b
|
|
23 | 23 | raise ImproperlyConfigured("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__) |
24 | 24 | |
25 | 25 | from MySQLdb.converters import conversions |
26 | | from MySQLdb.constants import FIELD_TYPE, FLAG, CLIENT |
| 26 | from MySQLdb.constants import FIELD_TYPE, CLIENT |
27 | 27 | |
28 | 28 | from django.db import utils |
29 | 29 | from django.db.backends import * |
… |
… |
|
279 | 279 | |
280 | 280 | self.server_version = None |
281 | 281 | self.features = DatabaseFeatures(self) |
282 | | self.ops = DatabaseOperations() |
| 282 | self.ops = DatabaseOperations(self) |
283 | 283 | self.client = DatabaseClient(self) |
284 | 284 | self.creation = DatabaseCreation(self) |
285 | 285 | self.introspection = DatabaseIntrospection(self) |
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
a
|
b
|
|
84 | 84 | def autoinc_sql(self, table, column): |
85 | 85 | # To simulate auto-incrementing primary keys in Oracle, we have to |
86 | 86 | # create a sequence and a trigger. |
87 | | sq_name = get_sequence_name(table) |
88 | | tr_name = get_trigger_name(table) |
| 87 | sq_name = self.get_sequence_name(table) |
| 88 | tr_name = self.get_trigger_name(table) |
89 | 89 | tbl_name = self.quote_name(table) |
90 | 90 | col_name = self.quote_name(column) |
91 | 91 | sequence_sql = """ |
… |
… |
|
197 | 197 | return " DEFERRABLE INITIALLY DEFERRED" |
198 | 198 | |
199 | 199 | def drop_sequence_sql(self, table): |
200 | | return "DROP SEQUENCE %s;" % self.quote_name(get_sequence_name(table)) |
| 200 | return "DROP SEQUENCE %s;" % self.quote_name(self.get_sequence_name(table)) |
201 | 201 | |
202 | 202 | def fetch_returned_insert_id(self, cursor): |
203 | 203 | return long(cursor._insert_id_var.getvalue()) |
… |
… |
|
209 | 209 | return "%s" |
210 | 210 | |
211 | 211 | def last_insert_id(self, cursor, table_name, pk_name): |
212 | | sq_name = get_sequence_name(table_name) |
| 212 | sq_name = self.get_sequence_name(table_name) |
213 | 213 | cursor.execute('SELECT "%s".currval FROM dual' % sq_name) |
214 | 214 | return cursor.fetchone()[0] |
215 | 215 | |
… |
… |
|
285 | 285 | # Since we've just deleted all the rows, running our sequence |
286 | 286 | # ALTER code will reset the sequence to 0. |
287 | 287 | for sequence_info in sequences: |
288 | | sequence_name = get_sequence_name(sequence_info['table']) |
| 288 | sequence_name = self.get_sequence_name(sequence_info['table']) |
289 | 289 | table_name = self.quote_name(sequence_info['table']) |
290 | 290 | column_name = self.quote_name(sequence_info['column'] or 'id') |
291 | 291 | query = _get_sequence_reset_sql() % {'sequence': sequence_name, |
… |
… |
|
304 | 304 | for f in model._meta.local_fields: |
305 | 305 | if isinstance(f, models.AutoField): |
306 | 306 | table_name = self.quote_name(model._meta.db_table) |
307 | | sequence_name = get_sequence_name(model._meta.db_table) |
| 307 | sequence_name = self.get_sequence_name(model._meta.db_table) |
308 | 308 | column_name = self.quote_name(f.column) |
309 | 309 | output.append(query % {'sequence': sequence_name, |
310 | 310 | 'table': table_name, |
… |
… |
|
315 | 315 | for f in model._meta.many_to_many: |
316 | 316 | if not f.rel.through: |
317 | 317 | table_name = self.quote_name(f.m2m_db_table()) |
318 | | sequence_name = get_sequence_name(f.m2m_db_table()) |
| 318 | sequence_name = self.get_sequence_name(f.m2m_db_table()) |
319 | 319 | column_name = self.quote_name('id') |
320 | 320 | output.append(query % {'sequence': sequence_name, |
321 | 321 | 'table': table_name, |
… |
… |
|
365 | 365 | raise NotImplementedError("Bit-wise or is not supported in Oracle.") |
366 | 366 | return super(DatabaseOperations, self).combine_expression(connector, sub_expressions) |
367 | 367 | |
| 368 | def get_sequence_name(self, table): |
| 369 | name_length = self.max_name_length() - 3 |
| 370 | return '%s_SQ' % util.truncate_name(table, name_length).upper() |
| 371 | |
| 372 | def get_trigger_name(self, table): |
| 373 | name_length = self.max_name_length() - 3 |
| 374 | return '%s_TR' % util.truncate_name(table, name_length).upper() |
| 375 | |
368 | 376 | |
369 | 377 | class _UninitializedOperatorsDescriptor(object): |
370 | 378 | |
… |
… |
|
415 | 423 | self.features = DatabaseFeatures(self) |
416 | 424 | use_returning_into = self.settings_dict["OPTIONS"].get('use_returning_into', True) |
417 | 425 | self.features.can_return_id_from_insert = use_returning_into |
418 | | self.ops = DatabaseOperations() |
| 426 | self.ops = DatabaseOperations(self) |
419 | 427 | self.client = DatabaseClient(self) |
420 | 428 | self.creation = DatabaseCreation(self) |
421 | 429 | self.introspection = DatabaseIntrospection(self) |
… |
… |
|
776 | 784 | END LOOP; |
777 | 785 | END; |
778 | 786 | /""" |
779 | | |
780 | | |
781 | | def get_sequence_name(table): |
782 | | name_length = DatabaseOperations().max_name_length() - 3 |
783 | | return '%s_SQ' % util.truncate_name(table, name_length).upper() |
784 | | |
785 | | |
786 | | def get_trigger_name(table): |
787 | | name_length = DatabaseOperations().max_name_length() - 3 |
788 | | return '%s_TR' % util.truncate_name(table, name_length).upper() |
diff --git a/django/db/backends/postgresql_psycopg2/operations.py b/django/db/backends/postgresql_psycopg2/operations.py
a
|
b
|
|
5 | 5 | |
6 | 6 | class DatabaseOperations(BaseDatabaseOperations): |
7 | 7 | def __init__(self, connection): |
8 | | super(DatabaseOperations, self).__init__() |
| 8 | super(DatabaseOperations, self).__init__(connection) |
9 | 9 | self._postgres_version = None |
10 | | self.connection = connection |
11 | 10 | |
12 | 11 | def _get_postgres_version(self): |
13 | 12 | if self._postgres_version is None: |
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
a
|
b
|
|
88 | 88 | # It would be more straightforward if we could use the sqlite strftime |
89 | 89 | # function, but it does not allow for keeping six digits of fractional |
90 | 90 | # second information, nor does it allow for formatting date and datetime |
91 | | # values differently. So instead we register our own function that |
92 | | # formats the datetime combined with the delta in a manner suitable |
| 91 | # values differently. So instead we register our own function that |
| 92 | # formats the datetime combined with the delta in a manner suitable |
93 | 93 | # for comparisons. |
94 | | return u'django_format_dtdelta(%s, "%s", "%d", "%d", "%d")' % (sql, |
| 94 | return u'django_format_dtdelta(%s, "%s", "%d", "%d", "%d")' % (sql, |
95 | 95 | connector, timedelta.days, timedelta.seconds, timedelta.microseconds) |
96 | 96 | |
97 | 97 | def date_trunc_sql(self, lookup_type, field_name): |
… |
… |
|
179 | 179 | super(DatabaseWrapper, self).__init__(*args, **kwargs) |
180 | 180 | |
181 | 181 | self.features = DatabaseFeatures(self) |
182 | | self.ops = DatabaseOperations() |
| 182 | self.ops = DatabaseOperations(self) |
183 | 183 | self.client = DatabaseClient(self) |
184 | 184 | self.creation = DatabaseCreation(self) |
185 | 185 | self.introspection = DatabaseIntrospection(self) |
diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
a
|
b
|
|
232 | 232 | self.assertEqual(list(cursor.fetchmany(2)), [(u'Jane', u'Doe'), (u'John', u'Doe')]) |
233 | 233 | self.assertEqual(list(cursor.fetchall()), [(u'Mary', u'Agnelline'), (u'Peter', u'Parker')]) |
234 | 234 | |
| 235 | def test_database_operations_helper_class(self): |
| 236 | # Ticket #13630 |
| 237 | self.assertTrue(hasattr(connection, 'ops')) |
| 238 | self.assertTrue(hasattr(connection.ops, 'connection')) |
| 239 | self.assertEqual(connection, connection.ops.connection) |
| 240 | |
235 | 241 | |
236 | 242 | # We don't make these tests conditional because that means we would need to |
237 | 243 | # check and differentiate between: |