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)
diff --git a/relational_gui/guihandler.py b/relational_gui/guihandler.py
index 586e5d5..f6e3a4e 100644
--- a/relational_gui/guihandler.py
+++ b/relational_gui/guihandler.py
@@ -15,6 +15,7 @@
# along with this program. If not, see .
#
# author Salvo "LtWorf" Tomaselli
+import base64
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
@@ -360,10 +361,13 @@ class relForm(QtWidgets.QMainWindow):
self.settings.setValue('maingui/geometry', self.saveGeometry())
self.settings.setValue('maingui/windowState', self.saveState())
self.settings.setValue('maingui/splitter', self.ui.splitter.saveState())
- self.settings.setValue('maingui/relations', self.user_interface.session_dump())
+ self.settings.setValue('maingui/relations', base64.b64encode(self.user_interface.session_dump()).decode())
def _restore_settings(self):
- self.user_interface.session_restore(self.settings.value('maingui/relations'))
+ try:
+ self.user_interface.session_restore(base64.b64decode(self.settings.value('maingui/relations')))
+ except:
+ pass
self.updateRelations()
self.setMultiline(self.settings.value('multiline', 'false') == 'true')