This file is indexed.

/usr/share/pyshared/axiom/_pysqlite2.py is in python-axiom 0.7.1-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# -*- test-case-name: axiom.test.test_pysqlite2 -*-

"""
PySQLite2 Connection and Cursor wrappers.

These provide a uniform interface on top of PySQLite2 for Axiom, particularly
including error handling behavior and exception types.
"""

import time, sys

try:
    # Prefer the third-party module, as it is easier to update, and so may
    # be newer or otherwise better.
    from pysqlite2 import dbapi2
except ImportError:
    # But fall back to the stdlib module if we're on Python 2.6 or newer,
    # because it should work too.  Don't do this for Python 2.5 because
    # there are critical, data-destroying bugs in that version.
    if sys.version_info >= (2, 6):
        import sqlite3 as dbapi2
    else:
        raise

from twisted.python import log

from axiom import errors, iaxiom

class Connection(object):
    def __init__(self, connection, timeout=None):
        self._connection = connection
        self._timeout = timeout


    def fromDatabaseName(cls, dbFilename, timeout=None, isolationLevel=None):
        return cls(dbapi2.connect(dbFilename, timeout=0,
                                  isolation_level=isolationLevel))
    fromDatabaseName = classmethod(fromDatabaseName)


    def cursor(self):
        return Cursor(self, self._timeout)


    def identifySQLError(self, sql, args, e):
        """
        Identify an appropriate SQL error object for the given message for the
        supported versions of sqlite.

        @return: an SQLError
        """
        message = e.args[0]
        if message.startswith("table") and message.endswith("already exists"):
            return errors.TableAlreadyExists(sql, args, e)
        return errors.SQLError(sql, args, e)



class Cursor(object):
    def __init__(self, connection, timeout):
        self._connection = connection
        self._cursor = connection._connection.cursor()
        self.timeout = timeout


    def __iter__(self):
        return iter(self._cursor)


    def time(self):
        """
        Return the current wallclock time as a float representing seconds
        from an fixed but arbitrary point.
        """
        return time.time()


    def sleep(self, seconds):
        """
        Block for the given number of seconds.

        @type seconds: C{float}
        """
        time.sleep(seconds)


    def execute(self, sql, args=()):
        try:
            try:
                blockedTime = 0.0
                t = self.time()
                try:
                    # SQLite3 uses something like exponential backoff when
                    # trying to acquire a database lock.  This means that even
                    # for very long timeouts, it may only attempt to acquire
                    # the lock a handful of times.  Another process which is
                    # executing frequent, short-lived transactions may acquire
                    # and release the lock many times between any two attempts
                    # by this one to acquire it.  If this process gets unlucky
                    # just a few times, this execute may fail to acquire the
                    # lock within the specified timeout.

                    # Since attempting to acquire the lock is a fairly cheap
                    # operation, we take another route.  SQLite3 is always told
                    # to use a timeout of 0 - ie, acquire it on the first try
                    # or fail instantly.  We will keep doing this, ten times a
                    # second, until the actual timeout expires.

                    # What would be really fantastic is a notification
                    # mechanism for information about the state of the lock
                    # changing.  Of course this clearly insane, no one has ever
                    # managed to invent a tool for communicating one bit of
                    # information between multiple processes.
                    while 1:
                        try:
                            return self._cursor.execute(sql, args)
                        except dbapi2.OperationalError, e:
                            if e.args[0] == 'database is locked':
                                now = self.time()
                                if self.timeout is not None:
                                    if (now - t) > self.timeout:
                                        raise errors.TimeoutError(sql, self.timeout, e)
                                self.sleep(0.1)
                                blockedTime = self.time() - t
                            else:
                                raise
                finally:
                    txntime = self.time() - t
                    if txntime - blockedTime > 2.0:
                        log.msg('Extremely long execute: %s' % (txntime - blockedTime,))
                        log.msg(sql)
                        # import traceback; traceback.print_stack()
                    log.msg(interface=iaxiom.IStatEvent,
                            stat_cursor_execute_time=txntime,
                            stat_cursor_blocked_time=blockedTime)
            except dbapi2.OperationalError, e:
                if e.args[0] == 'database schema has changed':
                    return self._cursor.execute(sql, args)
                raise
        except (dbapi2.ProgrammingError,
                dbapi2.InterfaceError,
                dbapi2.OperationalError), e:
            raise self._connection.identifySQLError(sql, args, e)


    def lastRowID(self):
        return self._cursor.lastrowid


    def close(self):
        self._cursor.close()


# Export some names from the underlying module.
sqlite_version_info = dbapi2.sqlite_version_info
OperationalError = dbapi2.OperationalError

__all__ = [
    'OperationalError',
    'Connection',
    'sqlite_version_info',
    ]