Django

Code

root/django/trunk/django/db/backends/sqlite3/base.py

Revision 9060, 7.8 kB (checked in by mtredinnick, 3 weeks ago)

Fixed #9113 -- Improved exception message reporting when importing sqlite3 fails.

  • Property svn:eol-style set to native
Line 
1 """
2 SQLite3 backend for django.
3
4 Python 2.3 and 2.4 require pysqlite2 (http://pysqlite.org/).
5
6 Python 2.5 and later use the sqlite3 module in the standard library.
7 """
8
9 from django.db.backends import *
10 from django.db.backends.sqlite3.client import DatabaseClient
11 from django.db.backends.sqlite3.creation import DatabaseCreation
12 from django.db.backends.sqlite3.introspection import DatabaseIntrospection
13
14 try:
15     try:
16         from sqlite3 import dbapi2 as Database
17     except ImportError, e1:
18         from pysqlite2 import dbapi2 as Database
19 except ImportError, exc:
20     import sys
21     from django.core.exceptions import ImproperlyConfigured
22     if sys.version_info < (2, 5, 0):
23         module = 'pysqlite2'
24     else:
25         module = 'sqlite3'
26         exc = e1
27     raise ImproperlyConfigured, "Error loading %s module: %s" % (module, exc)
28
29 try:
30     import decimal
31 except ImportError:
32     from django.utils import _decimal as decimal # for Python 2.3
33
34 DatabaseError = Database.DatabaseError
35 IntegrityError = Database.IntegrityError
36
37 Database.register_converter("bool", lambda s: str(s) == '1')
38 Database.register_converter("time", util.typecast_time)
39 Database.register_converter("date", util.typecast_date)
40 Database.register_converter("datetime", util.typecast_timestamp)
41 Database.register_converter("timestamp", util.typecast_timestamp)
42 Database.register_converter("TIMESTAMP", util.typecast_timestamp)
43 Database.register_converter("decimal", util.typecast_decimal)
44 Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal)
45 if Database.version_info >= (2,4,1):
46     # Starting in 2.4.1, the str type is not accepted anymore, therefore,
47     # we convert all str objects to Unicode
48     # As registering a adapter for a primitive type causes a small
49     # slow-down, this adapter is only registered for sqlite3 versions
50     # needing it.
51     Database.register_adapter(str, lambda s:s.decode('utf-8'))
52
53 class DatabaseFeatures(BaseDatabaseFeatures):
54     # SQLite cannot handle us only partially reading from a cursor's result set
55     # and then writing the same rows to the database in another cursor. This
56     # setting ensures we always read result sets fully into memory all in one
57     # go.
58     can_use_chunked_reads = False
59
60 class DatabaseOperations(BaseDatabaseOperations):
61     def date_extract_sql(self, lookup_type, field_name):
62         # sqlite doesn't support extract, so we fake it with the user-defined
63         # function django_extract that's registered in connect().
64         return 'django_extract("%s", %s)' % (lookup_type.lower(), field_name)
65
66     def date_trunc_sql(self, lookup_type, field_name):
67         # sqlite doesn't support DATE_TRUNC, so we fake it with a user-defined
68         # function django_date_trunc that's registered in connect().
69         return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
70
71     def drop_foreignkey_sql(self):
72         return ""
73
74     def pk_default_value(self):
75         return 'NULL'
76
77     def quote_name(self, name):
78         if name.startswith('"') and name.endswith('"'):
79             return name # Quoting once is enough.
80         return '"%s"' % name
81
82     def no_limit_value(self):
83         return -1
84
85     def sql_flush(self, style, tables, sequences):
86         # NB: The generated SQL below is specific to SQLite
87         # Note: The DELETE FROM... SQL generated below works for SQLite databases
88         # because constraints don't exist
89         sql = ['%s %s %s;' % \
90                 (style.SQL_KEYWORD('DELETE'),
91                  style.SQL_KEYWORD('FROM'),
92                  style.SQL_FIELD(self.quote_name(table))
93                  ) for table in tables]
94         # Note: No requirement for reset of auto-incremented indices (cf. other
95         # sql_flush() implementations). Just return SQL at this point
96         return sql
97
98     def year_lookup_bounds(self, value):
99         first = '%s-01-01'
100         second = '%s-12-31 23:59:59.999999'
101         return [first % value, second % value]
102
103 class DatabaseWrapper(BaseDatabaseWrapper):
104    
105     # SQLite requires LIKE statements to include an ESCAPE clause if the value
106     # being escaped has a percent or underscore in it.
107     # See http://www.sqlite.org/lang_expr.html for an explanation.
108     operators = {
109         'exact': '= %s',
110         'iexact': "LIKE %s ESCAPE '\\'",
111         'contains': "LIKE %s ESCAPE '\\'",
112         'icontains': "LIKE %s ESCAPE '\\'",
113         'regex': 'REGEXP %s',
114         'iregex': "REGEXP '(?i)' || %s",
115         'gt': '> %s',
116         'gte': '>= %s',
117         'lt': '< %s',
118         'lte': '<= %s',
119         'startswith': "LIKE %s ESCAPE '\\'",
120         'endswith': "LIKE %s ESCAPE '\\'",
121         'istartswith': "LIKE %s ESCAPE '\\'",
122         'iendswith': "LIKE %s ESCAPE '\\'",
123     }
124
125     def __init__(self, *args, **kwargs):
126         super(DatabaseWrapper, self).__init__(*args, **kwargs)
127        
128         self.features = DatabaseFeatures()
129         self.ops = DatabaseOperations()
130         self.client = DatabaseClient()
131         self.creation = DatabaseCreation(self)
132         self.introspection = DatabaseIntrospection(self)
133         self.validation = BaseDatabaseValidation()
134
135     def _cursor(self, settings):
136         if self.connection is None:
137             if not settings.DATABASE_NAME:
138                 from django.core.exceptions import ImproperlyConfigured
139                 raise ImproperlyConfigured, "Please fill out DATABASE_NAME in the settings module before using the database."
140             kwargs = {
141                 'database': settings.DATABASE_NAME,
142                 'detect_types': Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES,
143             }
144             kwargs.update(self.options)
145             self.connection = Database.connect(**kwargs)
146             # Register extract, date_trunc, and regexp functions.
147             self.connection.create_function("django_extract", 2, _sqlite_extract)
148             self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)
149             self.connection.create_function("regexp", 2, _sqlite_regexp)
150         return self.connection.cursor(factory=SQLiteCursorWrapper)
151
152     def close(self):
153         from django.conf import settings
154         # If database is in memory, closing the connection destroys the
155         # database. To prevent accidental data loss, ignore close requests on
156         # an in-memory db.
157         if settings.DATABASE_NAME != ":memory:":
158             BaseDatabaseWrapper.close(self)
159
160 class SQLiteCursorWrapper(Database.Cursor):
161     """
162     Django uses "format" style placeholders, but pysqlite2 uses "qmark" style.
163     This fixes it -- but note that if you want to use a literal "%s" in a query,
164     you'll need to use "%%s".
165     """
166     def execute(self, query, params=()):
167         query = self.convert_query(query, len(params))
168         return Database.Cursor.execute(self, query, params)
169
170     def executemany(self, query, param_list):
171         try:
172           query = self.convert_query(query, len(param_list[0]))
173           return Database.Cursor.executemany(self, query, param_list)
174         except (IndexError,TypeError):
175           # No parameter list provided
176           return None
177
178     def convert_query(self, query, num_params):
179         return query % tuple("?" * num_params)
180
181 def _sqlite_extract(lookup_type, dt):
182     try:
183         dt = util.typecast_timestamp(dt)
184     except (ValueError, TypeError):
185         return None
186     return unicode(getattr(dt, lookup_type))
187
188 def _sqlite_date_trunc(lookup_type, dt):
189     try:
190         dt = util.typecast_timestamp(dt)
191     except (ValueError, TypeError):
192         return None
193     if lookup_type == 'year':
194         return "%i-01-01 00:00:00" % dt.year
195     elif lookup_type == 'month':
196         return "%i-%02i-01 00:00:00" % (dt.year, dt.month)
197     elif lookup_type == 'day':
198         return "%i-%02i-%02i 00:00:00" % (dt.year, dt.month, dt.day)
199
200 def _sqlite_regexp(re_pattern, re_string):
201     import re
202     try:
203         return bool(re.search(re_pattern, re_string))
204     except:
205         return False
Note: See TracBrowser for help on using the browser.