diff options
| author | drebs <drebs@leap.se> | 2013-03-04 22:59:44 -0300 | 
|---|---|---|
| committer | drebs <drebs@leap.se> | 2013-03-04 22:59:44 -0300 | 
| commit | 0baf100c59655d1fbe1424f685328ba2de080c98 (patch) | |
| tree | 53d8942e80aa711df6728d2496f2fe57f766fc13 | |
| parent | 4c80e2d98ba0935559ffb153174e70bc73af8f3c (diff) | |
Monkey patch sqlite3 to use pysqlcipher.dbapi2.
| -rw-r--r-- | backends/sqlcipher.py | 141 | 
1 files changed, 10 insertions, 131 deletions
| diff --git a/backends/sqlcipher.py b/backends/sqlcipher.py index a2ec9840..5d2569bf 100644 --- a/backends/sqlcipher.py +++ b/backends/sqlcipher.py @@ -1,30 +1,16 @@ -# Copyright 2011 Canonical Ltd. -# -# This file is part of u1db. -# -# u1db is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License version 3 -# as published by the Free Software Foundation. -# -# u1db is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with u1db.  If not, see <http://www.gnu.org/licenses/>. -  """A U1DB backend that uses SQLCipher as its persistence layer."""  import os  from pysqlcipher import dbapi2 -from sqlite3 import dbapi2 as sqlite3_dbapi2  import time -from u1db.backends.sqlite_backend import ( -    SQLiteDatabase, -    SQLitePartialExpandDatabase, +from leap import util +from u1db.backends import sqlite_backend +util.logger.debug( +    "Monkey-patching u1db.backends.sqlite_backend with pysqlcipher.dbapi2..."  ) +sqlite_backend.dbapi2 = dbapi2 +  from u1db import (      errors,  ) @@ -57,7 +43,7 @@ class DatabaseIsNotEncrypted(Exception):      pass -class SQLCipherDatabase(SQLitePartialExpandDatabase): +class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):      """A U1DB implementation that uses SQLCipher as its persistence layer."""      _index_storage_value = 'expand referenced encrypted' @@ -91,9 +77,9 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase):              try:                  # try to open an encrypted database with the regular u1db                  # backend should raise a DatabaseError exception. -                SQLitePartialExpandDatabase(sqlite_file) +                sqlite_backend.SQLitePartialExpandDatabase(sqlite_file)                  raise DatabaseIsNotEncrypted() -            except sqlite3_dbapi2.DatabaseError: +            except dbapi2.DatabaseError:                  pass      @classmethod @@ -174,111 +160,4 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase):              doc.syncable = bool(c.fetchone()[0])          return doc -    # TODO: remove methods below after solving Exception handling problem. -    def _is_initialized(self, c): -        """Check if this database has been initialized.""" -        c.execute("PRAGMA case_sensitive_like=ON") -        try: -            c.execute("SELECT value FROM u1db_config" -                      " WHERE name = 'sql_schema'") -        except dbapi2.OperationalError: -            # The table does not exist yet -            val = None -        else: -            val = c.fetchone() -        if val is not None: -            return True -        return False - -    def get_from_index(self, index_name, *key_values): -        definition = self._get_index_definition(index_name) -        if len(key_values) != len(definition): -            raise errors.InvalidValueForIndex() -        statement, args = self._format_query(definition, key_values) -        c = self._db_handle.cursor() -        try: -            c.execute(statement, tuple(args)) -        except dbapi2.OperationalError, e: -            raise dbapi2.OperationalError( -                str(e) + -                '\nstatement: %s\nargs: %s\n' % (statement, args)) -        res = c.fetchall() -        results = [] -        for row in res: -            doc = self._factory(row[0], row[1], row[2]) -            doc.has_conflicts = row[3] > 0 -            results.append(doc) -        return results - -    def get_range_from_index(self, index_name, start_value=None, -                             end_value=None): -        """Return all documents with key values in the specified range.""" -        definition = self._get_index_definition(index_name) -        statement, args = self._format_range_query( -            definition, start_value, end_value) -        c = self._db_handle.cursor() -        try: -            c.execute(statement, tuple(args)) -        except dbapi2.OperationalError, e: -            raise dbapi2.OperationalError(str(e) + -                '\nstatement: %s\nargs: %s\n' % (statement, args)) -        res = c.fetchall() -        results = [] -        for row in res: -            doc = self._factory(row[0], row[1], row[2]) -            doc.has_conflicts = row[3] > 0 -            results.append(doc) -        return results - -    def get_index_keys(self, index_name): -        c = self._db_handle.cursor() -        definition = self._get_index_definition(index_name) -        value_fields = ', '.join([ -            'd%d.value' % i for i in range(len(definition))]) -        tables = ["document_fields d%d" % i for i in range(len(definition))] -        novalue_where = [ -            "d.doc_id = d%d.doc_id AND d%d.field_name = ?" % (i, i) for i in -            range(len(definition))] -        where = [ -            novalue_where[i] + (" AND d%d.value NOT NULL" % (i,)) for i in -            range(len(definition))] -        statement = ( -            "SELECT %s FROM document d, %s WHERE %s GROUP BY %s;" % ( -                value_fields, ', '.join(tables), ' AND '.join(where), -                value_fields)) -        try: -            c.execute(statement, tuple(definition)) -        except dbapi2.OperationalError, e: -            raise dbapi2.OperationalError(str(e) + -                '\nstatement: %s\nargs: %s\n' % (statement, tuple(definition))) -        return c.fetchall() - -    def delete_index(self, index_name): -        with self._db_handle: -            c = self._db_handle.cursor() -            c.execute("DELETE FROM index_definitions WHERE name = ?", -                      (index_name,)) -            c.execute( -                "DELETE FROM document_fields WHERE document_fields.field_name " -                " NOT IN (SELECT field from index_definitions)") - -    def create_index(self, index_name, *index_expressions): -        with self._db_handle: -            c = self._db_handle.cursor() -            cur_fields = self._get_indexed_fields() -            definition = [(index_name, idx, field) -                          for idx, field in enumerate(index_expressions)] -            try: -                c.executemany("INSERT INTO index_definitions VALUES (?, ?, ?)", -                              definition) -            except dbapi2.IntegrityError as e: -                stored_def = self._get_index_definition(index_name) -                if stored_def == [x[-1] for x in definition]: -                    return -                raise errors.IndexNameTakenError, e, sys.exc_info()[2] -            new_fields = set( -                [f for f in index_expressions if f not in cur_fields]) -            if new_fields: -                self._update_all_indexes(new_fields) - -SQLiteDatabase.register_implementation(SQLCipherDatabase) +sqlite_backend.SQLiteDatabase.register_implementation(SQLCipherDatabase) | 
