Enable one optimization

Due to the fact that the nodes are different classes, this required some refactor.
master
Salvo 'LtWorf' Tomaselli 2020-06-09 11:18:33 +07:00
parent 3e524278e8
commit 0dcd639c9d
No known key found for this signature in database
GPG Key ID: B3A7CF0C801886CF
2 changed files with 54 additions and 47 deletions

@ -30,6 +30,7 @@
from io import StringIO
from tokenize import generate_tokens
from typing import Tuple
from relational import parser
@ -98,36 +99,7 @@ def replace_node(replace, replacement):
replace.left = replacement.left
def recoursive_scan(function, node, rels=None):
'''Does a recoursive optimization on the tree.
This function will recoursively execute the function given
as "function" parameter starting from node to all the tree.
if rels is provided it will be passed as argument to the function.
Otherwise the function will be called just on the node.
Result value: function is supposed to return the amount of changes
it has performed on the tree.
The various result will be added up and this final value will be the
returned value.'''
changes = 0
# recoursive scan
if node.kind == parser.UNARY:
if rels != None:
changes += function(node.child, rels)
else:
changes += function(node.child)
elif node.kind == parser.BINARY:
if rels != None:
changes += function(node.right, rels)
changes += function(node.left, rels)
else:
changes += function(node.right)
changes += function(node.left)
return changes
def duplicated_select(n: parser.Node) -> int:
def duplicated_select(n: parser.Node) -> Tuple[parser.Node, int]:
'''This function locates and deletes things like
σ a ( σ a(C)) and the ones like σ a ( σ b(C))
replacing the 1st one with a single select and
@ -135,19 +107,22 @@ def duplicated_select(n: parser.Node) -> int:
in and
'''
changes = 0
if n.name == SELECTION and n.child.name == SELECTION:
while n.name == SELECTION and n.child.name == SELECTION:
changes += 1
prop = n.prop
if n.prop != n.child.prop: # Nested but different, joining them
n.prop = n.prop + " and " + n.child.prop
prop = n.prop + " and " + n.child.prop
# This adds parenthesis if they are needed
if n.child.prop.startswith('(') or n.prop.startswith('('):
n.prop = '(%s)' % n.prop
n.child = n.child.child
changes = 1
changes += duplicated_select(n)
return changes + recoursive_scan(duplicated_select, n)
prop = '(%s)' % prop
n = parser.Unary(
SELECTION,
prop,
n.child.child,
)
return n, changes
def futile_union_intersection_subtraction(n: parser.Node) -> int:
@ -706,10 +681,10 @@ def useless_projection(n, rels) -> int:
changes = 1
replace_node(n, n.child)
return changes + recoursive_scan(useless_projection, n, rels)
return changes + recursive_scan(useless_projection, n, rels)
general_optimizations = [
#duplicated_select,
duplicated_select,
#down_to_unions_subtractions_intersections,
#duplicated_projection,
#selection_inside_projection,

@ -1,5 +1,5 @@
# Relational
# Copyright (C) 2008-2016 Salvo "LtWorf" Tomaselli
# Copyright (C) 2008-2020 Salvo "LtWorf" Tomaselli
#
# Relational is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -22,10 +22,10 @@
# relational query, or it can be a parse tree for a relational expression (ie: class parser.node).
# The functions will always return a string with the optimized query, but if a parse tree was provided,
# the parse tree itself will be modified accordingly.
from typing import Union, Optional, Dict, Any
from typing import Union, Optional, Dict, Any, Tuple
from relational import optimizations
from relational.parser import Node, RELATION, UNARY, BINARY, op_functions, tokenize, tree
from relational.parser import Node, Variable, Unary, Binary, op_functions, tokenize, tree
from relational import querysplit
from relational.maintenance import UserInterface
@ -88,10 +88,10 @@ def optimize_all(expression: Union[str, Node], rels: ContextDict, specific: bool
total += res
if general:
for i in optimizations.general_optimizations:
res = i(n) # Performs the optimization
if res != 0 and dbg:
n, c = recursive_scan(i, n, None)
if c != 0 and dbg:
debug.append(str(n))
total += res
total += c
if tostr:
return str(n)
else:
@ -117,3 +117,35 @@ def general_optimize(expression):
Return value: this will return an optimized version of the expression'''
return optimize_all(expression, None, specific=False, general=True)
def recursive_scan(function, node, rels) -> Tuple[Node, int]:
'''Does a recursive optimization on the tree.
This function will recursively execute the function given
as "function" parameter starting from node to all the tree.
if rels is provided it will be passed as argument to the function.
Otherwise the function will be called just on the node.
Result value: function is supposed to return the amount of changes
it has performed on the tree.
The various result will be added up and this final value will be the
returned value.'''
args = []
if rels:
args.append(rels)
changes = 0
node, c = function(node, *args)
changes += c
if isinstance(node, Unary):
node.child, c = recursive_scan(function, node.child, rels)
changes += c
elif isinstance(node, Binary):
node.left, c = recursive_scan(function, node.left, rels)
changes += c
node.right, c = recursive_scan(function, node.right, rels)
changes += c
return node, changes