Enable one optimization

Due to the fact that the nodes are different classes, this required some refactor.
This commit is contained in:
Salvo 'LtWorf' Tomaselli 2020-06-09 11:18:33 +02: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

View File

@ -30,6 +30,7 @@
from io import StringIO from io import StringIO
from tokenize import generate_tokens from tokenize import generate_tokens
from typing import Tuple
from relational import parser from relational import parser
@ -98,36 +99,7 @@ def replace_node(replace, replacement):
replace.left = replacement.left replace.left = replacement.left
def recoursive_scan(function, node, rels=None): def duplicated_select(n: parser.Node) -> Tuple[parser.Node, int]:
'''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:
'''This function locates and deletes things like '''This function locates and deletes things like
σ a ( σ a(C)) and the ones like σ a ( σ b(C)) σ a ( σ a(C)) and the ones like σ a ( σ b(C))
replacing the 1st one with a single select and replacing the 1st one with a single select and
@ -135,19 +107,22 @@ def duplicated_select(n: parser.Node) -> int:
in and in and
''' '''
changes = 0 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 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 # This adds parenthesis if they are needed
if n.child.prop.startswith('(') or n.prop.startswith('('): if n.child.prop.startswith('(') or n.prop.startswith('('):
n.prop = '(%s)' % n.prop prop = '(%s)' % prop
n = parser.Unary(
n.child = n.child.child SELECTION,
changes = 1 prop,
changes += duplicated_select(n) n.child.child,
)
return changes + recoursive_scan(duplicated_select, n) return n, changes
def futile_union_intersection_subtraction(n: parser.Node) -> int: def futile_union_intersection_subtraction(n: parser.Node) -> int:
@ -706,10 +681,10 @@ def useless_projection(n, rels) -> int:
changes = 1 changes = 1
replace_node(n, n.child) replace_node(n, n.child)
return changes + recoursive_scan(useless_projection, n, rels) return changes + recursive_scan(useless_projection, n, rels)
general_optimizations = [ general_optimizations = [
#duplicated_select, duplicated_select,
#down_to_unions_subtractions_intersections, #down_to_unions_subtractions_intersections,
#duplicated_projection, #duplicated_projection,
#selection_inside_projection, #selection_inside_projection,

View File

@ -1,5 +1,5 @@
# Relational # 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 # Relational is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # 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). # 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 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. # 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 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 import querysplit
from relational.maintenance import UserInterface from relational.maintenance import UserInterface
@ -88,10 +88,10 @@ def optimize_all(expression: Union[str, Node], rels: ContextDict, specific: bool
total += res total += res
if general: if general:
for i in optimizations.general_optimizations: for i in optimizations.general_optimizations:
res = i(n) # Performs the optimization n, c = recursive_scan(i, n, None)
if res != 0 and dbg: if c != 0 and dbg:
debug.append(str(n)) debug.append(str(n))
total += res total += c
if tostr: if tostr:
return str(n) return str(n)
else: else:
@ -117,3 +117,35 @@ def general_optimize(expression):
Return value: this will return an optimized version of the expression''' Return value: this will return an optimized version of the expression'''
return optimize_all(expression, None, specific=False, general=True) 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