app/django/db/backends/sqlite3/base.py
changeset 54 03e267d67478
child 323 ff1a9aa48cfd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/django/db/backends/sqlite3/base.py	Fri Jul 18 18:22:23 2008 +0000
@@ -0,0 +1,173 @@
+"""
+SQLite3 backend for django.
+
+Python 2.3 and 2.4 require pysqlite2 (http://pysqlite.org/).
+
+Python 2.5 and later use the sqlite3 module in the standard library.
+"""
+
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
+try:
+    try:
+        from sqlite3 import dbapi2 as Database
+    except ImportError:
+        from pysqlite2 import dbapi2 as Database
+except ImportError, e:
+    import sys
+    from django.core.exceptions import ImproperlyConfigured
+    if sys.version_info < (2, 5, 0):
+        module = 'pysqlite2'
+    else:
+        module = 'sqlite3'
+    raise ImproperlyConfigured, "Error loading %s module: %s" % (module, e)
+
+try:
+    import decimal
+except ImportError:
+    from django.utils import _decimal as decimal # for Python 2.3
+
+DatabaseError = Database.DatabaseError
+IntegrityError = Database.IntegrityError
+
+Database.register_converter("bool", lambda s: str(s) == '1')
+Database.register_converter("time", util.typecast_time)
+Database.register_converter("date", util.typecast_date)
+Database.register_converter("datetime", util.typecast_timestamp)
+Database.register_converter("timestamp", util.typecast_timestamp)
+Database.register_converter("TIMESTAMP", util.typecast_timestamp)
+Database.register_converter("decimal", util.typecast_decimal)
+Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal)
+
+class DatabaseFeatures(BaseDatabaseFeatures):
+    supports_constraints = False
+
+class DatabaseOperations(BaseDatabaseOperations):
+    def date_extract_sql(self, lookup_type, field_name):
+        # sqlite doesn't support extract, so we fake it with the user-defined
+        # function django_extract that's registered in connect().
+        return 'django_extract("%s", %s)' % (lookup_type.lower(), field_name)
+
+    def date_trunc_sql(self, lookup_type, field_name):
+        # sqlite doesn't support DATE_TRUNC, so we fake it with a user-defined
+        # function django_date_trunc that's registered in connect().
+        return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
+
+    def drop_foreignkey_sql(self):
+        return ""
+
+    def pk_default_value(self):
+        return 'NULL'
+
+    def quote_name(self, name):
+        if name.startswith('"') and name.endswith('"'):
+            return name # Quoting once is enough.
+        return '"%s"' % name
+
+    def no_limit_value(self):
+        return -1
+
+    def sql_flush(self, style, tables, sequences):
+        # NB: The generated SQL below is specific to SQLite
+        # Note: The DELETE FROM... SQL generated below works for SQLite databases
+        # because constraints don't exist
+        sql = ['%s %s %s;' % \
+                (style.SQL_KEYWORD('DELETE'),
+                 style.SQL_KEYWORD('FROM'),
+                 style.SQL_FIELD(self.quote_name(table))
+                 ) for table in tables]
+        # Note: No requirement for reset of auto-incremented indices (cf. other
+        # sql_flush() implementations). Just return SQL at this point
+        return sql
+
+class DatabaseWrapper(BaseDatabaseWrapper):
+    features = DatabaseFeatures()
+    ops = DatabaseOperations()
+
+    # 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.
+    operators = {
+        'exact': '= %s',
+        'iexact': "LIKE %s ESCAPE '\\'",
+        'contains': "LIKE %s ESCAPE '\\'",
+        'icontains': "LIKE %s ESCAPE '\\'",
+        'regex': 'REGEXP %s',
+        'iregex': "REGEXP '(?i)' || %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 '\\'",
+    }
+
+    def _cursor(self, settings):
+        if self.connection is None:
+            kwargs = {
+                'database': settings.DATABASE_NAME,
+                'detect_types': Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES,
+            }
+            kwargs.update(self.options)
+            self.connection = Database.connect(**kwargs)
+            # Register extract, date_trunc, and regexp functions.
+            self.connection.create_function("django_extract", 2, _sqlite_extract)
+            self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)
+            self.connection.create_function("regexp", 2, _sqlite_regexp)
+        return self.connection.cursor(factory=SQLiteCursorWrapper)
+
+    def close(self):
+        from django.conf import settings
+        # If database is in memory, closing the connection destroys the
+        # database. To prevent accidental data loss, ignore close requests on
+        # an in-memory db.
+        if settings.DATABASE_NAME != ":memory:":
+            BaseDatabaseWrapper.close(self)
+
+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".
+    """
+    def execute(self, query, params=()):
+        query = self.convert_query(query, len(params))
+        return Database.Cursor.execute(self, query, params)
+
+    def executemany(self, query, param_list):
+        try:
+          query = self.convert_query(query, len(param_list[0]))
+          return Database.Cursor.executemany(self, query, param_list)
+        except (IndexError,TypeError):
+          # No parameter list provided
+          return None
+
+    def convert_query(self, query, num_params):
+        return query % tuple("?" * num_params)
+
+def _sqlite_extract(lookup_type, dt):
+    try:
+        dt = util.typecast_timestamp(dt)
+    except (ValueError, TypeError):
+        return None
+    return str(getattr(dt, lookup_type))
+
+def _sqlite_date_trunc(lookup_type, dt):
+    try:
+        dt = util.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 _sqlite_regexp(re_pattern, re_string):
+    import re
+    try:
+        return bool(re.search(re_pattern, re_string))
+    except:
+        return False