public void PrintCost(Treenode node)
        {
            if (node.NodeType == Treenode.Type.sel)
            {
                Console.WriteLine("\n" + node.NodeType.ToString() + '[' + node.Condition.ToString() + ']');
                Console.WriteLine(node.IntData.selApproach.ToString());
                Console.WriteLine("I/O Cost: " + node.IntData.numberOfIOs.ToString());
                Evaluator.totalCost += node.IntData.numberOfIOs;
            }
            else if (node.NodeType == Treenode.Type.proj)
            {
                Console.WriteLine("\n" + node.NodeType.ToString() + '[' + node.ProjectionColl.ToString() + ']');
                Console.WriteLine(node.IntData.prApproach.ToString());
                Console.WriteLine("I/O Cost: " + node.IntData.numberOfIOs.ToString());
                Evaluator.totalCost += node.IntData.numberOfIOs;
            }
            else if (node.NodeType == Treenode.Type.join)
            {
                Console.WriteLine("\n" + node.NodeType.ToString() + '[' + node.Condition.ToString() + ']');
                Console.WriteLine(node.IntData.joinApproach.ToString());
                Console.WriteLine("I/O Cost: " + node.IntData.numberOfIOs.ToString());
                Evaluator.totalCost += node.IntData.numberOfIOs;
            }

            if (node.Operand1 != null)
                PrintCost(node.Operand1);
            if (node.Operand2 != null)
                PrintCost(node.Operand2);
        }
        public static Treenode getOperand(Treenode node, List<Treenode> operands)
        {
            Treenode result = null;
            CompositeCondition compcond = node.Condition;
            AtomicCondition atomcond = compcond[0];
            ConditionElement condelem1 = atomcond.Attribute1;
            ConditionElement condelem2 = atomcond.Attribute2;

            foreach (Treenode fnode in operands)
            {
                Treenode initialNode = fnode;
                Treenode tempnode = initialNode;

                while (tempnode.NodeType != Treenode.Type.relation)
                    if (tempnode.Operand1 != null)
                        tempnode = tempnode.Operand1;

                if (tempnode.RelationName.Equals(condelem1.RelationName) || tempnode.RelationName.Equals(condelem2.RelationName))
                    result = initialNode;
            }

            if (result != null)
                operands.Remove(result);

            return result;
        }
 public Treenode(Type nodetype, Treenode father, Treenode oper1, Treenode oper2, CompositeCondition cCondition, ProjectionCollection projCollection)
 {
     NodeType = nodetype;
     Parent = father;
     Operand1 = oper1;
     Operand2 = oper2;
     Condition = cCondition;
     ProjectionColl = projCollection;
     IntData = new IntermediateData(0, 0, 0, 0);
 }
        public static void pushDown(List<ConditionElement> elements, Treenode node)
        {
            if (node.NodeType == Treenode.Type.proj)
            {
                ProjectionCollection pcollection = node.ProjectionColl;
                foreach (ProjectionElement pelement in pcollection)
                    elements.Add(new ConditionElement(pelement.RelationName + '.' + pelement.Attribute));
            }
            else if (node.NodeType == Treenode.Type.join)
            {
                AtomicCondition atcond = node.Condition[0];
                elements.Add(atcond.Attribute1);
                elements.Add(atcond.Attribute2);
            }
            else if (node.NodeType == Treenode.Type.relation)
            {
                string relName = node.RelationName;
                ProjectionCollection pcollection = new ProjectionCollection();
                foreach (ConditionElement celement in elements)
                    if (relName.Equals(celement.RelationName))
                        pcollection.Add(new ProjectionElement(celement.RelationName, celement.Attribute));

                Treenode newproj = new Treenode(Treenode.Type.proj, node.Parent, node, null, null, pcollection);

                if (node.Parent.NodeType == Treenode.Type.sel)
                {
                    if (node.Parent.Parent.Operand1 == node.Parent)
                        node.Parent.Parent.Operand1 = newproj;
                    else if (node.Parent.Parent.Operand2 == node.Parent)
                        node.Parent.Parent.Operand2 = newproj;

                    node.Parent.Parent = newproj;
                    newproj.Operand1 = node.Parent;
                }
                else
                {
                    if (node.Parent.Operand1 == node)
                        node.Parent.Operand1 = newproj;
                    else if (node.Parent.Operand2 == node)
                        node.Parent.Operand2 = newproj;

                    node.Parent = newproj;
                    newproj.Operand1 = node;
                }
            }

            if (node.Operand1 != null)
                pushDown(elements, node.Operand1);
            if (node.Operand2 != null)
                pushDown(elements, node.Operand2);
        }
        public static void conjuctiveSelectionSeparation(Treenode node, Treenode previous)
        {
            if (node != null)
            {
                if (node.NodeType == Treenode.Type.sel && node.Condition.ConditionType == CompositeCondition.Type.conjunctions)
                {
                    Treenode next = node.Operand1;
                    CompositeCondition condition = node.Condition;

                    int i = 0;
                    foreach (AtomicCondition atcond in condition)
                    {
                        i++;
                        Treenode newnode = new Treenode(Treenode.Type.sel, previous, null, null, new CompositeCondition(atcond.ToString()), null);

                        if (previous != null)
                        {
                            if (previous.NodeType == Treenode.Type.sel || previous.NodeType == Treenode.Type.proj)
                                previous.Operand1 = newnode;
                            else if (previous.NodeType == Treenode.Type.join)
                            {
                                if (previous.Operand1 == node)
                                    previous.Operand1 = newnode;
                                else if (previous.Operand2 == node)
                                    previous.Operand2 = newnode;
                            }
                        }
                        previous = newnode;

                        if (i == condition.Count())
                        {
                            newnode.Operand1 = next;

                            if (next != null)
                                next.Parent = newnode;
                        }
                    }
                }

                if (node.Operand1 != null)
                    conjuctiveSelectionSeparation(node.Operand1, node);
                if (node.Operand2 != null)
                    conjuctiveSelectionSeparation(node.Operand1, node);
            }
        }
        public static void selectionPushDown(Treenode node, Treenode pushnode, Treenode previous, Treenode next)
        {
            if (node != null)
            {
                if (node.NodeType == Treenode.Type.relation)
                {
                    AtomicCondition atcond = pushnode.Condition[0];

                    if (atcond.Attribute1.RelationName.Equals(node.RelationName))
                    {
                        Treenode tempprevious = node.Parent;
                        pushnode.Parent = tempprevious;
                        node.Parent = pushnode;
                        pushnode.Operand1 = node;
                        next.Parent = previous;

                        if (previous != null)
                        {
                            if (previous.Operand1 == pushnode)
                                previous.Operand1 = next;
                            else if (previous.Operand2 == pushnode)
                                previous.Operand2 = next;
                        }

                        if (tempprevious != null)
                        {
                            if (tempprevious.Operand1 == node)
                                tempprevious.Operand1 = pushnode;
                            else if (tempprevious.Operand2 == node)
                                tempprevious.Operand2 = pushnode;
                        }
                    }
                }
                else
                {
                    if (node.Operand1 != null)
                        selectionPushDown(node.Operand1, pushnode, previous, next);
                    if (node.Operand2 != null)
                        selectionPushDown(node.Operand2, pushnode, previous, next);
                }
            }
        }
        public static void findNodes(List<Treenode> nodeList, List<Treenode> operandsList, Treenode node)
        {
            if (node != null)
                if (node.NodeType == Treenode.Type.join)
                {
                    nodeList.Add(node);
                    if (node.Operand1 != null)
                    {
                        if (node.Operand1.NodeType != Treenode.Type.join)
                            operandsList.Add(node.Operand1);
                        if (node.Operand2.NodeType != Treenode.Type.join)
                            operandsList.Add(node.Operand2);
                    }
                }

            if (node.Operand1 != null)
                findNodes(nodeList, operandsList, node.Operand1);
            if (node.Operand2 != null)
                findNodes(nodeList, operandsList, node.Operand2);
        }
        public void PrintNodes(Treenode node)
        {
            if (node != null)
            {
                if (node.NodeType == Treenode.Type.relation)
                    Console.Write(node.RelationName);
                else if (node.NodeType == Treenode.Type.sel || node.NodeType == Treenode.Type.join)
                    Console.Write(node.NodeType.ToString() + '[' + node.Condition.ToString() + ']');
                else Console.Write(node.NodeType.ToString() + '[' + node.ProjectionColl.ToString() + ']');
            }

            if (node.Operand1 != null)
            {
                Console.Write('(');
                PrintNodes(node.Operand1);
                Console.Write(')');
            }
            if (node.Operand2 != null)
            {
                Console.Write('(');
                PrintNodes(node.Operand2);
                Console.Write(')');
            }
        }
        public static void findSelectNodes(List<Treenode> nodes, Treenode node)
        {
            if (node != null)
            {
                if (node.NodeType == Treenode.Type.sel)
                    nodes.Add(node);

                if (node.Operand1 != null)
                    findSelectNodes(nodes, node.Operand1);
                if (node.Operand2 != null)
                    findSelectNodes(nodes, node.Operand2);
            }
        }
        public static void selectOptimalOperator(Treenode node)
        {
            if (node.Operand1 != null)
                selectOptimalOperator(node.Operand1);
            if (node.Operand2 != null)
                selectOptimalOperator(node.Operand2);

            long minCost = long.MaxValue, tempCost = long.MaxValue;

            if (node.NodeType == Treenode.Type.sel)
            {
                Operations.SelectionApproach sapproach = Operations.SelectionApproach.LinearScan;

                tempCost = Operations.nodeIOCostEstimation(node, null, Operations.SelectionApproach.LinearScan, null);
                if (tempCost < minCost)
                {
                    minCost = tempCost;
                    node.IntData.selApproach = Operations.SelectionApproach.LinearScan;
                }

                tempCost = Operations.nodeIOCostEstimation(node, null, Operations.SelectionApproach.UsingIndex, null);
                if (tempCost < minCost)
                {
                    sapproach = Operations.SelectionApproach.UsingIndex;
                    minCost = tempCost;
                    node.IntData.selApproach = Operations.SelectionApproach.UsingIndex;
                }

                tempCost = Operations.nodeIOCostEstimation(node, null, Operations.SelectionApproach.BinarySearch, null);
                if (tempCost < minCost)
                {
                    sapproach = Operations.SelectionApproach.BinarySearch;
                    minCost = tempCost;
                    node.IntData.selApproach = Operations.SelectionApproach.BinarySearch;
                }

                Operations.nodeIOCostEstimation(node, null, sapproach, null);
                node.IntData.numberOfIOs = minCost;
            }
            else if (node.NodeType == Treenode.Type.join)
            {
                Operations.JoinApproach japproach = Operations.JoinApproach.NestedLoops;

                tempCost = Operations.nodeIOCostEstimation(node, Operations.JoinApproach.NestedLoops, null, null);
                if (tempCost < minCost)
                {
                    minCost = tempCost;
                    node.IntData.joinApproach = Operations.JoinApproach.NestedLoops;
                }

                tempCost = Operations.nodeIOCostEstimation(node, Operations.JoinApproach.HashBased, null, null);
                if (tempCost < minCost)
                {
                    japproach = Operations.JoinApproach.HashBased;
                    minCost = tempCost;
                    node.IntData.joinApproach = Operations.JoinApproach.HashBased;
                }

                tempCost = Operations.nodeIOCostEstimation(node, Operations.JoinApproach.SortMerge, null, null);
                if (tempCost < minCost)
                {
                    japproach = Operations.JoinApproach.SortMerge;
                    minCost = tempCost;
                    node.IntData.joinApproach = Operations.JoinApproach.SortMerge;
                }

                Operations.nodeIOCostEstimation(node, japproach, null, null);
                node.IntData.numberOfIOs = minCost;
            }
            else if (node.NodeType == Treenode.Type.proj)
            {
                Operations.ProjectionApproach papproach = Operations.ProjectionApproach.Hashing;

                tempCost = Operations.nodeIOCostEstimation(node, null, null, Operations.ProjectionApproach.Hashing);
                if (tempCost < minCost)
                {
                    minCost = tempCost;
                    node.IntData.prApproach = Operations.ProjectionApproach.Hashing;
                }

                tempCost = Operations.nodeIOCostEstimation(node, null, null, Operations.ProjectionApproach.Sorting);
                if (tempCost < minCost)
                {
                    papproach = Operations.ProjectionApproach.Sorting;
                    minCost = tempCost;
                    node.IntData.prApproach = Operations.ProjectionApproach.Sorting;
                }

                Operations.nodeIOCostEstimation(node, null, null, papproach);
                node.IntData.numberOfIOs = minCost;
            }
            else
                Operations.nodeIOCostEstimation(node, null, null, null);
        }
        public static int smallerNode(Treenode node1, Treenode node2)
        {

            node1.produceIntData();
            node2.produceIntData();
            if (node1.IntData.TotalSize < node2.IntData.TotalSize)
                return -1;
            else if (node1.IntData.TotalSize > node2.IntData.TotalSize)
                return 1;
            else return 0;
        }
 public Querytree()
 {
     Root = new Treenode();
 }
        public static long nodeIOCostEstimation(Treenode node, JoinApproach? japproach, SelectionApproach? sapproach, ProjectionApproach? papproach)
        {
            if (node.NodeType == Treenode.Type.join)
            {
                if (japproach == JoinApproach.NestedLoops)
                {
                    string relName1 = node.Condition[0].Attribute1.RelationName;
                    Relation rel1 = Catalog.Data[relName1];                                
                    long tuplesPerPage1 = Parameters.BufferSize / node.Operand1.IntData.TupleSize;
                    long pageBuffers1 = node.Operand1.IntData.Tuples / tuplesPerPage1;
                    long tuplesPerPage2 = Parameters.BufferSize / node.Operand2.IntData.TupleSize;
                    long pageBuffers2 = node.Operand2.IntData.Tuples / tuplesPerPage2;

                    node.produceIntData();

                    return (long)Decimal.Ceiling(pageBuffers1 / (Parameters.AvailableBuffers - 2)) * pageBuffers2 + pageBuffers1;
                }
                else if (japproach == JoinApproach.SortMerge)
                {
                    string relName1 = node.Condition[0].Attribute1.RelationName;
                    Relation rel1 = Catalog.Data[relName1];
                    string relName2 = node.Condition[0].Attribute2.RelationName;
                    Relation rel2 = Catalog.Data[relName2];
                    long tuplesPerPage1 = Parameters.BufferSize / node.Operand1.IntData.TupleSize;
                    long pageBuffers1 = node.Operand1.IntData.Tuples / tuplesPerPage1;
                    long tuplesPerPage2 = Parameters.BufferSize / node.Operand2.IntData.TupleSize;
                    long pageBuffers2 = node.Operand2.IntData.Tuples / tuplesPerPage2;
                    List<Attribute> attrlist1 = rel1.Attributes;
                    List<Attribute> attrlist2 = rel1.Attributes;
                    string attrName1 = node.Condition[0].Attribute1.Attribute;
                    string attrName2 = node.Condition[0].Attribute2.Attribute;

                    node.produceIntData();

                    foreach (Attribute attr1 in attrlist1)
                        foreach (Attribute attr2 in attrlist2)
                            if (attr1.AttributeName.Equals(attrName1) && attr2.AttributeName.Equals(attrName2))
                                if (rel1.isSorted && rel2.isSorted && attr1.AttributeName.Equals(rel1.SortedTo) && attr2.AttributeName.Equals(rel2.SortedTo))                                  
                                    return pageBuffers1 + pageBuffers2;
                                else if (rel2.isSorted && attr2.AttributeName.Equals(rel2.SortedTo))
                                    return pageBuffers2 + pageBuffers1 * (2 * logBaseCeil(pageBuffers1, Parameters.AvailableBuffers) + 2);
                                else if (rel1.isSorted && attr1.AttributeName.Equals(rel1.SortedTo))
                                    return pageBuffers1 + pageBuffers2 * (2 * logBaseCeil(pageBuffers2, Parameters.AvailableBuffers) + 2);
                                else
                                    return pageBuffers1 * (2 * logBaseCeil(pageBuffers1, Parameters.AvailableBuffers) + 2) +
                                           pageBuffers2 * (2 * logBaseCeil(pageBuffers2, Parameters.AvailableBuffers) + 2);
                }
                else if (japproach == JoinApproach.HashBased)
                {
                    node.produceIntData();
                    
                    return 3 * (node.Operand1.IntData.TupleSize + node.Operand2.IntData.TupleSize);
                }
            }
            else if (node.NodeType == Treenode.Type.sel)
            {
                if (sapproach == SelectionApproach.BinarySearch)
                {
                    long tuplesPerPage1 = Parameters.BufferSize / node.Operand1.IntData.TupleSize;
                    long pageBuffers1 = node.Operand1.IntData.Tuples / tuplesPerPage1;
                    string relName1 = node.Condition[0].Attribute1.RelationName;
                    Relation rel1 = Catalog.Data[relName1];
                    List<Attribute> attrlist1 = rel1.Attributes;
                    string attrName1 = node.Condition[0].Attribute1.Attribute;

                    node.produceIntData();

                    foreach (Attribute attr in attrlist1)
                        if (attr.AttributeName.Equals(attrName1))
                            if (rel1.isSorted && attr.AttributeName.Equals(rel1.SortedTo))
                                return (long)logBaseCeil(pageBuffers1, 2);
                    return long.MaxValue;
                }
                else if (sapproach == SelectionApproach.LinearScan)
                {
                    long tuplesPerPage1 = Parameters.BufferSize / node.Operand1.IntData.TupleSize;
                    long pageBuffers1 = node.Operand1.IntData.Tuples / tuplesPerPage1;
                    string relName1 = node.Condition[0].Attribute1.RelationName;
                    Relation rel1 = Catalog.Data[relName1];
                    List<Attribute> attrlist1 = rel1.Attributes;
                    string attrName1 = node.Condition[0].Attribute1.Attribute;

                    node.produceIntData();

                    foreach (Attribute attr in attrlist1)
                        if (attr.AttributeName.Equals(attrName1) && attr.AttrUse == Attribute.AttrUses.primaryKey)
                            return (long)Decimal.Ceiling(pageBuffers1 / 2);
                    return pageBuffers1;
                }
                else if (sapproach == SelectionApproach.UsingIndex)
                {
                    long tuplesPerPage1 = Parameters.BufferSize / node.Operand1.IntData.TupleSize;
                    long pageBuffers1 = node.Operand1.IntData.Tuples / tuplesPerPage1;
                    string relName1 = node.Condition[0].Attribute1.RelationName;
                    Relation rel1 = Catalog.Data[relName1];
                    List<Attribute> attrlist1 = rel1.Attributes;
                    string attrName1 = node.Condition[0].Attribute1.Attribute;

                    node.produceIntData();

                    foreach (Attribute attr in attrlist1)
                        if (attr.AttributeName.Equals(attrName1) && attr.IsIndex)
                            if (attr.IndexType == Attribute.IndexTypes.bPlusTree)
                                return attr.BplusTreeLength;
                            else if (attr.IndexType == Attribute.IndexTypes.extendibleHashing)
                                return 1;
                            else if (attr.IndexType == Attribute.IndexTypes.staticHashing)
                                return attr.BplusTreeLength + 1;
                    return long.MaxValue;
                }

            }
            else if (node.NodeType == Treenode.Type.proj)
            {
                if (papproach == ProjectionApproach.Sorting)
                {
                    long tuplesPerPage1 = Parameters.BufferSize / node.Operand1.IntData.TupleSize;
                    long pageBuffers1 = node.Operand1.IntData.Tuples / tuplesPerPage1;

                    node.produceIntData();
                    return pageBuffers1 * (2 * logBaseCeil(pageBuffers1, Parameters.AvailableBuffers) + 1);
                }
                else if (papproach == ProjectionApproach.Hashing)
                {
                    long tuplesPerPage1 = Parameters.BufferSize / node.Operand1.IntData.TupleSize;
                    long pageBuffers1 = node.Operand1.IntData.Tuples / tuplesPerPage1;

                    node.produceIntData();
                    return 4 * pageBuffers1;
                }
            }
            else if (node.NodeType == Treenode.Type.relation)
            {
                string relName1 = node.RelationName;
                Relation rel1 = Catalog.Data[relName1];
                node.IntData.TupleSize = rel1.TupleSize;
                node.IntData.Tuples = rel1.cardinality;
                node.IntData.TotalSize = rel1.cardinality * rel1.TupleSize;

                node.produceIntData();
            }
            return -1;
        }