diff --git a/relational/optimizations.py b/relational/optimizations.py index 7ee3268..a091f6c 100644 --- a/relational/optimizations.py +++ b/relational/optimizations.py @@ -34,25 +34,15 @@ from typing import Tuple, Dict from relational.relation import Relation from relational import parser +from relational.parser import Binary, Unary, PRODUCT, \ + DIFFERENCE, UNION, INTERSECTION, DIVISION, JOIN, \ + JOIN_LEFT, JOIN_RIGHT, JOIN_FULL, PROJECTION, \ + SELECTION, RENAME, ARROW sel_op = ( '//=', '**=', 'and', 'not', 'in', '//', '**', '<<', '>>', '==', '!=', '>=', '<=', '+=', '-=', '*=', '/=', '%=', 'or', '+', '-', '*', '/', '&', '|', '^', '~', '<', '>', '%', '=', '(', ')', ',', '[', ']') -PRODUCT = parser.PRODUCT -DIFFERENCE = parser.DIFFERENCE -UNION = parser.UNION -INTERSECTION = parser.INTERSECTION -DIVISION = parser.DIVISION -JOIN = parser.JOIN -JOIN_LEFT = parser.JOIN_LEFT -JOIN_RIGHT = parser.JOIN_RIGHT -JOIN_FULL = parser.JOIN_FULL -PROJECTION = parser.PROJECTION -SELECTION = parser.SELECTION -RENAME = parser.RENAME -ARROW = parser.ARROW - def find_duplicates(node, dups=None): ''' @@ -72,7 +62,7 @@ def duplicated_select(n: parser.Node) -> Tuple[parser.Node, int]: in and ''' changes = 0 - while isinstance(n, parser.Unary) and n.name == SELECTION and isinstance(n.child, parser.Unary) and n.child.name == SELECTION: + while isinstance(n, Unary) and n.name == SELECTION and isinstance(n.child, Unary) and n.child.name == SELECTION: changes += 1 prop = n.prop @@ -82,7 +72,7 @@ def duplicated_select(n: parser.Node) -> Tuple[parser.Node, int]: # This adds parenthesis if they are needed if n.child.prop.startswith('(') or n.prop.startswith('('): prop = '(%s)' % prop - n = parser.Unary( + n = Unary( SELECTION, prop, n.child.child, @@ -125,14 +115,14 @@ def futile_union_intersection_subtraction(n: parser.Node) -> Tuple[parser.Node, elif n.name == DIFFERENCE and \ n.right.name == SELECTION and \ n.right.child == n.left: - return parser.Unary( + return Unary( SELECTION, '(not (%s))' % n.right.prop, n.right.child), 1 # Subtraction of the same thing or with selection on the left child elif n.name == DIFFERENCE and (n.left == n.right or (n.left.name == SELECTION and n.left.child == n.right)): - return parser.Unary( + return Unary( SELECTION, 'False', n.get_left_leaf() @@ -147,12 +137,12 @@ def down_to_unions_subtractions_intersections(n: parser.Node) -> Tuple[parser.No ''' changes = 0 _o = (UNION, DIFFERENCE, INTERSECTION) - if isinstance(n, parser.Unary) and n.name == SELECTION and n.child.name in _o: - assert isinstance(n.child, parser.Binary) - l = parser.Unary(SELECTION, n.prop, n.child.left) - r = parser.Unary(SELECTION, n.prop, n.child.right) + if isinstance(n, Unary) and n.name == SELECTION and n.child.name in _o: + assert isinstance(n.child, Binary) + l = Unary(SELECTION, n.prop, n.child.left) + r = Unary(SELECTION, n.prop, n.child.right) - return parser.Binary(n.child.name, l, r), 1 + return Binary(n.child.name, l, r), 1 return n, 0 @@ -160,8 +150,8 @@ def duplicated_projection(n: parser.Node) -> Tuple[parser.Node, int]: '''This function locates thing like π i ( π j (R)) and replaces them with π i (R)''' - if isinstance(n, parser.Unary) and n.name == PROJECTION and isinstance(n.child, parser.Unary) and n.child.name == PROJECTION: - return parser.Unary( + if isinstance(n, Unary) and n.name == PROJECTION and isinstance(n.child, Unary) and n.child.name == PROJECTION: + return Unary( PROJECTION, n.prop, n.child.child), 1 @@ -171,14 +161,14 @@ def duplicated_projection(n: parser.Node) -> Tuple[parser.Node, int]: def selection_inside_projection(n: parser.Node) -> Tuple[parser.Node, int]: '''This function locates things like σ j (π k(R)) and converts them into π k(σ j (R))''' - if isinstance(n, parser.Unary) and n.name == SELECTION and isinstance(n.child, parser.Unary) and n.child.name == PROJECTION: - child = parser.Unary( + if isinstance(n, Unary) and n.name == SELECTION and isinstance(n.child, Unary) and n.child.name == PROJECTION: + child = Unary( SELECTION, n.prop, n.child.child ) - return parser.Unary(PROJECTION, n.child.prop, child), 0 + return Unary(PROJECTION, n.child.prop, child), 0 return n, 0 @@ -192,8 +182,8 @@ def swap_union_renames(n: parser.Node) -> Tuple[parser.Node, int]: l_vars = n.left.get_rename_prop() r_vars = n.right.get_rename_prop() if r_vars == l_vars: - child = parser.Binary(n.name, n.left.child, n.right.child) - return parser.Unary(RENAME, n.left.prop, child), 1 + child = Binary(n.name, n.left.child, n.right.child) + return Unary(RENAME, n.left.prop, child), 1 return n, 0 @@ -231,7 +221,7 @@ def subsequent_renames(n: parser.Node) -> Tuple[parser.Node, int]: # Located two nested renames. prop = n.prop + ',' + n.child.prop child = n.child.child - n = parser.Unary(RENAME, prop, child) + n = Unary(RENAME, prop, child) # Creating a dictionary with the attributes renames = n.get_rename_prop() @@ -306,7 +296,7 @@ def swap_rename_projection(n: parser.Node) -> Tuple[parser.Node, int]: Will also eliminate fields in the rename that are cut in the projection. ''' - if isinstance(n, parser.Unary) and n.name == PROJECTION and n.child.name == RENAME: + if isinstance(n, Unary) and n.name == PROJECTION and n.child.name == RENAME: # π index,name(ρ id➡index(R)) renames = n.child.get_rename_prop() projections = set(n.get_projection_prop()) @@ -322,9 +312,9 @@ def swap_rename_projection(n: parser.Node) -> Tuple[parser.Node, int]: if i not in projections: del renames[i] - child = parser.Unary(PROJECTION,'' , n.child.child) + child = Unary(PROJECTION,'' , n.child.child) child.set_projection_prop(projections) - n = parser.Unary(RENAME, '', child) + n = Unary(RENAME, '', child) n.set_rename_prop(renames) return n, 1 @@ -339,7 +329,7 @@ def swap_rename_select(n: parser.Node) -> int: Renaming the attributes used in the selection, so the operation is still valid.''' - if isinstance(n, parser.Unary) and n.name == SELECTION and n.child.name == RENAME: + if isinstance(n, Unary) and n.name == SELECTION and n.child.name == RENAME: # This is an inverse mapping for the rename renames = {v: k for k, v in n.child.get_rename_prop().items()} @@ -354,8 +344,8 @@ def swap_rename_select(n: parser.Node) -> int: if len(splitted) > 1: tokens[i] += '.' + splitted[1] - child = parser.Unary(SELECTION, ' '.join(tokens), n.child.child) - return parser.Unary(RENAME, n.child.prop, child), 1 + child = Unary(SELECTION, ' '.join(tokens), n.child.child) + return Unary(RENAME, n.child.prop, child), 1 return n, 0 @@ -389,7 +379,7 @@ def select_union_intersect_subtract(n: parser.Node) -> int: prop = t_str % (n.left.prop, op, n.right.prop) else: prop = '%s %s %s' % (n.left.prop, op, n.right.prop) - return parser.Unary(SELECTION, prop, n.left.child), 1 + return Unary(SELECTION, prop, n.left.child), 1 return n, 0 @@ -403,13 +393,13 @@ def union_and_product(n: parser.Node) -> Tuple[parser.Node, int]: if n.left.left == n.right.left or n.left.left == n.right.right: l = n.left.right r = n.right.left if n.left.left == n.right.right else n.right.right - newchild = parser.Binary(UNION, l, r) - return parser.Binary(n.left.name, n.left.left, newchild), 1 + newchild = Binary(UNION, l, r) + return Binary(n.left.name, n.left.left, newchild), 1 elif n.left.right == n.right.left or n.left.left == n.right.right: l = n.left.left r = n.right.left if n.right.left == n.right.right else n.right.right - newchild = parser.Binary(UNION, l, r) - return parser.Binary(n.left.name, n.left.right, newchild), 1 + newchild = Binary(UNION, l, r) + return Binary(n.left.name, n.left.right, newchild), 1 return n, 0 @@ -429,8 +419,8 @@ def projection_and_union(n: parser.Node, rels: Dict[str, Relation]) -> Tuple[par n.right.name == PROJECTION and \ set(n.left.child.result_format(rels)) == set(n.right.child.result_format(rels)): - child = parser.Binary(UNION, n.left.child, n.right.child) - return parser.Unary(PROJECTION, n.right.prop, child), 0 + child = Binary(UNION, n.left.child, n.right.child) + return Unary(PROJECTION, n.right.prop, child), 0 return n, 0 @@ -439,7 +429,7 @@ def selection_and_product(n: parser.Node, rels: Dict[str, Relation]) -> parser.N σ l (σ j (R) * σ i (Q)). Where j contains only attributes belonging to R, i contains attributes belonging to Q and l contains attributes belonging to both''' - if isinstance(n, parser.Unary) and n.name == SELECTION and n.child.name in (PRODUCT, JOIN): + if isinstance(n, Unary) and n.name == SELECTION and n.child.name in (PRODUCT, JOIN): l_attr = n.child.left.result_format(rels) r_attr = n.child.right.result_format(rels) @@ -484,7 +474,7 @@ def selection_and_product(n: parser.Node, rels: Dict[str, Relation]) -> parser.N l_prop = ' and '.join((' '.join(i) for i in left)) if '(' in l_prop: l_prop = '(%s)' % l_prop - l_node = parser.Unary(SELECTION, l_prop, n.child.left) + l_node = Unary(SELECTION, l_prop, n.child.left) else: l_node = n.child.left @@ -493,18 +483,18 @@ def selection_and_product(n: parser.Node, rels: Dict[str, Relation]) -> parser.N r_prop = ' and '.join((' '.join(i) for i in right)) if '(' in r_prop: r_prop = '(%s)' % r_prop - r_node = parser.Unary(SELECTION, r_prop, n.child.right) + r_node = Unary(SELECTION, r_prop, n.child.right) else: r_node = n.child.right - b_node = parser.Binary(n.child.name, l_node, r_node) + b_node = Binary(n.child.name, l_node, r_node) # Changing main selection if both: both_prop = ' and '.join((' '.join(i) for i in both)) if '(' in both_prop: both_prop = '(%s)' % both_prop - r = parser.Unary(SELECTION, both_prop, b_node) + r = Unary(SELECTION, both_prop, b_node) return r, len(left) + len(right) else: # No need for general select return b_node, 1 @@ -516,7 +506,7 @@ def useless_projection(n: parser.Node, rels: Dict[str, Relation]) -> Tuple[parse ''' Removes projections that are over all the fields ''' - if isinstance(n, parser.Unary) and n.name == PROJECTION and \ + if isinstance(n, Unary) and n.name == PROJECTION and \ set(n.child.result_format(rels)) == set(i.strip() for i in n.prop.split(',')): return n.child, 1