web/lib/django/db/backends/sqlite3/base.py
author ymh <ymh.work@gmail.com>
Wed, 02 Jun 2010 18:57:35 +0200
changeset 38 77b6da96e6f1
permissions -rw-r--r--
update django
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
38
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
"""
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
SQLite3 backend for django.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
Python 2.4 requires pysqlite2 (http://pysqlite.org/).
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
Python 2.5 and later can use a pysqlite2 module or the sqlite3 module in the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
standard library.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
"""
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    10
import re
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    11
import sys
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    12
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    13
from django.db import utils
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    14
from django.db.backends import *
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    15
from django.db.backends.signals import connection_created
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    16
from django.db.backends.sqlite3.client import DatabaseClient
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    17
from django.db.backends.sqlite3.creation import DatabaseCreation
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    18
from django.db.backends.sqlite3.introspection import DatabaseIntrospection
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    19
from django.utils.safestring import SafeString
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    20
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    21
try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    22
    try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    23
        from pysqlite2 import dbapi2 as Database
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    24
    except ImportError, e1:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    25
        from sqlite3 import dbapi2 as Database
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    26
except ImportError, exc:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    27
    import sys
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    28
    from django.core.exceptions import ImproperlyConfigured
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    29
    if sys.version_info < (2, 5, 0):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    30
        module = 'pysqlite2 module'
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    31
        exc = e1
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    32
    else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    33
        module = 'either pysqlite2 or sqlite3 modules (tried in that order)'
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    34
    raise ImproperlyConfigured("Error loading %s: %s" % (module, exc))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    36
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    37
DatabaseError = Database.DatabaseError
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
IntegrityError = Database.IntegrityError
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    39
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    40
Database.register_converter("bool", lambda s: str(s) == '1')
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    41
Database.register_converter("time", util.typecast_time)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    42
Database.register_converter("date", util.typecast_date)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    43
Database.register_converter("datetime", util.typecast_timestamp)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    44
Database.register_converter("timestamp", util.typecast_timestamp)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    45
Database.register_converter("TIMESTAMP", util.typecast_timestamp)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    46
Database.register_converter("decimal", util.typecast_decimal)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    47
Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    48
if Database.version_info >= (2,4,1):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
    # Starting in 2.4.1, the str type is not accepted anymore, therefore,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    50
    # we convert all str objects to Unicode
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
    # As registering a adapter for a primitive type causes a small
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    52
    # slow-down, this adapter is only registered for sqlite3 versions
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    53
    # needing it.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    54
    Database.register_adapter(str, lambda s:s.decode('utf-8'))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    55
    Database.register_adapter(SafeString, lambda s:s.decode('utf-8'))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    56
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    57
class DatabaseFeatures(BaseDatabaseFeatures):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    58
    # SQLite cannot handle us only partially reading from a cursor's result set
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    59
    # and then writing the same rows to the database in another cursor. This
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
    # setting ensures we always read result sets fully into memory all in one
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    61
    # go.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    62
    can_use_chunked_reads = False
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    63
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    64
class DatabaseOperations(BaseDatabaseOperations):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    65
    def date_extract_sql(self, lookup_type, field_name):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    66
        # sqlite doesn't support extract, so we fake it with the user-defined
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    67
        # function django_extract that's registered in connect(). Note that
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    68
        # single quotes are used because this is a string (and could otherwise
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    69
        # cause a collision with a field name).
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    70
        return "django_extract('%s', %s)" % (lookup_type.lower(), field_name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    72
    def date_trunc_sql(self, lookup_type, field_name):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    73
        # sqlite doesn't support DATE_TRUNC, so we fake it with a user-defined
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    74
        # function django_date_trunc that's registered in connect(). Note that
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    75
        # single quotes are used because this is a string (and could otherwise
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    76
        # cause a collision with a field name).
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    77
        return "django_date_trunc('%s', %s)" % (lookup_type.lower(), field_name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    78
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    79
    def drop_foreignkey_sql(self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    80
        return ""
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    81
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    82
    def pk_default_value(self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    83
        return 'NULL'
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    84
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    85
    def quote_name(self, name):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    86
        if name.startswith('"') and name.endswith('"'):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    87
            return name # Quoting once is enough.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    88
        return '"%s"' % name
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    89
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    90
    def no_limit_value(self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    91
        return -1
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    92
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    93
    def sql_flush(self, style, tables, sequences):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    94
        # NB: The generated SQL below is specific to SQLite
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    95
        # Note: The DELETE FROM... SQL generated below works for SQLite databases
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    96
        # because constraints don't exist
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    97
        sql = ['%s %s %s;' % \
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    98
                (style.SQL_KEYWORD('DELETE'),
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    99
                 style.SQL_KEYWORD('FROM'),
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   100
                 style.SQL_FIELD(self.quote_name(table))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   101
                 ) for table in tables]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   102
        # Note: No requirement for reset of auto-incremented indices (cf. other
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   103
        # sql_flush() implementations). Just return SQL at this point
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   104
        return sql
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   105
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   106
    def year_lookup_bounds(self, value):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   107
        first = '%s-01-01'
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   108
        second = '%s-12-31 23:59:59.999999'
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   109
        return [first % value, second % value]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   110
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   111
    def convert_values(self, value, field):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   112
        """SQLite returns floats when it should be returning decimals,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   113
        and gets dates and datetimes wrong.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   114
        For consistency with other backends, coerce when required.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   115
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   116
        internal_type = field.get_internal_type()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   117
        if internal_type == 'DecimalField':
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   118
            return util.typecast_decimal(field.format_number(value))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   119
        elif internal_type and internal_type.endswith('IntegerField') or internal_type == 'AutoField':
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   120
            return int(value)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   121
        elif internal_type == 'DateField':
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   122
            return util.typecast_date(value)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   123
        elif internal_type == 'DateTimeField':
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   124
            return util.typecast_timestamp(value)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   125
        elif internal_type == 'TimeField':
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   126
            return util.typecast_time(value)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   127
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   128
        # No field, or the field isn't known to be a decimal or integer
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   129
        return value
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   130
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   131
class DatabaseWrapper(BaseDatabaseWrapper):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   132
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   133
    # SQLite requires LIKE statements to include an ESCAPE clause if the value
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   134
    # being escaped has a percent or underscore in it.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   135
    # See http://www.sqlite.org/lang_expr.html for an explanation.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   136
    operators = {
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   137
        'exact': '= %s',
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   138
        'iexact': "LIKE %s ESCAPE '\\'",
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   139
        'contains': "LIKE %s ESCAPE '\\'",
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   140
        'icontains': "LIKE %s ESCAPE '\\'",
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   141
        'regex': 'REGEXP %s',
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   142
        'iregex': "REGEXP '(?i)' || %s",
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   143
        'gt': '> %s',
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   144
        'gte': '>= %s',
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   145
        'lt': '< %s',
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   146
        'lte': '<= %s',
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   147
        'startswith': "LIKE %s ESCAPE '\\'",
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   148
        'endswith': "LIKE %s ESCAPE '\\'",
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   149
        'istartswith': "LIKE %s ESCAPE '\\'",
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   150
        'iendswith': "LIKE %s ESCAPE '\\'",
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   151
    }
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   152
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   153
    def __init__(self, *args, **kwargs):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   154
        super(DatabaseWrapper, self).__init__(*args, **kwargs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   155
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   156
        self.features = DatabaseFeatures()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   157
        self.ops = DatabaseOperations()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   158
        self.client = DatabaseClient(self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   159
        self.creation = DatabaseCreation(self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   160
        self.introspection = DatabaseIntrospection(self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   161
        self.validation = BaseDatabaseValidation(self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   162
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   163
    def _cursor(self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   164
        if self.connection is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   165
            settings_dict = self.settings_dict
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   166
            if not settings_dict['NAME']:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   167
                from django.core.exceptions import ImproperlyConfigured
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   168
                raise ImproperlyConfigured("Please fill out the database NAME in the settings module before using the database.")
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   169
            kwargs = {
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   170
                'database': settings_dict['NAME'],
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   171
                'detect_types': Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   172
            }
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   173
            kwargs.update(settings_dict['OPTIONS'])
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   174
            self.connection = Database.connect(**kwargs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   175
            # Register extract, date_trunc, and regexp functions.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   176
            self.connection.create_function("django_extract", 2, _sqlite_extract)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   177
            self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   178
            self.connection.create_function("regexp", 2, _sqlite_regexp)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   179
            connection_created.send(sender=self.__class__)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   180
        return self.connection.cursor(factory=SQLiteCursorWrapper)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   181
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   182
    def close(self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   183
        # If database is in memory, closing the connection destroys the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   184
        # database. To prevent accidental data loss, ignore close requests on
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   185
        # an in-memory db.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   186
        if self.settings_dict['NAME'] != ":memory:":
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   187
            BaseDatabaseWrapper.close(self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   188
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   189
FORMAT_QMARK_REGEX = re.compile(r'(?![^%])%s')
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   190
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   191
class SQLiteCursorWrapper(Database.Cursor):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   192
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   193
    Django uses "format" style placeholders, but pysqlite2 uses "qmark" style.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   194
    This fixes it -- but note that if you want to use a literal "%s" in a query,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   195
    you'll need to use "%%s".
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   196
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   197
    def execute(self, query, params=()):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   198
        query = self.convert_query(query)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   199
        try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   200
            return Database.Cursor.execute(self, query, params)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   201
        except Database.IntegrityError, e:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   202
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   203
        except Database.DatabaseError, e:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   204
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   205
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   206
    def executemany(self, query, param_list):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   207
        query = self.convert_query(query)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   208
        try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   209
            return Database.Cursor.executemany(self, query, param_list)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   210
        except Database.IntegrityError, e:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   211
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   212
        except Database.DatabaseError, e:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   213
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   214
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   215
    def convert_query(self, query):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   216
        return FORMAT_QMARK_REGEX.sub('?', query).replace('%%','%')
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   217
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   218
def _sqlite_extract(lookup_type, dt):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   219
    if dt is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   220
        return None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   221
    try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   222
        dt = util.typecast_timestamp(dt)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   223
    except (ValueError, TypeError):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   224
        return None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   225
    if lookup_type == 'week_day':
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   226
        return (dt.isoweekday() % 7) + 1
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   227
    else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   228
        return getattr(dt, lookup_type)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   229
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   230
def _sqlite_date_trunc(lookup_type, dt):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   231
    try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   232
        dt = util.typecast_timestamp(dt)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   233
    except (ValueError, TypeError):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   234
        return None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   235
    if lookup_type == 'year':
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   236
        return "%i-01-01 00:00:00" % dt.year
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   237
    elif lookup_type == 'month':
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   238
        return "%i-%02i-01 00:00:00" % (dt.year, dt.month)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   239
    elif lookup_type == 'day':
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   240
        return "%i-%02i-%02i 00:00:00" % (dt.year, dt.month, dt.day)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   241
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   242
def _sqlite_regexp(re_pattern, re_string):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   243
    import re
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   244
    try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   245
        return bool(re.search(re_pattern, re_string))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   246
    except:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   247
        return False