sqlite.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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. def check_db_version():
  37. """
  38. check the data base version query the right table
  39. """
  40. try:
  41. filename = config.get_value('Database', 'filename')
  42. con = sqlite.connect(filename)
  43. cur = con.cursor()
  44. cur.execute("PRAGMA TABLE_INFO(DBVERSION)")
  45. row = cur.fetchone()
  46. if row is None:
  47. return "0.3"
  48. try:
  49. return row[-2]
  50. except IndexError:
  51. raise DatabaseException("Something seems fishy with the DB")
  52. except sqlite.DatabaseError, e:
  53. raise DatabaseException("SQLite: %s" % (e))
  54. class SQLiteDatabase(Database):
  55. """SQLite Database implementation"""
  56. def __init__(self):
  57. """Initialise SQLitePwmanDatabase instance."""
  58. Database.__init__(self)
  59. try:
  60. self._filename = config.get_value('Database', 'filename')
  61. except KeyError, e:
  62. raise DatabaseException(
  63. "SQLite: missing parameter [%s]" % (e))
  64. def _open(self):
  65. try:
  66. self._con = sqlite.connect(self._filename)
  67. self._cur = self._con.cursor()
  68. self._checktables()
  69. except sqlite.DatabaseError, e:
  70. raise DatabaseException("SQLite: %s" % (e))
  71. def close(self):
  72. self._cur.close()
  73. self._con.close()
  74. def listtags(self, all=False):
  75. sql = ''
  76. params = []
  77. if len(self._filtertags) == 0 or all:
  78. sql = "SELECT DATA FROM TAGS ORDER BY DATA ASC"
  79. else:
  80. sql = ("SELECT TAGS.DATA FROM LOOKUP"
  81. +" INNER JOIN TAGS ON LOOKUP.TAG = TAGS.ID"
  82. +" WHERE NODE IN (")
  83. first = True
  84. for t in self._filtertags:
  85. if not first:
  86. sql += " INTERSECT "
  87. else:
  88. first = False
  89. sql += ("SELECT NODE FROM LOOKUP LEFT JOIN TAGS ON TAG = TAGS.ID "
  90. + " WHERE TAGS.DATA = ?")
  91. params.append(cPickle.dumps(t))
  92. sql += ") EXCEPT SELECT DATA FROM TAGS WHERE "
  93. first = True
  94. for t in self._filtertags:
  95. if not first:
  96. sql += " OR "
  97. else:
  98. first = False
  99. sql += "TAGS.DATA = ?"
  100. params.append(cPickle.dumps(t))
  101. try:
  102. self._cur.execute(sql, params)
  103. tags = []
  104. row = self._cur.fetchone()
  105. while (row != None):
  106. tag = cPickle.loads(str(row[0]))
  107. tags.append(tag)
  108. row = self._cur.fetchone()
  109. return tags
  110. except sqlite.DatabaseError, e:
  111. raise DatabaseException("SQLite: %s" % (e))
  112. def getnodes(self, ids):
  113. nodes = []
  114. for i in ids:
  115. sql = "SELECT DATA FROM NODES WHERE ID = ?"
  116. try:
  117. self._cur.execute(sql, [i])
  118. row = self._cur.fetchone()
  119. if row != None:
  120. node = cPickle.loads(str(row[0]))
  121. node.set_id(i)
  122. nodes.append(node)
  123. except sqlite.DatabaseError, e:
  124. raise DatabaseException("SQLite: %s" % (e))
  125. return nodes
  126. def editnode(self, id, node):
  127. if not isinstance(node, Node): raise DatabaseException(
  128. "Tried to insert foreign object into database [%s]" % node)
  129. try:
  130. sql = "UPDATE NODES SET DATA = ? WHERE ID = ?";
  131. self._cur.execute(sql, [cPickle.dumps(node), id])
  132. except sqlite.DatabaseError, e:
  133. raise DatabaseException("SQLite: %s" % (e))
  134. self._setnodetags(node)
  135. self._checktags()
  136. self._commit()
  137. def addnodes(self, nodes):
  138. for n in nodes:
  139. sql = "INSERT INTO NODES(DATA) VALUES(?)"
  140. if not isinstance(n, Node): raise DatabaseException(
  141. "Tried to insert foreign object into database [%s]", n)
  142. value = cPickle.dumps(n)
  143. try:
  144. self._cur.execute(sql, [value])
  145. except sqlite.DatabaseError, e:
  146. raise DatabaseException("SQLite: %s" % (e))
  147. id = self._cur.lastrowid
  148. n.set_id(id)
  149. self._setnodetags(n)
  150. self._commit()
  151. def removenodes(self, nodes):
  152. for n in nodes:
  153. if not isinstance(n, Node): raise DatabaseException(
  154. "Tried to delete foreign object from database [%s]", n)
  155. try:
  156. sql = "DELETE FROM NODES WHERE ID = ?";
  157. self._cur.execute(sql, [n.get_id()])
  158. except sqlite.DatabaseError, e:
  159. raise DatabaseException("SQLite: %s" % (e))
  160. self._deletenodetags(n)
  161. self._checktags()
  162. self._commit()
  163. def listnodes(self):
  164. sql = ''
  165. params = []
  166. if len(self._filtertags) == 0:
  167. sql = "SELECT ID FROM NODES ORDER BY ID ASC"
  168. else:
  169. first = True
  170. for t in self._filtertags:
  171. if not first:
  172. sql += " INTERSECT "
  173. else:
  174. first = False
  175. sql += ("SELECT NODE FROM LOOKUP LEFT JOIN TAGS ON TAG = TAGS.ID"
  176. + " WHERE TAGS.DATA = ? ")
  177. params.append(cPickle.dumps(t))
  178. try:
  179. self._cur.execute(sql, params)
  180. ids = []
  181. row = self._cur.fetchone()
  182. while (row != None):
  183. ids.append(row[0])
  184. row = self._cur.fetchone()
  185. return ids
  186. except sqlite.DatabaseError, e:
  187. raise DatabaseException("SQLite: %s" % (e))
  188. def _commit(self):
  189. try:
  190. self._con.commit()
  191. except sqlite.DatabaseError, e:
  192. self._con.rollback()
  193. raise DatabaseException(
  194. "SQLite: Error commiting data to db [%s]" % (e))
  195. def _tagids(self, tags):
  196. ids = []
  197. for t in tags:
  198. sql = "SELECT ID FROM TAGS WHERE DATA = ?"
  199. if not isinstance(t, Tag): raise DatabaseException(
  200. "Tried to insert foreign object into database [%s]", t)
  201. data = cPickle.dumps(t)
  202. try:
  203. self._cur.execute(sql, [data])
  204. row = self._cur.fetchone()
  205. if (row != None):
  206. ids.append(row[0])
  207. else:
  208. sql = "INSERT INTO TAGS(DATA) VALUES(?)"
  209. self._cur.execute(sql, [data])
  210. ids.append(self._cur.lastrowid)
  211. except sqlite.DatabaseError, e:
  212. raise DatabaseException("SQLite: %s" % (e))
  213. return ids
  214. def _deletenodetags(self, node):
  215. try:
  216. sql = "DELETE FROM LOOKUP WHERE NODE = ?"
  217. self._cur.execute(sql, [node.get_id()])
  218. except sqlite.DatabaseError, e:
  219. raise DatabaseException("SQLite: %s" % (e))
  220. self._commit()
  221. def _setnodetags(self, node):
  222. self._deletenodetags(node)
  223. ids = self._tagids(node.get_tags())
  224. for i in ids:
  225. sql = "INSERT OR REPLACE INTO LOOKUP VALUES(?, ?)"
  226. params = [node.get_id(), i]
  227. try:
  228. self._cur.execute(sql, params)
  229. except sqlite.DatabaseError, e:
  230. raise DatabaseException("SQLite: %s" % (e))
  231. self._commit()
  232. def _checktags(self):
  233. try:
  234. sql = "DELETE FROM TAGS WHERE ID NOT IN (SELECT TAG FROM LOOKUP GROUP BY TAG)"
  235. self._cur.execute(sql)
  236. except sqlite.DatabaseError, e:
  237. raise DatabaseException("SQLite: %s" % (e))
  238. self._commit()
  239. def _checktables(self):
  240. """ Check if the Pwman tables exist """
  241. self._cur.execute("PRAGMA TABLE_INFO(NODES)")
  242. if (self._cur.fetchone() == None):
  243. # table doesn't exist, create it
  244. # SQLite does have constraints implemented at the moment
  245. # so datatype will just be a string
  246. self._cur.execute("CREATE TABLE NODES"
  247. + "(ID INTEGER PRIMARY KEY AUTOINCREMENT,"
  248. + "DATA BLOB NOT NULL)")
  249. self._cur.execute("CREATE TABLE TAGS"
  250. + "(ID INTEGER PRIMARY KEY AUTOINCREMENT,"
  251. + "DATA BLOB NOT NULL UNIQUE)")
  252. self._cur.execute("CREATE TABLE LOOKUP"
  253. + "(NODE INTEGER NOT NULL, TAG INTEGER NOT NULL,"
  254. + " PRIMARY KEY(NODE, TAG))")
  255. self._cur.execute("CREATE TABLE KEY"
  256. + "(THEKEY TEXT NOT NULL DEFAULT '')");
  257. self._cur.execute("INSERT INTO KEY VALUES('')");
  258. try:
  259. self._con.commit()
  260. except DatabaseError, e:
  261. self._con.rollback()
  262. raise e
  263. def savekey(self, key):
  264. sql = "UPDATE KEY SET THEKEY = ?"
  265. values = [key]
  266. self._cur.execute(sql, values)
  267. try:
  268. self._con.commit()
  269. except sqlite.DatabaseError, e:
  270. self._con.rollback()
  271. raise DatabaseException(
  272. "SQLite: Error saving key [%s]" % (e))
  273. def loadkey(self):
  274. """
  275. fetch the key to database. the key is also stored
  276. encrypted.
  277. """
  278. self._cur.execute("SELECT THEKEY FROM KEY");
  279. keyrow = self._cur.fetchone()
  280. if (keyrow[0] == ''):
  281. return None
  282. else:
  283. return keyrow[0]