Browse Source

- add new DB class for sqlite

oz123 11 năm trước cách đây
mục cha
commit
440f668686
1 tập tin đã thay đổi với 314 bổ sung0 xóa
  1. 314 0
      pwman/data/drivers/sqlite.py

+ 314 - 0
pwman/data/drivers/sqlite.py

@@ -59,6 +59,320 @@ def check_db_version():
         raise DatabaseException("SQLite: %s" % (e))
         
 
+class SQLiteDatabaseNewForm(Database):
+    """SQLite Database implementation"""
+
+    def __init__(self):
+        """Initialise SQLitePwmanDatabase instance."""
+        Database.__init__(self)
+
+        try:
+            self._filename = config.get_value('Database', 'filename')
+        except KeyError, e:
+            raise DatabaseException(
+                "SQLite: missing parameter [%s]" % (e))
+
+    def _open(self):
+        try:
+            self._con = sqlite.connect(self._filename)
+            self._cur = self._con.cursor()
+            self._checktables()
+        except sqlite.DatabaseError, e:
+            raise DatabaseException("SQLite: %s" % (e))
+
+    def close(self):
+        self._cur.close()
+        self._con.close()
+
+    def listtags(self, alltags=False):
+        sql = ''
+        params = []
+        if len(self._filtertags) == 0 or alltags:
+            sql = "SELECT DATA FROM TAGS ORDER BY DATA ASC"
+        else:
+            sql = ("SELECT TAGS.DATA FROM LOOKUP"
+                   + " INNER JOIN TAGS ON LOOKUP.TAG = TAGS.ID"
+                   + " WHERE NODE IN (")
+            first = True
+            # if using the command filter, the code crashes ...
+            #
+            for t in self._filtertags:
+                if not first:
+                    sql += " INTERSECT "
+                else:
+                    first = False
+
+                sql += ("SELECT NODE FROM LOOKUP LEFT JOIN TAGS ON TAG = "
+                        + " TAGS.ID WHERE TAGS.DATA = ?")
+                params.append(t.get_name())
+            sql += ") EXCEPT SELECT DATA FROM TAGS WHERE "
+            first = True
+            for t in self._filtertags:
+                if not first:
+                    sql += " OR "
+                else:
+                    first = False
+                sql += "TAGS.DATA = ?"
+                params.append(t)
+        try:
+            self._cur.execute(sql, params)
+            tags = []
+            row = self._cur.fetchone()
+            while row is not None:
+                tagstring = str(row[0])
+                m = re.search('S\"S\'(.+?)\'', tagstring)
+                if m:
+                    found = m.group(1)
+                    tags.append(Tag(found))
+                row = self._cur.fetchone()
+            return tags
+        except sqlite.DatabaseError, e:
+            raise DatabaseException("SQLite: %s" % (e))
+
+    def parse_node_string(self, string):
+        nodestring = string.split("##")
+        keyvals = {}
+        for pair in nodestring[:-1]:
+            key, val = pair.split(":")
+            keyvals[key.lstrip('##')] = val
+        tags = nodestring[-1]
+        tags = tags.lstrip("tags:")
+        tags = tags.split("tag:")
+        taginsts = []
+        for tag in tags:
+            _Tag = tag.rstrip("**endtag**")
+            Tag = (_Tag)
+            taginsts.append(Tag)
+        return keyvals, taginsts
+
+    def getnodes(self, ids):
+        """
+        object should always be: (ipwman.data.nodes
+        """
+        nodes = []
+        for i in ids:
+                sql = "SELECT DATA FROM NODES WHERE ID = ?"
+            # try:
+                self._cur.execute(sql, [i])
+                row = self._cur.fetchone()
+                if row is not None:
+                    nodestring = str(row[0])
+                    # if not nodestring.startswith("(ipwman.data.nodes"):
+                    #     raise DatabaseException(
+                #"Tried to load foreign object from database," \
+                #+ " this looks fishy in here...")
+                    nodeargs, tags = self.parse_node_string(nodestring)
+                    node = Node(**nodeargs)
+                    node.set_tags(tags)
+                    node.set_id(i)
+                    nodes.append(node)
+            # except sqlite.DatabaseError, e:
+            #   raise DatabaseException("SQLite: %s" % (e))
+        return nodes
+
+    def editnode(self, id, node):
+        try:
+            sql = "UPDATE NODES SET DATA = ? WHERE ID = ?"
+            self._cur.execute(sql, [node.dump_edit_to_db()[0], id])
+        except sqlite.DatabaseError, e:
+            raise DatabaseException("SQLite: %s" % (e))
+        self._setnodetags(node)
+        self._checktags()
+        self._commit()
+
+    def addnodes(self, nodes):
+        """
+        This method injects the data as PWMAN object using cPickle.
+        To make pwman more secure, either this method has to replaced.
+        Or whenever stuff is read from the database, there must be a
+        security check that it contains the correct objects!
+        Nodes passed to this methos are instances!
+        """
+        for n in nodes:
+            sql = "INSERT INTO NODES(DATA) VALUES(?)"
+            # if not isinstance(n, Node): raise DatabaseException(
+            #    "Tried to insert foreign object into database [%s]", n)
+            value = n.dump_to_db()
+            try:
+                self._cur.execute(sql, value)
+            except sqlite.DatabaseError, e:
+                raise DatabaseException("SQLite: %s" % (e))
+            idx = self._cur.lastrowid
+            n.set_id(idx)
+            self._setnodetags(n)
+            self._commit()
+
+    def removenodes(self, nodes):
+        for n in nodes:
+            # if not isinstance(n, Node): raise DatabaseException(
+            #    "Tried to delete foreign object from database [%s]", n)
+            try:
+                sql = "DELETE FROM NODES WHERE ID = ?"
+                self._cur.execute(sql, [n.get_id()])
+
+            except sqlite.DatabaseError, e:
+                raise DatabaseException("SQLite: %s" % (e))
+            self._deletenodetags(n)
+
+        self._checktags()
+        self._commit()
+
+    def listnodes(self):
+        sql = ''
+        params = []
+        if len(self._filtertags) == 0:
+            sql = "SELECT ID FROM NODES ORDER BY ID ASC"
+        else:
+            first = True
+            for t in self._filtertags:
+                if not first:
+                    sql += " INTERSECT "
+                else:
+                    first = False
+                sql += ("SELECT NODE FROM LOOKUP LEFT JOIN TAGS ON TAG = "
+                        " TAGS.ID WHERE TAGS.DATA = ? ")
+                params.append(t.get_name())
+        try:
+            self._cur.execute(sql, params)
+            ids = []
+            row = self._cur.fetchone()
+            while row is not None:
+                ids.append(row[0])
+                row = self._cur.fetchone()
+            return ids
+        except sqlite.DatabaseError, e:
+            raise DatabaseException("SQLite: %s" % (e))
+
+    def _commit(self):
+        try:
+            self._con.commit()
+        except sqlite.DatabaseError, e:
+            self._con.rollback()
+            raise DatabaseException(
+                "SQLite: Error commiting data to db [%s]" % (e))
+
+    def _tagids(self, tags):
+        ids = []
+        for tag in tags:
+            sql = "SELECT ID FROM TAGS WHERE DATA = ?"
+            # if not isinstance(t, Tag): raise DatabaseException(
+            #    "Tried to insert foreign object into database [%s]", t)
+            try:
+                if isinstance(tag, str):
+                    self._cur.execute(sql, [tag])
+                else:
+                    self._cur.execute(sql, [tag.get_name()])
+                row = self._cur.fetchone()
+                if (row is not None):
+                    ids.append(row[0])
+                else:
+                    sql = "INSERT INTO TAGS(DATA) VALUES(?)"
+                    if isinstance(tag, str):
+                        self._cur.execute(sql, [tag])
+                    else:
+                        self._cur.execute(sql, [tag.get_name()])
+
+                    ids.append(self._cur.lastrowid)
+            except sqlite.DatabaseError, e:
+                raise DatabaseException("SQLite: %s" % (e))
+        return ids
+
+    def _deletenodetags(self, node):
+        try:
+            sql = "DELETE FROM LOOKUP WHERE NODE = ?"
+            self._cur.execute(sql, [node.get_id()])
+        except sqlite.DatabaseError, e:
+            raise DatabaseException("SQLite: %s" % (e))
+        self._commit()
+
+    def _setnodetags(self, node):
+        self._deletenodetags(node)
+        ids = self._tagids(node.get_tags())
+        for i in ids:
+            sql = "INSERT OR REPLACE INTO LOOKUP VALUES(?, ?)"
+            params = [node.get_id(), i]
+
+            try:
+                self._cur.execute(sql, params)
+            except sqlite.DatabaseError, e:
+                raise DatabaseException("SQLite: %s" % (e))
+        self._commit()
+
+    def _checktags(self):
+        try:
+            sql = "DELETE FROM TAGS WHERE ID NOT IN (SELECT TAG FROM" \
+                + " LOOKUP GROUP BY TAG)"
+            self._cur.execute(sql)
+        except sqlite.DatabaseError, e:
+            raise DatabaseException("SQLite: %s" % (e))
+        self._commit()
+
+    def _checktables(self):
+        """
+        Check if the Pwman tables exist.
+        TODO: This method should check the version of the
+        database. If it finds an old format it should
+        exis, and prompt the user to convert the database
+        to the new version with a designated script.
+        """
+        self._cur.execute("PRAGMA TABLE_INFO(NODES)")
+        if (self._cur.fetchone() is None):
+            # table doesn't exist, create it
+            # SQLite does have constraints implemented at the moment
+            # so datatype will just be a string
+            self._cur.execute("CREATE TABLE NODES (ID INTEGER PRIMARY KEY"
+                              + " AUTOINCREMENT,DATA BLOB NOT NULL)")
+            self._cur.execute("CREATE TABLE TAGS"
+                              + "(ID INTEGER PRIMARY KEY AUTOINCREMENT,"
+                              + "DATA BLOB NOT NULL UNIQUE)")
+            self._cur.execute("CREATE TABLE LOOKUP"
+                              + "(NODE INTEGER NOT NULL, TAG INTEGER NOT NULL,"
+                              + " PRIMARY KEY(NODE, TAG))")
+
+            self._cur.execute("CREATE TABLE KEY"
+                              + "(THEKEY TEXT NOT NULL DEFAULT '')")
+            self._cur.execute("INSERT INTO KEY VALUES('')")
+            # create a table to hold DB version info
+            self._cur.execute("CREATE TABLE DBVERSION"
+                              + "(DBVERSION TEXT NOT NULL DEFAULT '0.4')")
+            self._cur.execute("INSERT INTO DBVERSION VALUES('0.4')")
+            try:
+                self._con.commit()
+            except DatabaseException, e:
+                self._con.rollback()
+                raise e
+
+    def savekey(self, key):
+        """
+        This function is saving the key to table KEY.
+        The key already arrives as an encrypted string.
+        It is the same self._keycrypted from
+        crypto py (check with id(self._keycrypted) and
+        id(key) here.
+        """
+        sql = "UPDATE KEY SET THEKEY = ?"
+        values = [key]
+        self._cur.execute(sql, values)
+        try:
+            self._con.commit()
+        except sqlite.DatabaseError, e:
+            self._con.rollback()
+            raise DatabaseException(
+                "SQLite: Error saving key [%s]" % (e))
+
+    def loadkey(self):
+        """
+        fetch the key to database. the key is also stored
+        encrypted.
+        """
+        self._cur.execute("SELECT THEKEY FROM KEY")
+        keyrow = self._cur.fetchone()
+        if (keyrow[0] == ''):
+            return None
+        else:
+            return keyrow[0]
+
+
 class SQLiteDatabase(Database):
     """SQLite Database implementation"""