summaryrefslogtreecommitdiff
path: root/django/core/db
diff options
context:
space:
mode:
authorAdrian Holovaty <adrian@holovaty.com>2006-05-02 01:31:56 +0000
committerAdrian Holovaty <adrian@holovaty.com>2006-05-02 01:31:56 +0000
commitf69cf70ed813a8cd7e1f963a14ae39103e8d5265 (patch)
treed3b32e84cd66573b3833ddf662af020f8ef2f7a8 /django/core/db
parentd5dbeaa9be359a4c794885c2e9f1b5a7e5e51fb8 (diff)
MERGED MAGIC-REMOVAL BRANCH TO TRUNK. This change is highly backwards-incompatible. Please read http://code.djangoproject.com/wiki/RemovingTheMagic for upgrade instructions.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@2809 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/core/db')
-rw-r--r--django/core/db/__init__.py43
-rw-r--r--django/core/db/backends/__init__.py0
-rw-r--r--django/core/db/backends/ado_mssql.py174
-rw-r--r--django/core/db/backends/mysql.py235
-rw-r--r--django/core/db/backends/postgresql.py238
-rw-r--r--django/core/db/backends/sqlite3.py230
-rw-r--r--django/core/db/base.py32
-rw-r--r--django/core/db/dicthelpers.py24
-rw-r--r--django/core/db/typecasts.py55
9 files changed, 0 insertions, 1031 deletions
diff --git a/django/core/db/__init__.py b/django/core/db/__init__.py
deleted file mode 100644
index 1d2f04b367..0000000000
--- a/django/core/db/__init__.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""
-This is the core database connection.
-
-All Django code assumes database SELECT statements cast the resulting values as such:
- * booleans are mapped to Python booleans
- * dates are mapped to Python datetime.date objects
- * times are mapped to Python datetime.time objects
- * timestamps are mapped to Python datetime.datetime objects
-"""
-
-from django.conf.settings import DATABASE_ENGINE
-
-try:
- dbmod = __import__('django.core.db.backends.%s' % DATABASE_ENGINE, '', '', [''])
-except ImportError, exc:
- # The database backend wasn't found. Display a helpful error message
- # listing all possible database backends.
- from django.core.exceptions import ImproperlyConfigured
- import os
- backend_dir = os.path.join(__path__[0], 'backends')
- available_backends = [f[:-3] for f in os.listdir(backend_dir) if f.endswith('.py') and not f.startswith('__init__')]
- available_backends.sort()
- raise ImproperlyConfigured, "Could not load database backend: %s. Is your DATABASE_ENGINE setting (currently, %r) spelled correctly? Available options are: %s" % \
- (exc, DATABASE_ENGINE, ", ".join(map(repr, available_backends)))
-
-DatabaseError = dbmod.DatabaseError
-db = dbmod.DatabaseWrapper()
-dictfetchone = dbmod.dictfetchone
-dictfetchmany = dbmod.dictfetchmany
-dictfetchall = dbmod.dictfetchall
-dictfetchall = dbmod.dictfetchall
-get_last_insert_id = dbmod.get_last_insert_id
-get_date_extract_sql = dbmod.get_date_extract_sql
-get_date_trunc_sql = dbmod.get_date_trunc_sql
-get_limit_offset_sql = dbmod.get_limit_offset_sql
-get_random_function_sql = dbmod.get_random_function_sql
-get_table_list = dbmod.get_table_list
-get_table_description = dbmod.get_table_description
-get_relations = dbmod.get_relations
-get_indexes = dbmod.get_indexes
-OPERATOR_MAPPING = dbmod.OPERATOR_MAPPING
-DATA_TYPES = dbmod.DATA_TYPES
-DATA_TYPES_REVERSE = dbmod.DATA_TYPES_REVERSE
diff --git a/django/core/db/backends/__init__.py b/django/core/db/backends/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
--- a/django/core/db/backends/__init__.py
+++ /dev/null
diff --git a/django/core/db/backends/ado_mssql.py b/django/core/db/backends/ado_mssql.py
deleted file mode 100644
index 4afe0cef70..0000000000
--- a/django/core/db/backends/ado_mssql.py
+++ /dev/null
@@ -1,174 +0,0 @@
-"""
-ADO MSSQL database backend for Django.
-
-Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/
-"""
-
-from django.core.db import base
-from django.core.db.dicthelpers import *
-import adodbapi as Database
-import datetime
-try:
- import mx
-except ImportError:
- mx = None
-
-DatabaseError = Database.DatabaseError
-
-# We need to use a special Cursor class because adodbapi expects question-mark
-# param style, but Django expects "%s". This cursor converts question marks to
-# format-string style.
-class Cursor(Database.Cursor):
- def executeHelper(self, operation, isStoredProcedureCall, parameters=None):
- if parameters is not None and "%s" in operation:
- operation = operation.replace("%s", "?")
- Database.Cursor.executeHelper(self, operation, isStoredProcedureCall, parameters)
-
-class Connection(Database.Connection):
- def cursor(self):
- return Cursor(self)
-Database.Connection = Connection
-
-origCVtoP = Database.convertVariantToPython
-def variantToPython(variant, adType):
- if type(variant) == bool and adType == 11:
- return variant # bool not 1/0
- res = origCVtoP(variant, adType)
- if mx is not None and type(res) == mx.DateTime.mxDateTime.DateTimeType:
- # Convert ms.DateTime objects to Python datetime.datetime objects.
- tv = list(res.tuple()[:7])
- tv[-2] = int(tv[-2])
- return datetime.datetime(*tuple(tv))
- if type(res) == float and str(res)[-2:] == ".0":
- return int(res) # If float but int, then int.
- return res
-Database.convertVariantToPython = variantToPython
-
-try:
- # Only exists in python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from python 2.4
- from django.utils._threading_local import local
-
-class DatabaseWrapper(local):
- def __init__(self):
- self.connection = None
- self.queries = []
-
- def cursor(self):
- from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PORT, DATABASE_PASSWORD, DEBUG
- if self.connection is None:
- if DATABASE_NAME == '' or DATABASE_USER == '':
- from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file."
- if not DATABASE_HOST:
- DATABASE_HOST = "127.0.0.1"
- # TODO: Handle DATABASE_PORT.
- conn_string = "PROVIDER=SQLOLEDB;DATA SOURCE=%s;UID=%s;PWD=%s;DATABASE=%s" % (DATABASE_HOST, DATABASE_USER, DATABASE_PASSWORD, DATABASE_NAME)
- self.connection = Database.connect(conn_string)
- cursor = self.connection.cursor()
- if DEBUG:
- return base.CursorDebugWrapper(cursor, self)
- return cursor
-
- def commit(self):
- return self.connection.commit()
-
- def rollback(self):
- if self.connection:
- return self.connection.rollback()
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
-
- def quote_name(self, name):
- if name.startswith('[') and name.endswith(']'):
- return name # Quoting once is enough.
- return '[%s]' % name
-
-def get_last_insert_id(cursor, table_name, pk_name):
- cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name))
- return cursor.fetchone()[0]
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- return "DATEPART(%s, %s)" % (lookup_type, table_name)
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- if lookup_type=='year':
- return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name
- if lookup_type=='month':
- return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name)
- if lookup_type=='day':
- return "Convert(datetime, Convert(varchar(12), %s))" % field_name
-
-def get_limit_offset_sql(limit, offset=None):
- # TODO: This is a guess. Make sure this is correct.
- sql = "LIMIT %s" % limit
- if offset and offset != 0:
- sql += " OFFSET %s" % offset
- return sql
-
-def get_random_function_sql():
- return "RAND()"
-
-def get_table_list(cursor):
- raise NotImplementedError
-
-def get_table_description(cursor, table_name):
- raise NotImplementedError
-
-def get_relations(cursor, table_name):
- raise NotImplementedError
-
-def get_indexes(cursor, table_name):
- raise NotImplementedError
-
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': 'LIKE %s',
- 'contains': 'LIKE %s',
- 'icontains': 'LIKE %s',
- 'ne': '!= %s',
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': 'LIKE %s',
- 'endswith': 'LIKE %s',
- 'istartswith': 'LIKE %s',
- 'iendswith': 'LIKE %s',
-}
-
-DATA_TYPES = {
- 'AutoField': 'int IDENTITY (1, 1)',
- 'BooleanField': 'bit',
- 'CharField': 'varchar(%(maxlength)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
- 'DateField': 'smalldatetime',
- 'DateTimeField': 'smalldatetime',
- 'FileField': 'varchar(100)',
- 'FilePathField': 'varchar(100)',
- 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
- 'ImageField': 'varchar(100)',
- 'IntegerField': 'int',
- 'IPAddressField': 'char(15)',
- 'ManyToManyField': None,
- 'NullBooleanField': 'bit',
- 'OneToOneField': 'int',
- 'PhoneNumberField': 'varchar(20)',
- 'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)',
- 'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)',
- 'SlugField': 'varchar(%(maxlength)s)',
- 'SmallIntegerField': 'smallint',
- 'TextField': 'text',
- 'TimeField': 'time',
- 'URLField': 'varchar(200)',
- 'USStateField': 'varchar(2)',
-}
-
-DATA_TYPES_REVERSE = {}
diff --git a/django/core/db/backends/mysql.py b/django/core/db/backends/mysql.py
deleted file mode 100644
index d0e27e6f44..0000000000
--- a/django/core/db/backends/mysql.py
+++ /dev/null
@@ -1,235 +0,0 @@
-"""
-MySQL database backend for Django.
-
-Requires MySQLdb: http://sourceforge.net/projects/mysql-python
-"""
-
-from django.core.db import base, typecasts
-from django.core.db.dicthelpers import *
-import MySQLdb as Database
-from MySQLdb.converters import conversions
-from MySQLdb.constants import FIELD_TYPE
-import types
-
-DatabaseError = Database.DatabaseError
-
-django_conversions = conversions.copy()
-django_conversions.update({
- types.BooleanType: typecasts.rev_typecast_boolean,
- FIELD_TYPE.DATETIME: typecasts.typecast_timestamp,
- FIELD_TYPE.DATE: typecasts.typecast_date,
- FIELD_TYPE.TIME: typecasts.typecast_time,
-})
-
-# This is an extra debug layer over MySQL queries, to display warnings.
-# It's only used when DEBUG=True.
-class MysqlDebugWrapper:
- def __init__(self, cursor):
- self.cursor = cursor
-
- def execute(self, sql, params=()):
- try:
- return self.cursor.execute(sql, params)
- except Database.Warning, w:
- self.cursor.execute("SHOW WARNINGS")
- raise Database.Warning, "%s: %s" % (w, self.cursor.fetchall())
-
- def executemany(self, sql, param_list):
- try:
- return self.cursor.executemany(sql, param_list)
- except Database.Warning:
- self.cursor.execute("SHOW WARNINGS")
- raise Database.Warning, "%s: %s" % (w, self.cursor.fetchall())
-
- def __getattr__(self, attr):
- if self.__dict__.has_key(attr):
- return self.__dict__[attr]
- else:
- return getattr(self.cursor, attr)
-
-try:
- # Only exists in python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from python 2.4
- from django.utils._threading_local import local
-
-class DatabaseWrapper(local):
- def __init__(self):
- self.connection = None
- self.queries = []
-
- def _valid_connection(self):
- if self.connection is not None:
- try:
- self.connection.ping()
- return True
- except DatabaseError:
- self.connection.close()
- self.connection = None
- return False
-
- def cursor(self):
- from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PORT, DATABASE_PASSWORD, DEBUG
- if not self._valid_connection():
- kwargs = {
- 'user': DATABASE_USER,
- 'db': DATABASE_NAME,
- 'passwd': DATABASE_PASSWORD,
- 'host': DATABASE_HOST,
- 'conv': django_conversions,
- }
- if DATABASE_PORT:
- kwargs['port'] = DATABASE_PORT
- self.connection = Database.connect(**kwargs)
- cursor = self.connection.cursor()
- if self.connection.get_server_info() >= '4.1':
- cursor.execute("SET NAMES utf8")
- if DEBUG:
- return base.CursorDebugWrapper(MysqlDebugWrapper(cursor), self)
- return cursor
-
- def commit(self):
- self.connection.commit()
-
- def rollback(self):
- if self.connection:
- try:
- self.connection.rollback()
- except Database.NotSupportedError:
- pass
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
-
- def quote_name(self, name):
- if name.startswith("`") and name.endswith("`"):
- return name # Quoting once is enough.
- return "`%s`" % name
-
-def get_last_insert_id(cursor, table_name, pk_name):
- return cursor.lastrowid
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
- return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), table_name)
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
- # MySQL doesn't support DATE_TRUNC, so we fake it by subtracting intervals.
- # If you know of a better way to do this, please file a Django ticket.
- # Note that we can't use DATE_FORMAT directly because that causes the output
- # to be a string rather than a datetime object, and we need MySQL to return
- # a date so that it's typecasted properly into a Python datetime object.
- subtractions = ["interval (DATE_FORMAT(%s, '%%%%s')) second - interval (DATE_FORMAT(%s, '%%%%i')) minute - interval (DATE_FORMAT(%s, '%%%%H')) hour" % (field_name, field_name, field_name)]
- if lookup_type in ('year', 'month'):
- subtractions.append(" - interval (DATE_FORMAT(%s, '%%%%e')-1) day" % field_name)
- if lookup_type == 'year':
- subtractions.append(" - interval (DATE_FORMAT(%s, '%%%%m')-1) month" % field_name)
- return "(%s - %s)" % (field_name, ''.join(subtractions))
-
-def get_limit_offset_sql(limit, offset=None):
- sql = "LIMIT "
- if offset and offset != 0:
- sql += "%s," % offset
- return sql + str(limit)
-
-def get_random_function_sql():
- return "RAND()"
-
-def get_table_list(cursor):
- "Returns a list of table names in the current database."
- cursor.execute("SHOW TABLES")
- return [row[0] for row in cursor.fetchall()]
-
-def get_table_description(cursor, table_name):
- "Returns a description of the table, with the DB-API cursor.description interface."
- cursor.execute("SELECT * FROM %s LIMIT 1" % DatabaseWrapper().quote_name(table_name))
- return cursor.description
-
-def get_relations(cursor, table_name):
- raise NotImplementedError
-
-def get_indexes(cursor, table_name):
- """
- Returns a dictionary of fieldname -> infodict for the given table,
- where each infodict is in the format:
- {'primary_key': boolean representing whether it's the primary key,
- 'unique': boolean representing whether it's a unique index}
- """
- cursor.execute("SHOW INDEX FROM %s" % DatabaseWrapper().quote_name(table_name))
- indexes = {}
- for row in cursor.fetchall():
- indexes[row[4]] = {'primary_key': (row[2] == 'PRIMARY'), 'unique': not bool(row[1])}
- return indexes
-
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': 'LIKE %s',
- 'contains': 'LIKE BINARY %s',
- 'icontains': 'LIKE %s',
- 'ne': '!= %s',
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': 'LIKE BINARY %s',
- 'endswith': 'LIKE BINARY %s',
- 'istartswith': 'LIKE %s',
- 'iendswith': 'LIKE %s',
-}
-
-# This dictionary maps Field objects to their associated MySQL column
-# types, as strings. Column-type strings can contain format strings; they'll
-# be interpolated against the values of Field.__dict__ before being output.
-# If a column type is set to None, it won't be included in the output.
-DATA_TYPES = {
- 'AutoField': 'integer AUTO_INCREMENT',
- 'BooleanField': 'bool',
- 'CharField': 'varchar(%(maxlength)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
- 'DateField': 'date',
- 'DateTimeField': 'datetime',
- 'FileField': 'varchar(100)',
- 'FilePathField': 'varchar(100)',
- 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
- 'ImageField': 'varchar(100)',
- 'IntegerField': 'integer',
- 'IPAddressField': 'char(15)',
- 'ManyToManyField': None,
- 'NullBooleanField': 'bool',
- 'OneToOneField': 'integer',
- 'PhoneNumberField': 'varchar(20)',
- 'PositiveIntegerField': 'integer UNSIGNED',
- 'PositiveSmallIntegerField': 'smallint UNSIGNED',
- 'SlugField': 'varchar(%(maxlength)s)',
- 'SmallIntegerField': 'smallint',
- 'TextField': 'longtext',
- 'TimeField': 'time',
- 'URLField': 'varchar(200)',
- 'USStateField': 'varchar(2)',
-}
-
-DATA_TYPES_REVERSE = {
- FIELD_TYPE.BLOB: 'TextField',
- FIELD_TYPE.CHAR: 'CharField',
- FIELD_TYPE.DECIMAL: 'FloatField',
- FIELD_TYPE.DATE: 'DateField',
- FIELD_TYPE.DATETIME: 'DateTimeField',
- FIELD_TYPE.DOUBLE: 'FloatField',
- FIELD_TYPE.FLOAT: 'FloatField',
- FIELD_TYPE.INT24: 'IntegerField',
- FIELD_TYPE.LONG: 'IntegerField',
- FIELD_TYPE.LONGLONG: 'IntegerField',
- FIELD_TYPE.SHORT: 'IntegerField',
- FIELD_TYPE.STRING: 'TextField',
- FIELD_TYPE.TIMESTAMP: 'DateTimeField',
- FIELD_TYPE.TINY_BLOB: 'TextField',
- FIELD_TYPE.MEDIUM_BLOB: 'TextField',
- FIELD_TYPE.LONG_BLOB: 'TextField',
- FIELD_TYPE.VAR_STRING: 'CharField',
-}
diff --git a/django/core/db/backends/postgresql.py b/django/core/db/backends/postgresql.py
deleted file mode 100644
index 0bc799c247..0000000000
--- a/django/core/db/backends/postgresql.py
+++ /dev/null
@@ -1,238 +0,0 @@
-"""
-PostgreSQL database backend for Django.
-
-Requires psycopg 1: http://initd.org/projects/psycopg1
-"""
-
-from django.core.db import base, typecasts
-import psycopg as Database
-
-DatabaseError = Database.DatabaseError
-
-try:
- # Only exists in python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from python 2.4
- from django.utils._threading_local import local
-
-class DatabaseWrapper(local):
- def __init__(self):
- self.connection = None
- self.queries = []
-
- def cursor(self):
- from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PORT, DATABASE_PASSWORD, DEBUG, TIME_ZONE
- if self.connection is None:
- if DATABASE_NAME == '':
- from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file."
- conn_string = "dbname=%s" % DATABASE_NAME
- if DATABASE_USER:
- conn_string = "user=%s %s" % (DATABASE_USER, conn_string)
- if DATABASE_PASSWORD:
- conn_string += " password='%s'" % DATABASE_PASSWORD
- if DATABASE_HOST:
- conn_string += " host=%s" % DATABASE_HOST
- if DATABASE_PORT:
- conn_string += " port=%s" % DATABASE_PORT
- self.connection = Database.connect(conn_string)
- self.connection.set_isolation_level(1) # make transactions transparent to all cursors
- cursor = self.connection.cursor()
- cursor.execute("SET TIME ZONE %s", [TIME_ZONE])
- if DEBUG:
- return base.CursorDebugWrapper(cursor, self)
- return cursor
-
- def commit(self):
- return self.connection.commit()
-
- def rollback(self):
- if self.connection:
- return self.connection.rollback()
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
-
- def quote_name(self, name):
- if name.startswith('"') and name.endswith('"'):
- return name # Quoting once is enough.
- return '"%s"' % name
-
-def dictfetchone(cursor):
- "Returns a row from the cursor as a dict"
- return cursor.dictfetchone()
-
-def dictfetchmany(cursor, number):
- "Returns a certain number of rows from a cursor as a dict"
- return cursor.dictfetchmany(number)
-
-def dictfetchall(cursor):
- "Returns all rows from a cursor as a dict"
- return cursor.dictfetchall()
-
-def get_last_insert_id(cursor, table_name, pk_name):
- cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
- return cursor.fetchone()[0]
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
- return "EXTRACT('%s' FROM %s)" % (lookup_type, table_name)
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
- return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
-
-def get_limit_offset_sql(limit, offset=None):
- sql = "LIMIT %s" % limit
- if offset and offset != 0:
- sql += " OFFSET %s" % offset
- return sql
-
-def get_random_function_sql():
- return "RANDOM()"
-
-def get_table_list(cursor):
- "Returns a list of table names in the current database."
- cursor.execute("""
- SELECT c.relname
- FROM pg_catalog.pg_class c
- LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
- WHERE c.relkind IN ('r', 'v', '')
- AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
- AND pg_catalog.pg_table_is_visible(c.oid)""")
- return [row[0] for row in cursor.fetchall()]
-
-def get_table_description(cursor, table_name):
- "Returns a description of the table, with the DB-API cursor.description interface."
- cursor.execute("SELECT * FROM %s LIMIT 1" % DatabaseWrapper().quote_name(table_name))
- return cursor.description
-
-def get_relations(cursor, table_name):
- """
- Returns a dictionary of {field_index: (field_index_other_table, other_table)}
- representing all relationships to the given table. Indexes are 0-based.
- """
- cursor.execute("""
- SELECT con.conkey, con.confkey, c2.relname
- FROM pg_constraint con, pg_class c1, pg_class c2
- WHERE c1.oid = con.conrelid
- AND c2.oid = con.confrelid
- AND c1.relname = %s
- AND con.contype = 'f'""", [table_name])
- relations = {}
- for row in cursor.fetchall():
- try:
- # row[0] and row[1] are like "{2}", so strip the curly braces.
- relations[int(row[0][1:-1]) - 1] = (int(row[1][1:-1]) - 1, row[2])
- except ValueError:
- continue
- return relations
-
-def get_indexes(cursor, table_name):
- """
- Returns a dictionary of fieldname -> infodict for the given table,
- where each infodict is in the format:
- {'primary_key': boolean representing whether it's the primary key,
- 'unique': boolean representing whether it's a unique index}
- """
- # Get the table description because we only have the column indexes, and we
- # need the column names.
- desc = get_table_description(cursor, table_name)
- # This query retrieves each index on the given table.
- cursor.execute("""
- SELECT idx.indkey, idx.indisunique, idx.indisprimary
- FROM pg_catalog.pg_class c, pg_catalog.pg_class c2,
- pg_catalog.pg_index idx
- WHERE c.oid = idx.indrelid
- AND idx.indexrelid = c2.oid
- AND c.relname = %s""", [table_name])
- indexes = {}
- for row in cursor.fetchall():
- # row[0] (idx.indkey) is stored in the DB as an array. It comes out as
- # a string of space-separated integers. This designates the field
- # indexes (1-based) of the fields that have indexes on the table.
- # Here, we skip any indexes across multiple fields.
- if ' ' in row[0]:
- continue
- col_name = desc[int(row[0])-1][0]
- indexes[col_name] = {'primary_key': row[2], 'unique': row[1]}
- return indexes
-
-# Register these custom typecasts, because Django expects dates/times to be
-# in Python's native (standard-library) datetime/time format, whereas psycopg
-# use mx.DateTime by default.
-try:
- Database.register_type(Database.new_type((1082,), "DATE", typecasts.typecast_date))
-except AttributeError:
- raise Exception, "You appear to be using psycopg version 2, which isn't supported yet, because it's still in beta. Use psycopg version 1 instead: http://initd.org/projects/psycopg1"
-Database.register_type(Database.new_type((1083,1266), "TIME", typecasts.typecast_time))
-Database.register_type(Database.new_type((1114,1184), "TIMESTAMP", typecasts.typecast_timestamp))
-Database.register_type(Database.new_type((16,), "BOOLEAN", typecasts.typecast_boolean))
-
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': 'ILIKE %s',
- 'contains': 'LIKE %s',
- 'icontains': 'ILIKE %s',
- 'ne': '!= %s',
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': 'LIKE %s',
- 'endswith': 'LIKE %s',
- 'istartswith': 'ILIKE %s',
- 'iendswith': 'ILIKE %s',
-}
-
-# This dictionary maps Field objects to their associated PostgreSQL column
-# types, as strings. Column-type strings can contain format strings; they'll
-# be interpolated against the values of Field.__dict__ before being output.
-# If a column type is set to None, it won't be included in the output.
-DATA_TYPES = {
- 'AutoField': 'serial',
- 'BooleanField': 'boolean',
- 'CharField': 'varchar(%(maxlength)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
- 'DateField': 'date',
- 'DateTimeField': 'timestamp with time zone',
- 'FileField': 'varchar(100)',
- 'FilePathField': 'varchar(100)',
- 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
- 'ImageField': 'varchar(100)',
- 'IntegerField': 'integer',
- 'IPAddressField': 'inet',
- 'ManyToManyField': None,
- 'NullBooleanField': 'boolean',
- 'OneToOneField': 'integer',
- 'PhoneNumberField': 'varchar(20)',
- 'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)',
- 'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)',
- 'SlugField': 'varchar(%(maxlength)s)',
- 'SmallIntegerField': 'smallint',
- 'TextField': 'text',
- 'TimeField': 'time',
- 'URLField': 'varchar(200)',
- 'USStateField': 'varchar(2)',
-}
-
-# Maps type codes to Django Field types.
-DATA_TYPES_REVERSE = {
- 16: 'BooleanField',
- 21: 'SmallIntegerField',
- 23: 'IntegerField',
- 25: 'TextField',
- 869: 'IPAddressField',
- 1043: 'CharField',
- 1082: 'DateField',
- 1083: 'TimeField',
- 1114: 'DateTimeField',
- 1184: 'DateTimeField',
- 1266: 'TimeField',
- 1700: 'FloatField',
-}
diff --git a/django/core/db/backends/sqlite3.py b/django/core/db/backends/sqlite3.py
deleted file mode 100644
index 1b2ae8cd84..0000000000
--- a/django/core/db/backends/sqlite3.py
+++ /dev/null
@@ -1,230 +0,0 @@
-"""
-SQLite3 backend for django. Requires pysqlite2 (http://pysqlite.org/).
-"""
-
-from django.core.db import base, typecasts
-from django.core.db.dicthelpers import *
-from pysqlite2 import dbapi2 as Database
-DatabaseError = Database.DatabaseError
-
-# Register adaptors ###########################################################
-
-Database.register_converter("bool", lambda s: str(s) == '1')
-Database.register_converter("time", typecasts.typecast_time)
-Database.register_converter("date", typecasts.typecast_date)
-Database.register_converter("datetime", typecasts.typecast_timestamp)
-
-# Database wrapper ############################################################
-
-def utf8rowFactory(cursor, row):
- def utf8(s):
- if type(s) == unicode:
- return s.encode("utf-8")
- else:
- return s
- return [utf8(r) for r in row]
-
-try:
- # Only exists in python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from python 2.4
- from django.utils._threading_local import local
-
-class DatabaseWrapper(local):
- def __init__(self):
- self.connection = None
- self.queries = []
-
- def cursor(self):
- from django.conf.settings import DATABASE_NAME, DEBUG
- if self.connection is None:
- self.connection = Database.connect(DATABASE_NAME, detect_types=Database.PARSE_DECLTYPES)
- # register extract and date_trun functions
- self.connection.create_function("django_extract", 2, _sqlite_extract)
- self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)
- cursor = self.connection.cursor(factory=SQLiteCursorWrapper)
- cursor.row_factory = utf8rowFactory
- if DEBUG:
- return base.CursorDebugWrapper(cursor, self)
- else:
- return cursor
-
- def commit(self):
- self.connection.commit()
-
- def rollback(self):
- if self.connection:
- self.connection.rollback()
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
-
- def quote_name(self, name):
- if name.startswith('"') and name.endswith('"'):
- return name # Quoting once is enough.
- return '"%s"' % name
-
-class SQLiteCursorWrapper(Database.Cursor):
- """
- Django uses "format" style placeholders, but pysqlite2 uses "qmark" style.
- This fixes it -- but note that if you want to use a literal "%s" in a query,
- you'll need to use "%%s" (which I belive is true of other wrappers as well).
- """
-
- def execute(self, query, params=[]):
- query = self.convert_query(query, len(params))
- return Database.Cursor.execute(self, query, params)
-
- def executemany(self, query, params=[]):
- query = self.convert_query(query, len(params[0]))
- return Database.Cursor.executemany(self, query, params)
-
- def convert_query(self, query, num_params):
- # XXX this seems too simple to be correct... is this right?
- return query % tuple("?" * num_params)
-
-# Helper functions ############################################################
-
-def get_last_insert_id(cursor, table_name, pk_name):
- return cursor.lastrowid
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- # sqlite doesn't support extract, so we fake it with the user-defined
- # function _sqlite_extract that's registered in connect(), above.
- return 'django_extract("%s", %s)' % (lookup_type.lower(), table_name)
-
-def _sqlite_extract(lookup_type, dt):
- try:
- dt = typecasts.typecast_timestamp(dt)
- except (ValueError, TypeError):
- return None
- return str(getattr(dt, lookup_type))
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- # sqlite doesn't support DATE_TRUNC, so we fake it as above.
- return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
-
-def get_limit_offset_sql(limit, offset=None):
- sql = "LIMIT %s" % limit
- if offset and offset != 0:
- sql += " OFFSET %s" % offset
- return sql
-
-def get_random_function_sql():
- return "RANDOM()"
-
-def _sqlite_date_trunc(lookup_type, dt):
- try:
- dt = typecasts.typecast_timestamp(dt)
- except (ValueError, TypeError):
- return None
- if lookup_type == 'year':
- return "%i-01-01 00:00:00" % dt.year
- elif lookup_type == 'month':
- return "%i-%02i-01 00:00:00" % (dt.year, dt.month)
- elif lookup_type == 'day':
- return "%i-%02i-%02i 00:00:00" % (dt.year, dt.month, dt.day)
-
-def get_table_list(cursor):
- cursor.execute("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
- return [row[0] for row in cursor.fetchall()]
-
-def get_table_description(cursor, table_name):
- cursor.execute("PRAGMA table_info(%s)" % DatabaseWrapper().quote_name(table_name))
- return [(row[1], row[2], None, None) for row in cursor.fetchall()]
-
-def get_relations(cursor, table_name):
- raise NotImplementedError
-
-def get_indexes(cursor, table_name):
- raise NotImplementedError
-
-# Operators and fields ########################################################
-
-# SQLite requires LIKE statements to include an ESCAPE clause if the value
-# being escaped has a percent or underscore in it.
-# See http://www.sqlite.org/lang_expr.html for an explanation.
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': "LIKE %s ESCAPE '\\'",
- 'contains': "LIKE %s ESCAPE '\\'",
- 'icontains': "LIKE %s ESCAPE '\\'",
- 'ne': '!= %s',
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': "LIKE %s ESCAPE '\\'",
- 'endswith': "LIKE %s ESCAPE '\\'",
- 'istartswith': "LIKE %s ESCAPE '\\'",
- 'iendswith': "LIKE %s ESCAPE '\\'",
-}
-
-# SQLite doesn't actually support most of these types, but it "does the right
-# thing" given more verbose field definitions, so leave them as is so that
-# schema inspection is more useful.
-DATA_TYPES = {
- 'AutoField': 'integer',
- 'BooleanField': 'bool',
- 'CharField': 'varchar(%(maxlength)s)',
- 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
- 'DateField': 'date',
- 'DateTimeField': 'datetime',
- 'FileField': 'varchar(100)',
- 'FilePathField': 'varchar(100)',
- 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
- 'ImageField': 'varchar(100)',
- 'IntegerField': 'integer',
- 'IPAddressField': 'char(15)',
- 'ManyToManyField': None,
- 'NullBooleanField': 'bool',
- 'OneToOneField': 'integer',
- 'PhoneNumberField': 'varchar(20)',
- 'PositiveIntegerField': 'integer unsigned',
- 'PositiveSmallIntegerField': 'smallint unsigned',
- 'SlugField': 'varchar(%(maxlength)s)',
- 'SmallIntegerField': 'smallint',
- 'TextField': 'text',
- 'TimeField': 'time',
- 'URLField': 'varchar(200)',
- 'USStateField': 'varchar(2)',
-}
-
-# Maps SQL types to Django Field types. Some of the SQL types have multiple
-# entries here because SQLite allows for anything and doesn't normalize the
-# field type; it uses whatever was given.
-BASE_DATA_TYPES_REVERSE = {
- 'bool': 'BooleanField',
- 'boolean': 'BooleanField',
- 'smallint': 'SmallIntegerField',
- 'smallinteger': 'SmallIntegerField',
- 'int': 'IntegerField',
- 'integer': 'IntegerField',
- 'text': 'TextField',
- 'char': 'CharField',
- 'date': 'DateField',
- 'datetime': 'DateTimeField',
- 'time': 'TimeField',
-}
-
-# This light wrapper "fakes" a dictionary interface, because some SQLite data
-# types include variables in them -- e.g. "varchar(30)" -- and can't be matched
-# as a simple dictionary lookup.
-class FlexibleFieldLookupDict:
- def __getitem__(self, key):
- key = key.lower()
- try:
- return BASE_DATA_TYPES_REVERSE[key]
- except KeyError:
- import re
- m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key)
- if m:
- return ('CharField', {'maxlength': int(m.group(1))})
- raise KeyError
-
-DATA_TYPES_REVERSE = FlexibleFieldLookupDict()
diff --git a/django/core/db/base.py b/django/core/db/base.py
deleted file mode 100644
index 62cca9d0be..0000000000
--- a/django/core/db/base.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from time import time
-
-class CursorDebugWrapper:
- def __init__(self, cursor, db):
- self.cursor = cursor
- self.db = db
-
- def execute(self, sql, params=[]):
- start = time()
- result = self.cursor.execute(sql, params)
- stop = time()
- self.db.queries.append({
- 'sql': sql % tuple(params),
- 'time': "%.3f" % (stop - start),
- })
- return result
-
- def executemany(self, sql, param_list):
- start = time()
- result = self.cursor.executemany(sql, param_list)
- stop = time()
- self.db.queries.append({
- 'sql': 'MANY: ' + sql + ' ' + str(tuple(param_list)),
- 'time': "%.3f" % (stop - start),
- })
- return result
-
- def __getattr__(self, attr):
- if self.__dict__.has_key(attr):
- return self.__dict__[attr]
- else:
- return getattr(self.cursor, attr)
diff --git a/django/core/db/dicthelpers.py b/django/core/db/dicthelpers.py
deleted file mode 100644
index 5aedc51aed..0000000000
--- a/django/core/db/dicthelpers.py
+++ /dev/null
@@ -1,24 +0,0 @@
-"""
-Helper functions for dictfetch* for databases that don't natively support them.
-"""
-
-def _dict_helper(desc, row):
- "Returns a dictionary for the given cursor.description and result row."
- return dict([(desc[col[0]][0], col[1]) for col in enumerate(row)])
-
-def dictfetchone(cursor):
- "Returns a row from the cursor as a dict"
- row = cursor.fetchone()
- if not row:
- return None
- return _dict_helper(cursor.description, row)
-
-def dictfetchmany(cursor, number):
- "Returns a certain number of rows from a cursor as a dict"
- desc = cursor.description
- return [_dict_helper(desc, row) for row in cursor.fetchmany(number)]
-
-def dictfetchall(cursor):
- "Returns all rows from a cursor as a dict"
- desc = cursor.description
- return [_dict_helper(desc, row) for row in cursor.fetchall()]
diff --git a/django/core/db/typecasts.py b/django/core/db/typecasts.py
deleted file mode 100644
index 9be9062626..0000000000
--- a/django/core/db/typecasts.py
+++ /dev/null
@@ -1,55 +0,0 @@
-import datetime
-
-###############################################
-# Converters from database (string) to Python #
-###############################################
-
-def typecast_date(s):
- return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null
-
-def typecast_time(s): # does NOT store time zone information
- if not s: return None
- hour, minutes, seconds = s.split(':')
- if '.' in seconds: # check whether seconds have a fractional part
- seconds, microseconds = seconds.split('.')
- else:
- microseconds = '0'
- return datetime.time(int(hour), int(minutes), int(seconds), int(float('.'+microseconds) * 1000000))
-
-def typecast_timestamp(s): # does NOT store time zone information
- # "2005-07-29 15:48:00.590358-05"
- # "2005-07-29 09:56:00-05"
- if not s: return None
- if not ' ' in s: return typecast_date(s)
- d, t = s.split()
- # Extract timezone information, if it exists. Currently we just throw
- # it away, but in the future we may make use of it.
- if '-' in t:
- t, tz = t.split('-', 1)
- tz = '-' + tz
- elif '+' in t:
- t, tz = t.split('+', 1)
- tz = '+' + tz
- else:
- tz = ''
- dates = d.split('-')
- times = t.split(':')
- seconds = times[2]
- if '.' in seconds: # check whether seconds have a fractional part
- seconds, microseconds = seconds.split('.')
- else:
- microseconds = '0'
- return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]),
- int(times[0]), int(times[1]), int(seconds), int(float('.'+microseconds) * 1000000))
-
-def typecast_boolean(s):
- if s is None: return None
- if not s: return False
- return str(s)[0].lower() == 't'
-
-###############################################
-# Converters from Python to database (string) #
-###############################################
-
-def rev_typecast_boolean(obj, d):
- return obj and '1' or '0'