2009-12-22 23:18:51 +08:00
|
|
|
import decimal
|
2011-02-12 21:02:42 +08:00
|
|
|
try:
|
|
|
|
import thread
|
|
|
|
except ImportError:
|
|
|
|
import dummy_thread as thread
|
2009-12-22 23:18:51 +08:00
|
|
|
from threading import local
|
2009-01-15 19:06:34 +08:00
|
|
|
|
2011-01-12 21:39:31 +08:00
|
|
|
from django.conf import settings
|
2009-12-22 23:18:51 +08:00
|
|
|
from django.db import DEFAULT_DB_ALIAS
|
2008-07-29 13:09:29 +08:00
|
|
|
from django.db.backends import util
|
2011-02-12 21:02:42 +08:00
|
|
|
from django.db.transaction import TransactionManagementError
|
2008-07-29 13:09:29 +08:00
|
|
|
from django.utils import datetime_safe
|
2009-12-22 23:18:51 +08:00
|
|
|
from django.utils.importlib import import_module
|
2008-07-29 13:09:29 +08:00
|
|
|
|
2011-01-12 21:39:31 +08:00
|
|
|
|
2007-08-20 05:30:57 +08:00
|
|
|
class BaseDatabaseWrapper(local):
|
2007-08-20 06:29:57 +08:00
|
|
|
"""
|
|
|
|
Represents a database connection.
|
|
|
|
"""
|
|
|
|
ops = None
|
2010-12-04 02:15:54 +08:00
|
|
|
vendor = 'unknown'
|
2009-12-22 23:18:51 +08:00
|
|
|
|
|
|
|
def __init__(self, settings_dict, alias=DEFAULT_DB_ALIAS):
|
2009-03-11 11:39:34 +08:00
|
|
|
# `settings_dict` should be a dictionary containing keys such as
|
2009-12-22 23:18:51 +08:00
|
|
|
# NAME, USER, etc. It's called `settings_dict` instead of `settings`
|
|
|
|
# to disambiguate it from Django settings modules.
|
2007-08-20 05:30:57 +08:00
|
|
|
self.connection = None
|
|
|
|
self.queries = []
|
2009-03-11 11:39:34 +08:00
|
|
|
self.settings_dict = settings_dict
|
2009-12-22 23:18:51 +08:00
|
|
|
self.alias = alias
|
2010-10-12 11:33:19 +08:00
|
|
|
self.use_debug_cursor = None
|
2009-12-22 23:18:51 +08:00
|
|
|
|
2011-01-17 17:52:47 +08:00
|
|
|
# Transaction related attributes
|
|
|
|
self.transaction_state = []
|
|
|
|
self.savepoint_state = 0
|
2011-02-12 21:02:42 +08:00
|
|
|
self._dirty = None
|
2011-01-17 17:52:47 +08:00
|
|
|
|
2009-12-22 23:18:51 +08:00
|
|
|
def __eq__(self, other):
|
2010-11-19 16:08:08 +08:00
|
|
|
return self.alias == other.alias
|
2009-12-22 23:18:51 +08:00
|
|
|
|
|
|
|
def __ne__(self, other):
|
|
|
|
return not self == other
|
2007-08-20 05:30:57 +08:00
|
|
|
|
|
|
|
def _commit(self):
|
|
|
|
if self.connection is not None:
|
|
|
|
return self.connection.commit()
|
|
|
|
|
|
|
|
def _rollback(self):
|
|
|
|
if self.connection is not None:
|
|
|
|
return self.connection.rollback()
|
|
|
|
|
2009-03-11 15:06:50 +08:00
|
|
|
def _enter_transaction_management(self, managed):
|
|
|
|
"""
|
|
|
|
A hook for backend-specific changes required when entering manual
|
|
|
|
transaction handling.
|
|
|
|
"""
|
|
|
|
pass
|
|
|
|
|
|
|
|
def _leave_transaction_management(self, managed):
|
|
|
|
"""
|
|
|
|
A hook for backend-specific changes required when leaving manual
|
|
|
|
transaction handling. Will usually be implemented only when
|
|
|
|
_enter_transaction_management() is also required.
|
|
|
|
"""
|
|
|
|
pass
|
|
|
|
|
2008-08-12 13:34:56 +08:00
|
|
|
def _savepoint(self, sid):
|
|
|
|
if not self.features.uses_savepoints:
|
|
|
|
return
|
2009-04-11 15:51:07 +08:00
|
|
|
self.cursor().execute(self.ops.savepoint_create_sql(sid))
|
2008-08-12 13:34:56 +08:00
|
|
|
|
|
|
|
def _savepoint_rollback(self, sid):
|
|
|
|
if not self.features.uses_savepoints:
|
|
|
|
return
|
2009-04-11 15:51:07 +08:00
|
|
|
self.cursor().execute(self.ops.savepoint_rollback_sql(sid))
|
2008-08-12 13:34:56 +08:00
|
|
|
|
|
|
|
def _savepoint_commit(self, sid):
|
|
|
|
if not self.features.uses_savepoints:
|
|
|
|
return
|
2009-04-11 15:51:07 +08:00
|
|
|
self.cursor().execute(self.ops.savepoint_commit_sql(sid))
|
2008-08-12 13:34:56 +08:00
|
|
|
|
2011-02-12 21:02:42 +08:00
|
|
|
def enter_transaction_management(self, managed=True):
|
|
|
|
"""
|
|
|
|
Enters transaction management for a running thread. It must be balanced with
|
|
|
|
the appropriate leave_transaction_management call, since the actual state is
|
|
|
|
managed as a stack.
|
|
|
|
|
|
|
|
The state and dirty flag are carried over from the surrounding block or
|
|
|
|
from the settings, if there is no surrounding block (dirty is always false
|
|
|
|
when no current block is running).
|
|
|
|
"""
|
|
|
|
if self.transaction_state:
|
|
|
|
self.transaction_state.append(self.transaction_state[-1])
|
|
|
|
else:
|
|
|
|
self.transaction_state.append(settings.TRANSACTIONS_MANAGED)
|
|
|
|
|
|
|
|
if self._dirty is None:
|
|
|
|
self._dirty = False
|
|
|
|
self._enter_transaction_management(managed)
|
|
|
|
|
|
|
|
def leave_transaction_management(self):
|
|
|
|
"""
|
|
|
|
Leaves transaction management for a running thread. A dirty flag is carried
|
|
|
|
over to the surrounding block, as a commit will commit all changes, even
|
|
|
|
those from outside. (Commits are on connection level.)
|
|
|
|
"""
|
|
|
|
self._leave_transaction_management(self.is_managed())
|
|
|
|
if self.transaction_state:
|
|
|
|
del self.transaction_state[-1]
|
|
|
|
else:
|
|
|
|
raise TransactionManagementError("This code isn't under transaction "
|
|
|
|
"management")
|
|
|
|
if self._dirty:
|
|
|
|
self.rollback()
|
|
|
|
raise TransactionManagementError("Transaction managed block ended with "
|
|
|
|
"pending COMMIT/ROLLBACK")
|
|
|
|
self._dirty = False
|
|
|
|
|
|
|
|
def is_dirty(self):
|
|
|
|
"""
|
|
|
|
Returns True if the current transaction requires a commit for changes to
|
|
|
|
happen.
|
|
|
|
"""
|
|
|
|
return self._dirty
|
|
|
|
|
|
|
|
def set_dirty(self):
|
|
|
|
"""
|
|
|
|
Sets a dirty flag for the current thread and code streak. This can be used
|
|
|
|
to decide in a managed block of code to decide whether there are open
|
|
|
|
changes waiting for commit.
|
|
|
|
"""
|
|
|
|
if self._dirty is not None:
|
|
|
|
self._dirty = True
|
|
|
|
else:
|
|
|
|
raise TransactionManagementError("This code isn't under transaction "
|
|
|
|
"management")
|
|
|
|
|
|
|
|
def set_clean(self):
|
|
|
|
"""
|
|
|
|
Resets a dirty flag for the current thread and code streak. This can be used
|
|
|
|
to decide in a managed block of code to decide whether a commit or rollback
|
|
|
|
should happen.
|
|
|
|
"""
|
|
|
|
if self._dirty is not None:
|
|
|
|
self._dirty = False
|
|
|
|
else:
|
|
|
|
raise TransactionManagementError("This code isn't under transaction management")
|
|
|
|
self.clean_savepoints()
|
|
|
|
|
|
|
|
def clean_savepoints(self):
|
|
|
|
self.savepoint_state = 0
|
|
|
|
|
|
|
|
def is_managed(self):
|
|
|
|
"""
|
|
|
|
Checks whether the transaction manager is in manual or in auto state.
|
|
|
|
"""
|
|
|
|
if self.transaction_state:
|
|
|
|
return self.transaction_state[-1]
|
|
|
|
return settings.TRANSACTIONS_MANAGED
|
|
|
|
|
|
|
|
def managed(self, flag=True):
|
|
|
|
"""
|
|
|
|
Puts the transaction manager into a manual state: managed transactions have
|
|
|
|
to be committed explicitly by the user. If you switch off transaction
|
|
|
|
management and there is a pending commit/rollback, the data will be
|
|
|
|
commited.
|
|
|
|
"""
|
|
|
|
top = self.transaction_state
|
|
|
|
if top:
|
|
|
|
top[-1] = flag
|
|
|
|
if not flag and self.is_dirty():
|
|
|
|
self._commit()
|
|
|
|
self.set_clean()
|
|
|
|
else:
|
|
|
|
raise TransactionManagementError("This code isn't under transaction "
|
|
|
|
"management")
|
|
|
|
|
|
|
|
def commit_unless_managed(self):
|
|
|
|
"""
|
|
|
|
Commits changes if the system is not in managed transaction mode.
|
|
|
|
"""
|
|
|
|
if not self.is_managed():
|
|
|
|
self._commit()
|
|
|
|
self.clean_savepoints()
|
|
|
|
else:
|
|
|
|
self.set_dirty()
|
|
|
|
|
|
|
|
def rollback_unless_managed(self):
|
|
|
|
"""
|
|
|
|
Rolls back changes if the system is not in managed transaction mode.
|
|
|
|
"""
|
|
|
|
if not self.is_managed():
|
|
|
|
self._rollback()
|
|
|
|
else:
|
|
|
|
self.set_dirty()
|
|
|
|
|
|
|
|
def commit(self):
|
|
|
|
"""
|
|
|
|
Does the commit itself and resets the dirty flag.
|
|
|
|
"""
|
|
|
|
self._commit()
|
|
|
|
self.set_clean()
|
|
|
|
|
|
|
|
def rollback(self):
|
|
|
|
"""
|
|
|
|
This function does the rollback itself and resets the dirty flag.
|
|
|
|
"""
|
|
|
|
self._rollback()
|
|
|
|
self.set_clean()
|
|
|
|
|
|
|
|
def savepoint(self):
|
|
|
|
"""
|
|
|
|
Creates a savepoint (if supported and required by the backend) inside the
|
|
|
|
current transaction. Returns an identifier for the savepoint that will be
|
|
|
|
used for the subsequent rollback or commit.
|
|
|
|
"""
|
|
|
|
thread_ident = thread.get_ident()
|
|
|
|
|
|
|
|
self.savepoint_state += 1
|
|
|
|
|
|
|
|
tid = str(thread_ident).replace('-', '')
|
|
|
|
sid = "s%s_x%d" % (tid, self.savepoint_state)
|
|
|
|
self._savepoint(sid)
|
|
|
|
return sid
|
|
|
|
|
|
|
|
def savepoint_rollback(self, sid):
|
|
|
|
"""
|
|
|
|
Rolls back the most recent savepoint (if one exists). Does nothing if
|
|
|
|
savepoints are not supported.
|
|
|
|
"""
|
|
|
|
if self.savepoint_state:
|
|
|
|
self._savepoint_rollback(sid)
|
|
|
|
|
|
|
|
def savepoint_commit(self, sid):
|
|
|
|
"""
|
|
|
|
Commits the most recent savepoint (if one exists). Does nothing if
|
|
|
|
savepoints are not supported.
|
|
|
|
"""
|
|
|
|
if self.savepoint_state:
|
|
|
|
self._savepoint_commit(sid)
|
|
|
|
|
2007-08-20 05:30:57 +08:00
|
|
|
def close(self):
|
|
|
|
if self.connection is not None:
|
|
|
|
self.connection.close()
|
|
|
|
self.connection = None
|
|
|
|
|
|
|
|
def cursor(self):
|
2010-10-12 11:33:19 +08:00
|
|
|
if (self.use_debug_cursor or
|
|
|
|
(self.use_debug_cursor is None and settings.DEBUG)):
|
2011-02-12 21:03:34 +08:00
|
|
|
cursor = self.make_debug_cursor(self._cursor())
|
|
|
|
else:
|
|
|
|
cursor = util.CursorWrapper(self._cursor(), self)
|
2007-08-20 05:30:57 +08:00
|
|
|
return cursor
|
|
|
|
|
|
|
|
def make_debug_cursor(self, cursor):
|
|
|
|
return util.CursorDebugWrapper(cursor, self)
|
2007-08-20 06:29:57 +08:00
|
|
|
|
2007-08-20 10:20:33 +08:00
|
|
|
class BaseDatabaseFeatures(object):
|
2009-01-15 19:06:34 +08:00
|
|
|
allows_group_by_pk = False
|
2008-07-29 13:09:29 +08:00
|
|
|
# True if django.db.backend.utils.typecast_timestamp is used on values
|
|
|
|
# returned from dates() calls.
|
2007-08-20 10:20:33 +08:00
|
|
|
needs_datetime_string_cast = True
|
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
|
|
|
empty_fetchmany_value = []
|
2008-04-28 19:51:52 +08:00
|
|
|
update_can_self_select = True
|
2010-10-11 20:55:17 +08:00
|
|
|
|
|
|
|
# Does the backend distinguish between '' and None?
|
2008-06-16 11:15:04 +08:00
|
|
|
interprets_empty_strings_as_nulls = False
|
2010-10-11 20:55:17 +08:00
|
|
|
|
2011-03-09 06:41:25 +08:00
|
|
|
# Does the backend allow inserting duplicate rows when a unique_together
|
|
|
|
# constraint exists, but one of the unique_together columns is NULL?
|
|
|
|
ignores_nulls_in_unique_constraints = True
|
|
|
|
|
2008-07-16 02:47:32 +08:00
|
|
|
can_use_chunked_reads = True
|
2009-03-11 15:06:50 +08:00
|
|
|
can_return_id_from_insert = False
|
|
|
|
uses_autocommit = False
|
2008-08-12 13:34:56 +08:00
|
|
|
uses_savepoints = False
|
2010-10-11 20:55:17 +08:00
|
|
|
|
2008-09-01 08:49:03 +08:00
|
|
|
# If True, don't use integer foreign keys referring to, e.g., positive
|
|
|
|
# integer primary keys.
|
|
|
|
related_fields_match_type = False
|
2010-04-05 01:05:43 +08:00
|
|
|
allow_sliced_subqueries = True
|
2007-08-20 10:20:33 +08:00
|
|
|
|
2010-10-11 20:55:17 +08:00
|
|
|
# Does the default test database allow multiple connections?
|
|
|
|
# Usually an indication that the test database is in-memory
|
|
|
|
test_db_allows_multiple_connections = True
|
|
|
|
|
|
|
|
# Can an object be saved without an explicit primary key?
|
|
|
|
supports_unspecified_pk = False
|
|
|
|
|
|
|
|
# Can a fixture contain forward references? i.e., are
|
|
|
|
# FK constraints checked at the end of transaction, or
|
|
|
|
# at the end of each save operation?
|
|
|
|
supports_forward_references = True
|
|
|
|
|
|
|
|
# Does a dirty transaction need to be rolled back
|
|
|
|
# before the cursor can be used again?
|
|
|
|
requires_rollback_on_dirty_transaction = False
|
|
|
|
|
|
|
|
# Does the backend allow very long model names without error?
|
|
|
|
supports_long_model_names = True
|
|
|
|
|
|
|
|
# Is there a REAL datatype in addition to floats/doubles?
|
|
|
|
has_real_datatype = False
|
|
|
|
supports_subqueries_in_group_by = True
|
|
|
|
supports_bitwise_or = True
|
|
|
|
|
|
|
|
# Do time/datetime fields have microsecond precision?
|
|
|
|
supports_microsecond_precision = True
|
|
|
|
|
|
|
|
# Does the __regex lookup support backreferencing and grouping?
|
|
|
|
supports_regex_backreferencing = True
|
|
|
|
|
|
|
|
# Can date/datetime lookups be performed using a string?
|
|
|
|
supports_date_lookup_using_string = True
|
|
|
|
|
|
|
|
# Can datetimes with timezones be used?
|
|
|
|
supports_timezones = True
|
|
|
|
|
|
|
|
# When performing a GROUP BY, is an ORDER BY NULL required
|
|
|
|
# to remove any ordering?
|
|
|
|
requires_explicit_null_ordering_when_grouping = False
|
|
|
|
|
|
|
|
# Is there a 1000 item limit on query parameters?
|
2010-10-19 08:14:41 +08:00
|
|
|
supports_1000_query_parameters = True
|
2010-10-11 20:55:17 +08:00
|
|
|
|
|
|
|
# Can an object have a primary key of 0? MySQL says No.
|
|
|
|
allows_primary_key_0 = True
|
|
|
|
|
2010-11-10 00:46:42 +08:00
|
|
|
# Do we need to NULL a ForeignKey out, or can the constraint check be
|
|
|
|
# deferred
|
|
|
|
can_defer_constraint_checks = False
|
|
|
|
|
2010-12-22 11:34:04 +08:00
|
|
|
# date_interval_sql can properly handle mixed Date/DateTime fields and timedeltas
|
|
|
|
supports_mixed_date_datetime_comparisons = True
|
|
|
|
|
2010-10-11 20:55:17 +08:00
|
|
|
# Features that need to be confirmed at runtime
|
|
|
|
# Cache whether the confirmation has been performed.
|
|
|
|
_confirmed = False
|
|
|
|
supports_transactions = None
|
|
|
|
supports_stddev = None
|
2011-02-01 22:42:52 +08:00
|
|
|
can_introspect_foreign_keys = None
|
2010-10-11 20:55:17 +08:00
|
|
|
|
|
|
|
def __init__(self, connection):
|
|
|
|
self.connection = connection
|
|
|
|
|
|
|
|
def confirm(self):
|
|
|
|
"Perform manual checks of any database features that might vary between installs"
|
|
|
|
self._confirmed = True
|
|
|
|
self.supports_transactions = self._supports_transactions()
|
|
|
|
self.supports_stddev = self._supports_stddev()
|
2011-02-01 22:42:52 +08:00
|
|
|
self.can_introspect_foreign_keys = self._can_introspect_foreign_keys()
|
2010-10-11 20:55:17 +08:00
|
|
|
|
|
|
|
def _supports_transactions(self):
|
|
|
|
"Confirm support for transactions"
|
|
|
|
cursor = self.connection.cursor()
|
|
|
|
cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
|
|
|
|
self.connection._commit()
|
|
|
|
cursor.execute('INSERT INTO ROLLBACK_TEST (X) VALUES (8)')
|
|
|
|
self.connection._rollback()
|
|
|
|
cursor.execute('SELECT COUNT(X) FROM ROLLBACK_TEST')
|
|
|
|
count, = cursor.fetchone()
|
|
|
|
cursor.execute('DROP TABLE ROLLBACK_TEST')
|
|
|
|
self.connection._commit()
|
|
|
|
return count == 0
|
|
|
|
|
|
|
|
def _supports_stddev(self):
|
|
|
|
"Confirm support for STDDEV and related stats functions"
|
|
|
|
class StdDevPop(object):
|
|
|
|
sql_function = 'STDDEV_POP'
|
|
|
|
|
|
|
|
try:
|
|
|
|
self.connection.ops.check_aggregate_support(StdDevPop())
|
2010-10-28 10:59:22 +08:00
|
|
|
except NotImplementedError:
|
2010-10-11 20:55:17 +08:00
|
|
|
self.supports_stddev = False
|
|
|
|
|
2011-02-01 22:42:52 +08:00
|
|
|
def _can_introspect_foreign_keys(self):
|
|
|
|
"Confirm support for introspected foreign keys"
|
|
|
|
# Every database can do this reliably, except MySQL,
|
|
|
|
# which can't do it for MyISAM tables
|
|
|
|
return True
|
|
|
|
|
2010-10-11 20:55:17 +08:00
|
|
|
|
2007-08-20 06:29:57 +08:00
|
|
|
class BaseDatabaseOperations(object):
|
|
|
|
"""
|
|
|
|
This class encapsulates all backend-specific differences, such as the way
|
|
|
|
a backend performs ordering or calculates the ID of a recently-inserted
|
|
|
|
row.
|
|
|
|
"""
|
2009-12-22 23:18:51 +08:00
|
|
|
compiler_module = "django.db.models.sql.compiler"
|
|
|
|
|
2011-04-05 08:19:17 +08:00
|
|
|
def __init__(self, connection):
|
|
|
|
self.connection = connection
|
2011-01-12 21:39:31 +08:00
|
|
|
self._cache = None
|
2009-12-22 23:18:51 +08:00
|
|
|
|
2007-09-15 02:12:36 +08:00
|
|
|
def autoinc_sql(self, table, column):
|
2007-08-20 06:29:57 +08:00
|
|
|
"""
|
|
|
|
Returns any SQL needed to support auto-incrementing primary keys, or
|
|
|
|
None if no SQL is necessary.
|
|
|
|
|
|
|
|
This SQL is executed when a table is created.
|
|
|
|
"""
|
|
|
|
return None
|
2007-08-20 06:40:06 +08:00
|
|
|
|
|
|
|
def date_extract_sql(self, lookup_type, field_name):
|
|
|
|
"""
|
|
|
|
Given a lookup_type of 'year', 'month' or 'day', returns the SQL that
|
|
|
|
extracts a value from the given date field field_name.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
2007-08-20 06:47:43 +08:00
|
|
|
|
2010-12-22 11:34:04 +08:00
|
|
|
def date_interval_sql(self, sql, connector, timedelta):
|
|
|
|
"""
|
|
|
|
Implements the date interval functionality for expressions
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2007-08-20 06:47:43 +08:00
|
|
|
def date_trunc_sql(self, lookup_type, field_name):
|
|
|
|
"""
|
|
|
|
Given a lookup_type of 'year', 'month' or 'day', returns the SQL that
|
|
|
|
truncates the given date field field_name to a DATE object with only
|
|
|
|
the given specificity.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
2007-08-20 06:55:05 +08:00
|
|
|
|
|
|
|
def datetime_cast_sql(self):
|
|
|
|
"""
|
|
|
|
Returns the SQL necessary to cast a datetime value so that it will be
|
|
|
|
retrieved as a Python datetime object instead of a string.
|
2007-08-20 06:57:08 +08:00
|
|
|
|
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
|
|
|
This SQL should include a '%s' in place of the field's name.
|
2007-08-20 06:55:05 +08:00
|
|
|
"""
|
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
|
|
|
return "%s"
|
2007-08-20 07:03:38 +08:00
|
|
|
|
|
|
|
def deferrable_sql(self):
|
|
|
|
"""
|
|
|
|
Returns the SQL necessary to make a constraint "initially deferred"
|
|
|
|
during a CREATE TABLE statement.
|
|
|
|
"""
|
|
|
|
return ''
|
2007-08-20 07:07:34 +08:00
|
|
|
|
|
|
|
def drop_foreignkey_sql(self):
|
|
|
|
"""
|
|
|
|
Returns the SQL command that drops a foreign key.
|
|
|
|
"""
|
|
|
|
return "DROP CONSTRAINT"
|
2007-08-20 07:13:06 +08:00
|
|
|
|
2007-08-20 11:08:32 +08:00
|
|
|
def drop_sequence_sql(self, table):
|
|
|
|
"""
|
|
|
|
Returns any SQL necessary to drop the sequence for the given table.
|
|
|
|
Returns None if no SQL is necessary.
|
|
|
|
"""
|
|
|
|
return None
|
|
|
|
|
2009-03-13 07:41:27 +08:00
|
|
|
def fetch_returned_insert_id(self, cursor):
|
|
|
|
"""
|
|
|
|
Given a cursor object that has just performed an INSERT...RETURNING
|
|
|
|
statement into a table that has an auto-incrementing ID, returns the
|
|
|
|
newly created ID.
|
|
|
|
"""
|
|
|
|
return cursor.fetchone()[0]
|
|
|
|
|
2007-08-20 11:03:40 +08:00
|
|
|
def field_cast_sql(self, db_type):
|
|
|
|
"""
|
|
|
|
Given a column type (e.g. 'BLOB', 'VARCHAR'), returns the SQL necessary
|
|
|
|
to cast it before using it in a WHERE statement. Note that the
|
|
|
|
resulting string should contain a '%s' placeholder for the column being
|
|
|
|
searched against.
|
|
|
|
"""
|
|
|
|
return '%s'
|
|
|
|
|
2008-12-10 13:19:27 +08:00
|
|
|
def force_no_ordering(self):
|
|
|
|
"""
|
|
|
|
Returns a list used in the "ORDER BY" clause to force no ordering at
|
|
|
|
all. Returning an empty list means that nothing will be included in the
|
|
|
|
ordering.
|
|
|
|
"""
|
|
|
|
return []
|
|
|
|
|
2007-08-20 07:13:06 +08:00
|
|
|
def fulltext_search_sql(self, field_name):
|
|
|
|
"""
|
|
|
|
Returns the SQL WHERE clause to use in order to perform a full-text
|
|
|
|
search of the given field_name. Note that the resulting string should
|
|
|
|
contain a '%s' placeholder for the value being searched against.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Full-text search is not implemented for this database backend')
|
2007-08-20 07:18:43 +08:00
|
|
|
|
2007-10-24 03:00:31 +08:00
|
|
|
def last_executed_query(self, cursor, sql, params):
|
|
|
|
"""
|
|
|
|
Returns a string of the query last executed by the given cursor, with
|
|
|
|
placeholders replaced with actual values.
|
|
|
|
|
|
|
|
`sql` is the raw query containing placeholders, and `params` is the
|
|
|
|
sequence of parameters. These are used by default, but this method
|
|
|
|
exists for database backends to provide a better implementation
|
|
|
|
according to their own quoting schemes.
|
|
|
|
"""
|
|
|
|
from django.utils.encoding import smart_unicode, force_unicode
|
|
|
|
|
|
|
|
# Convert params to contain Unicode values.
|
2010-03-09 22:46:33 +08:00
|
|
|
to_unicode = lambda s: force_unicode(s, strings_only=True, errors='replace')
|
2007-10-24 03:00:31 +08:00
|
|
|
if isinstance(params, (list, tuple)):
|
|
|
|
u_params = tuple([to_unicode(val) for val in params])
|
|
|
|
else:
|
|
|
|
u_params = dict([(to_unicode(k), to_unicode(v)) for k, v in params.items()])
|
|
|
|
|
|
|
|
return smart_unicode(sql) % u_params
|
|
|
|
|
2007-08-20 07:18:43 +08:00
|
|
|
def last_insert_id(self, cursor, table_name, pk_name):
|
|
|
|
"""
|
|
|
|
Given a cursor object that has just performed an INSERT statement into
|
|
|
|
a table that has an auto-incrementing ID, returns the newly created ID.
|
|
|
|
|
|
|
|
This method also receives the table name and the name of the primary-key
|
|
|
|
column.
|
|
|
|
"""
|
|
|
|
return cursor.lastrowid
|
2007-08-20 07:24:59 +08:00
|
|
|
|
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
|
|
|
def lookup_cast(self, lookup_type):
|
|
|
|
"""
|
|
|
|
Returns the string to use in a query when performing lookups
|
|
|
|
("contains", "like", etc). The resulting string should contain a '%s'
|
|
|
|
placeholder for the column being searched against.
|
|
|
|
"""
|
|
|
|
return "%s"
|
|
|
|
|
2010-09-17 03:53:41 +08:00
|
|
|
def max_in_list_size(self):
|
|
|
|
"""
|
|
|
|
Returns the maximum number of items that can be passed in a single 'IN'
|
|
|
|
list condition, or None if the backend does not impose a limit.
|
|
|
|
"""
|
|
|
|
return None
|
|
|
|
|
2007-08-20 07:53:39 +08:00
|
|
|
def max_name_length(self):
|
|
|
|
"""
|
|
|
|
Returns the maximum length of table and column names, or None if there
|
|
|
|
is no limit.
|
|
|
|
"""
|
|
|
|
return None
|
2007-08-20 07:59:06 +08:00
|
|
|
|
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
|
|
|
def no_limit_value(self):
|
|
|
|
"""
|
|
|
|
Returns the value to use for the LIMIT when we are wanting "LIMIT
|
|
|
|
infinity". Returns None if the limit clause can be omitted in this case.
|
|
|
|
"""
|
2009-03-10 19:21:46 +08:00
|
|
|
raise NotImplementedError
|
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
|
|
|
|
2007-08-20 07:59:06 +08:00
|
|
|
def pk_default_value(self):
|
|
|
|
"""
|
|
|
|
Returns the value to use during an INSERT statement to specify that
|
|
|
|
the field should use its default value.
|
|
|
|
"""
|
|
|
|
return 'DEFAULT'
|
2007-08-20 08:04:20 +08:00
|
|
|
|
2009-03-14 05:04:48 +08:00
|
|
|
def process_clob(self, value):
|
|
|
|
"""
|
|
|
|
Returns the value of a CLOB column, for backends that return a locator
|
|
|
|
object that requires additional processing.
|
|
|
|
"""
|
|
|
|
return value
|
|
|
|
|
2009-03-11 15:06:50 +08:00
|
|
|
def return_insert_id(self):
|
|
|
|
"""
|
2009-03-13 07:41:27 +08:00
|
|
|
For backends that support returning the last insert ID as part
|
|
|
|
of an insert query, this method returns the SQL and params to
|
|
|
|
append to the INSERT query. The returned fragment should
|
|
|
|
contain a format string to hold the appropriate column.
|
2009-03-11 15:06:50 +08:00
|
|
|
"""
|
|
|
|
pass
|
|
|
|
|
2009-12-22 23:18:51 +08:00
|
|
|
def compiler(self, compiler_name):
|
2007-08-20 10:39:05 +08:00
|
|
|
"""
|
2009-12-22 23:18:51 +08:00
|
|
|
Returns the SQLCompiler class corresponding to the given name,
|
|
|
|
in the namespace corresponding to the `compiler_module` attribute
|
|
|
|
on this backend.
|
2007-08-20 10:39:05 +08:00
|
|
|
"""
|
2011-01-12 21:39:31 +08:00
|
|
|
if self._cache is None:
|
|
|
|
self._cache = import_module(self.compiler_module)
|
|
|
|
return getattr(self._cache, compiler_name)
|
2007-08-20 10:39:05 +08:00
|
|
|
|
2007-08-20 09:03:33 +08:00
|
|
|
def quote_name(self, name):
|
|
|
|
"""
|
|
|
|
Returns a quoted version of the given table, index or column name. Does
|
|
|
|
not quote the given name if it's already been quoted.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2007-08-20 08:04:20 +08:00
|
|
|
def random_function_sql(self):
|
|
|
|
"""
|
|
|
|
Returns a SQL expression that returns a random value.
|
|
|
|
"""
|
|
|
|
return 'RANDOM()'
|
2007-08-20 08:15:53 +08:00
|
|
|
|
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
|
|
|
def regex_lookup(self, lookup_type):
|
|
|
|
"""
|
|
|
|
Returns the string to use in a query when performing regular expression
|
|
|
|
lookups (using "regex" or "iregex"). The resulting string should
|
|
|
|
contain a '%s' placeholder for the column being searched against.
|
|
|
|
|
|
|
|
If the feature is not supported (or part of it is not supported), a
|
|
|
|
NotImplementedError exception can be raised.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2008-08-12 13:34:56 +08:00
|
|
|
def savepoint_create_sql(self, sid):
|
|
|
|
"""
|
|
|
|
Returns the SQL for starting a new savepoint. Only required if the
|
|
|
|
"uses_savepoints" feature is True. The "sid" parameter is a string
|
|
|
|
for the savepoint id.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def savepoint_commit_sql(self, sid):
|
|
|
|
"""
|
|
|
|
Returns the SQL for committing the given savepoint.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def savepoint_rollback_sql(self, sid):
|
|
|
|
"""
|
|
|
|
Returns the SQL for rolling back the given savepoint.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
|
|
|
|
2007-08-20 08:15:53 +08:00
|
|
|
def sql_flush(self, style, tables, sequences):
|
|
|
|
"""
|
|
|
|
Returns a list of SQL statements required to remove all data from
|
|
|
|
the given database tables (without actually removing the tables
|
|
|
|
themselves).
|
|
|
|
|
|
|
|
The `style` argument is a Style object as returned by either
|
|
|
|
color_style() or no_style() in django.core.management.color.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
2007-08-20 08:21:10 +08:00
|
|
|
|
|
|
|
def sequence_reset_sql(self, style, model_list):
|
|
|
|
"""
|
|
|
|
Returns a list of the SQL statements required to reset sequences for
|
|
|
|
the given models.
|
|
|
|
|
|
|
|
The `style` argument is a Style object as returned by either
|
|
|
|
color_style() or no_style() in django.core.management.color.
|
|
|
|
"""
|
|
|
|
return [] # No sequence reset required by default.
|
2007-08-20 08:24:03 +08:00
|
|
|
|
|
|
|
def start_transaction_sql(self):
|
|
|
|
"""
|
|
|
|
Returns the SQL statement required to start a transaction.
|
|
|
|
"""
|
|
|
|
return "BEGIN;"
|
2007-08-20 08:30:19 +08:00
|
|
|
|
2010-05-28 21:46:12 +08:00
|
|
|
def end_transaction_sql(self, success=True):
|
|
|
|
if not success:
|
|
|
|
return "ROLLBACK;"
|
|
|
|
return "COMMIT;"
|
|
|
|
|
2008-09-11 07:03:07 +08:00
|
|
|
def tablespace_sql(self, tablespace, inline=False):
|
2007-08-20 08:30:19 +08:00
|
|
|
"""
|
2008-08-11 20:11:25 +08:00
|
|
|
Returns the SQL that will be appended to tables or rows to define
|
|
|
|
a tablespace. Returns '' if the backend doesn't use tablespaces.
|
2007-08-20 08:30:19 +08:00
|
|
|
"""
|
2008-08-11 20:11:25 +08:00
|
|
|
return ''
|
2008-08-12 13:34:56 +08:00
|
|
|
|
2008-06-16 11:15:04 +08:00
|
|
|
def prep_for_like_query(self, x):
|
|
|
|
"""Prepares a value for use in a LIKE query."""
|
|
|
|
from django.utils.encoding import smart_unicode
|
|
|
|
return smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
|
2008-07-29 13:09:29 +08:00
|
|
|
|
2008-08-28 13:42:05 +08:00
|
|
|
# Same as prep_for_like_query(), but called for "iexact" matches, which
|
|
|
|
# need not necessarily be implemented using "LIKE" in the backend.
|
|
|
|
prep_for_iexact_query = prep_for_like_query
|
|
|
|
|
2008-07-29 13:09:29 +08:00
|
|
|
def value_to_db_date(self, value):
|
|
|
|
"""
|
|
|
|
Transform a date value to an object compatible with what is expected
|
|
|
|
by the backend driver for date columns.
|
|
|
|
"""
|
|
|
|
if value is None:
|
|
|
|
return None
|
|
|
|
return datetime_safe.new_date(value).strftime('%Y-%m-%d')
|
|
|
|
|
|
|
|
def value_to_db_datetime(self, value):
|
|
|
|
"""
|
|
|
|
Transform a datetime value to an object compatible with what is expected
|
2008-07-30 11:16:39 +08:00
|
|
|
by the backend driver for datetime columns.
|
2008-07-29 13:09:29 +08:00
|
|
|
"""
|
|
|
|
if value is None:
|
|
|
|
return None
|
|
|
|
return unicode(value)
|
|
|
|
|
|
|
|
def value_to_db_time(self, value):
|
|
|
|
"""
|
|
|
|
Transform a datetime value to an object compatible with what is expected
|
2008-07-30 11:16:39 +08:00
|
|
|
by the backend driver for time columns.
|
2008-07-29 13:09:29 +08:00
|
|
|
"""
|
|
|
|
if value is None:
|
|
|
|
return None
|
|
|
|
return unicode(value)
|
|
|
|
|
|
|
|
def value_to_db_decimal(self, value, max_digits, decimal_places):
|
|
|
|
"""
|
|
|
|
Transform a decimal.Decimal value to an object compatible with what is
|
|
|
|
expected by the backend driver for decimal (numeric) columns.
|
|
|
|
"""
|
|
|
|
if value is None:
|
|
|
|
return None
|
|
|
|
return util.format_number(value, max_digits, decimal_places)
|
|
|
|
|
|
|
|
def year_lookup_bounds(self, value):
|
|
|
|
"""
|
|
|
|
Returns a two-elements list with the lower and upper bound to be used
|
|
|
|
with a BETWEEN operator to query a field value using a year lookup
|
|
|
|
|
|
|
|
`value` is an int, containing the looked-up year.
|
|
|
|
"""
|
|
|
|
first = '%s-01-01 00:00:00'
|
|
|
|
second = '%s-12-31 23:59:59.999999'
|
|
|
|
return [first % value, second % value]
|
|
|
|
|
|
|
|
def year_lookup_bounds_for_date_field(self, value):
|
|
|
|
"""
|
|
|
|
Returns a two-elements list with the lower and upper bound to be used
|
|
|
|
with a BETWEEN operator to query a DateField value using a year lookup
|
|
|
|
|
|
|
|
`value` is an int, containing the looked-up year.
|
|
|
|
|
|
|
|
By default, it just calls `self.year_lookup_bounds`. Some backends need
|
|
|
|
this hook because on their DB date fields can't be compared to values
|
|
|
|
which include a time part.
|
|
|
|
"""
|
|
|
|
return self.year_lookup_bounds(value)
|
|
|
|
|
2009-01-15 19:06:34 +08:00
|
|
|
def convert_values(self, value, field):
|
|
|
|
"""Coerce the value returned by the database backend into a consistent type that
|
|
|
|
is compatible with the field type.
|
|
|
|
"""
|
|
|
|
internal_type = field.get_internal_type()
|
|
|
|
if internal_type == 'DecimalField':
|
|
|
|
return value
|
|
|
|
elif internal_type and internal_type.endswith('IntegerField') or internal_type == 'AutoField':
|
|
|
|
return int(value)
|
|
|
|
elif internal_type in ('DateField', 'DateTimeField', 'TimeField'):
|
|
|
|
return value
|
|
|
|
# No field, or the field isn't known to be a decimal or integer
|
|
|
|
# Default to a float
|
|
|
|
return float(value)
|
|
|
|
|
2009-02-02 20:03:31 +08:00
|
|
|
def check_aggregate_support(self, aggregate_func):
|
|
|
|
"""Check that the backend supports the provided aggregate
|
|
|
|
|
|
|
|
This is used on specific backends to rule out known aggregates
|
|
|
|
that are known to have faulty implementations. If the named
|
|
|
|
aggregate function has a known problem, the backend should
|
|
|
|
raise NotImplemented.
|
|
|
|
"""
|
|
|
|
pass
|
2009-01-15 19:06:34 +08:00
|
|
|
|
2009-02-24 19:15:31 +08:00
|
|
|
def combine_expression(self, connector, sub_expressions):
|
|
|
|
"""Combine a list of subexpressions into a single expression, using
|
|
|
|
the provided connecting operator. This is required because operators
|
|
|
|
can vary between backends (e.g., Oracle with %% and &) and between
|
|
|
|
subexpression types (e.g., date expressions)
|
|
|
|
"""
|
|
|
|
conn = ' %s ' % connector
|
|
|
|
return conn.join(sub_expressions)
|
|
|
|
|
2008-08-11 20:11:25 +08:00
|
|
|
class BaseDatabaseIntrospection(object):
|
|
|
|
"""
|
|
|
|
This class encapsulates all backend-specific introspection utilities
|
|
|
|
"""
|
|
|
|
data_types_reverse = {}
|
|
|
|
|
|
|
|
def __init__(self, connection):
|
|
|
|
self.connection = connection
|
|
|
|
|
2009-08-22 05:42:39 +08:00
|
|
|
def get_field_type(self, data_type, description):
|
|
|
|
"""Hook for a database backend to use the cursor description to
|
|
|
|
match a Django field type to a database column.
|
|
|
|
|
|
|
|
For Oracle, the column data_type on its own is insufficient to
|
|
|
|
distinguish between a FloatField and IntegerField, for example."""
|
|
|
|
return self.data_types_reverse[data_type]
|
|
|
|
|
2008-08-11 20:11:25 +08:00
|
|
|
def table_name_converter(self, name):
|
|
|
|
"""Apply a conversion to the name for the purposes of comparison.
|
2008-08-12 13:34:56 +08:00
|
|
|
|
2008-08-11 20:11:25 +08:00
|
|
|
The default table name converter is for case sensitive comparison.
|
|
|
|
"""
|
|
|
|
return name
|
2008-08-12 13:34:56 +08:00
|
|
|
|
2008-08-11 20:11:25 +08:00
|
|
|
def table_names(self):
|
|
|
|
"Returns a list of names of all tables that exist in the database."
|
|
|
|
cursor = self.connection.cursor()
|
|
|
|
return self.get_table_list(cursor)
|
|
|
|
|
|
|
|
def django_table_names(self, only_existing=False):
|
|
|
|
"""
|
|
|
|
Returns a list of all table names that have associated Django models and
|
|
|
|
are in INSTALLED_APPS.
|
|
|
|
|
|
|
|
If only_existing is True, the resulting list will only include the tables
|
|
|
|
that actually exist in the database.
|
|
|
|
"""
|
2010-03-10 21:43:23 +08:00
|
|
|
from django.db import models, router
|
2008-08-11 20:11:25 +08:00
|
|
|
tables = set()
|
|
|
|
for app in models.get_apps():
|
|
|
|
for model in models.get_models(app):
|
2009-03-09 11:35:02 +08:00
|
|
|
if not model._meta.managed:
|
|
|
|
continue
|
2010-03-10 21:43:23 +08:00
|
|
|
if not router.allow_syncdb(self.connection.alias, model):
|
|
|
|
continue
|
2008-08-11 20:11:25 +08:00
|
|
|
tables.add(model._meta.db_table)
|
|
|
|
tables.update([f.m2m_db_table() for f in model._meta.local_many_to_many])
|
|
|
|
if only_existing:
|
2010-10-31 08:53:58 +08:00
|
|
|
existing_tables = self.table_names()
|
|
|
|
tables = [
|
|
|
|
t
|
|
|
|
for t in tables
|
|
|
|
if self.table_name_converter(t) in existing_tables
|
|
|
|
]
|
2008-08-11 20:11:25 +08:00
|
|
|
return tables
|
|
|
|
|
|
|
|
def installed_models(self, tables):
|
|
|
|
"Returns a set of all models represented by the provided list of table names."
|
2010-03-10 21:43:23 +08:00
|
|
|
from django.db import models, router
|
2008-08-11 20:11:25 +08:00
|
|
|
all_models = []
|
|
|
|
for app in models.get_apps():
|
|
|
|
for model in models.get_models(app):
|
2010-03-10 21:43:23 +08:00
|
|
|
if router.allow_syncdb(self.connection.alias, model):
|
|
|
|
all_models.append(model)
|
2010-11-02 13:41:46 +08:00
|
|
|
tables = map(self.table_name_converter, tables)
|
|
|
|
return set([
|
|
|
|
m for m in all_models
|
|
|
|
if self.table_name_converter(m._meta.db_table) in tables
|
2008-08-11 20:11:25 +08:00
|
|
|
])
|
2008-08-12 13:34:56 +08:00
|
|
|
|
2008-08-11 20:11:25 +08:00
|
|
|
def sequence_list(self):
|
|
|
|
"Returns a list of information about all DB sequences for all models in all apps."
|
2010-03-10 21:43:23 +08:00
|
|
|
from django.db import models, router
|
2008-08-11 20:11:25 +08:00
|
|
|
|
|
|
|
apps = models.get_apps()
|
|
|
|
sequence_list = []
|
|
|
|
|
|
|
|
for app in apps:
|
|
|
|
for model in models.get_models(app):
|
2009-03-09 11:35:02 +08:00
|
|
|
if not model._meta.managed:
|
|
|
|
continue
|
2010-03-10 21:43:23 +08:00
|
|
|
if not router.allow_syncdb(self.connection.alias, model):
|
|
|
|
continue
|
2008-08-11 20:11:25 +08:00
|
|
|
for f in model._meta.local_fields:
|
|
|
|
if isinstance(f, models.AutoField):
|
|
|
|
sequence_list.append({'table': model._meta.db_table, 'column': f.column})
|
|
|
|
break # Only one AutoField is allowed per model, so don't bother continuing.
|
|
|
|
|
|
|
|
for f in model._meta.local_many_to_many:
|
2009-04-13 15:07:51 +08:00
|
|
|
# If this is an m2m using an intermediate table,
|
|
|
|
# we don't need to reset the sequence.
|
|
|
|
if f.rel.through is None:
|
|
|
|
sequence_list.append({'table': f.m2m_db_table(), 'column': None})
|
2008-08-11 20:11:25 +08:00
|
|
|
|
|
|
|
return sequence_list
|
2008-08-12 13:34:56 +08:00
|
|
|
|
2008-08-11 20:11:25 +08:00
|
|
|
class BaseDatabaseClient(object):
|
|
|
|
"""
|
2008-09-09 10:13:58 +08:00
|
|
|
This class encapsulates all backend-specific methods for opening a
|
|
|
|
client shell.
|
2008-08-11 20:11:25 +08:00
|
|
|
"""
|
2008-09-09 10:13:58 +08:00
|
|
|
# This should be a string representing the name of the executable
|
|
|
|
# (e.g., "psql"). Subclasses must override this.
|
|
|
|
executable_name = None
|
|
|
|
|
2009-03-11 11:39:34 +08:00
|
|
|
def __init__(self, connection):
|
|
|
|
# connection is an instance of BaseDatabaseWrapper.
|
|
|
|
self.connection = connection
|
|
|
|
|
2008-08-11 20:11:25 +08:00
|
|
|
def runshell(self):
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
class BaseDatabaseValidation(object):
|
|
|
|
"""
|
|
|
|
This class encapsualtes all backend-specific model validation.
|
|
|
|
"""
|
2009-12-22 23:18:51 +08:00
|
|
|
def __init__(self, connection):
|
|
|
|
self.connection = connection
|
|
|
|
|
2008-08-11 20:11:25 +08:00
|
|
|
def validate_field(self, errors, opts, f):
|
|
|
|
"By default, there is no backend-specific validation"
|
|
|
|
pass
|