0001from sqlobject.dbconnection import DBAPI
0002from sqlobject.col import popKey
0003
0004sqlite = None
0005using_sqlite2 = False
0006
0007class SQLiteConnection(DBAPI):
0008
0009    supportTransactions = True
0010    dbName = 'sqlite'
0011    schemes = [dbName]
0012
0013    def __init__(self, filename, autoCommit=1, **kw):
0014        global sqlite
0015        global using_sqlite2
0016        if sqlite is None:
0017            try:
0018                from pysqlite2 import dbapi2 as sqlite
0019                using_sqlite2 = True
0020            except ImportError:
0021                import sqlite
0022                using_sqlite2 = False
0023        self.module = sqlite
0024        self.filename = filename  # full path to sqlite-db-file
0025        # connection options
0026        opts = {}
0027        if using_sqlite2:
0028            if autoCommit:
0029                opts["isolation_level"] = None
0030            if 'encoding' in kw:
0031                import warnings
0032                warnings.warn(DeprecationWarning("pysqlite2 does not support the encoding option"))
0033            opts["detect_types"] = sqlite.PARSE_DECLTYPES
0034            for col_type in "text", "char", "varchar":
0035                sqlite.register_converter(col_type, stop_pysqlite2_converting_strings_to_unicode)
0036                sqlite.register_converter(col_type.upper(), stop_pysqlite2_converting_strings_to_unicode)
0037        else:
0038            opts['autocommit'] = autoCommit
0039            if 'encoding' in kw:
0040                opts['encoding'] = popKey(kw, 'encoding')
0041            if 'mode' in kw:
0042                opts['mode'] = int(popKey(kw, 'mode'), 0)
0043        if 'timeout' in kw:
0044            opts['timeout'] = float(popKey(kw, 'timeout'))
0045        # use only one connection for sqlite - supports multiple)
0046        # cursors per connection
0047        self._conn = sqlite.connect(self.filename, **opts)
0048        DBAPI.__init__(self, **kw)
0049
0050    def connectionFromURI(cls, uri):
0051        user, password, host, port, path, args = cls._parseURI(uri)
0052        assert host is None, (
0053            "SQLite can only be used locally (with a URI like "
0054            "sqlite:///file or sqlite:/file, not %r)" % uri)
0055        assert user is None and password is None, (
0056            "You may not provide usernames or passwords for SQLite "
0057            "databases")
0058        if path == "/:memory:": path = ":memory:"
0059        return cls(filename=path, **args)
0060    connectionFromURI = classmethod(connectionFromURI)
0061
0062    def uri(self):
0063        return 'sqlite:///%s' % self.filename
0064
0065    def _setAutoCommit(self, conn, auto):
0066        if using_sqlite2:
0067            if auto:
0068                conn.isolation_level = None
0069            else:
0070                conn.isolation_level = ""
0071        else:
0072            conn.autocommit = auto
0073
0074    def _setIsolationLevel(self, conn, level):
0075        if not using_sqlite2:
0076            return
0077        conn.isolation_level = level
0078
0079    def makeConnection(self):
0080        return self._conn
0081
0082    def _queryInsertID(self, conn, soInstance, id, names, values):
0083        table = soInstance.sqlmeta.table
0084        idName = soInstance.sqlmeta.idName
0085        c = conn.cursor()
0086        if id is not None:
0087            names = [idName] + names
0088            values = [id] + values
0089        q = self._insertSQL(table, names, values)
0090        if self.debug:
0091            self.printDebug(conn, q, 'QueryIns')
0092        c.execute(q)
0093        # lastrowid is a DB-API extension from "PEP 0249":
0094        if id is None:
0095            id = int(c.lastrowid)
0096        if self.debugOutput:
0097            self.printDebug(conn, id, 'QueryIns', 'result')
0098        return id
0099
0100    def _insertSQL(self, table, names, values):
0101        if not names:
0102            assert not values
0103            # INSERT INTO table () VALUES () isn't allowed in
0104            # SQLite (though it is in other databases)
0105            return ("INSERT INTO %s VALUES (NULL)" % table)
0106        else:
0107            return DBAPI._insertSQL(self, table, names, values)
0108
0109    def _queryAddLimitOffset(self, query, start, end):
0110        if not start:
0111            return "%s LIMIT %i" % (query, end)
0112        if not end:
0113            return "%s LIMIT 0 OFFSET %i" % (query, start)
0114        return "%s LIMIT %i OFFSET %i" % (query, end-start, start)
0115
0116    def createColumn(self, soClass, col):
0117        return col.sqliteCreateSQL()
0118
0119    def createIDColumn(self, soClass):
0120        return '%s INTEGER PRIMARY KEY' % soClass.sqlmeta.idName
0121
0122    def joinSQLType(self, join):
0123        return 'INT NOT NULL'
0124
0125    def tableExists(self, tableName):
0126        result = self.queryOne("SELECT tbl_name FROM sqlite_master WHERE type='table' AND tbl_name = '%s'" % tableName)
0127        # turn it into a boolean:
0128        return not not result
0129
0130    def createIndexSQL(self, soClass, index):
0131        return index.sqliteCreateIndexSQL(soClass)
0132
0133def stop_pysqlite2_converting_strings_to_unicode(s):
0134    return s