/* Check if the Scan corresponding to the RelationSchema is already present in the join_operators. */ boolean relationAlreadyContainedInAJoinOperator(BaseRelationSchema rs) { ScanOperator so = findScanOperator(rs); for (JoinOperator jo : join_operators) if ((so == jo.getLeftOperator()) || (so == jo.getRightOperator())) return true; return false; }
/* Create a query plan, the operators etc. */ boolean plan() { construct_scan_operators(); if (query_relations.size() == 1) { /* It is a single table query. We are essentially done. */ assert scan_operators.size() == 1; root = scan_operators.get(0); } else { /* Before creating the join operators, we will first choose an order in which to do the joins. For now, we will use a simple ordering that results in a left-deep plan. We will start with any join predicate, and create a join operator for that using the Scans. We will then choose some join predicate that does not require a Cartesian product. */ /* Let's first create a Vector containing the join predicates. */ Vector<Predicate> join_predicates_remaining = new Vector<Predicate>(); for (Predicate p : query_predicates) if (p.isJoinPredicate()) join_predicates_remaining.add(p); if (join_predicates_remaining.size() != (scan_operators.size() - 1)) { System.out.println("=========> The query is not well formed"); return false; } join_operators = new Vector<JoinOperator>(); /* We will choose the first join operator arbitrarily. */ int num_join_predicates = join_predicates_remaining.size(); for (int i = 0; i < num_join_predicates; i++) { if (i == 0) { /* The first join predicate is used to create the bottommost join operator, with two scans as children. */ Predicate jp = join_predicates_remaining.get(0); join_predicates_remaining.remove(0); ScanOperator left = findScanOperator(jp.leftRelationSchema()); ScanOperator right = findScanOperator(jp.rightRelationSchema()); join_operators.add(JoinOperator.createNewJoinOperator(left, right, jp)); } else { /* Find the first join predicate whose left or right RelationSchema is already present. */ Predicate next_jp = null; for (Predicate jp : join_predicates_remaining) { boolean leftContained = relationAlreadyContainedInAJoinOperator(jp.leftRelationSchema()); boolean rightContained = relationAlreadyContainedInAJoinOperator(jp.rightRelationSchema()); if (leftContained || rightContained) { if (leftContained && rightContained) { System.out.println( "=========> Query not well-formed: There is a cycle in the query"); return false; } /* We have found a valid join predicate. Break. */ next_jp = jp; break; } } if (next_jp == null) { System.out.println( "=========> Query not well-formed: I think the query requires a Cartesian Product."); return false; } join_predicates_remaining.removeElement(next_jp); /* One quirk here is that we may need to swap the two arguments of the join predicate to match the left and right. */ if (relationAlreadyContainedInAJoinOperator(next_jp.rightRelationSchema())) next_jp.swap(); join_operators.add( JoinOperator.createNewJoinOperator( join_operators.lastElement(), findScanOperator(next_jp.rightRelationSchema()), next_jp)); } } /* Finally: we need to set the root to be the very last join operator. */ root = join_operators.lastElement(); } root = new ProjectOperator(root, select_attributes, distinct, order_by_attributes); return true; }