From f0d50eabee070ea6fd320b49834a593fb7393b16 Mon Sep 17 00:00:00 2001 From: Salvo 'LtWorf' Tomaselli Date: Sun, 21 Aug 2016 11:03:45 +0200 Subject: [PATCH] Query splitter complete --- relational/optimizer.py | 5 ++-- relational/querysplit.py | 57 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/relational/optimizer.py b/relational/optimizer.py index 4c0dc1c..1fb2ee1 100644 --- a/relational/optimizer.py +++ b/relational/optimizer.py @@ -25,6 +25,7 @@ from relational import optimizations from relational import parser +from relational import querysplit from relational.maintenance import UserInterface @@ -57,8 +58,8 @@ def optimize_program(code, rels): parsed = parser.tree(query) optimizations.replace_leaves(parsed, context) context[res] = parsed - result = optimize_all(context[last_res], rels) - return result + node = optimize_all(context[last_res], rels, tostr=False) + return querysplit.split(node, rels) def optimize_all(expression, rels, specific=True, general=True, debug=None,tostr=True): diff --git a/relational/querysplit.py b/relational/querysplit.py index a80d07a..d6cd699 100644 --- a/relational/querysplit.py +++ b/relational/querysplit.py @@ -19,6 +19,52 @@ # This module splits a query into a program. +from relational import parser + + +class Program: + def __init__(self, rels): + self.queries = [] + self.dictionary = {} # Key is the query, value is the relation + self.vgen = vargen(rels, 'optm_') + + def __str__(self): + r = '' + for q in self.queries: + r += '%s = %s' % (q[0], q[1]) + '\n' + return r.rstrip() + + def append_query(self, node): + strnode = str(node) + + rel = self.dictionary.get(strnode) + if rel: + return rel + + qname = next(self.vgen) + self.queries.append((qname, node)) + n = parser.Node() + n.kind = parser.RELATION + n.name = qname + self.dictionary[strnode] = n + return n + +def _separate(node, program): + if node.kind == parser.UNARY and node.child.kind != parser.RELATION: + _separate(node.child, program) + rel = program.append_query(node.child) + node.child = rel + elif node.kind == parser.BINARY: + if node.left.kind != parser.RELATION: + _separate(node.left, program) + rel = program.append_query(node.left) + node.left = rel + if node.right.kind != parser.RELATION: + _separate(node.right, program) + rel = program.append_query(node.right) + node.right = rel + program.append_query(node) + def vargen(avoid, prefix=''): ''' Generates temp variables. @@ -40,3 +86,14 @@ def vargen(avoid, prefix=''): if r not in avoid: yield r count += 1 + +def split(node, rels): + ''' + Split a query into a program. + + The idea is that if there are duplicated subdtrees they + get executed only once. + ''' + p = Program(rels) + _separate(node, p) + return str(p)