Advertisement
S0lll0s

Relational Algebra to SQL Subqueries

Mar 11th, 2015
540
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.41 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. # NAME         PYTHON-NOTATION                             HASKELL-NOTATION
  4. # selektion:   S[a.name != b.name]( ... )                  S String Rel
  5. # projektion:  P[a.name, b.budget]( ... )                  P String Rel
  6. # join:        J[a.budget = b.budget, proj]( RELA, RELB )  J String String Rel Rel
  7. # rename:      R[budget->geld, name->zeug]( ... )          R [(String,String)] Rel
  8. # from:        F[a]( ... )                                 F String Rel
  9. #              T[""]()                                     T String
  10. #
  11. # Beispiel: P[a.name,a.einnahmen,b.alter,CONCAT(b.vname, b.nname)](J[a.angestellter = b.id, a.name, a.einnahmen, b.alter, b.vname, b.nname](T["a"](), T["b"]()))
  12. import re
  13.  
  14. def inherit_docstring(cls):
  15.     for name, func in vars(cls).items():
  16.         if not func.__doc__:
  17.             for parent in cls.__bases__:
  18.                 parfunc = getattr(parent, name)
  19.                 if parfunc and getattr(parfunc, '__doc__', None):
  20.                     func.__doc__ = parfunc.__doc__
  21.                     break
  22.     return cls
  23.  
  24. class Node(object):
  25.     def __init__(self):
  26.         """
  27.        Vor.: der Konstruktor wird korrekt aufgerufen
  28.        Erg.: -
  29.        Eff.: ein Neues Objekt vom Typ {} wird erstellt
  30.        """.format(type(self))
  31.         self.children = []
  32.  
  33.     def appendChild(self, child):
  34.         """Appends a Node below this one.
  35.        
  36.        Vor.: "self" und "child" sind Objekte, die von "Node" erben
  37.        Erg.: -
  38.        Eff.: "child" wird unter "self" angehängt
  39.        """
  40.         self.children.append(child)
  41.  
  42.     def render(self):
  43.         """Renders the node to an SQL-command.
  44.        
  45.        Vor.: "self" ist ein Objekt, dass von "Node" erbt
  46.        Erg.: ein String, der "self" als SQL-Befehlt repräsentiert
  47.        Eff.: -
  48.        """
  49.         pass
  50.  
  51. class TableNode(Node):
  52.     def __init__(self, name):
  53.         self.name = name
  54.  
  55.     @inherit_docstring
  56.     def render(self):
  57.         return self.name
  58.  
  59. class RenameRelNode(Node):
  60.     def __init__(self, new):
  61.         self.new = new
  62.         self.children = []
  63.  
  64.     @inherit_docstring
  65.     def render(self):
  66.         return "{} as {}".format(self.children[0].render(), self.new)
  67.  
  68. class JoinNode(Node):
  69.     def __init__(self, condition, *attrs):
  70.         self.condition  = condition
  71.         self.attrs      = ", ".join(attrs)
  72.         self.children = []
  73.  
  74.     @inherit_docstring
  75.     def render(self):
  76.         return "(SELECT {} FROM {}, {} WHERE {})".format(self.attrs, self.children[0].render(), self.children[1].render(), self.condition)
  77.  
  78. class ProjectionNode(Node):
  79.     def __init__(self, *attrs):
  80.         self.attrs = attrs
  81.         self.children = []
  82.  
  83.     @inherit_docstring
  84.     def render(self):
  85.         return "(SELECT {} FROM {})".format(self.attrs, self.children[0].render())
  86.  
  87. class SelectionNode(Node):
  88.     def __init__(self, condition):
  89.         self.condition = condition
  90.         self.children = []
  91.  
  92.     @inherit_docstring
  93.     def render(self):
  94.         return "(SELECT * FROM {} WHERE {})".format(self.children[0].render(), self.condition)
  95.  
  96. class RenameNode(Node):
  97.     def __init__(self, names):
  98.         self.names = names
  99.         self.children = []
  100.  
  101.     @inherit_docstring
  102.     def render(self):
  103.         return "(SELECT {} FROM {})".format( ", ".join([ "{} as {}".format(old, self.names[old]) for old in self.names]),  self.children[0].render())
  104.  
  105. class RelAlgParser(Node):
  106.     regex = re.compile("^(S|P|J|F|T|R)\[([^\[]*)\]\((.*)\)$")
  107.  
  108.     types = {
  109.         "S": SelectionNode,
  110.         "P": ProjectionNode,
  111.         "J": JoinNode,
  112.         "F": RenameRelNode,
  113.         "R": RenameNode,
  114.         "T": TableNode
  115.     }
  116.  
  117.     def splitExpr(self, string):
  118.         """Splits a string on commata, but minds nested parenthesis, brackets and quotation marks.
  119.  
  120.        For example: "abc, def(efg, hijk), (a,b[)c'd]', end"   =>  ["abc", "def(efg, hijk)", "(a,b[)c'd'", "end"]
  121.        split = string.split(",")
  122.        
  123.        Vor.: "string" ist ein String
  124.        Erg.: "string", an allen Kommas, die nicht in Klammern ('(', '[') oder Anführungszeichen stehen (''', '"'), in eine Liste unterteilt.
  125.        Eff.: -
  126.        """
  127.         res = [""]
  128.         symbols = {
  129.             "(": ( 1, "("),
  130.             ")": (-1, "("),
  131.             "[": ( 1, "["),
  132.             "]": (-1, "["),
  133.             "'": ( 1, "'"),
  134.             '"': ( 1, '"')
  135.         }
  136.         counts = { "(": 0, "[": 0, "'": 0, '"': 0 }
  137.  
  138.         for e in string.split(","):
  139.             for symbol in symbols:
  140.                 typ = symbols[symbol]
  141.                 counts[typ[1]] += e.count(symbol) * typ[0]
  142.             counts["'"] = counts["'"] % 2
  143.             counts['"'] = counts['"'] % 2
  144.  
  145.             res[-1] += e + ","
  146.             if len(res) > 0 and all(map(lambda x: counts[x]==0, counts)): # all counts zero
  147.                 res[-1] = res[-1][:-1]  # remove trailing ","
  148.                 if res[-1] != "":
  149.                     res.append("")      # new part
  150.  
  151.         return res[:-1]
  152.  
  153.     def parse(self, string):
  154.         """ecursively transforms an expression of Relational Algebra into an AST.
  155.        
  156.        Vor.: "string" ist ein String, auf den das definierte Muster passt
  157.        Erg.: Wurzel-Knoten (Node), der den äußersten Befehl des relational-algebraischen Ausdrucks in "string" enthält.
  158.        Eff.: Alle weiteren Befehle in "string" werden unter dem Wurzel-Knoten in einem Baum angeordnet
  159.        """
  160.         match = re.match(self.regex, string)
  161.         if not match:
  162.             print("ERR: no match in '{}'".format(string))
  163.             return None
  164.         func, params, rels = match.groups()
  165.  
  166.         node = self.types[func](*list(map(str.strip, self.splitExpr(params))))
  167.         for rel in map(str.strip, self.splitExpr(rels)):
  168.             node.appendChild(self.parse(rel))
  169.         return node
  170.  
  171. if __name__ == "__main__":
  172.     import sys
  173.     parser = RelAlgParser()
  174.     cmd = ""
  175.     if len(sys.argv) > 1:
  176.         cmd = sys.argv[1]
  177.     else:
  178.         cmd = input()
  179.     print( parser.parse(cmd).render() ) # argv[1] is das erste Argument in der Konsole
  180.    
  181. """
  182. class FA(object):
  183.    def __init__(self, states, moves, ends):
  184.        self.states = states
  185.        self.moves = moves # moves = (from, char, to) / (from, None, to)
  186.        self.ends = ends
  187.  
  188.    def newDfa( self ):
  189.        state = self.new()
  190.        n = FA( set([frozenset(state.pos)]), set(), set() )
  191.        new = True
  192.        while new:
  193.            new = False
  194.            nstates = set()
  195.            for s in n.states:
  196.                d = {}
  197.                nmoves = set()
  198.                for m in [ (m[1], m[2]) for m in self.moves if m[0] in s ]:
  199.                    if not m[1] in d:
  200.                        d[m[0]] = set()
  201.                    d[m[0]].add(m[1])
  202.                    for k in d:
  203.                        if not d[k] in n.states:
  204.                            nstates.add(frozenset(d[k]))
  205.                            new = True
  206.                        if not (s, k, frozenset(d[k])) in n.moves:
  207.                            nmoves.add( (s,k,frozenset(d[k])) )
  208.                n.moves |= nmoves
  209.            n.states |= nstates
  210.  
  211.        states = {}
  212.        nstates = n.states.copy()
  213.        for i,s in enumerate(n.states):
  214.            states[s] = i
  215.            if any(ss in self.ends for ss in s):
  216.                n.ends.add(i)
  217.            nstates.remove(s)
  218.            nstates.add(i)
  219.        n.states = nstates
  220.                
  221.        nmoves = n.moves.copy()
  222.        for i,m in enumerate(n.moves):
  223.            print ( m, m[2] )
  224.            nmoves.remove(m)
  225.            nmoves.add( (states[m[0]],m[1],states[m[2]]) )
  226.        n.moves = nmoves
  227.  
  228.        return n
  229.        
  230.  
  231.    def new( self, start=1 ):
  232.        return NFAState( self, start )
  233.    
  234.    def newD( self, start=1 ):
  235.        return DFAState( self, start )
  236.  
  237. class NFAState(object):
  238.    def __init__( self, nfa, start ):
  239.        self.nfa = nfa
  240.        self.reset( start )
  241.  
  242.    def reset( self, start ):
  243.        self.pos = set([start])
  244.        self.close()
  245.  
  246.    def doesTrans( self, str ):
  247.        return self.trans(str) >= self.nfa.ends
  248.  
  249.    def trans( self, str ):
  250.        for char in str:
  251.            self.onetrans( char )
  252.        return self.pos
  253.  
  254.    def onetrans( self, char ):
  255.        self.onemove(char);
  256.        self.close();
  257.  
  258.    def onemove( self, char ):
  259.        self.pos = set([ to for (f, via, to) in self.nfa.moves if f in self.pos and via == char ])
  260.  
  261.    def close( self ):
  262.        new = set([ to for (f, via, to) in self.nfa.moves if f in self.pos and via == None ])
  263.        self.pos = self.pos.union(new)
  264.  
  265. class DFAState(object):
  266.    def __init__( self, dfa, start ):
  267.        self.dfa = dfa
  268.        self.pos = start
  269.        
  270.    def reset( self, start ):
  271.        self.pos = start
  272.        
  273.    def doesTrans( self, str ):
  274.        return self.trans(str) in self.dfa.ends
  275.  
  276.    def trans( self, str ):
  277.        for char in str:
  278.            self.onemove( char )
  279.        return self.pos
  280.  
  281.    def onemove( self, char ):
  282.        print( "{}? --{}-> ??".format(self.pos , char ) )
  283.        self.pos = [ to for (f, via, to) in self.dfa.moves if f == self.pos and via == char ][0]
  284.  
  285. if __name__ == "__main__":
  286.    nfa = FA( set([1,2,3,4,5]), set([(1,'a',2), (3, None, 2), (2, 'a', 4), (4,'b',3), (4, None, 5), (2, 'c', 5), (2, 'c', 3)]), set([4,5]))
  287.    print( nfa.new().doesTrans( "abc" ), nfa.new().trans( "abc" ) )
  288. """
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement