11 | * Provides a set of methods that can be used to access these variables from
12 | * anywhere.
13 | *
14 | * @Threadsafe
15 | */
16 | public class Database {
17 | private static AtomicReference
8 | * Change the value of the DEBUG_LEVEL constant using a system property:
9 | * simpledb.Debug. For example, on the command line, use -Dsimpledb.Debug=x,
10 | * or simply -Dsimpledb.Debug to enable it at level 0.
11 | * The log(level, message, ...) method will print to standard output if the
12 | * level number is less than or equal to the currently set DEBUG_LEVEL.
13 | */
14 |
15 | public class Debug {
16 | private static final int DEBUG_LEVEL;
17 | static {
18 | String debug = System.getProperty("simpledb.Debug");
19 | if (debug == null) {
20 | // No system property = disabled
21 | DEBUG_LEVEL = -1;
22 | } else if (debug.length() == 0) {
23 | // Empty property = level 0
24 | DEBUG_LEVEL = 0;
25 | } else {
26 | DEBUG_LEVEL = Integer.parseInt(debug);
27 | }
28 | }
29 |
30 | private static final int DEFAULT_LEVEL = 0;
31 |
32 | /** Log message if the log level >= level. Uses printf. */
33 | public static void log(int level, String message, Object... args) {
34 | if (isEnabled(level)) {
35 | System.out.printf(message, args);
36 | System.out.println();
37 | }
38 | }
39 |
40 | /** @return true if level is being logged. */
41 | public static boolean isEnabled(int level) {
42 | return level <= DEBUG_LEVEL;
43 | }
44 |
45 | /** @return true if the default level is being logged. */
46 | public static boolean isEnabled() {
47 | return isEnabled(DEFAULT_LEVEL);
48 | }
49 |
50 | /** Logs message at the default log level. */
51 | public static void log(String message, Object... args) {
52 | log(DEFAULT_LEVEL, message, args);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/Delete.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * The delete operator. Delete reads tuples from its child operator and removes
7 | * them from the table they belong to.
8 | */
9 | public class Delete extends Operator {
10 |
11 | private static final long serialVersionUID = 1L;
12 |
13 | /**
14 | * Constructor specifying the transaction that this delete belongs to as
15 | * well as the child to read from.
16 | *
17 | * @param t
18 | * The transaction this delete runs in
19 | * @param child
20 | * The child operator from which to read tuples for deletion
21 | */
22 | private TransactionId tid;
23 | private OpIterator child;
24 | private OpIterator[] opIterators;
25 | private TupleDesc td = new TupleDesc(new Type[]{Type.INT_TYPE});
26 | private boolean deleted;
27 | public Delete(TransactionId t, OpIterator child) {
28 | tid = t;
29 | this.child = child;
30 | deleted = false;
31 | }
32 |
33 | public TupleDesc getTupleDesc() {
34 | return td;
35 | }
36 |
37 | public void open() throws DbException, TransactionAbortedException {
38 | child.open();
39 | super.open();
40 | }
41 |
42 | public void close() {
43 | super.close();
44 | child.close();
45 | }
46 |
47 | public void rewind() throws DbException, TransactionAbortedException {
48 | close();
49 | open();
50 | }
51 |
52 | /**
53 | * Deletes tuples as they are read from the child operator. Deletes are
54 | * processed via the buffer pool (which can be accessed via the
55 | * Database.getBufferPool() method.
56 | *
57 | * @return A 1-field tuple containing the number of deleted records.
58 | * @see Database#getBufferPool
59 | * @see BufferPool#deleteTuple
60 | */
61 | protected Tuple fetchNext() throws TransactionAbortedException, DbException {
62 | if(deleted) return null;
63 | int num = 0;
64 | while(child.hasNext())
65 | {
66 | Tuple tuple = child.next();
67 | try {
68 | Database.getBufferPool().deleteTuple(tid, tuple);
69 | } catch (IOException e) {
70 | e.printStackTrace();
71 | }
72 | num++;
73 | }
74 | deleted = true;
75 | Tuple t = new Tuple(td);
76 | t.setField(0, new IntField(num));
77 | return t;
78 | }
79 |
80 | @Override
81 | public OpIterator[] getChildren() {
82 | opIterators[0] = child;
83 | return opIterators;
84 | }
85 |
86 | @Override
87 | public void setChildren(OpIterator[] children) {
88 | opIterators = children;
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/Field.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | import java.io.*;
4 |
5 | /**
6 | * Interface for values of fields in tuples in SimpleDB.
7 | */
8 | public interface Field extends Serializable{
9 | /**
10 | * Write the bytes representing this field to the specified
11 | * DataOutputStream.
12 | * @see DataOutputStream
13 | * @param dos The DataOutputStream to write to.
14 | */
15 | void serialize(DataOutputStream dos) throws IOException;
16 |
17 | /**
18 | * Compare the value of this field object to the passed in value.
19 | * @param op The operator
20 | * @param value The value to compare this Field to
21 | * @return Whether or not the comparison yields true.
22 | */
23 | public boolean compare(Predicate.Op op, Field value);
24 |
25 | /**
26 | * Returns the type of this field (see {@link Type#INT_TYPE} or {@link Type#STRING_TYPE}
27 | * @return type of this field
28 | */
29 | public Type getType();
30 |
31 | /**
32 | * Hash code.
33 | * Different Field objects representing the same value should probably
34 | * return the same hashCode.
35 | */
36 | public int hashCode();
37 | public boolean equals(Object field);
38 |
39 | public String toString();
40 | }
41 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/Filter.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | import java.util.*;
4 |
5 | /**
6 | * Filter is an operator that implements a relational select.
7 | */
8 | public class Filter extends Operator {
9 |
10 | private static final long serialVersionUID = 1L;
11 | private Predicate predicate;
12 | private OpIterator child;
13 | private OpIterator[] opIterators;
14 | /**
15 | * Constructor accepts a predicate to apply and a child operator to read
16 | * tuples to filter from.
17 | *
18 | * @param p
19 | * The predicate to filter tuples with
20 | * @param child
21 | * The child operator
22 | */
23 | public Filter(Predicate p, OpIterator child) {
24 | predicate = p;
25 | this.child = child;
26 | opIterators = new OpIterator[1];
27 | }
28 |
29 | public Predicate getPredicate() {
30 | return predicate;
31 | }
32 |
33 | public TupleDesc getTupleDesc() {
34 | return child.getTupleDesc();
35 | }
36 |
37 | public void open() throws DbException, NoSuchElementException,
38 | TransactionAbortedException {
39 | child.open();
40 | super.open();
41 | }
42 |
43 | public void close() {
44 | super.close();
45 | child.close();
46 | }
47 |
48 | public void rewind() throws DbException, TransactionAbortedException {
49 | close();
50 | open();
51 | }
52 |
53 | /**
54 | * AbstractDbIterator.readNext implementation. Iterates over tuples from the
55 | * child operator, applying the predicate to them and returning those that
56 | * pass the predicate (i.e. for which the Predicate.filter() returns true.)
57 | *
58 | * @return The next tuple that passes the filter, or null if there are no
59 | * more tuples
60 | * @see Predicate#filter
61 | */
62 | protected Tuple fetchNext() throws NoSuchElementException,
63 | TransactionAbortedException, DbException {
64 | while (child.hasNext()){
65 | Tuple tuple = child.next();
66 | if(predicate.filter(tuple))
67 | return tuple;
68 | }
69 | return null;
70 | }
71 |
72 | @Override
73 | public OpIterator[] getChildren() {
74 | opIterators[0] = child;
75 | return opIterators;
76 | }
77 |
78 | @Override
79 | public void setChildren(OpIterator[] children) {
80 | opIterators = children;
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/HeapPageId.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | /** Unique identifier for HeapPage objects. */
4 | public class HeapPageId implements PageId {
5 |
6 | /**
7 | * Constructor. Create a page id structure for a specific page of a
8 | * specific table.
9 | *
10 | * @param tableId The table that is being referenced
11 | * @param pgNo The page number in that table.
12 | */
13 | private int tableId;
14 | private int pgNo;
15 | public HeapPageId(int tableId, int pgNo) {
16 | this.pgNo = pgNo;
17 | this.tableId = tableId;
18 | }
19 |
20 | /** @return the table associated with this PageId */
21 | public int getTableId() {
22 | return tableId;
23 | }
24 |
25 | /**
26 | * @return the page number in the table getTableId() associated with
27 | * this PageId
28 | */
29 | public int getPageNumber() {
30 | return pgNo;
31 | }
32 |
33 | /**
34 | * @return a hash code for this page, represented by the concatenation of
35 | * the table number and the page number (needed if a PageId is used as a
36 | * key in a hash table in the BufferPool, for example.)
37 | * @see BufferPool
38 | */
39 | public int hashCode() {
40 | int res = 5;
41 | res = 7 * res + tableId;
42 | res = 7 * res + pgNo;
43 | return res;
44 | }
45 |
46 | /**
47 | * Compares one PageId to another.
48 | *
49 | * @param o The object to compare against (must be a PageId)
50 | * @return true if the objects are equal (e.g., page numbers and table
51 | * ids are the same)
52 | */
53 | public boolean equals(Object o) {
54 | if(o==null)
55 | return false;
56 | if(!(o instanceof HeapPageId))
57 | return false;
58 | if(o == this)
59 | return true;
60 |
61 | HeapPageId heapPageId = (HeapPageId)o;
62 | return pgNo == heapPageId.pgNo && tableId == heapPageId.tableId;
63 | }
64 |
65 | /**
66 | * Return a representation of this object as an array of
67 | * integers, for writing to disk. Size of returned array must contain
68 | * number of integers that corresponds to number of args to one of the
69 | * constructors.
70 | */
71 | public int[] serialize() {
72 | int data[] = new int[2];
73 |
74 | data[0] = getTableId();
75 | data[1] = getPageNumber();
76 | return data;
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/IndexOpIterator.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 | import java.util.*;
3 |
4 | /** IndexDBIterator is the interface that index access methods
5 | implement in SimpleDb.
6 | */
7 | public interface IndexOpIterator extends OpIterator {
8 | /** Open the access method such that when getNext is called, it
9 | iterates through the tuples that satisfy ipred.
10 | @param ipred The predicate that is used to scan the index.
11 | */
12 | public void open(IndexPredicate ipred)
13 | throws NoSuchElementException, DbException, TransactionAbortedException;
14 |
15 | /** Begin a new index scan with the specified predicate.
16 | @param ipred The predicate that is used to scan the index.
17 | */
18 | public void rewind(IndexPredicate ipred)
19 | throws DbException, TransactionAbortedException;
20 | }
21 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/IndexPredicate.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * IndexPredicate compares a field which has index on it against a given value
7 | * @see IndexOpIterator
8 | */
9 | public class IndexPredicate implements Serializable {
10 |
11 | private static final long serialVersionUID = 1L;
12 |
13 | private Predicate.Op op;
14 | private Field fieldvalue;
15 |
16 | /**
17 | * Constructor.
18 | *
19 | * @param fvalue The value that the predicate compares against.
20 | * @param op The operation to apply (as defined in Predicate.Op); either
21 | * Predicate.Op.GREATER_THAN, Predicate.Op.LESS_THAN, Predicate.Op.EQUAL,
22 | * Predicate.Op.GREATER_THAN_OR_EQ, or Predicate.Op.LESS_THAN_OR_EQ
23 | * @see Predicate
24 | */
25 | public IndexPredicate(Predicate.Op op, Field fvalue) {
26 | this.op = op;
27 | this.fieldvalue = fvalue;
28 | }
29 |
30 | public Field getField() {
31 | return fieldvalue;
32 | }
33 |
34 | public Predicate.Op getOp() {
35 | return op;
36 | }
37 |
38 | /** Return true if the fieldvalue in the supplied predicate
39 | is satisfied by this predicate's fieldvalue and
40 | operator.
41 | @param ipd The field to compare against.
42 | */
43 | public boolean equals(IndexPredicate ipd) {
44 | if (ipd == null)
45 | return false;
46 | return (op.equals(ipd.op) && fieldvalue.equals(ipd.fieldvalue));
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/IntField.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | import java.io.*;
4 |
5 | /**
6 | * Instance of Field that stores a single integer.
7 | */
8 | public class IntField implements Field {
9 |
10 | private static final long serialVersionUID = 1L;
11 |
12 | private final int value;
13 |
14 | public int getValue() {
15 | return value;
16 | }
17 |
18 | /**
19 | * Constructor.
20 | *
21 | * @param i The value of this field.
22 | */
23 | public IntField(int i) {
24 | value = i;
25 | }
26 |
27 | public String toString() {
28 | return Integer.toString(value);
29 | }
30 |
31 | public int hashCode() {
32 | return value;
33 | }
34 |
35 | public boolean equals(Object field) {
36 | return ((IntField) field).value == value;
37 | }
38 |
39 | public void serialize(DataOutputStream dos) throws IOException {
40 | dos.writeInt(value);
41 | }
42 |
43 | /**
44 | * Compare the specified field to the value of this Field.
45 | * Return semantics are as specified by Field.compare
46 | *
47 | * @throws IllegalCastException if val is not an IntField
48 | * @see Field#compare
49 | */
50 | public boolean compare(Predicate.Op op, Field val) {
51 |
52 | IntField iVal = (IntField) val;
53 |
54 | switch (op) {
55 | case EQUALS:
56 | return value == iVal.value;
57 | case NOT_EQUALS:
58 | return value != iVal.value;
59 |
60 | case GREATER_THAN:
61 | return value > iVal.value;
62 |
63 | case GREATER_THAN_OR_EQ:
64 | return value >= iVal.value;
65 |
66 | case LESS_THAN:
67 | return value < iVal.value;
68 |
69 | case LESS_THAN_OR_EQ:
70 | return value <= iVal.value;
71 |
72 | case LIKE:
73 | return value == iVal.value;
74 | }
75 |
76 | return false;
77 | }
78 |
79 | /**
80 | * Return the Type of this field.
81 | * @return Type.INT_TYPE
82 | */
83 | public Type getType() {
84 | return Type.INT_TYPE;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/JoinPredicate.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * JoinPredicate compares fields of two tuples using a predicate. JoinPredicate
7 | * is most likely used by the Join operator.
8 | */
9 | public class JoinPredicate implements Serializable {
10 |
11 | private static final long serialVersionUID = 1L;
12 |
13 | /**
14 | * Constructor -- create a new predicate over two fields of two tuples.
15 | *
16 | * @param field1
17 | * The field index into the first tuple in the predicate
18 | * @param field2
19 | * The field index into the second tuple in the predicate
20 | * @param op
21 | * The operation to apply (as defined in Predicate.Op); either
22 | * Predicate.Op.GREATER_THAN, Predicate.Op.LESS_THAN,
23 | * Predicate.Op.EQUAL, Predicate.Op.GREATER_THAN_OR_EQ, or
24 | * Predicate.Op.LESS_THAN_OR_EQ
25 | * @see Predicate
26 | */
27 | int field1;
28 | int field2;
29 | Predicate.Op op;
30 | public JoinPredicate(int field1, Predicate.Op op, int field2) {
31 | this.field1 = field1;
32 | this.field2 = field2;
33 | this.op = op;
34 | }
35 |
36 | /**
37 | * Apply the predicate to the two specified tuples. The comparison can be
38 | * made through Field's compare method.
39 | *
40 | * @return true if the tuples satisfy the predicate.
41 | */
42 | public boolean filter(Tuple t1, Tuple t2) {
43 |
44 | return t1.getField(field1).compare(op, t2.getField(field2));
45 | }
46 |
47 | public int getField1()
48 | {
49 | return field1;
50 | }
51 |
52 | public int getField2()
53 | {
54 | return field2;
55 | }
56 |
57 | public Predicate.Op getOperator()
58 | {
59 | return op;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/LogicalFilterNode.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | /** A LogicalFilterNode represents the parameters of a filter in the WHERE clause of a query.
4 |
5 | Filter is of the form t.f p c
6 |
7 | Where t is a table, f is a field in t, p is a predicate, and c is a constant
8 | */
9 | public class LogicalFilterNode {
10 | /** The alias of a table (or the name if no alias) over which the filter ranges */
11 | public String tableAlias;
12 |
13 | /** The predicate in the filter */
14 | public Predicate.Op p;
15 |
16 | /* The constant on the right side of the filter */
17 | public String c;
18 |
19 | /** The field from t which is in the filter. The pure name, without alias or tablename*/
20 | public String fieldPureName;
21 |
22 | public String fieldQuantifiedName;
23 |
24 | public LogicalFilterNode(String table, String field, Predicate.Op pred, String constant) {
25 | tableAlias = table;
26 | p = pred;
27 | c = constant;
28 | String[] tmps = field.split("[.]");
29 | if (tmps.length>1)
30 | fieldPureName = tmps[tmps.length-1];
31 | else
32 | fieldPureName=field;
33 | this.fieldQuantifiedName = tableAlias+"."+fieldPureName;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/LogicalJoinNode.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | /** A LogicalJoinNode represens the state needed of a join of two
4 | * tables in a LogicalQueryPlan */
5 | public class LogicalJoinNode {
6 |
7 | /** The first table to join (may be null). It's the alias of the table (if no alias, the true table name) */
8 | public String t1Alias;
9 |
10 | /** The second table to join (may be null). It's the alias of the table, (if no alias, the true table name).*/
11 | public String t2Alias;
12 |
13 | /** The name of the field in t1 to join with. It's the pure name of a field, rather that alias.field. */
14 | public String f1PureName;
15 |
16 | public String f1QuantifiedName;
17 |
18 | /** The name of the field in t2 to join with. It's the pure name of a field.*/
19 | public String f2PureName;
20 |
21 | public String f2QuantifiedName;
22 |
23 | /** The join predicate */
24 | public Predicate.Op p;
25 |
26 | public LogicalJoinNode() {
27 | }
28 |
29 | public LogicalJoinNode(String table1, String table2, String joinField1, String joinField2, Predicate.Op pred) {
30 | t1Alias = table1;
31 | t2Alias = table2;
32 | String[] tmps = joinField1.split("[.]");
33 | if (tmps.length>1)
34 | f1PureName = tmps[tmps.length-1];
35 | else
36 | f1PureName=joinField1;
37 | tmps = joinField2.split("[.]");
38 | if (tmps.length>1)
39 | f2PureName = tmps[tmps.length-1];
40 | else
41 | f2PureName = joinField2;
42 | p = pred;
43 | this.f1QuantifiedName = t1Alias+"."+this.f1PureName;
44 | this.f2QuantifiedName = t2Alias+"."+this.f2PureName;
45 | }
46 |
47 | /** Return a new LogicalJoinNode with the inner and outer (t1.f1
48 | * and t2.f2) tables swapped. */
49 | public LogicalJoinNode swapInnerOuter() {
50 | Predicate.Op newp;
51 | if (p == Predicate.Op.GREATER_THAN)
52 | newp = Predicate.Op.LESS_THAN;
53 | else if (p == Predicate.Op.GREATER_THAN_OR_EQ)
54 | newp = Predicate.Op.LESS_THAN_OR_EQ;
55 | else if (p == Predicate.Op.LESS_THAN)
56 | newp = Predicate.Op.GREATER_THAN;
57 | else if (p == Predicate.Op.LESS_THAN_OR_EQ)
58 | newp = Predicate.Op.GREATER_THAN_OR_EQ;
59 | else
60 | newp = p;
61 |
62 | LogicalJoinNode j2 = new LogicalJoinNode(t2Alias,t1Alias,f2PureName,f1PureName, newp);
63 | return j2;
64 | }
65 |
66 | @Override public boolean equals(Object o) {
67 | LogicalJoinNode j2 =(LogicalJoinNode)o;
68 | return (j2.t1Alias.equals(t1Alias) || j2.t1Alias.equals(t2Alias)) && (j2.t2Alias.equals(t1Alias) || j2.t2Alias.equals(t2Alias));
69 | }
70 |
71 | @Override public String toString() {
72 | return t1Alias + ":" + t2Alias ;//+ ";" + f1 + " " + p + " " + f2;
73 | }
74 |
75 | @Override public int hashCode() {
76 | return t1Alias.hashCode() + t2Alias.hashCode() + f1PureName.hashCode() + f2PureName.hashCode();
77 | }
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/LogicalScanNode.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | /** A LogicalScanNode represents table in the FROM list in a
4 | * LogicalQueryPlan */
5 | public class LogicalScanNode {
6 |
7 | /** The name (alias) of the table as it is used in the query */
8 | public String alias;
9 |
10 | /** The table identifier (can be passed to {@link Catalog#getDatabaseFile})
11 | * to retrieve a DbFile */
12 | public int t;
13 |
14 | public LogicalScanNode(int table, String tableAlias) {
15 | this.alias = tableAlias;
16 | this.t = table;
17 | }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/LogicalSelectListNode.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | /** A LogicalSelectListNode represents a clause in the select list in
4 | * a LogicalQueryPlan
5 | */
6 | public class LogicalSelectListNode {
7 | /** The field name being selected; the name may be (optionally) be
8 | * qualified with a table name or alias.
9 | */
10 | public String fname;
11 |
12 | /** The aggregation operation over the field (if any) */
13 | public String aggOp;
14 |
15 | public LogicalSelectListNode(String aggOp, String fname) {
16 | this.aggOp = aggOp;
17 | this.fname = fname;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/LogicalSubplanJoinNode.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | /** A LogicalSubplanJoinNode represens the state needed of a join of a
4 | * table to a subplan in a LogicalQueryPlan -- inherits state from
5 | * {@link LogicalJoinNode}; t2 and f2 should always be null
6 | */
7 | public class LogicalSubplanJoinNode extends LogicalJoinNode {
8 |
9 | /** The subplan (used on the inner) of the join */
10 | OpIterator subPlan;
11 |
12 | public LogicalSubplanJoinNode(String table1, String joinField1, OpIterator sp, Predicate.Op pred) {
13 | t1Alias = table1;
14 | String[] tmps = joinField1.split("[.]");
15 | if (tmps.length>1)
16 | f1PureName = tmps[tmps.length-1];
17 | else
18 | f1PureName=joinField1;
19 | f1QuantifiedName=t1Alias+"."+f1PureName;
20 | subPlan = sp;
21 | p = pred;
22 | }
23 |
24 | @Override public int hashCode() {
25 | return t1Alias.hashCode() + f1PureName.hashCode() + subPlan.hashCode();
26 | }
27 |
28 | @Override public boolean equals(Object o) {
29 | LogicalJoinNode j2 =(LogicalJoinNode)o;
30 | if (!(o instanceof LogicalSubplanJoinNode))
31 | return false;
32 |
33 | return (j2.t1Alias.equals(t1Alias) && j2.f1PureName.equals(f1PureName) && ((LogicalSubplanJoinNode)o).subPlan.equals(subPlan));
34 | }
35 |
36 | public LogicalSubplanJoinNode swapInnerOuter() {
37 | LogicalSubplanJoinNode j2 = new LogicalSubplanJoinNode(t1Alias,f1PureName,subPlan, p);
38 | return j2;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/OpIterator.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 | import java.io.Serializable;
3 | import java.util.*;
4 |
5 | /**
6 | * OpIterator is the iterator interface that all SimpleDB operators should
7 | * implement. If the iterator is not open, none of the methods should work,
8 | * and should throw an IllegalStateException. In addition to any
9 | * resource allocation/deallocation, an open method should call any
10 | * child iterator open methods, and in a close method, an iterator
11 | * should call its children's close methods.
12 | */
13 | public interface OpIterator extends Serializable{
14 | /**
15 | * Opens the iterator. This must be called before any of the other methods.
16 | * @throws DbException when there are problems opening/accessing the database.
17 | */
18 | public void open()
19 | throws DbException, TransactionAbortedException;
20 |
21 | /** Returns true if the iterator has more tuples.
22 | * @return true f the iterator has more tuples.
23 | * @throws IllegalStateException If the iterator has not been opened
24 | */
25 | public boolean hasNext() throws DbException, TransactionAbortedException;
26 |
27 | /**
28 | * Returns the next tuple from the operator (typically implementing by reading
29 | * from a child operator or an access method).
30 | *
31 | * @return the next tuple in the iteration.
32 | * @throws NoSuchElementException if there are no more tuples.
33 | * @throws IllegalStateException If the iterator has not been opened
34 | */
35 | public Tuple next() throws DbException, TransactionAbortedException, NoSuchElementException;
36 |
37 | /**
38 | * Resets the iterator to the start.
39 | * @throws DbException when rewind is unsupported.
40 | * @throws IllegalStateException If the iterator has not been opened
41 | */
42 | public void rewind() throws DbException, TransactionAbortedException;
43 |
44 | /**
45 | * Returns the TupleDesc associated with this OpIterator.
46 | * @return the TupleDesc associated with this OpIterator.
47 | */
48 | public TupleDesc getTupleDesc();
49 |
50 | /**
51 | * Closes the iterator. When the iterator is closed, calling next(),
52 | * hasNext(), or rewind() should fail by throwing IllegalStateException.
53 | */
54 | public void close();
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/Page.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | /**
4 | * Page is the interface used to represent pages that are resident in the
5 | * BufferPool. Typically, DbFiles will read and write pages from disk.
6 | *
7 | * Pages may be "dirty", indicating that they have been modified since they
8 | * were last written out to disk.
9 | *
10 | * For recovery purposes, pages MUST have a single constructor of the form:
11 | * Page(PageId id, byte[] data)
12 | */
13 | public interface Page {
14 |
15 | /**
16 | * Return the id of this page. The id is a unique identifier for a page
17 | * that can be used to look up the page on disk or determine if the page
18 | * is resident in the buffer pool.
19 | *
20 | * @return the id of this page
21 | */
22 | public PageId getId();
23 |
24 | /**
25 | * Get the id of the transaction that last dirtied this page, or null if the page is clean..
26 | *
27 | * @return The id of the transaction that last dirtied this page, or null
28 | */
29 | public TransactionId isDirty();
30 |
31 | /**
32 | * Set the dirty state of this page as dirtied by a particular transaction
33 | */
34 | public void markDirty(boolean dirty, TransactionId tid);
35 |
36 | /**
37 | * Generates a byte array representing the contents of this page.
38 | * Used to serialize this page to disk.
39 | *
40 | * The invariant here is that it should be possible to pass the byte array
41 | * generated by getPageData to the Page constructor and have it produce
42 | * an identical Page object.
43 | *
44 | * @return A byte array correspond to the bytes of this page.
45 | */
46 |
47 | public byte[] getPageData();
48 |
49 | /** Provide a representation of this page before any modifications were made
50 | to it. Used by recovery.
51 | */
52 | public Page getBeforeImage();
53 |
54 | /*
55 | * a transaction that wrote this page just committed it.
56 | * copy current content to the before image.
57 | */
58 | public void setBeforeImage();
59 | }
60 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/PageId.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | /** PageId is an interface to a specific page of a specific table. */
4 | public interface PageId {
5 |
6 | /** Return a representation of this page id object as a collection of
7 | integers (used for logging)
8 |
9 | This class MUST have a constructor that accepts n integer parameters,
10 | where n is the number of integers returned in the array from serialize.
11 | */
12 | public int[] serialize();
13 |
14 | /** @return the unique tableid hashcode with this PageId */
15 | public int getTableId();
16 |
17 | /**
18 | * @return a hash code for this page, represented by the concatenation of
19 | * the table number and the page number (needed if a PageId is used as a
20 | * key in a hash table in the BufferPool, for example.)
21 | * @see BufferPool
22 | */
23 | public int hashCode();
24 |
25 | /**
26 | * Compares one PageId to another.
27 | *
28 | * @param o The object to compare against (must be a PageId)
29 | * @return true if the objects are equal (e.g., page numbers and table
30 | * ids are the same)
31 | */
32 | public boolean equals(Object o);
33 |
34 | public int getPageNumber();
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/ParsingException.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 | import java.lang.Exception;
3 |
4 | public class ParsingException extends Exception {
5 | public ParsingException(String string) {
6 | super(string);
7 | }
8 |
9 | public ParsingException(Exception e) {
10 | super(e);
11 | }
12 |
13 | /**
14 | *
15 | */
16 | private static final long serialVersionUID = 1L;
17 | }
18 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/Permissions.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | /**
4 | * Class representing requested permissions to a relation/file.
5 | * Private constructor with two static objects READ_ONLY and READ_WRITE that
6 | * represent the two levels of permission.
7 | */
8 | public class Permissions {
9 | int permLevel;
10 |
11 | private Permissions(int permLevel) {
12 | this.permLevel = permLevel;
13 | }
14 |
15 | public String toString() {
16 | if (permLevel == 0)
17 | return "READ_ONLY";
18 | if (permLevel == 1)
19 | return "READ_WRITE";
20 | return "UNKNOWN";
21 | }
22 |
23 | public static final Permissions READ_ONLY = new Permissions(0);
24 | public static final Permissions READ_WRITE = new Permissions(1);
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/PlanCache.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 | import java.util.HashMap;
3 | import java.util.Set;
4 | import java.util.Vector;
5 |
6 | /** A PlanCache is a helper class that can be used to store the best
7 | * way to order a given set of joins */
8 | public class PlanCache {
9 | HashMap
13 | * Our implementation is written in terms of an IntHistogram by converting
14 | * each String to an integer.
15 | *
16 | * @param buckets
17 | * the number of buckets
18 | */
19 | public StringHistogram(int buckets) {
20 | hist = new IntHistogram(buckets, minVal(), maxVal());
21 | }
22 |
23 | /**
24 | * Convert a string to an integer, with the property that if the return
25 | * value(s1) < return value(s2), then s1 < s2
26 | */
27 | private int stringToInt(String s) {
28 | int i;
29 | int v = 0;
30 | for (i = 3; i >= 0; i--) {
31 | if (s.length() > 3 - i) {
32 | int ci = (int) s.charAt(3 - i);
33 | v += (ci) << (i * 8);
34 | }
35 | }
36 |
37 | // XXX: hack to avoid getting wrong results for
38 | // strings which don't output in the range min to max
39 | if (!(s.equals("") || s.equals("zzzz"))) {
40 | if (v < minVal()) {
41 | v = minVal();
42 | }
43 |
44 | if (v > maxVal()) {
45 | v = maxVal();
46 | }
47 | }
48 |
49 | return v;
50 | }
51 |
52 | /** @return the maximum value indexed by the histogram */
53 | int maxVal() {
54 | return stringToInt("zzzz");
55 | }
56 |
57 | /** @return the minimum value indexed by the histogram */
58 | int minVal() {
59 | return stringToInt("");
60 | }
61 |
62 | /** Add a new value to thte histogram */
63 | public void addValue(String s) {
64 | int val = stringToInt(s);
65 | hist.addValue(val);
66 | }
67 |
68 | /**
69 | * Estimate the selectivity (as a double between 0 and 1) of the specified
70 | * predicate over the specified string
71 | *
72 | * @param op
73 | * The operation being applied
74 | * @param s
75 | * The string to apply op to
76 | */
77 | public double estimateSelectivity(Predicate.Op op, String s) {
78 | int val = stringToInt(s);
79 | return hist.estimateSelectivity(op, val);
80 | }
81 |
82 | /**
83 | * @return the average selectivity of this histogram.
84 | *
85 | * This is not an indispensable method to implement the basic join
86 | * optimization. It may be needed if you want to implement a more
87 | * efficient optimization
88 | * */
89 | public double avgSelectivity() {
90 | return hist.avgSelectivity();
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/Transaction.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | import java.io.*;
4 |
5 | /**
6 | * Transaction encapsulates information about the state of
7 | * a transaction and manages transaction commit / abort.
8 | */
9 |
10 | public class Transaction {
11 | private final TransactionId tid;
12 | volatile boolean started = false;
13 |
14 | public Transaction() {
15 | tid = new TransactionId();
16 | }
17 |
18 | /** Start the transaction running */
19 | public void start() {
20 | started = true;
21 | try {
22 | Database.getLogFile().logXactionBegin(tid);
23 | } catch (IOException e) {
24 | e.printStackTrace();
25 | }
26 | }
27 |
28 | public TransactionId getId() {
29 | return tid;
30 | }
31 |
32 | /** Finish the transaction */
33 | public void commit() throws IOException {
34 | transactionComplete(false);
35 | }
36 |
37 | /** Finish the transaction */
38 | public void abort() throws IOException {
39 | transactionComplete(true);
40 | }
41 |
42 | /** Handle the details of transaction commit / abort */
43 | public void transactionComplete(boolean abort) throws IOException {
44 |
45 | if (started) {
46 | //write commit / abort records
47 | if (abort) {
48 | Database.getLogFile().logAbort(tid); //does rollback too
49 | } else {
50 | //write all the dirty pages for this transaction out
51 | Database.getBufferPool().flushPages(tid);
52 | Database.getLogFile().logCommit(tid);
53 | }
54 |
55 | try {
56 | Database.getBufferPool().transactionComplete(tid, !abort); // release locks
57 | } catch (IOException e) {
58 | e.printStackTrace();
59 | }
60 |
61 | //setting this here means we could possibly write multiple abort records -- OK?
62 | started = false;
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/TransactionAbortedException.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | import java.lang.Exception;
4 |
5 | /** Exception that is thrown when a transaction has aborted. */
6 | public class TransactionAbortedException extends Exception {
7 | private static final long serialVersionUID = 1L;
8 |
9 | public TransactionAbortedException() {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/TransactionId.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | import java.io.Serializable;
4 | import java.util.concurrent.atomic.AtomicLong;
5 |
6 | /**
7 | * TransactionId is a class that contains the identifier of a transaction.
8 | */
9 | public class TransactionId implements Serializable {
10 |
11 | private static final long serialVersionUID = 1L;
12 |
13 | static AtomicLong counter = new AtomicLong(0);
14 | final long myid;
15 |
16 | public TransactionId() {
17 | myid = counter.getAndIncrement();
18 | }
19 |
20 | public long getId() {
21 | return myid;
22 | }
23 |
24 | @Override
25 | public boolean equals(Object obj) {
26 | if (this == obj)
27 | return true;
28 | if (obj == null)
29 | return false;
30 | if (getClass() != obj.getClass())
31 | return false;
32 | TransactionId other = (TransactionId) obj;
33 | if (myid != other.myid)
34 | return false;
35 | return true;
36 | }
37 |
38 | @Override
39 | public int hashCode() {
40 | final int prime = 31;
41 | int result = 1;
42 | result = prime * result + (int) (myid ^ (myid >>> 32));
43 | return result;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/simple-db/src/simpledb/TupleIterator.java:
--------------------------------------------------------------------------------
1 | package simpledb;
2 |
3 | import java.util.*;
4 |
5 | /**
6 | * Implements a OpIterator by wrapping an Iterable