diff --git a/opteryx/planner/cost_based_optimizer/bench/use_heap_sort.py b/opteryx/planner/cost_based_optimizer/bench/use_heap_sort.py deleted file mode 100644 index 02aedbc4..00000000 --- a/opteryx/planner/cost_based_optimizer/bench/use_heap_sort.py +++ /dev/null @@ -1,53 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Optimization Rule - Combine Operators for Effeciency - -Type: Heuristic -Goal: Reduce rows -""" - -from opteryx import operators -from opteryx.models.execution_tree import ExecutionTree -from opteryx.utils import random_string - - -def use_heap_sort(plan: ExecutionTree, properties): - """ - This action merges sort and limit nodes to use an algorithm which performs both - faster than if they are performed as separate steps. - """ - - # find the in-scope nodes - sort_nodes = plan.get_nodes_of_type(operators.SortNode) - - # killer questions - if any aren't met, bail - if sort_nodes is None: - return plan - - for nid in sort_nodes: - next_nids = plan.outgoing_edges(nid) - if len(next_nids) != 1: - continue - next_nid = next_nids.pop()[1] - limit_node = plan[next_nid] - if isinstance(limit_node, operators.LimitNode): - sort_node = plan[nid] - heap_sort = operators.HeapSortNode( - properties=properties, order=sort_node.order, limit=limit_node.limit - ) - plan.insert_node_before(f"heap-sort-{random_string()}", heap_sort, nid) - plan.remove_node(nid, heal=True) - plan.remove_node(next_nid, heal=True) - - return plan diff --git a/opteryx/planner/cost_based_optimizer/strategies/constant_folding.py b/opteryx/planner/cost_based_optimizer/strategies/constant_folding.py index 712f3567..5a445ada 100644 --- a/opteryx/planner/cost_based_optimizer/strategies/constant_folding.py +++ b/opteryx/planner/cost_based_optimizer/strategies/constant_folding.py @@ -32,7 +32,6 @@ import numpy from orso.types import OrsoTypes -from opteryx.exceptions import InvalidInternalStateError from opteryx.managers.expression import NodeType from opteryx.managers.expression import evaluate from opteryx.managers.expression import get_all_nodes_of_type @@ -78,6 +77,93 @@ def fold_constants(root: Node) -> Node: root.left = fold_constants(root.left) root.right = fold_constants(root.right) + # is we have a logical expression and one side is a constant, + # we simplify the expression + if root.node_type == NodeType.OR: + if ( + root.left.node_type == NodeType.LITERAL + and root.left.type == OrsoTypes.BOOLEAN + and root.left.value + ): + # True OR anything is True + return root.left + if ( + root.right.node_type == NodeType.LITERAL + and root.right.type == OrsoTypes.BOOLEAN + and root.right.value + ): + # True OR anything is True + return root.right + if ( + root.left.node_type == NodeType.LITERAL + and root.left.type == OrsoTypes.BOOLEAN + and not root.left.value + ): + # False OR x is x + return root.right + if ( + root.right.node_type == NodeType.LITERAL + and root.right.type == OrsoTypes.BOOLEAN + and not root.right.value + ): + return root.left + + elif root.node_type == NodeType.AND: + if ( + root.left.node_type == NodeType.LITERAL + and root.left.type == OrsoTypes.BOOLEAN + and not root.left.value + ): + # False AND anything is False + return root.left + if ( + root.right.node_type == NodeType.LITERAL + and root.right.type == OrsoTypes.BOOLEAN + and not root.right.value + ): + return root.right + if ( + root.left.node_type == NodeType.LITERAL + and root.left.type == OrsoTypes.BOOLEAN + and root.left.value + ): + # True AND x is x + return root.right + if ( + root.right.node_type == NodeType.LITERAL + and root.right.type == OrsoTypes.BOOLEAN + and root.right.value + ): + return root.left + + elif root.node_type == NodeType.XOR: + if ( + root.left.node_type == NodeType.LITERAL + and root.left.type == OrsoTypes.BOOLEAN + and root.left.value + ): + # True XOR x is NOT x + return Node(NodeType.NOT, root.right) + if ( + root.right.node_type == NodeType.LITERAL + and root.right.type == OrsoTypes.BOOLEAN + and root.right.value + ): + return Node(NodeType.NOT, root.left) + if ( + root.left.node_type == NodeType.LITERAL + and root.left.type == OrsoTypes.BOOLEAN + and not root.left.value + ): + # False XOR x is x + return root.right + if ( + root.right.node_type == NodeType.LITERAL + and root.right.type == OrsoTypes.BOOLEAN + and not root.right.value + ): + return root.left + return root identifiers = get_all_nodes_of_type(root, (NodeType.IDENTIFIER, NodeType.WILDCARD))