sqlite.py 10 KB

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