summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrebs <drebs@leap.se>2013-03-04 22:59:44 -0300
committerdrebs <drebs@leap.se>2013-03-04 22:59:44 -0300
commit0baf100c59655d1fbe1424f685328ba2de080c98 (patch)
tree53d8942e80aa711df6728d2496f2fe57f766fc13
parent4c80e2d98ba0935559ffb153174e70bc73af8f3c (diff)
Monkey patch sqlite3 to use pysqlcipher.dbapi2.
-rw-r--r--backends/sqlcipher.py141
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)