1 """ |
1 """ |
2 SQLite3 backend for django. |
2 SQLite3 backend for django. |
3 |
3 |
4 Python 2.3 and 2.4 require pysqlite2 (http://pysqlite.org/). |
4 Python 2.4 requires pysqlite2 (http://pysqlite.org/). |
5 |
5 |
6 Python 2.5 and later can use a pysqlite2 module or the sqlite3 module in the |
6 Python 2.5 and later can use a pysqlite2 module or the sqlite3 module in the |
7 standard library. |
7 standard library. |
8 """ |
8 """ |
9 |
9 |
|
10 import re |
|
11 import sys |
|
12 |
|
13 from django.db import utils |
10 from django.db.backends import * |
14 from django.db.backends import * |
11 from django.db.backends.signals import connection_created |
15 from django.db.backends.signals import connection_created |
12 from django.db.backends.sqlite3.client import DatabaseClient |
16 from django.db.backends.sqlite3.client import DatabaseClient |
13 from django.db.backends.sqlite3.creation import DatabaseCreation |
17 from django.db.backends.sqlite3.creation import DatabaseCreation |
14 from django.db.backends.sqlite3.introspection import DatabaseIntrospection |
18 from django.db.backends.sqlite3.introspection import DatabaseIntrospection |
25 if sys.version_info < (2, 5, 0): |
29 if sys.version_info < (2, 5, 0): |
26 module = 'pysqlite2 module' |
30 module = 'pysqlite2 module' |
27 exc = e1 |
31 exc = e1 |
28 else: |
32 else: |
29 module = 'either pysqlite2 or sqlite3 modules (tried in that order)' |
33 module = 'either pysqlite2 or sqlite3 modules (tried in that order)' |
30 raise ImproperlyConfigured, "Error loading %s: %s" % (module, exc) |
34 raise ImproperlyConfigured("Error loading %s: %s" % (module, exc)) |
31 |
35 |
32 try: |
|
33 import decimal |
|
34 except ImportError: |
|
35 from django.utils import _decimal as decimal # for Python 2.3 |
|
36 |
36 |
37 DatabaseError = Database.DatabaseError |
37 DatabaseError = Database.DatabaseError |
38 IntegrityError = Database.IntegrityError |
38 IntegrityError = Database.IntegrityError |
39 |
39 |
40 Database.register_converter("bool", lambda s: str(s) == '1') |
40 Database.register_converter("bool", lambda s: str(s) == '1') |
62 can_use_chunked_reads = False |
62 can_use_chunked_reads = False |
63 |
63 |
64 class DatabaseOperations(BaseDatabaseOperations): |
64 class DatabaseOperations(BaseDatabaseOperations): |
65 def date_extract_sql(self, lookup_type, field_name): |
65 def date_extract_sql(self, lookup_type, field_name): |
66 # sqlite doesn't support extract, so we fake it with the user-defined |
66 # sqlite doesn't support extract, so we fake it with the user-defined |
67 # function django_extract that's registered in connect(). |
67 # function django_extract that's registered in connect(). Note that |
68 return 'django_extract("%s", %s)' % (lookup_type.lower(), field_name) |
68 # single quotes are used because this is a string (and could otherwise |
|
69 # cause a collision with a field name). |
|
70 return "django_extract('%s', %s)" % (lookup_type.lower(), field_name) |
69 |
71 |
70 def date_trunc_sql(self, lookup_type, field_name): |
72 def date_trunc_sql(self, lookup_type, field_name): |
71 # sqlite doesn't support DATE_TRUNC, so we fake it with a user-defined |
73 # sqlite doesn't support DATE_TRUNC, so we fake it with a user-defined |
72 # function django_date_trunc that's registered in connect(). |
74 # function django_date_trunc that's registered in connect(). Note that |
73 return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name) |
75 # single quotes are used because this is a string (and could otherwise |
|
76 # cause a collision with a field name). |
|
77 return "django_date_trunc('%s', %s)" % (lookup_type.lower(), field_name) |
74 |
78 |
75 def drop_foreignkey_sql(self): |
79 def drop_foreignkey_sql(self): |
76 return "" |
80 return "" |
77 |
81 |
78 def pk_default_value(self): |
82 def pk_default_value(self): |
152 self.features = DatabaseFeatures() |
156 self.features = DatabaseFeatures() |
153 self.ops = DatabaseOperations() |
157 self.ops = DatabaseOperations() |
154 self.client = DatabaseClient(self) |
158 self.client = DatabaseClient(self) |
155 self.creation = DatabaseCreation(self) |
159 self.creation = DatabaseCreation(self) |
156 self.introspection = DatabaseIntrospection(self) |
160 self.introspection = DatabaseIntrospection(self) |
157 self.validation = BaseDatabaseValidation() |
161 self.validation = BaseDatabaseValidation(self) |
158 |
162 |
159 def _cursor(self): |
163 def _cursor(self): |
160 if self.connection is None: |
164 if self.connection is None: |
161 settings_dict = self.settings_dict |
165 settings_dict = self.settings_dict |
162 if not settings_dict['DATABASE_NAME']: |
166 if not settings_dict['NAME']: |
163 from django.core.exceptions import ImproperlyConfigured |
167 from django.core.exceptions import ImproperlyConfigured |
164 raise ImproperlyConfigured, "Please fill out DATABASE_NAME in the settings module before using the database." |
168 raise ImproperlyConfigured("Please fill out the database NAME in the settings module before using the database.") |
165 kwargs = { |
169 kwargs = { |
166 'database': settings_dict['DATABASE_NAME'], |
170 'database': settings_dict['NAME'], |
167 'detect_types': Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES, |
171 'detect_types': Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES, |
168 } |
172 } |
169 kwargs.update(settings_dict['DATABASE_OPTIONS']) |
173 kwargs.update(settings_dict['OPTIONS']) |
170 self.connection = Database.connect(**kwargs) |
174 self.connection = Database.connect(**kwargs) |
171 # Register extract, date_trunc, and regexp functions. |
175 # Register extract, date_trunc, and regexp functions. |
172 self.connection.create_function("django_extract", 2, _sqlite_extract) |
176 self.connection.create_function("django_extract", 2, _sqlite_extract) |
173 self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc) |
177 self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc) |
174 self.connection.create_function("regexp", 2, _sqlite_regexp) |
178 self.connection.create_function("regexp", 2, _sqlite_regexp) |
177 |
181 |
178 def close(self): |
182 def close(self): |
179 # If database is in memory, closing the connection destroys the |
183 # If database is in memory, closing the connection destroys the |
180 # database. To prevent accidental data loss, ignore close requests on |
184 # database. To prevent accidental data loss, ignore close requests on |
181 # an in-memory db. |
185 # an in-memory db. |
182 if self.settings_dict['DATABASE_NAME'] != ":memory:": |
186 if self.settings_dict['NAME'] != ":memory:": |
183 BaseDatabaseWrapper.close(self) |
187 BaseDatabaseWrapper.close(self) |
|
188 |
|
189 FORMAT_QMARK_REGEX = re.compile(r'(?![^%])%s') |
184 |
190 |
185 class SQLiteCursorWrapper(Database.Cursor): |
191 class SQLiteCursorWrapper(Database.Cursor): |
186 """ |
192 """ |
187 Django uses "format" style placeholders, but pysqlite2 uses "qmark" style. |
193 Django uses "format" style placeholders, but pysqlite2 uses "qmark" style. |
188 This fixes it -- but note that if you want to use a literal "%s" in a query, |
194 This fixes it -- but note that if you want to use a literal "%s" in a query, |
189 you'll need to use "%%s". |
195 you'll need to use "%%s". |
190 """ |
196 """ |
191 def execute(self, query, params=()): |
197 def execute(self, query, params=()): |
192 query = self.convert_query(query, len(params)) |
198 query = self.convert_query(query) |
193 return Database.Cursor.execute(self, query, params) |
199 try: |
|
200 return Database.Cursor.execute(self, query, params) |
|
201 except Database.IntegrityError, e: |
|
202 raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2] |
|
203 except Database.DatabaseError, e: |
|
204 raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2] |
194 |
205 |
195 def executemany(self, query, param_list): |
206 def executemany(self, query, param_list): |
|
207 query = self.convert_query(query) |
196 try: |
208 try: |
197 query = self.convert_query(query, len(param_list[0])) |
209 return Database.Cursor.executemany(self, query, param_list) |
198 return Database.Cursor.executemany(self, query, param_list) |
210 except Database.IntegrityError, e: |
199 except (IndexError,TypeError): |
211 raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2] |
200 # No parameter list provided |
212 except Database.DatabaseError, e: |
201 return None |
213 raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2] |
202 |
214 |
203 def convert_query(self, query, num_params): |
215 def convert_query(self, query): |
204 return query % tuple("?" * num_params) |
216 return FORMAT_QMARK_REGEX.sub('?', query).replace('%%','%') |
205 |
217 |
206 def _sqlite_extract(lookup_type, dt): |
218 def _sqlite_extract(lookup_type, dt): |
207 if dt is None: |
219 if dt is None: |
208 return None |
220 return None |
209 try: |
221 try: |