diff --git a/doc/lab5design.txt b/doc/lab5design.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7485aa6fb75536a126fd227cfb2a85c98331282 --- /dev/null +++ b/doc/lab5design.txt @@ -0,0 +1,62 @@ +CS122 Assignment 5 - Advanced Subqueries - Design Document +========================================================== + +A: Subquery Planning +--------------------- + +A1. Which planner did your team add subquery planning to? How easy or + difficult was it to incorporate subquery-planning into the planner? + +A2. Briefly outline the process by which you perform subquery planning in + your query planner. Also explain briefly how your subquery-planner works. + +A3. Briefly describe how you detect whether there are subqueries in the + GROUP BY and ORDER BY clauses. How do you make sure this doesn't + interfere with subqueries in other clauses? + +B: Correlated Evaluation +------------------------- + +B1. How easy or difficult was it to incorporate support for correlated + evaluation into your query planner? Did it affect the sequence of + steps in any substantial ways? + +D: Extra Credit [OPTIONAL] +--------------------------- + +If you implemented any extra-credit tasks for this assignment, describe +them here. The description should be like this, with stuff in "<>" replaced. +(The value i starts at 1 and increments...) + +D<i>: <one-line description> + + <brief summary of what you did, including the specific classes that + we should look at for your implementation> + + <brief summary of test-cases that demonstrate/exercise your extra work> + +E: Feedback [OPTIONAL] +----------------------- + +WE NEED YOUR FEEDBACK! Thoughtful and constructive input will help us to +improve future versions of the course. These questions are OPTIONAL, and +your answers will not affect your grade in any way (including if you hate +everything about the assignment and databases in general, or Donnie and/or +the TAs in particular). Feel free to answer as many or as few of them as +you wish. + +E1. What parts of the assignment were most time-consuming? Why? + +E2. Did you find any parts of the assignment particularly instructive? + Correspondingly, did any parts feel like unnecessary busy-work? + +E3. Did you particularly enjoy any parts of the assignment? Were there + any parts that you particularly disliked? + +E4. Were there any critical details that you wish had been provided with the + assignment, that we should consider including in subsequent versions of + the assignment? + +E5. Do you have any other suggestions for how future versions of the + assignment can be improved? + diff --git a/doc/lab5info.txt b/doc/lab5info.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c6e73f0a7fd921286608852f7e5bf114b9ddd06 --- /dev/null +++ b/doc/lab5info.txt @@ -0,0 +1,33 @@ +CS122 Assignment 5 - Advanced Subqueries +======================================== + +Please completely fill out this document so that we know who participated on +the assignment, any late extensions received, and how much time the assignment +took for your team. Thank you! + +L1. List your team name and the people who worked on this assignment. + + <team name> + + <name> + <name> + ... + +L2. Specify the tag and commit-hash of the Git commit you are submitting for + your assignment. (You can list the hashes of all tags with the command + "git show-ref --tags".) + + Tag: <tag> + Commit hash: <hash> + +L3. Specify how many late tokens you are applying to this assignment, if any. + Similarly, if your team received an extension from Donnie then please + indicate how many days extension you received. You may leave this blank + if it is not relevant to this submission. + + <tokens / extension> + +L4. For each teammate, briefly describe what parts of the assignment each + teammate focused on, along with the total hours spent on the assignment. + + diff --git a/src/main/java/edu/caltech/nanodb/plannodes/MaterializeNode.java b/src/main/java/edu/caltech/nanodb/plannodes/MaterializeNode.java new file mode 100644 index 0000000000000000000000000000000000000000..6768762b59805046d7afcbea512a7bd992fa6fa6 --- /dev/null +++ b/src/main/java/edu/caltech/nanodb/plannodes/MaterializeNode.java @@ -0,0 +1,173 @@ +package edu.caltech.nanodb.plannodes; + + +import java.util.ArrayList; +import java.util.List; + +import edu.caltech.nanodb.expressions.OrderByExpression; +import edu.caltech.nanodb.expressions.TupleLiteral; +import edu.caltech.nanodb.relations.Tuple; + + +/** + * <p> + * This plan-node materializes the results of a child plan-node in memory. + * The tuples of the child plan-node are fetched on-demand (not all at once + * at the start of plan-node execution), and are cached within this plan-node. + * If the child plan produces disk-backed tuples, this plan-node caches a copy + * of the tuple so that the disk-backed tuple can be unpinned. + * </p> + * <p> + * Note that a more typical implementation of a "materialize" node would have + * a maximum in-memory footprint, and would store tuples to a temporary disk + * file when this maximum memory size is reached. However, the memory + * allocation for in-memory tuples is not managed by the Buffer Manager, so it + * really isn't possible for the materialize node to provide this kind of + * functionality. + * </p> + */ +public class MaterializeNode extends PlanNode { + + /** + * This collection holds the tuples that have been generated by the child + * plan so far. + */ + private ArrayList<Tuple> tuples; + + + /** + * This field stores the index of the "current tuple" as the materialized + * results are traversed. + */ + private int currentTupleIndex; + + + /** This field stores the index of the tuple when a position is marked. */ + private int markedTupleIndex; + + + + /** + * When this flag is true, the child plan-node has finished generating + * all of its results. + */ + private boolean childNodeFinished; + + + + public MaterializeNode(PlanNode leftChild) { + super(leftChild); + } + + + @Override + public List<OrderByExpression> resultsOrderedBy() { + return leftChild.resultsOrderedBy(); + } + + + @Override + public boolean supportsMarking() { + return true; + } + + + @Override + public void prepare() { + leftChild.prepare(); + + schema = leftChild.getSchema(); + stats = leftChild.getStats(); + cost = leftChild.getCost(); + + tuples = new ArrayList<>(); + currentTupleIndex = -1; + markedTupleIndex = -1; + childNodeFinished = false; + } + + + @Override + public Tuple getNextTuple() { + Tuple tup = null; + + assert currentTupleIndex >= -1; + assert currentTupleIndex <= tuples.size(); + + if (currentTupleIndex + 1 < tuples.size()) { + // Moving forward the "current tuple" index will stay within the + // tuples we have so far. + currentTupleIndex++; + tup = tuples.get(currentTupleIndex); + } + else { + // Moving forward the "current tuple" index will move beyond the + // tuples we have so far. Need to see if we have consumed all + // child tuples yet. + + if (!childNodeFinished) { + // Try to fetch another tuple from the child plan-node, if + // there is one. + tup = leftChild.getNextTuple(); + if (tup != null) { + if (tup.isDiskBacked()) { + // Make an in-memory version of the tuple we can cache. + Tuple copy = new TupleLiteral(tup); + tup.unpin(); + tup = copy; + } + + tuples.add(tup); + currentTupleIndex++; + } + else { + // The child has no more tuples. + childNodeFinished = true; + } + + assert currentTupleIndex <= tuples.size(); + } + } + + return tup; + } + + + @Override + public void markCurrentPosition() { + markedTupleIndex = currentTupleIndex; + } + + @Override + public void resetToLastMark() { + currentTupleIndex = markedTupleIndex; + } + + @Override + public void cleanUp() { + leftChild.cleanUp(); + + tuples = null; + currentTupleIndex = -1; + } + + @Override + public String toString() { + return "Materialize"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MaterializeNode) { + MaterializeNode other = (MaterializeNode) obj; + return leftChild.equals(other.leftChild); + } + + return false; + } + + @Override + public int hashCode() { + return leftChild.hashCode(); + } +} diff --git a/src/test/java/edu/caltech/test/nanodb/sql/TestExists.java b/src/test/java/edu/caltech/test/nanodb/sql/TestExists.java index 15a00c45ac8a34927a17a12c294c388dee45ea05..141ac15a1c459d0150a6b8e3d5a08aa5611ffa1d 100644 --- a/src/test/java/edu/caltech/test/nanodb/sql/TestExists.java +++ b/src/test/java/edu/caltech/test/nanodb/sql/TestExists.java @@ -11,7 +11,7 @@ import edu.caltech.nanodb.server.CommandResult; * This class exercises the database with some simple EXISTS operations, to * verify that the most basic functionality works. **/ -@Test(groups={"sql"}) +@Test(groups={"sql", "hw5"}) public class TestExists extends SqlTestCase { public TestExists() { super("setup_testExists"); diff --git a/src/test/java/edu/caltech/test/nanodb/sql/TestInPredicates.java b/src/test/java/edu/caltech/test/nanodb/sql/TestInPredicates.java index 0ee670bc5765b1a7507b6d5d1cf824474b192635..ce990b1b6fcae013775823f131af031968d6fdb3 100644 --- a/src/test/java/edu/caltech/test/nanodb/sql/TestInPredicates.java +++ b/src/test/java/edu/caltech/test/nanodb/sql/TestInPredicates.java @@ -67,7 +67,7 @@ public class TestInPredicates extends SqlTestCase { * * @throws Exception if any query parsing or execution issues occur. */ - @Test(groups={"sql"}) + @Test(groups={"sql", "hw5"}) public void testInSubquery() throws Throwable { CommandResult result; TupleLiteral[] expected1 = { diff --git a/src/test/java/edu/caltech/test/nanodb/sql/TestScalarSubquery.java b/src/test/java/edu/caltech/test/nanodb/sql/TestScalarSubquery.java index 53708109a5079d9250cd7ae1e062737d105d3f23..be4c31364fdcc7de0cf5b5c3364afb37e335c121 100644 --- a/src/test/java/edu/caltech/test/nanodb/sql/TestScalarSubquery.java +++ b/src/test/java/edu/caltech/test/nanodb/sql/TestScalarSubquery.java @@ -13,7 +13,7 @@ import edu.caltech.nanodb.server.CommandResult; * This class exercises the database with some simple scalar subqueries, to * verify that the most basic functionality works. **/ -@Test(groups={"sql"}) +@Test(groups={"sql", "hw5"}) public class TestScalarSubquery extends SqlTestCase { public TestScalarSubquery() { super("setup_testExists");