sqlite.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #============================================================================
  2. # This file is part of Pwman3.
  3. #
  4. # Pwman3 is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License, version 2
  6. # as published by the Free Software Foundation;
  7. #
  8. # Pwman3 is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with Pwman3; if not, write to the Free Software
  15. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. #============================================================================
  17. # Copyright (C) 2012 Oz Nahum <nahumoz@gmail.com>
  18. #============================================================================
  19. #============================================================================
  20. # Copyright (C) 2006 Ivan Kelly <ivan@ivankelly.net>
  21. #============================================================================
  22. """SQLite Database implementation."""
  23. from pwman.data.database import Database, DatabaseException
  24. from pwman.data.nodes import Node
  25. from pwman.data.tags import Tag
  26. import sys
  27. if sys.version_info > (2, 5):
  28. import sqlite3 as sqlite
  29. else:
  30. try:
  31. from pysqlite2 import dbapi2 as sqlite
  32. except ImportError:
  33. raise DatabaseException("python-sqlite2 not installed")
  34. import pwman.util.config as config
  35. import cPickle
  36. class SQLiteDatabase(Database):
  37. """SQLite Database implementation"""
  38. def __init__(self):
  39. """Initialise SQLitePwmanDatabase instance."""
  40. Database.__init__(self)
  41. try:
  42. self._filename = config.get_value('Database', 'filename')
  43. except KeyError, e:
  44. raise DatabaseException(
  45. "SQLite: missing parameter [%s]" % (e))
  46. def _open(self):
  47. try:
  48. self._con = sqlite.connect(self._filename)
  49. self._cur = self._con.cursor()
  50. self._checktables()
  51. except sqlite.DatabaseError, e:
  52. raise DatabaseException("SQLite: %s" % (e))
  53. def close(self):
  54. self._cur.close()
  55. self._con.close()
  56. def listtags(self, all=False):
  57. sql = ''
  58. params = []
  59. if len(self._filtertags) == 0 or all:
  60. sql = "SELECT DATA FROM TAGS ORDER BY DATA ASC"
  61. else:
  62. sql = ("SELECT TAGS.DATA FROM LOOKUP"
  63. +" INNER JOIN TAGS ON LOOKUP.TAG = TAGS.ID"
  64. +" WHERE NODE IN (")
  65. first = True
  66. for t in self._filtertags:
  67. if not first:
  68. sql += " INTERSECT "
  69. else:
  70. first = False
  71. sql += ("SELECT NODE FROM LOOKUP LEFT JOIN TAGS ON TAG = TAGS.ID "
  72. + " WHERE TAGS.DATA = ?")
  73. params.append(cPickle.dumps(t))
  74. sql += ") EXCEPT SELECT DATA FROM TAGS WHERE "
  75. first = True
  76. for t in self._filtertags:
  77. if not first:
  78. sql += " OR "
  79. else:
  80. first = False
  81. sql += "TAGS.DATA = ?"
  82. params.append(cPickle.dumps(t))
  83. try:
  84. self._cur.execute(sql, params)
  85. tags = []
  86. row = self._cur.fetchone()
  87. while (row != None):
  88. tag = cPickle.loads(str(row[0]))
  89. tags.append(tag)
  90. row = self._cur.fetchone()
  91. return tags
  92. except sqlite.DatabaseError, e:
  93. raise DatabaseException("SQLite: %s" % (e))
  94. def getnodes(self, ids):
  95. nodes = []
  96. for i in ids:
  97. sql = "SELECT DATA FROM NODES WHERE ID = ?"
  98. try:
  99. self._cur.execute(sql, [i])
  100. row = self._cur.fetchone()
  101. if row != None:
  102. node = cPickle.loads(str(row[0]))
  103. node.set_id(i)
  104. nodes.append(node)
  105. except sqlite.DatabaseError, e:
  106. raise DatabaseException("SQLite: %s" % (e))
  107. return nodes
  108. def editnode(self, id, node):
  109. if not isinstance(node, Node): raise DatabaseException(
  110. "Tried to insert foreign object into database [%s]" % node)
  111. try:
  112. sql = "UPDATE NODES SET DATA = ? WHERE ID = ?";
  113. self._cur.execute(sql, [cPickle.dumps(node), id])
  114. except sqlite.DatabaseError, e:
  115. raise DatabaseException("SQLite: %s" % (e))
  116. self._setnodetags(node)
  117. self._checktags()
  118. self._commit()
  119. def addnodes(self, nodes):
  120. for n in nodes:
  121. sql = "INSERT INTO NODES(DATA) VALUES(?)"
  122. if not isinstance(n, Node): raise DatabaseException(
  123. "Tried to insert foreign object into database [%s]", n)
  124. value = cPickle.dumps(n)
  125. try:
  126. self._cur.execute(sql, [value])
  127. except sqlite.DatabaseError, e:
  128. raise DatabaseException("SQLite: %s" % (e))
  129. id = self._cur.lastrowid
  130. n.set_id(id)
  131. self._setnodetags(n)
  132. self._commit()
  133. def removenodes(self, nodes):
  134. for n in nodes:
  135. if not isinstance(n, Node): raise DatabaseException(
  136. "Tried to delete foreign object from database [%s]", n)
  137. try:
  138. sql = "DELETE FROM NODES WHERE ID = ?";
  139. self._cur.execute(sql, [n.get_id()])
  140. except sqlite.DatabaseError, e:
  141. raise DatabaseException("SQLite: %s" % (e))
  142. self._deletenodetags(n)
  143. self._checktags()
  144. self._commit()
  145. def listnodes(self):
  146. sql = ''
  147. params = []
  148. if len(self._filtertags) == 0:
  149. sql = "SELECT ID FROM NODES ORDER BY ID ASC"
  150. else:
  151. first = True
  152. for t in self._filtertags:
  153. if not first:
  154. sql += " INTERSECT "
  155. else:
  156. first = False
  157. sql += ("SELECT NODE FROM LOOKUP LEFT JOIN TAGS ON TAG = TAGS.ID"
  158. + " WHERE TAGS.DATA = ? ")
  159. params.append(cPickle.dumps(t))
  160. try:
  161. self._cur.execute(sql, params)
  162. ids = []
  163. row = self._cur.fetchone()
  164. while (row != None):
  165. ids.append(row[0])
  166. row = self._cur.fetchone()
  167. return ids
  168. except sqlite.DatabaseError, e:
  169. raise DatabaseException("SQLite: %s" % (e))
  170. def _commit(self):
  171. try:
  172. self._con.commit()
  173. except sqlite.DatabaseError, e:
  174. self._con.rollback()
  175. raise DatabaseException(
  176. "SQLite: Error commiting data to db [%s]" % (e))
  177. def _tagids(self, tags):
  178. ids = []
  179. for t in tags:
  180. sql = "SELECT ID FROM TAGS WHERE DATA = ?"
  181. if not isinstance(t, Tag): raise DatabaseException(
  182. "Tried to insert foreign object into database [%s]", t)
  183. data = cPickle.dumps(t)
  184. try:
  185. self._cur.execute(sql, [data])
  186. row = self._cur.fetchone()
  187. if (row != None):
  188. ids.append(row[0])
  189. else:
  190. sql = "INSERT INTO TAGS(DATA) VALUES(?)"
  191. self._cur.execute(sql, [data])
  192. ids.append(self._cur.lastrowid)
  193. except sqlite.DatabaseError, e:
  194. raise DatabaseException("SQLite: %s" % (e))
  195. return ids
  196. def _deletenodetags(self, node):
  197. try:
  198. sql = "DELETE FROM LOOKUP WHERE NODE = ?"
  199. self._cur.execute(sql, [node.get_id()])
  200. except sqlite.DatabaseError, e:
  201. raise DatabaseException("SQLite: %s" % (e))
  202. self._commit()
  203. def _setnodetags(self, node):
  204. self._deletenodetags(node)
  205. ids = self._tagids(node.get_tags())
  206. for i in ids:
  207. sql = "INSERT OR REPLACE INTO LOOKUP VALUES(?, ?)"
  208. params = [node.get_id(), i]
  209. try:
  210. self._cur.execute(sql, params)
  211. except sqlite.DatabaseError, e:
  212. raise DatabaseException("SQLite: %s" % (e))
  213. self._commit()
  214. def _checktags(self):
  215. try:
  216. sql = "DELETE FROM TAGS WHERE ID NOT IN (SELECT TAG FROM LOOKUP GROUP BY TAG)"
  217. self._cur.execute(sql)
  218. except sqlite.DatabaseError, e:
  219. raise DatabaseException("SQLite: %s" % (e))
  220. self._commit()
  221. def _checktables(self):
  222. """ Check if the Pwman tables exist """
  223. self._cur.execute("PRAGMA TABLE_INFO(NODES)")
  224. if (self._cur.fetchone() == None):
  225. # table doesn't exist, create it
  226. # SQLite does have constraints implemented at the moment
  227. # so datatype will just be a string
  228. self._cur.execute("CREATE TABLE NODES"
  229. + "(ID INTEGER PRIMARY KEY AUTOINCREMENT,"
  230. + "DATA BLOB NOT NULL)")
  231. self._cur.execute("CREATE TABLE TAGS"
  232. + "(ID INTEGER PRIMARY KEY AUTOINCREMENT,"
  233. + "DATA BLOB NOT NULL UNIQUE)")
  234. self._cur.execute("CREATE TABLE LOOKUP"
  235. + "(NODE INTEGER NOT NULL, TAG INTEGER NOT NULL,"
  236. + " PRIMARY KEY(NODE, TAG))")
  237. self._cur.execute("CREATE TABLE KEY"
  238. + "(THEKEY TEXT NOT NULL DEFAULT '')");
  239. self._cur.execute("INSERT INTO KEY VALUES('')");
  240. try:
  241. self._con.commit()
  242. except DatabaseError, e:
  243. self._con.rollback()
  244. raise e
  245. def savekey(self, key):
  246. sql = "UPDATE KEY SET THEKEY = ?"
  247. values = [key]
  248. self._cur.execute(sql, values)
  249. try:
  250. self._con.commit()
  251. except sqlite.DatabaseError, e:
  252. self._con.rollback()
  253. raise DatabaseException(
  254. "SQLite: Error saving key [%s]" % (e))
  255. def loadkey(self):
  256. """
  257. fetch the key to database. the key is also stored
  258. encrypted.
  259. """
  260. self._cur.execute("SELECT THEKEY FROM KEY");
  261. keyrow = self._cur.fetchone()
  262. if (keyrow[0] == ''):
  263. return None
  264. else:
  265. return keyrow[0]