This commit is contained in:
2024-04-09 15:06:59 -04:00
parent 4478618a17
commit 8a25672da0
43 changed files with 0 additions and 5772 deletions
-2
View File
@@ -1,2 +0,0 @@
bin/
.DS_Store
-20
View File
@@ -1,20 +0,0 @@
JDKPATH = /usr
LIBPATH = lib/bufmgr.jar:lib/diskmgr.jar:lib/heap.jar:lib/index.jar:lib/junit.jar:lib/org.hamcrest.core_1.3.0.v201303031735.jar
SRCPATH = src/main/java/*/
TESTPATH = src/test/java/*/
CLASSPATH = .:..:$(LIBPATH)
BINPATH = $(JDKPATH)/bin
JAVAC = $(JDKPATH)/bin/javac
JAVA = $(JDKPATH)/bin/java
PROGS = xx
all: $(PROGS)
compile:${SRCPATH}*.java
$(JAVAC) -cp $(CLASSPATH) -d bin ${SRCPATH}*.java ${TESTPATH}*.java
xx : compile
$(JAVA) -cp $(CLASSPATH):bin tests.ROTest
Binary file not shown.
-131
View File
@@ -1,131 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.cs.purdue</groupId>
<artifactId>cs448p3</artifactId>
<version>1.0-SNAPSHOT</version>
<name>cs448p3</name>
<url>https://www.cs.purdue.edu/homes/bb/cs448f19/</url>
<properties>
<java.version>10</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>minibase</groupId>
<artifactId>bufmgr</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/bufmgr.jar</systemPath>
</dependency>
<dependency>
<groupId>minibase</groupId>
<artifactId>diskmgr</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/diskmgr.jar</systemPath>
<type>jar</type>
</dependency>
<dependency>
<groupId>minibase</groupId>
<artifactId>heap</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/heap.jar</systemPath>
</dependency>
<dependency>
<groupId>minibase</groupId>
<artifactId>index</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/index.jar</systemPath>
</dependency>
</dependencies>
<build>
<pluginManagement>
<!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>test.TestDriver</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
File diff suppressed because one or more lines are too long
@@ -1,79 +0,0 @@
package global;
/**
* Enumeration class for predicate operators.
*/
public class AttrOperator {
public static final int EQ = 11;
public static final int NEQ = 12;
public static final int GT = 13;
public static final int GTE = 14;
public static final int LT = 15;
public static final int LTE = 16;
// --------------------------------------------------------------------------
/**
* Private constructor (static class).
*/
private AttrOperator() {}
/**
* Returns the constant value for the string representation (i.e. inverse of
* the toString() method).
*/
public static int toValue(String str) {
// it may have been better to use the parse tree node, but this
// makes it easier to release class projects independently
if (str.equals("=")) {
return EQ;
} else if (str.equals("<>")) {
return NEQ;
} else if (str.equals(">")) {
return GT;
} else if (str.equals(">=")) {
return GTE;
} else if (str.equals("<")) {
return LT;
} else if (str.equals("<=")) {
return LTE;
} else {
throw new IllegalArgumentException("unknown operator");
}
} // public static int toValue(String str)
/**
* Returns a string representation of an AttrOperator.
*/
public static String toString(int value) {
switch (value) {
case EQ:
return "=";
case NEQ:
return "<>";
case GT:
return ">";
case GTE:
return ">=";
case LT:
return "<";
case LTE:
return "<=";
} // switch
return ("Unexpected AttrOperator " + value);
} // public static String toString(int value)
} // public class AttrOperator
@@ -1,98 +0,0 @@
package global;
/**
* Enumeration class for attribute data types.
*/
public class AttrType {
public static final int INTEGER = 11;
public static final int FLOAT = 12;
public static final int STRING = 13;
public static final int COLNAME = 21;
public static final int FIELDNO = 22;
// --------------------------------------------------------------------------
/**
* Private constructor (static class).
*/
private AttrType() {}
/**
* Gets the AttrType of the given value; i.e. not applicable for column names
* or field numbers.
*
* @throws IllegalArgumentException if obj is not an AttrType
*/
public static int getType(Object obj) {
if (obj instanceof Integer) {
return INTEGER;
}
if (obj instanceof Float) {
return FLOAT;
}
if (obj instanceof String) {
return STRING;
}
// otherwise, unknown type
throw new IllegalArgumentException("Unknown AttrType "
+ obj.getClass().getName());
} // public static int getType(Object obj)
/**
* Returns a string representation of an AttrType.
*/
public static String toString(int value) {
switch (value) {
case INTEGER:
return "INTEGER";
case FLOAT:
return "FLOAT";
case STRING:
return "STRING";
case COLNAME:
return "COLNAME";
case FIELDNO:
return "FIELDNO";
} // switch
return ("Unexpected AttrType " + value);
} // public static String toString(int value)
/**
* Returns the AttrType that match the given type (@link String)
* @param type
* @return
*/
public static int fromString(String type) {
switch (type) {
case "INTEGER":
return INTEGER;
case "FLOAT":
return FLOAT;
case "STRING":
default:
return STRING;
}
} // public static int fromString (String type)
} // public class AttrType
@@ -1,122 +0,0 @@
package global;
/**
* Provides conversion routines for getting and setting data in byte arrays.
*/
public class Convert {
/**
* Reads from the given byte array at the specified position, and converts it
* into a unicode character.
*/
public static char getCharValue(int pos, byte[] data) {
// ignoring that UTF-8 could be up to six bytes
return (char) data[pos];
} // public static char getCharValue(int pos, byte[] data)
/**
* Writes a unicode character into the given byte array at the specified
* position.
*/
public static void setCharValue(char value, int pos, byte[] data) {
// ignoring that UTF-8 could be up to six bytes
data[pos] = (byte) value;
} // public static void setCharValue(char value, int pos, byte[] data)
/**
* Reads from the given byte array at the specified position, and converts it
* into a short.
*/
public static short getShortValue(int pos, byte[] data) {
return (short) (((data[pos] & 0xff) << 8) | (data[pos + 1] & 0xff));
} // public static short getShortValue(int pos, byte[] data)
/**
* Writes a short into the given byte array at the specified position.
*/
public static void setShortValue(short value, int pos, byte[] data) {
data[pos] = (byte) ((value >> 8) & 0xff);
data[pos + 1] = (byte) (value & 0xff);
} // public static void setShortValue(short value, int pos, byte[] data)
/**
* Reads from the given byte array at the specified position, and converts it
* into an integer.
*/
public static int getIntValue(int pos, byte[] data) {
return ((data[pos] & 0xff) << 24) | ((data[pos + 1] & 0xff) << 16)
| ((data[pos + 2] & 0xff) << 8) | (data[pos + 3] & 0xff);
} // public static int getIntValue(int pos, byte[] data)
/**
* Writes an integer into the given byte array at the specified position.
*/
public static void setIntValue(int value, int pos, byte[] data) {
data[pos] = (byte) ((value >> 24) & 0xff);
data[pos + 1] = (byte) ((value >> 16) & 0xff);
data[pos + 2] = (byte) ((value >> 8) & 0xff);
data[pos + 3] = (byte) (value & 0xff);
} // public static void setIntValue(int value, int pos, byte[] data)
/**
* Reads from the given byte array at the specified position, and converts it
* to a float.
*/
public static float getFloatValue(int pos, byte[] data) {
// let java do the IEEE 754 conversion
return Float.intBitsToFloat(getIntValue(pos, data));
} // public static float getFloatValue(int pos, byte[] data)
/**
* Writes a float into the given byte array at the specified position.
*/
public static void setFloatValue(float value, int pos, byte[] data) {
// let java do the IEEE 754 conversion
setIntValue(Float.floatToIntBits(value), pos, data);
} // public static void setFloatValue(float value, int pos, byte[] data)
/**
* Reads from the given byte array at the specified position, and converts it
* to a string of given length.
*/
public static String getStringValue(int pos, byte[] data, int length) {
// validate the maximum length
int buflen = data.length - pos;
if (buflen < length) {
length = buflen;
}
// is there any way in Java to avoid these mem copies?
return new String(data, pos, length).trim();
} // public static String getStringValue(int pos, byte[] data, int length)
/**
* Writes a string into the given byte array at the specified position.
*/
public static void setStringValue(String value, int pos, byte[] data) {
// is there any way in Java to avoid these mem copies?
byte[] ba = value.getBytes();
System.arraycopy(ba, 0, data, pos, ba.length);
} // public static void setStringValue(String value, int pos, byte[] data)
} // public class Convert
@@ -1,57 +0,0 @@
package global;
/**
* Global constants; implement this interface to access them conveniently.
*/
public interface GlobalConst {
//
// Disk Manager Constants
//
/** Size of a page, in bytes. */
public static final int PAGE_SIZE = 1024;
/** Page number of an invalid page (i.e. null pointer). */
public static final int INVALID_PAGEID = -1;
/** Page number of the first page in a database file. */
public static final int FIRST_PAGEID = 0;
/** Maximum size of a name (i.e. of files or attributes). */
public static final int NAME_MAXLEN = 50;
//
// Buffer Manager Constants
//
/** Replace the buffer frame with an existing memory page. */
public static final boolean PIN_MEMCPY = true;
/** Replace an existing memory page with the current disk page. */
public static final boolean PIN_DISKIO = false;
/** Forces the page to be written to disk when unpinned. */
public static final boolean UNPIN_DIRTY = true;
/** Optimization to avoid writing to disk when unpinned. */
public static final boolean UNPIN_CLEAN = false;
//
// Heap File Constants
//
/** Length of an "empty" slot in a heap file page. */
public static final int EMPTY_SLOT = -1;
//
// System Catalog Constants
//
/** Maximum length of a column (in bytes). */
public static final int MAX_COLSIZE = 1001;
/** Maximum length of a tuple (in bytes). */
public static final int MAX_TUPSIZE = 1004;
} // public interface GlobalConst
@@ -1,89 +0,0 @@
package global;
import bufmgr.BufMgr;
import diskmgr.DiskMgr;
/**
* Definitions for the running Minibase system, including references to static
* layers and database-level attributes.
*/
public class Minibase {
/** Name of the data file. */
public static String DatabaseName;
/** The Minibase Disk Space Manager. */
public static DiskMgr DiskManager;
/** The Minibase Buffer Manager. */
public static BufMgr BufferManager;
// --------------------------------------------------------------------------
/**
* Constructs and starts an instance of Minibase, given the configuration.
*
* @param dbname Name of the data file
* @param num_pgs Number of pages to allocate
* @param bufpoolsize Buffer pool size (in pages)
* @param replacement_policy Buffer pool replacement policy
* @param exists If the database already exists on disk
*/
public Minibase(String dbname, int num_pgs, int bufpoolsize,
String replacement_policy, boolean exists) {
// simply initialize the database
init(dbname, num_pgs, bufpoolsize, replacement_policy, exists);
} // constructor
/**
* Initializes the current instance of Minibase with the given configuration.
*
* @param dbname Name of the data file
* @param num_pgs Number of pages to allocate
* @param bufpoolsize Buffer pool size (in pages)
* @param replacement_policy Buffer pool replacement policy
* @param exists If the database already exists on disk
*/
public void init(String dbname, int num_pgs, int bufpoolsize,
String replacement_policy, boolean exists) {
// save the file name
DatabaseName = dbname;
// load the static layers
try {
DiskManager = new DiskMgr();
BufferManager = new BufMgr(bufpoolsize);
} catch (Exception exc) {
haltSystem(exc);
}
// create or open the database
try {
if (exists) {
DiskManager.openDB(dbname);
} else {
DiskManager.createDB(dbname, num_pgs);
BufferManager.flushAllPages();
}
} catch (Exception exc) {
haltSystem(exc);
}
} // init
/**
* Displays an unrecoverable error and halts the system.
*/
public static void haltSystem(Exception exc) {
System.err.println("\n*** Unrecoverable system error ***");
exc.printStackTrace();
Runtime.getRuntime().exit(1);
}
} // public class Minibase
@@ -1,133 +0,0 @@
package global;
/**
* Lowest-level view of a disk page.
*/
public class Page implements GlobalConst {
/** The actual byte array for the page. */
protected byte[] data;
// --------------------------------------------------------------------------
/**
* Default constructor; creates a blank page.
*/
public Page() {
data = new byte[PAGE_SIZE];
}
/**
* Constructor that wraps the given byte array.
*/
public Page(byte[] data) {
setData(data);
}
/**
* Get accessor for the data byte array.
*/
public byte[] getData() {
return data;
}
/**
* Set accessor for the data byte array.
*
* @throws IllegalArgumentException if the data array size is invalid
*/
public void setData(byte[] data) {
if (data.length != PAGE_SIZE) {
Minibase.haltSystem(new IllegalArgumentException(
"Invalid page buffer size"));
}
this.data = data;
}
/**
* Sets this page's data array to share the given page's data array.
*/
public void setPage(Page page) {
this.data = page.data;
}
/**
* Copies the contents of the given page's buffer into this page's buffer.
*/
public void copyPage(Page page) {
System.arraycopy(page.data, 0, this.data, 0, PAGE_SIZE);
}
// --------------------------------------------------------------------------
/**
* Gets a char at the given page offset.
*/
public char getCharValue(int offset) {
return Convert.getCharValue(offset, data);
}
/**
* Sets a char at the given page offset.
*/
public void setCharValue(char value, int offset) {
Convert.setCharValue(value, offset, data);
}
/**
* Gets a short at the given page offset.
*/
public short getShortValue(int offset) {
return Convert.getShortValue(offset, data);
}
/**
* Sets a short at the given page offset.
*/
public void setShortValue(short value, int offset) {
Convert.setShortValue(value, offset, data);
}
/**
* Gets an int at the given page offset.
*/
public int getIntValue(int offset) {
return Convert.getIntValue(offset, data);
}
/**
* Sets an int at the given page offset.
*/
public void setIntValue(int value, int offset) {
Convert.setIntValue(value, offset, data);
}
/**
* Gets a float at the given page offset.
*/
public float getFloatValue(int offset) {
return Convert.getFloatValue(offset, data);
}
/**
* Sets a float at the given page offset.
*/
public void setFloatValue(float value, int offset) {
Convert.setFloatValue(value, offset, data);
}
/**
* Gets a string at the given page offset, given the maximum length.
*/
public String getStringValue(int offset, int length) {
return Convert.getStringValue(offset, data, length);
}
/**
* Sets a string at the given page offset.
*/
public void setStringValue(String value, int offset) {
Convert.setStringValue(value, offset, data);
}
} // public class Page implements GlobalConst
@@ -1,60 +0,0 @@
package global;
/**
* Although a PageId is simply an integer, wrapping it provides convenient
* methods and allows returning it via method parameters.
*/
public class PageId implements GlobalConst {
/** The actual page id value. */
public int pid;
// --------------------------------------------------------------------------
/**
* Default constructor.
*/
public PageId() {
pid = INVALID_PAGEID;
}
/**
* Constructs a PageId from the given value.
*/
public PageId(int pid) {
this.pid = pid;
}
/**
* Makes a copy of the given PageId.
*/
public void copyPageId(PageId pageNo) {
this.pid = pageNo.pid;
}
/**
* Returns a hash code value for the PageId.
*/
public int hashCode() {
return pid;
}
/**
* True if obj is a PageId with the same pid; false otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof PageId) {
PageId pageno = (PageId) obj;
return (this.pid == pageno.pid);
}
return false;
}
/**
* Returns a string representation of the PageId.
*/
public String toString() {
return Integer.toString(pid);
}
} // public class PageId implements GlobalConst
@@ -1,98 +0,0 @@
package global;
/**
* A record is uniquely identified by its page number and slot number.
*/
public class RID {
/** The record's page number. */
public PageId pageno;
/** The record's slot number. */
public int slotno;
// --------------------------------------------------------------------------
/**
* Default constructor.
*/
public RID() {
pageno = new PageId();
slotno = 0;
}
/**
* Copy constructor.
*/
public RID(RID rid) {
copyRID(rid);
}
/**
* Constructs an RID from the given values.
*/
public RID(PageId pageno, int slotno) {
this.pageno = new PageId();
this.pageno.pid = pageno.pid;
this.slotno = slotno;
}
/**
* Constructs an RID stored in the given data buffer.
*/
public RID(byte[] data, short offset) {
pageno = new PageId(Convert.getIntValue(offset, data));
slotno = Convert.getIntValue(offset + 4, data);
}
/**
* Writes the RID into the given data buffer.
*/
public void writeData(byte[] data, short offset) {
Convert.setIntValue(pageno.pid, offset, data);
Convert.setIntValue(slotno, offset + 4, data);
}
/**
* Gets the total length of the RID (in bytes).
*/
public short getLength() {
return 8;
}
/**
* Makes a copy of the given RID.
*/
public void copyRID(RID rid) {
this.pageno = new PageId();
this.pageno.pid = rid.pageno.pid;
slotno = rid.slotno;
}
/**
* Returns a hash code value for the RID.
*/
public int hashCode() {
// won't work if DB supports more than 65535 pages
return ((pageno.pid & 0xFFFF) << 16) | (slotno & 0xFFFF);
}
/**
* True if obj is an RID with the same values; false otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof RID) {
RID rid = (RID) obj;
return ((pageno.pid == rid.pageno.pid) && (slotno == rid.slotno));
}
return false;
}
/**
* Returns a string representation of the PageId.
*/
public String toString() {
return pageno.toString() + ":" + Integer.toString(slotno);
}
} // public class RID
@@ -1,291 +0,0 @@
package global;
/**
* Provides a general and type-safe way to store and compare index search keys.
*/
public class SearchKey implements Comparable<SearchKey> {
/** Internal type number for Integer keys. */
protected static final byte INTEGER_KEY = 1;
/** Internal type number for Float keys. */
protected static final byte FLOAT_KEY = 2;
/** Internal type number for String keys. */
protected static final byte STRING_KEY = 3;
// --------------------------------------------------------------------------
/** The type of the key value. */
protected byte type;
/** The size of the key value (in bytes). */
protected short size;
/** The actual key value. */
protected Object value;
// --------------------------------------------------------------------------
/**
* Constructs a new integer search key.
*/
public SearchKey(Integer value) {
this.type = INTEGER_KEY;
this.size = Integer.SIZE / Byte.SIZE;
this.value = value;
}
/**
* Constructs a new float search key.
*/
public SearchKey(Float value) {
this.type = FLOAT_KEY;
this.size = Float.SIZE / Byte.SIZE;
this.value = value;
}
/**
* Constructs a new string search key.
*/
public SearchKey(String value) {
this.type = STRING_KEY;
this.size = (short) value.length();
this.value = value;
}
/**
* Constructs a search key from a generic value.
*
* @throws IllegalArgumentException if value's type is invalid
*/
public SearchKey(Object value) {
// Integer key?
if (value instanceof Integer) {
this.type = INTEGER_KEY;
this.size = Integer.SIZE / Byte.SIZE;
this.value = value;
}
// Float key?
else if (value instanceof Float) {
this.type = FLOAT_KEY;
this.size = Float.SIZE / Byte.SIZE;
this.value = value;
}
// String key?
else if (value instanceof String) {
this.type = STRING_KEY;
this.size = (short) ((String) value).length();
this.value = value;
}
// otherwise, none of the above
else {
throw new IllegalArgumentException("invalid key value type");
}
} // public SearchKey(Object value)
/**
* Copy constructor for a search key.
*/
public SearchKey(SearchKey key) {
// copy the type and size
this.type = key.type;
this.size = key.size;
// copy the value
switch (key.type) {
case INTEGER_KEY:
this.value = new Integer((Integer) key.value);
break;
case FLOAT_KEY:
this.value = new Float((Float) key.value);
break;
case STRING_KEY:
this.value = new String((String) key.value);
break;
}
} // public SearchKey(SearchKey key)
// --------------------------------------------------------------------------
/**
* Constructs a SearchKey stored in the given data buffer.
*/
public SearchKey(byte[] data, short offset) {
// extract the type and size
type = data[offset];
size = Convert.getShortValue(offset + 1, data);
// extract the key value
switch (type) {
case INTEGER_KEY:
value = new Integer(Convert.getIntValue(offset + 3, data));
break;
case FLOAT_KEY:
value = new Float(Convert.getFloatValue(offset + 3, data));
break;
case STRING_KEY:
value = Convert.getStringValue(offset + 3, data, size);
break;
}
} // public SearchKey(byte[] data, short offset)
/**
* Writes the SearchKey into the given data buffer.
*/
public void writeData(byte[] data, short offset) {
// write the type and size
data[offset] = type;
Convert.setShortValue(size, offset + 1, data);
// write the key value
switch (type) {
case INTEGER_KEY:
Convert.setIntValue((Integer) value, offset + 3, data);
break;
case FLOAT_KEY:
Convert.setFloatValue((Float) value, offset + 3, data);
break;
case STRING_KEY:
Convert.setStringValue((String) value, offset + 3, data);
break;
}
} // public void writeData(byte[] data, short offset)
/**
* Gets the total length of the search key (in bytes).
*/
public short getLength() {
return (short) (3 + size);
}
// --------------------------------------------------------------------------
/**
* Gets the hash value for the search key, given the depth (i.e. number of
* bits to consider).
*/
public int getHash(int depth) {
// apply the appropriate calculation
int mask = (1 << depth) - 1;
switch (type) {
default:
case INTEGER_KEY:
int ikey = ((Integer) value).intValue();
return ikey & mask;
case FLOAT_KEY:
int fkey = Float.floatToIntBits((Float) value);
return fkey & mask;
case STRING_KEY:
// reverse the first four bytes of the string
byte[] s = ((String) value).getBytes();
int skey = 0;
int len = s.length > 4 ? 4 : s.length;
for (int i = 0; i < len; i++) {
skey |= (s[i] << (i * Byte.SIZE));
}
return skey & mask;
} // switch
} // public int getHash(int depth)
/**
* Returns true if the search key matches the given hash value, false
* otherwise.
*/
public boolean isHash(int hash) {
// calculate the bit depth (i.e. the left-most '1' bit)
int depth = (int) (Math.log(hash) / Math.log(2) + 1);
// compare the hash codes
return (getHash(depth) == hash);
} // public boolean isHash(int hash)
// --------------------------------------------------------------------------
/**
* Returns a generic hash code for the key value.
*/
public int hashCode() {
return value.hashCode();
}
/**
* True if obj is a SearchKey with the same values; false otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof SearchKey) {
SearchKey key = (SearchKey) obj;
return (value.equals(key.value));
}
return false;
}
/**
* Generically compares two search keys.
*
* @return a negative integer, zero, or a positive integer as this object is
* less than, equal to, or greater than the specified object
* @throws IllegalArgumentException if the search keys are not comparable
*/
public int compareTo(SearchKey key) {
// Integer comparison
if (value instanceof Integer) {
if (key.value instanceof Integer) {
Integer ikey1 = (Integer) this.value;
Integer ikey2 = (Integer) key.value;
return ikey1.compareTo(ikey2);
} else {
throw new IllegalArgumentException("search keys are not comparable");
}
}
// Float comparison
if (value instanceof Float) {
if (key.value instanceof Float) {
Float fkey1 = (Float) this.value;
Float fkey2 = (Float) key.value;
return fkey1.compareTo(fkey2);
} else {
throw new IllegalArgumentException("search keys are not comparable");
}
}
// default: String comparison
if (key.value instanceof String) {
String skey1 = (String) this.value;
String skey2 = (String) key.value;
return skey1.compareTo(skey2);
} else {
throw new IllegalArgumentException("search keys are not comparable");
}
} // public int compareTo(SearchKey key)
} // public class SearchKey implements Comparable<SearchKey>
@@ -1,23 +0,0 @@
package global;
/**
* One term in an ORDER BY clause; i.e. relations can be sorted on multiple
* (distinct) attributes, as well as in ascending or descending order.
*/
public class SortKey {
/** Column name or field number. */
public Object field;
/** True if descending order, false if ascending order. */
public boolean isDesc;
/**
* Constructs a SortKey from the given values.
*/
public SortKey(Object field, boolean isDesc) {
this.field = field;
this.isDesc = isDesc;
}
} // public class SortKey
@@ -1,92 +0,0 @@
package relop;
import global.RID;
import heap.HeapFile;
import heap.HeapScan;
/**
* Wrapper for heap file scan, the most basic access method. This "iterator"
* version takes schema into consideration and generates real tuples.
*/
public class FileScan extends Iterator {
private HeapFile file = null; // needed for restart(), getFile();
private HeapScan scan = null;
private RID rid = null;
private boolean isOpen;
/**
* Constructs a file scan, given the schema and heap file.
*/
public FileScan(Schema aSchema, HeapFile aFile) {
this.schema = aSchema;
this.file = aFile;
this.scan = file.openScan();
this.rid = new RID();
isOpen = true;
}
/**
* Gives a one-line explanation of the iterator, repeats the call on any
* child iterators, and increases the indent depth along the way.
*/
public void explain(int depth) {
for(int i = 0; i < depth; i++){
System.out.printf(" ");
}
System.out.printf("FileScan\n");
}
/**
* Restarts the iterator, i.e. as if it were just constructed.
*/
public void restart() {
scan.close();
scan = file.openScan();
//rid = new RID();
}
/**
* Returns true if the iterator is open; false otherwise.
*/
public boolean isOpen() {
return isOpen;
}
/**
* Closes the iterator, releasing any resources (i.e. pinned pages).
*/
public void close() {
scan.close();
isOpen = false;
}
/**
* Returns true if there are more tuples, false otherwise.
*/
public boolean hasNext() {
return scan.hasNext();
}
/**
* Gets the next tuple in the iteration.
*
* @throws IllegalStateException if no more tuples
*/
public Tuple getNext() {
return new Tuple(schema, scan.getNext(rid));
}
/**
* Gets the RID of the last tuple returned.
*/
public RID getLastRID() {
return rid;
}
// getter; added so HashJoin doesn't have to copy the file;
public HeapFile getFile(){
return file;
}
} // public class FileScan extends Iterator
@@ -1,52 +0,0 @@
package relop;
import heap.HeapFile;
import index.HashIndex;
import global.SearchKey;
import global.RID;
import global.AttrOperator;
import global.AttrType;
public class HashJoin extends Iterator {
public HashJoin(Iterator aIter1, Iterator aIter2, int aJoinCol1, int aJoinCol2){
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
@Override
public void explain(int depth) {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
@Override
public void restart() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
@Override
public boolean isOpen() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
@Override
public void close() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
@Override
public boolean hasNext() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
@Override
public Tuple getNext() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
} // end class HashJoin;
@@ -1,83 +0,0 @@
package relop;
import global.SearchKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
/**
* A extension to Java's hash table that allows duplicate keys.
* http://mindprod.com/jgloss/hashtable.html
*/
@SuppressWarnings("unchecked")
class HashTableDup extends Hashtable {
/**
* Maps the specified key to the specified value in this hashtable.
*/
public void add(SearchKey key, Tuple value) {
// to conserve RAM, duplicate values are either stored as single objects,
// pairs in an array, or multiples in an ArrayList
Object existing = get(key);
if (existing == null) {
// store the single value
put(key, value);
} else if (existing instanceof Tuple) {
// was a single object; make into a pair
put(key, new Tuple[] { (Tuple) existing, value });
} else if (existing instanceof Tuple[]) {
// was a pair; make into an ArrayList of 3
ArrayList<Tuple> a = new ArrayList<Tuple>();
a.addAll(Arrays.asList((Tuple[]) existing));
a.add(value);
put(key, a);
} else {
// just add to tail end of existing ArrayList
((ArrayList<Tuple>) existing).add(value);
} // else
} // public void add(SearchKey key, Tuple value)
/**
* Returns the values to which the specified key is mapped in this hashtable.
*/
public Tuple[] getAll(SearchKey key) {
// look up the key
Object match = get(key);
if (match == null) {
// not found
return null;
} else if (match instanceof Tuple) {
// return the single match
return new Tuple[] { (Tuple) match };
} else if (match instanceof Tuple[]) {
// return the matches
return (Tuple[]) match;
} else {
// convert ArrayList to Tuple[]
ArrayList<Tuple> a = (ArrayList<Tuple>) match;
return a.toArray(new Tuple[a.size()]);
} // elsee
} // public Tuple[] getAll(SearchKey key)
} // class HashTableDup extends Hashtable
@@ -1,89 +0,0 @@
package relop;
import global.SearchKey;
import heap.HeapFile;
import index.HashIndex;
/**
* Wrapper for bucket scan, an index access method.
*/
public class IndexScan extends Iterator {
/**
* Constructs an index scan, given the hash index and schema.
*/
public IndexScan(Schema schema, HashIndex index, HeapFile file) {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Gives a one-line explaination of the iterator, repeats the call on any
* child iterators, and increases the indent depth along the way.
*/
public void explain(int depth) {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Restarts the iterator, i.e. as if it were just constructed.
*/
public void restart() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Returns true if the iterator is open; false otherwise.
*/
public boolean isOpen() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Closes the iterator, releasing any resources (i.e. pinned pages).
*/
public void close() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Returns true if there are more tuples, false otherwise.
*/
public boolean hasNext() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Gets the next tuple in the iteration.
*
* @throws IllegalStateException if no more tuples
*/
public Tuple getNext() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Gets the key of the last tuple returned.
*/
public SearchKey getLastKey() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Returns the hash value for the bucket containing the next tuple, or maximum
* number of buckets if none.
*/
public int getNextHash() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
} // public class IndexScan extends Iterator
@@ -1,107 +0,0 @@
package relop;
/**
* Minibase Iterators
* Query execution is driven by a tree of relational operators, all of which are
* implemented as iterators. Results are requested by successive "get next
* tuple" calls on the root of the tree, which in turn makes similar calls to
* child iterators throughout the tree. Intermediate nodes (i.e. join iterators)
* drive the leaf-level nodes (i.e. file or index scan iterators).
*/
public abstract class Iterator {
/** Schema for resulting tuples; must be set in all subclass constructors. */
protected Schema schema;
// --------------------------------------------------------------------------
/**
* Gives a one-line explanation of the iterator, repeats the call on any
* child iterators, and increases the indent depth along the way.
*/
public abstract void explain(int depth);
/**
* Outputs the indentation for the given depth.
*/
protected void indent(int depth) {
for (int i = 0; i < depth * 2; i++) {
System.out.print(' ');
}
}
/**
* Restarts the iterator, i.e. as if it were just constructed.
*/
public abstract void restart();
/**
* Returns true if the iterator is open; false otherwise.
*/
public abstract boolean isOpen();
/**
* Closes the iterator, releasing any resources (i.e. pinned pages).
*/
public abstract void close();
/**
* Returns true if there are more tuples, false otherwise.
*/
public abstract boolean hasNext();
/**
* Gets the next tuple in the iteration.
*
* @throws IllegalStateException if no more tuples
*/
public abstract Tuple getNext();
/**
* Prints the schema, gets and prints all tuples, and closes the iterator.
*
* @return number of tuples processed
*/
public int execute() {
result = ""; //Modification to store result of queries for test case comparison
int cnt = 0;
getSchema().print();
Tuple next;
while (hasNext()) {
next = getNext();
next.print();
//Modification to store result of queries for test case comparison
result += next.toString() + "|";
cnt++;
}
if(result.length() > 0)
result = result.substring(0, result.length() - 1);
close();
return cnt;
}
/**
* Called by the garbage collector when there are no more references to the
* object; closes the iterator if it's still open.
*/
protected void finalize() throws Throwable {
if (isOpen()) {
close();
}
}
public void setSchema(Schema schema) {
this.schema = schema;
}
public Schema getSchema() {
return schema;
}
// *** DO NOT CHANGE ANY EXISTING METHODS OR VARIABLES BELOW THIS LINE ***
//Store values for test cases only
//String format: row0|row1|row2|...rowN|
private String result;
public String getResult() { return result; }
} // public abstract class Iterator
@@ -1,72 +0,0 @@
package relop;
import global.SearchKey;
import heap.HeapFile;
import index.HashIndex;
import index.HashScan;
/**
* Wrapper for hash scan, an index access method.
*/
public class KeyScan extends Iterator {
/**
* Constructs an index scan, given the hash index and schema.
*/
public KeyScan(Schema aSchema, HashIndex aIndex, SearchKey aKey, HeapFile aFile) {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Gives a one-line explanation of the iterator, repeats the call on any
* child iterators, and increases the indent depth along the way.
*/
public void explain(int depth) {
throw new UnsupportedOperationException("Not implemented");
}
/**
* Restarts the iterator, i.e. as if it were just constructed.
*/
public void restart() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Returns true if the iterator is open; false otherwise.
*/
public boolean isOpen() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Closes the iterator, releasing any resources (i.e. pinned pages).
*/
public void close() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Returns true if there are more tuples, false otherwise.
*/
public boolean hasNext() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Gets the next tuple in the iteration.
*
* @throws IllegalStateException if no more tuples
*/
public Tuple getNext() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
} // public class KeyScan extends Iterator
@@ -1,188 +0,0 @@
package relop;
import global.AttrOperator;
import global.AttrType;
/**
* Internal representation of simple SQL expressions. Operators are referenced
* by constants in global.AttrOperator, and operands can be constants or field
* numbers (i.e. if referring to an attribute).
*/
public class Predicate {
/** The operator. */
protected int oper;
/** Type of left operand. */
protected int ltype;
/** Left operand. */
protected Object left;
/** Type of right operand. */
protected int rtype;
/** Right operand. */
protected Object right;
// --------------------------------------------------------------------------
/**
* Constructs a predicate, given the expression.
*
* @param oper AttrOperator constant
* @param ltype AttrType of the field
* @param left operand value, field number, or column name
* @param rtype AttrType of the field
* @param right operand value, field number, or column name
*/
public Predicate(int oper, int ltype, Object left, int rtype, Object right) {
this.oper = oper;
this.ltype = ltype;
this.rtype = rtype;
this.left = left;
this.right = right;
}
/**
* Validates AttrType.COLNAME operands against the given schema.
*
* @return true if the predicate is valid, false otherwise
*/
public boolean validate(Schema schema) {
// if column name, make sure it exists
int type1 = ltype;
if (type1 == AttrType.COLNAME) {
int fldno = schema.fieldNumber((String) left);
if (fldno < 0) {
return false;
}
type1 = schema.fieldType(fldno);
}
int type2 = rtype;
if (type2 == AttrType.COLNAME) {
int fldno = schema.fieldNumber((String) right);
if (fldno < 0) {
return false;
}
type2 = schema.fieldType(fldno);
}
// test left and right type compatibility
return (type1 == type2);
} // public boolean validate(Schema schema)
/**
* Evaluates the predicate on the given tuple and returns true if it passes.
*
* @throws IllegalStateException if member data lead to an invalid operation
*/
public boolean evaluate(Tuple tuple) {
// if necessary, resolve column names to field numbers
if (ltype == AttrType.COLNAME) {
left = tuple.schema.fieldNumber((String) left);
ltype = AttrType.FIELDNO;
}
if (rtype == AttrType.COLNAME) {
right = tuple.schema.fieldNumber((String) right);
rtype = AttrType.FIELDNO;
}
// get the values to compare
int type = ltype;
Object lval = left;
if (ltype == AttrType.FIELDNO) {
type = tuple.schema.fieldType((Integer) lval);
lval = tuple.getField((Integer) lval);
}
Object rval = right;
if (rtype == AttrType.FIELDNO) {
rval = tuple.getField((Integer) rval);
}
// compare the values
int comp = 0;
switch (type) {
case AttrType.INTEGER:
comp = ((Integer) lval).compareTo((Integer) rval);
break;
case AttrType.FLOAT:
comp = ((Float) lval).compareTo((Float) rval);
break;
case AttrType.STRING:
comp = ((String) lval).compareTo((String) rval);
break;
default:
throw new IllegalStateException("unknown types to compare");
} // switch (type)
// evaluate the operator
switch (oper) {
case AttrOperator.EQ:
return (comp == 0);
case AttrOperator.NEQ:
return (comp != 0);
case AttrOperator.GT:
return (comp > 0);
case AttrOperator.GTE:
return (comp >= 0);
case AttrOperator.LT:
return (comp < 0);
case AttrOperator.LTE:
return (comp <= 0);
default:
throw new IllegalStateException("unknown operator to evaluate");
} // switch (oper)
} // public boolean evaluate(Tuple tuple)
/**
* Returns a string representation of the Predicate.
*/
public String toString() {
return opString(ltype, left) + ' ' + AttrOperator.toString(oper) + ' '
+ opString(rtype, right);
} // public String toString()
/**
* Returns a string representation of an operand.
*/
protected String opString(int type, Object operand) {
// get the string version
String str = operand.toString();
// wrap strings in single quotes
if (type == AttrType.STRING) {
return "'" + str + "'";
}
// wrap column numbers in braces
if (type == AttrType.FIELDNO) {
return "{" + str + "}";
}
// otherwise, just return the string
return str;
} // protected String opString(int type, Object obj)
} // public class Predicate
@@ -1,79 +0,0 @@
package relop;
/**
* The projection operator extracts columns from a relation; unlike in
* relational algebra, this operator does NOT eliminate duplicate tuples.
*/
public class Projection extends Iterator {
private Iterator iter = null;
private Integer[] fields = null;
private boolean isOpen;
/**
* Constructs a projection, given the underlying iterator and field numbers.
*/
public Projection(Iterator aIter, Integer... aFields) {
this.iter = aIter;
this.fields = aFields;
this.isOpen = true;
this.schema = new Schema(fields.length);
Schema iterSchema = iter.getSchema();
for(int i = 0; i < fields.length; i++){
this.schema.initField(i, iterSchema, fields[i]);
}
}
/**
* Gives a one-line explanation of the iterator, repeats the call on any
* child iterators, and increases the indent depth along the way.
*/
public void explain(int depth) {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Restarts the iterator, i.e. as if it were just constructed.
*/
public void restart() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Returns true if the iterator is open; false otherwise.
*/
public boolean isOpen() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Closes the iterator, releasing any resources (i.e. pinned pages).
*/
public void close() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Returns true if there are more tuples, false otherwise.
*/
public boolean hasNext() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Gets the next tuple in the iteration.
*
* @throws IllegalStateException if no more tuples
*/
public Tuple getNext() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
} // public class Projection extends Iterator
@@ -1,195 +0,0 @@
package relop;
import global.AttrType;
/**
* Each tuple has a schema that defines the logical view of the raw bytes; it
* describes the types, lengths, offsets, and names of a tuple's fields.
*/
public class Schema {
/** Minimum column width for output. */
public static final int MIN_WIDTH = 10;
// --------------------------------------------------------------------------
/** Attribute types of the fields. */
protected int[] types;
/** Variable lengths of the fields. */
protected int[] lengths;
/** Relative offsets of the fields. */
protected int[] offsets;
/** Column names of the fields. */
protected String[] names;
// --------------------------------------------------------------------------
/**
* Constructs a schema for the given number of fields.
*/
public Schema(int fldcnt) {
types = new int[fldcnt];
lengths = new int[fldcnt];
offsets = new int[fldcnt];
names = new String[fldcnt];
}
/**
* Sets the type, length, and name for the given field; this automatically
* calculates its offset, provided that fields are set in ascending order.
*/
public void initField(int fldno, int type, int length, String name) {
// save the type, length, and name
types[fldno] = type;
lengths[fldno] = length;
names[fldno] = name;
// calculate the relative offset
if (fldno > 0) {
offsets[fldno] = offsets[fldno - 1] + lengths[fldno - 1];
} else {
offsets[fldno] = 0;
}
} // public void initField(int fldno, int type, int length, String name)
/**
* Copies a field from another schema.
*
* @param fldno number of this field to set
* @param schema contains the info to copy
* @param srcno number of the field to copy
*/
public void initField(int fldno, Schema schema, int srcno) {
initField(fldno, schema.types[srcno], schema.lengths[srcno],
schema.names[srcno]);
}
/**
* Builds and returns a new schema resulting from joining two schemas.
*
* @param s1 the left schema
* @param s2 the right schema
*/
public static Schema join(Schema s1, Schema s2) {
// construct the new schema
int s1cnt = s1.getCount();
int s2cnt = s2.getCount();
Schema schema = new Schema(s1cnt + s2cnt);
// copy all fields from s1 and s2
int fldno = 0;
for (int i = 0; i < s1cnt; i++) {
schema.initField(fldno++, s1, i);
}
for (int i = 0; i < s2cnt; i++) {
schema.initField(fldno++, s2, i);
}
// return the resulting schema
return schema;
} // public static Schema join(Schema s1, Schema s2)
// --------------------------------------------------------------------------
/**
* Gets the number of fields in the schema.
*/
public int getCount() {
// all arrays are same length
return types.length;
}
/**
* Gets the size of a tuple (in bytes).
*/
public int getLength() {
int len = 0;
for (int i = 0; i < lengths.length; i++) {
len += lengths[i];
}
return len;
}
/**
* Gets the type of the given field.
*/
public int fieldType(int fldno) {
return types[fldno];
}
/**
* Gets the length of the given field.
*/
public int fieldLength(int fldno) {
return lengths[fldno];
}
/**
* Gets the offset of the given field.
*/
public int fieldOffset(int fldno) {
return offsets[fldno];
}
/**
* Gets the name of the given field.
*/
public String fieldName(int fldno) {
return names[fldno];
}
/**
* Gets the number of the field with the given name, or -1 if not found.
*/
public int fieldNumber(String name) {
for (int i = 0; i < names.length; i++) {
if (names[i].equalsIgnoreCase(name)) {
return i;
}
}
return -1;
}
/**
* Prints the schema (i.e. the first lines of typical query output).
*/
public void print() {
// print and space the column names
int len = 0;
for (int i = 0; i < types.length; i++) {
// print the column name
System.out.print(names[i]);
// figure out the padding
int collen = Math.max(names[i].length(), MIN_WIDTH);
if (types[i] == AttrType.STRING) {
collen = Math.max(lengths[i], collen);
}
len += collen;
// pad the output to the field length
for (int j = 0; j < collen - names[i].length(); j++) {
System.out.print(' ');
}
} // for
// print the line separator
System.out.println();
for (int i = 0; i < len; i++) {
System.out.print('-');
}
System.out.println();
} // public void print()
} // public class Schema
@@ -1,78 +0,0 @@
package relop;
/**
* The selection operator specifies which tuples to retain under a condition; in
* Minibase, this condition is simply a set of independent predicates logically
* connected by OR operators.
*/
public class Selection extends Iterator {
private Iterator iter = null;
private Predicate[] preds = null;
//boolean hasNext;
Tuple next = null;
private boolean consumed;
private boolean isOpen;
/**
* Constructs a selection, given the underlying iterator and predicates.
*/
public Selection(Iterator aIter, Predicate... aPreds) {
this.schema = aIter.getSchema();
this.iter = aIter;
this.preds = aPreds;
this.consumed = true;
this.isOpen = true;
}
/**
* Gives a one-line explanation of the iterator, repeats the call on any
* child iterators, and increases the indent depth along the way.
*/
public void explain(int depth) {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Restarts the iterator, i.e. as if it were just constructed.
*/
public void restart() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Returns true if the iterator is open; false otherwise.
*/
public boolean isOpen() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Closes the iterator, releasing any resources (i.e. pinned pages).
*/
public void close() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Returns true if there are more tuples, false otherwise.
*/
public boolean hasNext() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
/**
* Gets the next tuple in the iteration.
*
* @throws IllegalStateException if no more tuples
*/
public Tuple getNext() {
throw new UnsupportedOperationException("Not implemented");
//Your code here
}
} // public class Selection extends Iterator
@@ -1,126 +0,0 @@
package relop;
/**
* The simplest of all join algorithms: nested loops (see textbook, 3rd edition,
* section 14.4.1, page 454).
*/
public class SimpleJoin extends Iterator {
private Iterator outer;
private Iterator inner;
private Predicate[] preds;
private boolean startJoin = true;
Tuple leftTuple;
// boolean variable to indicate whether the pre-fetched tuple is consumed or not
private boolean nextTupleIsConsumed;
// pre-fetched tuple
private Tuple nextTuple;
/**
* Constructs a join, given the left and right iterators and join predicates
* (relative to the combined schema).
*/
public SimpleJoin(Iterator left, Iterator right, Predicate... preds) {
this.outer = left;
this.inner = right;
this.preds = preds;
this.schema = Schema.join(left.schema, right.schema);
nextTupleIsConsumed = true;
}
/**
* Gives a one-line explanation of the iterator, repeats the call on any
* child iterators, and increases the indent depth along the way.
*/
public void explain(int depth) {
throw new UnsupportedOperationException("Not implemented");
}
/**
* Restarts the iterator, i.e. as if it were just constructed.
*/
public void restart() {
outer.restart();
inner.restart();
nextTupleIsConsumed = true;
}
/**
* Returns true if the iterator is open; false otherwise.
*/
public boolean isOpen() {
return outer.isOpen() && inner.isOpen();
}
/**
* Closes the iterator, releasing any resources (i.e. pinned pages).
*/
public void close() {
outer.close();
inner.close();
}
/**
* Returns true if there are more tuples, false otherwise.
*
*/
public boolean hasNext() {
if (!nextTupleIsConsumed)
return true;
if (!outer.hasNext())
//if(!inner.hasNext() && !outer.hasNext()) // Piazza post 116
return false;
Tuple rightTuple;
if (startJoin) {
leftTuple = outer.getNext();
startJoin = false;
}
while (true) {
while (inner.hasNext()) {
rightTuple = inner.getNext();
// try to match
nextTuple = Tuple.join(leftTuple, rightTuple, this.schema);
for (int i = 0; i < preds.length; i++)
if (preds[i].evaluate(nextTuple)) {
nextTupleIsConsumed = false;
return true;
}
}
if (outer.hasNext()) {
leftTuple = outer.getNext();
inner.restart();
}
else
return false;
}
}
/**
* Gets the next tuple in the iteration.
*
* @throws IllegalStateException if no more tuples
*/
public Tuple getNext() {
nextTupleIsConsumed = true;
return nextTuple;
}
}
@@ -1,315 +0,0 @@
package relop;
import global.AttrType;
import global.Convert;
import global.RID;
import heap.HeapFile;
/**
* Each tuple in a relation is a collection of bytes that must fit within a
* single page. The Tuple class provides a logical view of fields, allowing get
* and set operations while automatically handling offsets and type conversions.
*/
public class Tuple {
/** Page buffer containing this tuple. */
protected byte[] data;
/** Schema information for the fields. */
protected Schema schema;
// --------------------------------------------------------------------------
/**
* Creates a new empty tuple, given its schema.
*
* @param schema logical information for the fields
*/
public Tuple(Schema schema) {
this.schema = schema;
data = new byte[schema.getLength()];
}
/**
* Creates a new tuple, given its schema and values.
*
* @param schema logical information for the fields
* @param values individual data values of the fields
*/
public Tuple(Schema schema, Object... values) {
this.schema = schema;
data = new byte[schema.getLength()];
setAllFields(values);
}
/**
* Creates a new tuple, given existing values to wrap.
*
* @param schema logical information for the fields
* @param data record buffer containing the tuple
*/
public Tuple(Schema schema, byte[] data) {
this.schema = schema;
this.data = data;
}
/**
* Builds and returns a new tuple resulting from joining two tuples.
*
* @param t1 the left tuple
* @param t2 the right tuple
* @param schema of the result
*/
public static Tuple join(Tuple t1, Tuple t2, Schema schema) {
// construct the new tuple
int t1cnt = t1.schema.getCount();
int t2cnt = t2.schema.getCount();
Tuple tuple = new Tuple(schema);
// copy all fields from t1 and t2
int fldno = 0;
for (int i = 0; i < t1cnt; i++) {
tuple.setField(fldno++, t1.getField(i));
}
for (int i = 0; i < t2cnt; i++) {
tuple.setField(fldno++, t2.getField(i));
}
// return the resulting tuple
return tuple;
} // public static Tuple join(Tuple t1, Tuple t2, Schema schema)
/**
* Gets the underlying data buffer.
*/
public byte[] getData() {
return data;
}
/**
* Inserts the tuple into the given heap file.
*/
public RID insertIntoFile(HeapFile file) {
return file.insertRecord(data);
}
/**
* Gets a field's value generically.
*/
public Object getField(int fldno) {
// refer to the schema for the appropriate conversion
switch (schema.fieldType(fldno)) {
case AttrType.INTEGER:
return getIntFld(fldno);
case AttrType.FLOAT:
return getFloatFld(fldno);
case AttrType.STRING:
return getStringFld(fldno);
default:
throw new IllegalStateException("invalid attribute type");
}
} // public Object getField(int fldno)
/**
* Gets a field's value generically, by column name.
*/
public Object getField(String fldName) {
return getField(schema.fieldNumber(fldName));
}
/**
* Sets a field's value generically.
*/
public void setField(int fldno, Object val) {
// refer to the schema for the appropriate conversion
switch (schema.fieldType(fldno)) {
case AttrType.INTEGER:
setIntFld(fldno, (Integer) val);
break;
case AttrType.FLOAT:
setFloatFld(fldno, (Float) val);
break;
case AttrType.STRING:
setStringFld(fldno, (String) val);
break;
default:
throw new IllegalStateException("invalid attribute type");
}
} // public void setField(int fldno, Object val)
/**
* Sets a field's value generically, by column name.
*/
public void setField(String fldName, Object val) {
setField(schema.fieldNumber(fldName), val);
}
/**
* Returns generic values for all fields.
*/
public Object[] getAllFields() {
Object[] values = new Object[schema.getCount()];
for (int i = 0; i < values.length; i++) {
values[i] = getField(i);
}
return values;
} // public Object[] getAllFields()
/**
* Sets all fields, given generic values.
*/
public void setAllFields(Object... values) {
for (int i = 0; i < values.length; i++) {
setField(i, values[i]);
}
} // public void setAllFields(Object... values)
/**
* Gets an integer field.
*/
public int getIntFld(int fldno) {
return Convert.getIntValue(schema.fieldOffset(fldno), data);
}
/**
* Sets an integer field.
*/
public void setIntFld(int fldno, int val) {
Convert.setIntValue(val, schema.fieldOffset(fldno), data);
}
/**
* Gets a float field.
*/
public float getFloatFld(int fldno) {
return Convert.getFloatValue(schema.fieldOffset(fldno), data);
}
/**
* Sets a float field.
*/
public void setFloatFld(int fldno, float val) {
Convert.setFloatValue(val, schema.fieldOffset(fldno), data);
}
/**
* Gets a string field.
*/
public String getStringFld(int fldno) {
return Convert.getStringValue(schema.fieldOffset(fldno), data, schema
.fieldLength(fldno));
}
/**
* Sets a string field (automatically truncates, if necessary).
*/
public void setStringFld(int fldno, String val) {
// truncate the string if too long
int len = schema.fieldLength(fldno);
if (val.length() > len) {
val = val.substring(0, len - 1);
}
// set the string and zero out the rest
int off = schema.fieldOffset(fldno);
Convert.setStringValue(val, off, data);
for (int i = val.length(); i < len; i++) {
data[off + i] = 0;
}
} // public void setStringFld(int fldno, String val)
/**
* Prints the tuple in a human-readable format.
*/
public void print() {
// print everything as a string, with padding
String str = null;
int cnt = schema.getCount();
for (int i = 0; i < cnt; i++) {
switch (schema.fieldType(i)) {
case AttrType.INTEGER:
str = Integer.toString(getIntFld(i));
System.out.print(str);
padOutput(0, str.length());
break;
case AttrType.FLOAT:
str = Float.toString(getFloatFld(i));
System.out.print(str);
padOutput(0, str.length());
break;
case AttrType.STRING:
str = getStringFld(i);
System.out.print(str);
padOutput(schema.fieldLength(i), str.length());
break;
}
}
System.out.println();
} // public void print()
/**
* Pads the current output to make columns line up.
*
* @param fieldLen minimum length of the current field
* @param outputLen length of the current output so far
*/
protected void padOutput(int fieldLen, int outputLen) {
fieldLen = Math.max(Schema.MIN_WIDTH, fieldLen);
for (int j = 0; j < fieldLen - outputLen; j++) {
System.out.print(' ');
}
} // protected void padOutput(int fieldLen, int outputLen)
// *** DO NOT CHANGE ANY EXISTING METHODS OR VARIABLES BELOW THIS LINE ***
//String format: field0|field1|field2|...fieldN|
public String toString()
{
String res = "";
for(int i = 0; i < schema.getCount(); i++)
{
switch(schema.fieldType(i))
{
case AttrType.FLOAT:
res += Float.toString(getFloatFld(i)) + "";
break;
case AttrType.INTEGER:
res += Integer.toString(getIntFld(i)) + ":";
break;
case AttrType.STRING:
res += getStringFld(i) + ":";
break;
}
}
if(res.length() > 0) res = res.substring(0, res.length()-1);
return res;
}
} // public class Tuple
@@ -1,51 +0,0 @@
package tests;
import global.AttrType;
import org.json.simple.JSONObject;
public class Field {
private int no;
private int type;
private int length;
private String name;
Field(JSONObject obj) {
no = ((Long) obj.get("no")).intValue();
type = AttrType.fromString((String) obj.get("type"));
length = ((Long) obj.get("length")).intValue();
name = (String) obj.get("name");
}
public Object getValue(String val) {
switch (type) {
case AttrType.INTEGER: {
return Integer.parseInt(val.trim());
}
case AttrType.FLOAT: {
return Float.parseFloat(val);
}
default: {
return val;
}
}
}
public int getNo() {
return no;
}
public int getType() {
return type;
}
public int getLength() {
return length;
}
public String getName() {
return name;
}
}
@@ -1,262 +0,0 @@
package tests;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import global.AttrOperator;
import global.AttrType;
import heap.HeapFile;
import relop.FileScan;
import relop.HashJoin;
import relop.Predicate;
import relop.Projection;
import relop.Schema;
import relop.Selection;
import relop.SimpleJoin;
import relop.Tuple;
// YOUR CODE FOR PART3 SHOULD GO HERE.
public class QEPTest extends TestDriver
{
/** The display name of the test suite. */
private static final String TEST_NAME = "QEP Tests";
/** Employee table schema. */
private static Schema s_emp;
/** Department table schema. */
private static Schema s_dept;
private static String empFilePath;
private static String deptFilePath;
private static HeapFile empHeapFile;
private static HeapFile deptHeapFile;
// --------------------------------------------------------------------------
/**
* Test application entry point; runs all tests.
* @throws IOException
*/
public static void main(String argv[]) throws IOException
{
empFilePath = argv[0] + "/Employee.txt";
deptFilePath = argv[0] + "/Department.txt";
// create a clean Minibase instance
QEPTest qepTest = new QEPTest();
qepTest.create_minibase();
initSchema();
loadData();
qepTest.q1();
qepTest.q2();
qepTest.q3();
qepTest.q4();
qepTest.q5();
qepTest.q6();
qepTest.q7();
qepTest.q8();
/*
qepTest.q5();
qepTest.q5_hash();
*/
}
public void q1()
{
System.out.println("\n 1) Display for each employee his Name and Salary:\n");
FileScan scan = new FileScan(s_emp, empHeapFile);
Projection pro = new Projection(scan, s_emp.fieldNumber(Constants.EmpNameColName) , s_emp.fieldNumber(Constants.EmpSalaryColName));
pro.execute();
}
public void q2()
{
System.out.println("\n 2) Display the Name for the departments with MinSalary = 1000:\n");
FileScan scan = new FileScan(s_dept, deptHeapFile);
Predicate pred = new Predicate(AttrOperator.EQ, AttrType.COLNAME, Constants.DeptMinSalaryColName, AttrType.FLOAT, 1000F);
Selection sel = new Selection(scan, pred);
Projection pro = new Projection(sel, s_dept.fieldNumber(Constants.DeptNameColName));
pro.execute();
}
public void q3()
{
System.out.println("\n 3) Display the Name for the departments with MinSalary = MaxSalary:\n");
FileScan scan = new FileScan(s_dept, deptHeapFile);
Predicate pred = new Predicate(AttrOperator.EQ, AttrType.COLNAME, Constants.DeptMinSalaryColName, AttrType.COLNAME, Constants.DeptMaxSalaryColName);
Selection sel = new Selection(scan, pred);
Projection pro = new Projection(sel, s_dept.fieldNumber(Constants.DeptNameColName));
pro.execute();
}
public void q4()
{
System.out.println("\n 4) Display the Name for employees whose Age > 30 and Salary < 1000:\n");
FileScan scan = new FileScan(s_emp, empHeapFile);
Predicate predAge = new Predicate(AttrOperator.GT, AttrType.COLNAME, Constants.EmpAgeColName, AttrType.FLOAT, 30F);
Predicate predSalary = new Predicate(AttrOperator.LT, AttrType.COLNAME, Constants.EmpSalaryColName, AttrType.FLOAT, 1000F);
Selection selAge = new Selection(scan, predAge);
Selection selSalary = new Selection(selAge, predSalary);
Projection projName = new Projection(selSalary, s_emp.fieldNumber(Constants.EmpNameColName));
projName.execute();
}
public void q5()
{
System.out.println("\n 5) For each employee, display his Salary and the Name of his department:\n");
FileScan empScan = new FileScan(s_emp, empHeapFile);
FileScan deptScan = new FileScan(s_dept, deptHeapFile);
Predicate joinPred = new Predicate(AttrOperator.EQ, AttrType.FIELDNO, 0, AttrType.FIELDNO, 8);
SimpleJoin join = new SimpleJoin(deptScan, empScan, joinPred);
Projection proj = new Projection(join, 7, 1);
proj.execute();
}
public void q6()
{
System.out.println("\n 6) Display the Name and Salary for employees who work in the department that has DeptId = 3:\n");
FileScan scan = new FileScan(s_emp, empHeapFile);
Predicate predDept = new Predicate(AttrOperator.EQ, AttrType.COLNAME, Constants.EmpDeptIDColName, AttrType.INTEGER, 3);
Selection sel = new Selection(scan, predDept);
Projection proj = new Projection(sel, s_emp.fieldNumber(Constants.EmpNameColName), s_emp.fieldNumber(Constants.EmpSalaryColName));
proj.execute();
}
public void q7()
{
System.out.println("\n 7) Display the Salary for each employee who works in a department that has MaxSalary > 100000:\n");
FileScan empScan = new FileScan(s_emp, empHeapFile);
FileScan deptScan = new FileScan(s_dept, deptHeapFile);
Predicate predMaxSalary = new Predicate(AttrOperator.GT, AttrType.COLNAME, Constants.DeptMaxSalaryColName, AttrType.FLOAT, 100000F);
Selection selDept = new Selection(deptScan, predMaxSalary);
Predicate joinPred = new Predicate(AttrOperator.EQ, AttrType.FIELDNO, 0, AttrType.FIELDNO, 8);
SimpleJoin join = new SimpleJoin(selDept, empScan, joinPred);
Projection proj = new Projection(join, 7);
proj.execute();
}
public void q8()
{
System.out.println("\n 8) Display the Name for each employee whose Salary is less than the MinSalary of his department:\n");
FileScan empScan = new FileScan(s_emp, empHeapFile);
FileScan deptScan = new FileScan(s_dept, deptHeapFile);
Predicate joinPred = new Predicate(AttrOperator.EQ, AttrType.FIELDNO, 0, AttrType.FIELDNO, 8);
SimpleJoin join = new SimpleJoin(deptScan, empScan, joinPred);
Predicate pred = new Predicate(AttrOperator.LT, AttrType.FIELDNO, 7, AttrType.FIELDNO, 2);
Selection sel = new Selection(join, pred);
Projection proj = new Projection(sel, 5);
proj.execute();
}
public void q5_hash()
{
System.out.println("\n 5) For each employee, display his Salary and the Name of his department:\n");
FileScan empScan = new FileScan(s_emp, empHeapFile);
FileScan deptScan = new FileScan(s_dept, deptHeapFile);
Predicate joinPred = new Predicate(AttrOperator.EQ, AttrType.FIELDNO, 0, AttrType.FIELDNO, 8);
//SimpleJoin join = new SimpleJoin(deptScan, empScan, joinPred);
HashJoin join = new HashJoin(deptScan, empScan, 0, 4);
Projection proj = new Projection(join, 7, 1);
proj.execute();
}
protected static void initSchema()
{
//initialize schema for the "Employee" table
s_emp = new Schema(5);
s_emp.initField(0, AttrType.INTEGER, 4, Constants.EmpIdColName);
s_emp.initField(1, AttrType.STRING, 40, Constants.EmpNameColName);
s_emp.initField(2, AttrType.FLOAT, 4, Constants.EmpAgeColName);
s_emp.initField(3, AttrType.FLOAT, 4, Constants.EmpSalaryColName);
s_emp.initField(4, AttrType.INTEGER, 4, Constants.EmpDeptIDColName);
//initialize schema for the "Department" table
s_dept = new Schema(4);
s_dept.initField(0, AttrType.INTEGER, 4, Constants.DeptIdColName);
s_dept.initField(1, AttrType.STRING, 40, Constants.DeptNameColName);
s_dept.initField(2, AttrType.FLOAT, 4, Constants.DeptMinSalaryColName);
s_dept.initField(3, AttrType.FLOAT, 4, Constants.DeptMaxSalaryColName);
}
protected static void loadData() throws IOException
{
empHeapFile = new HeapFile(null);
loadEmpTable(empHeapFile);
deptHeapFile = new HeapFile(null);
loadDeptTable(deptHeapFile);
}
protected static void loadEmpTable(HeapFile file) throws IOException
{
Tuple tuple = new Tuple(s_emp);
BufferedReader reader = new BufferedReader(new FileReader(empFilePath));
reader.readLine(); //ignore the header
String line = "";
String[] temp = null;
int empId; String empName; float age; float salary; int deptId;
while((line = reader.readLine()) != null)
{
temp = line.split(",");
empId = Integer.parseInt(temp[0].trim());
empName = temp[1].trim();
age = Float.parseFloat(temp[2].trim());
salary = Float.parseFloat(temp[3].trim());
deptId = Integer.parseInt(temp[4].trim());
tuple.setAllFields(empId, empName, age, salary, deptId);
tuple.insertIntoFile(file);
}
reader.close();
}
protected static void loadDeptTable(HeapFile file) throws IOException
{
Tuple tuple = new Tuple(s_dept);
BufferedReader reader = new BufferedReader(new FileReader(deptFilePath));
reader.readLine(); //ignore the header
String line = "";
String[] temp = null;
int deptId; String deptName; float minSalary; float maxSalary;
while((line = reader.readLine()) != null)
{
temp = line.split(",");
deptId = Integer.parseInt(temp[0].trim());
deptName = temp[1].trim();
minSalary = Float.parseFloat(temp[2].trim());
maxSalary = Float.parseFloat(temp[3].trim());
tuple.setAllFields(deptId, deptName, minSalary, maxSalary);
tuple.insertIntoFile(file);
}
reader.close();
}
static class Constants
{
public final static String EmpIdColName = "EmpId";
public final static String EmpNameColName = "Name";
public final static String EmpAgeColName = "Age";
public final static String EmpSalaryColName = "Salary";
public final static String EmpDeptIDColName = "DeptID";
public final static String DeptIdColName = "DeptId";
public final static String DeptNameColName = "Name";
public final static String DeptMinSalaryColName = "MinSalary";
public final static String DeptMaxSalaryColName = "MaxSalary";
}
}
@@ -1,367 +0,0 @@
package tests;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
import org.junit.After;
import org.junit.Before;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import global.AttrOperator;
import global.AttrType;
import global.RID;
import global.SearchKey;
import heap.HeapFile;
import index.HashIndex;
import relop.FileScan;
import relop.HashJoin;
import relop.IndexScan;
import relop.KeyScan;
import relop.Predicate;
import relop.Projection;
import relop.Schema;
import relop.Selection;
import relop.SimpleJoin;
import relop.Tuple;
import relop.Iterator;
import java.io.*;
import java.util.*;
import com.opencsv.CSVReader;
import org.json.simple.parser.JSONParser;
/**
* Test suite for the relop layer.
*/
public class ROTest extends TestDriver {
private static ROTest rot;
/** The display name of the test suite. */
private static final String TEST_NAME = "relational operator tests";
/** Size of tables in test3. */
private static final int SUPER_SIZE = 2000;
private Scanner in;
/** Drivers schema/table/index */
private static Schema s_drivers;
private static HeapFile f_drivers;
private static HashIndex idx_drivers;
private static Schema s_driversBig;
private static HeapFile f_driversBig;
private static HashIndex idx_driversBig;
/** Rides schema/table/index */
private static Schema s_rides;
private static HeapFile f_rides;
private static HashIndex idx_rides;
private static Schema s_ridesBig;
private static HeapFile f_ridesBig;
private static HashIndex idx_ridesBig;
/** Groups schema/table/index */
private static Schema s_groups;
private static HeapFile f_groups;
private static HashIndex idx_groups;
private static Schema s_groupsBig;
private static HeapFile f_groupsBig;
private static HashIndex idx_groupsBig;
/** Expected result strings for test cases */
private static HashMap<String, String> results;
/** */
private static void loadTable(Schema schema, HeapFile f_table, HashIndex idx_table, String table)
throws FileNotFoundException, IOException, ParseException {
// initialize schema for table
InputStream in = ClassLoader.getSystemResourceAsStream(table.concat(".json"));
JSONObject jsonObj = (JSONObject) new JSONParser().parse(new InputStreamReader(in));
JSONArray jsonFields = (JSONArray) jsonObj.get("schema");
Field[] fields = new Field[jsonFields.size()];
int key = ((Long) jsonObj.get("key")).intValue();
int xx = 0;
for (Object obj : jsonFields) {
Field field = new Field((JSONObject) obj);
fields[xx] = field; xx++;
schema.initField(field.getNo(), field.getType(), field.getLength(), field.getName());
}
// populate relation
in = ClassLoader.getSystemResourceAsStream(table.concat(".csv"));
try (CSVReader csvReader = new CSVReader(new InputStreamReader(in))) {
String[] values = null;
Tuple tuple = new Tuple(schema);
while((values = csvReader.readNext()) != null) {
for (int i=0; i<values.length; i++) {
tuple.setField(i, fields[i].getValue(values[i]));
}
idx_table.insertEntry(new SearchKey(fields[key].getValue(values[key])), f_table.insertRecord(tuple.getData()));
}
}
}
protected void execute_and_compare(String testDesc, String id, Iterator it)
{
it.execute();
it.close();
String[] sol = results.get(id).split("|");
Arrays.sort(sol);
String[] res = it.getResult().split("|");
Arrays.sort(res);
assertTrue("FAILURE: " + testDesc + " output {" + it.getResult() + "} did not match expected result, should be " + results.get(id), Arrays.equals(sol, res));
}
public static void main(String[] args) {
Result result = JUnitCore.runClasses(tests.ROTest.class);
for (Failure failure : result.getFailures()) {
System.out.println(failure.toString());
}
System.out.println(result.wasSuccessful());
}
@BeforeClass
public static void setupDB() throws Exception {
// create a clean Minibase instance
rot = new ROTest();
rot.create_minibase();
results = new HashMap<String, String>();
try
{
Scanner in = new Scanner(new File("solution.txt"));
String line;
String[] res;
while(in.hasNextLine())
{
line = in.nextLine();
res = line.split("=");
results.put(res[0],res[1]);
}
} catch (IOException e)
{
e.printStackTrace();
System.exit(1);
}
// "Drivers" table
s_drivers = new Schema(5);
f_drivers = new HeapFile("drivers");
idx_drivers = new HashIndex("drivers_idx");
loadTable(s_drivers, f_drivers, idx_drivers, "drivers");
s_driversBig = new Schema(5);
f_driversBig = new HeapFile("driversBig");
idx_driversBig = new HashIndex("drivers_idxBig");
loadTable(s_driversBig, f_driversBig, idx_driversBig, "driversBig");
// "Rides" table
s_rides = new Schema(4);
f_rides = new HeapFile("rides");
idx_rides = new HashIndex("rides_idx");
loadTable(s_rides, f_rides, idx_rides, "rides");
s_ridesBig = new Schema(4);
f_ridesBig = new HeapFile("ridesBig");
idx_ridesBig = new HashIndex("rides_idxBig");
loadTable(s_ridesBig, f_ridesBig, idx_ridesBig, "ridesBig");
// "Groups" table
s_groupsBig = new Schema(2);
f_groupsBig = new HeapFile("groupsBig");
idx_groupsBig = new HashIndex("groups_idxBig");
loadTable(s_groupsBig, f_groupsBig, idx_groupsBig, "groupsBig");
s_groups = new Schema(2);
f_groups = new HeapFile("groups");
idx_groups = new HashIndex("groups_idx");
loadTable(s_groups, f_groups, idx_groups, "groups");
System.out.println();
}
@AfterClass
public static void tearDownDB()
{
idx_drivers.deleteFile();
idx_rides.deleteFile();
idx_groups.deleteFile();
f_rides.deleteFile();
f_drivers.deleteFile();
f_groups.deleteFile();
rot.delete_minibase();
}
@Test
public void testFileScan() {
//Scan drivers table
Iterator fscan = new FileScan(s_drivers, f_drivers);
execute_and_compare("Filescan", "filescan", fscan);
}
@Test
public void testIndexScan() {
//Scan drivers index
Iterator idxscan = new IndexScan(s_drivers, idx_drivers, f_drivers);
execute_and_compare("IndexScan", "idxscan", idxscan);
}
@Test
public void testKeyScan() {
//Scan drivers index for key 20f
Iterator keyscan = new KeyScan(s_drivers, idx_drivers, new SearchKey(20f), f_drivers);
execute_and_compare("KeyScan", "keyscan", keyscan);
}
@Test
public void testSelection() {
//Selection drivers with age > 20
Iterator selection = new Selection(new FileScan(s_drivers, f_drivers),
new Predicate(AttrOperator.GT, AttrType.COLNAME, "age", AttrType.FLOAT, 20F));
execute_and_compare("Selection", "selection", selection);
}
@Test
public void testSelectionMultiplePredicates() {
Iterator selection_preds = new Selection(new FileScan(s_drivers, f_drivers),
new Predicate(AttrOperator.GT, AttrType.COLNAME, "age", AttrType.FLOAT, 23F),
new Predicate(AttrOperator.LT, AttrType.COLNAME, "age", AttrType.FLOAT, 19F));
execute_and_compare("Selection Multipled Predicates", "selection_preds", selection_preds);
}
@Test
public void testProjection() {
//Projection on Drivers: {FirstName, NumSeats}
Iterator projection = new Projection(new FileScan(s_drivers, f_drivers), s_drivers.fieldNumber("FirstName"), s_drivers.fieldNumber("NumSeats"));
execute_and_compare("Projection", "projection", projection);
}
@Test
public void testHashJoin() {
//HashJoin on Drivers X Rides on DriverID
Iterator hashjoin = new HashJoin(new FileScan(s_drivers, f_drivers),
new FileScan(s_rides, f_rides), 0, 0);
execute_and_compare("Hash Join", "hashjoin", hashjoin);
}
@Test
public void testSelectionPipelining() {
//Test all possible Iterator inputs to Selection
Iterator sel_idx = new Selection(new IndexScan(s_drivers, idx_drivers, f_drivers),
new Predicate(AttrOperator.EQ, AttrType.COLNAME, "FirstName", AttrType.STRING, "Walid"));
execute_and_compare("Selection - Pipelining IndexScan", "sel_idx", sel_idx);
Iterator sel_key = new Selection(new KeyScan(s_drivers, idx_drivers, new SearchKey(20F), f_drivers),
new Predicate(AttrOperator.EQ, AttrType.COLNAME, "FirstName", AttrType.STRING, "Walid"));
execute_and_compare("Selection - Pipelining Keyscan", "sel_key", sel_key);
Iterator sel_sel = new Selection(new Selection(new FileScan(s_drivers, f_drivers),
new Predicate(AttrOperator.EQ, AttrType.COLNAME, "Age", AttrType.FLOAT, 20F)),
new Predicate(AttrOperator.EQ, AttrType.COLNAME, "FirstName", AttrType.STRING, "Walid"));
execute_and_compare("Selection - Pipelining Selection", "sel_sel", sel_sel);
Iterator sel_proj = new Selection(new Projection(
new FileScan(s_drivers, f_drivers), s_drivers.fieldNumber("DriverId"), s_drivers.fieldNumber("FirstName")),
new Predicate(AttrOperator.EQ, AttrType.COLNAME, "FirstName", AttrType.STRING, "Walid"));
execute_and_compare("Selection - Pipelining Projection", "sel_proj", sel_proj);
/* Iterator sel_sj = new Selection(new SimpleJoin(new FileScan(s_drivers, f_drivers), new FileScan(s_rides, f_rides),
new Predicate(AttrOperator.EQ, AttrType.FIELDNO, 0, AttrType.FIELDNO, 5)),
new Predicate(AttrOperator.EQ, AttrType.COLNAME, "FirstName", AttrType.STRING, "Walid"));
execute_and_compare("Selection - Pipelining Simple Join", "sel_sj", sel_sj);
*/
Iterator sel_hj = new Selection(new HashJoin(new FileScan(s_drivers, f_drivers), new FileScan(s_rides, f_rides),0,0),
new Predicate(AttrOperator.EQ, AttrType.COLNAME, "FirstName", AttrType.STRING, "Walid"));
execute_and_compare("Selection - Pipelining Hash Join", "sel_jh", sel_hj);
}
@Test
public void testProjectionPipelining() {
//Test all possible Iterator inputs to HashJoin
Iterator proj_idx = new Projection(new IndexScan(s_drivers, idx_drivers, f_drivers),
s_drivers.fieldNumber("DriverId"), s_drivers.fieldNumber("Age"));
execute_and_compare("Projection - Pipelining IndexScan", "proj_idx", proj_idx);
Iterator proj_key = new Projection(new KeyScan(s_drivers, idx_drivers, new SearchKey(20F), f_drivers),
s_drivers.fieldNumber("DriverId"), s_drivers.fieldNumber("Age"));
execute_and_compare("Projection - Pipelining KeyScan", "proj_key", proj_key);
Iterator proj_sel = new Projection(new Selection(new FileScan(s_drivers, f_drivers),
new Predicate(AttrOperator.EQ, AttrType.COLNAME, "Age", AttrType.FLOAT, 20F)),
s_drivers.fieldNumber("DriverId"), s_drivers.fieldNumber("Age"));
execute_and_compare("Projection - Pipelining Selection", "proj_sel", proj_sel);
Iterator proj_proj = new Projection(new Projection(new FileScan(s_drivers, f_drivers),
s_drivers.fieldNumber("DriverId"), s_drivers.fieldNumber("FirstName"), s_drivers.fieldNumber("Age")),
0, 2);
execute_and_compare("Projection - Pipelining Projection", "proj_proj", proj_proj);
/*
Iterator proj_sj = new Projection(new SimpleJoin(new FileScan(s_drivers, f_drivers), new FileScan(s_rides, f_rides),
new Predicate(AttrOperator.EQ, AttrType.FIELDNO, 0, AttrType.FIELDNO, 5)),
0, 3);
execute_and_compare("Projection - Pipelining Simple Join", "proj_sj", proj_sj);
*/
Iterator proj_hj = new Projection(new HashJoin(new FileScan(s_drivers, f_drivers), new FileScan(s_rides, f_rides),0,0),
0, 3);
execute_and_compare("Projection - Pipelining Hash Join", "proj_hj", proj_hj);
}
@Test
public void testHashjoinPipelining() {
//Test all possible Iterator inputs to HashJoin
/*
Iterator hj_sel_sj = new HashJoin(new Selection(new FileScan(s_drivers, f_drivers),
new Predicate(AttrOperator.GTE, AttrType.COLNAME, "DriverId", AttrType.INTEGER, 1)),
new SimpleJoin(new FileScan(s_rides, f_rides), new FileScan(s_groups, f_groups),
new Predicate(AttrOperator.EQ, AttrType.COLNAME, "GroupId", AttrType.COLNAME, "DriverId")),0,0);
execute_and_compare("Hash Join - Pipelining Selection/Simple Join", "hj_sel_sj", hj_sel_sj);
*/
Iterator hj_proj_hj = new HashJoin(new Projection(new FileScan(s_drivers, f_drivers), s_drivers.fieldNumber("DriverId"), s_drivers.fieldNumber("Age")),
new HashJoin(new FileScan(s_rides, f_rides), new FileScan(s_groups, f_groups), 1, 0), 0, 0);
execute_and_compare("Hash Join - Pipelining Projection/Hash Join", "hj_proj_hj", hj_proj_hj);
Iterator hj_iscan_kscan = new HashJoin(new IndexScan(s_drivers, idx_drivers, f_drivers),
new KeyScan(s_rides, idx_rides, new SearchKey(1), f_rides), 0, 0);
execute_and_compare("Hash Join - Pipelining IndexScan/KeyScan", "hj_iscan_kscan", hj_iscan_kscan);
}
//This is an EXTRA test to do Drivers X Drivers using HashJoin and we will calibrate this by changing the value of HashTableDup in the HashTableDup class
@Test
public void testHashJoinOnBigTables() {
//HashJoin on Drivers X Rides on DriverID
//Anytime the HashTableDup count goes over the threshold, a runtimeexception is thrown
Iterator hashSame = new HashJoin(new FileScan(s_drivers, f_drivers),
new FileScan(s_drivers, f_drivers), 0, 0);
execute_and_compare("Hash Join", "hashSame", hashSame);
}
//This is second EXTRA test to do DriversBig X DriversBig using HashJoin and we will calibrate this by changing the value of HashTableDup in the HashTableDup class
//Anytime the HashTableDup count goes over the threshold, a runtimeexception is thrown
//In addition, any call to Simplejoin throws a RunTimeException
@Test
public void testHashJoinOnEqualTables() {
//HashJoin on Drivers X Rides on DriverID
Iterator hashEqual = new HashJoin(new FileScan(s_driversBig, f_driversBig),
new FileScan(s_driversBig, f_driversBig), 0, 0);
execute_and_compare("Hash Join", "hashEqual", hashEqual);
}
} // class ROTest extends TestDriver
@@ -1,179 +0,0 @@
package tests;
import global.GlobalConst;
import global.Minibase;
import java.io.File;
import java.util.ArrayList;
import java.util.Random;
/**
* <h3>Minibase Test Driver</h3>
* This base class contains common code to each layer's test suite.
*/
class TestDriver implements GlobalConst {
/** Success value, for readability. */
protected static final boolean PASS = true;
/** Failure value, for readability. */
protected static final boolean FAIL = false;
// --------------------------------------------------------------------------
/** Default database file name. */
protected String DB_PATH = System.getProperty("user.name") + ".minibase";
/** Default database size (in pages). */
protected int DB_SIZE = 10000;
/** Default buffer pool size (in pages) */
protected int BUF_SIZE = 100;
/** Default buffer pool replacement policy */
protected String BUF_POLICY = "Clock";
// --------------------------------------------------------------------------
/** Random generator; use the same seed to make tests deterministic. */
protected Random random;
/**
* Counter values saved with a particular description.
*/
protected class CountData {
public String desc;
public int reads;
public int writes;
public int allocs;
public int pinned;
} // protected class CountData
/**
* Incremental history of the performance counters; odd elements are snapshots
* before the tests, and even elements are after.
*/
protected ArrayList<CountData> counts;
// --------------------------------------------------------------------------
/**
* Deletes the database files from the disk.
*/
protected void delete_minibase() {
new File(DB_PATH).delete();
}
/**
* Creates a new database on the disk.
*/
protected void create_minibase() {
System.out.println("Creating database...\nReplacer: " + BUF_POLICY);
new Minibase(DB_PATH, DB_SIZE, BUF_SIZE, BUF_POLICY, false);
}
/**
* Loads an existing database from the disk.
*/
protected void load_minibase() {
System.out.println("Loading database...\nReplacer: " + BUF_POLICY);
new Minibase(DB_PATH, DB_SIZE, BUF_SIZE, BUF_POLICY, true);
}
// --------------------------------------------------------------------------
/**
* Resets the random generator to the default seed.
*/
protected void initRandom() {
random = new Random(74);
}
/**
* Resets the performance counter history.
*/
protected void initCounts() {
counts = new ArrayList<CountData>();
}
/**
* Saves the current performance counters, given the description.
*/
protected void saveCounts(String desc) {
// create the new count data
CountData data = new CountData();
counts.add(data);
data.desc = desc;
// save the counts (in correct order)
Minibase.BufferManager.flushAllPages();
data.reads = Minibase.DiskManager.getReadCount();
data.writes = Minibase.DiskManager.getWriteCount();
data.allocs = Minibase.DiskManager.getAllocCount();
data.pinned = BUF_SIZE - Minibase.BufferManager.getNumUnpinned();
} // protected void saveCounts(String desc)
/**
* Prints the performance counters (i.e. for the current test).
*/
protected void printCounters() {
CountData data = counts.get(counts.size() - 1);
System.out.println();
Minibase.BufferManager.flushAllPages();
System.out.println(" *** Number of reads: "
+ (Minibase.DiskManager.getReadCount() - data.reads));
System.out.println(" *** Number of writes: "
+ (Minibase.DiskManager.getWriteCount() - data.writes));
System.out.println(" *** Net total pages: "
+ (Minibase.DiskManager.getAllocCount() - data.allocs));
int numbufs = Minibase.BufferManager.getNumBuffers();
System.out
.println(" *** Remaining Pinned: "
+ (numbufs - Minibase.BufferManager.getNumUnpinned()) + " / "
+ numbufs);
} // protected void printCounters()
/**
* Prints the complete history of the performance counters.
*
* @param sepcnt how many lines to print before each separator
*/
protected void printSummary(int sepcnt) {
System.out.println();
String seperator = "--------------------------------------";
System.out.println(seperator);
System.out.println("\tReads\tWrites\tAllocs\tPinned");
int size = counts.size();
for (int i = 1; i < size; i += 2) {
if (i % (sepcnt * 2) == 1) {
System.out.println(seperator);
}
CountData before = counts.get(i - 1);
CountData after = counts.get(i);
System.out.print(after.desc);
System.out.print("\t" + (after.reads - before.reads));
System.out.print("\t" + (after.writes - before.writes));
System.out.print("\t" + (after.allocs - before.allocs));
System.out.print("\t" + (after.pinned - before.pinned));
System.out.println();
} // for
System.out.println(seperator);
} // protected void printSummary(int sepcnt)
} // class TestDriver implements GlobalConst
@@ -1,9 +0,0 @@
1, "Ahmed", "Elmagarmid", 25, 5
2, "Walid", "Aref", 20, 13
3, "Christopher", "Clifton", 18, 4
4, "Sunil", "Prabhakar", 22, 7
5, "Elisa", "Bertino", 26, 5
6, "Susanne", "Hambrusch", 23, 3
7, "David", "Eberts", 24, 8
8, "Arif", "Ghafoor", 20, 5
9, "Jeff", "Vitter", 19, 10
1 1 Ahmed Elmagarmid 25 5
2 2 Walid Aref 20 13
3 3 Christopher Clifton 18 4
4 4 Sunil Prabhakar 22 7
5 5 Elisa Bertino 26 5
6 6 Susanne Hambrusch 23 3
7 7 David Eberts 24 8
8 8 Arif Ghafoor 20 5
9 9 Jeff Vitter 19 10
@@ -1,35 +0,0 @@
{
"schema": [
{
"no": 0,
"type": "INTEGER",
"length": 4,
"name": "DriverId"
},
{
"no": 1,
"type": "STRING",
"length": 20,
"name": "FirstName"
},
{
"no": 2,
"type": "STRING",
"length": 20,
"name": "LastName"
},
{
"no": 3,
"type": "FLOAT",
"length": 4,
"name": "Age"
},
{
"no": 4,
"type": "INTEGER",
"length": 4,
"name": "NumSeats"
}
],
"key": 3
}
File diff suppressed because it is too large Load Diff
@@ -1,35 +0,0 @@
{
"schema": [
{
"no": 0,
"type": "INTEGER",
"length": 4,
"name": "DriverId"
},
{
"no": 1,
"type": "STRING",
"length": 20,
"name": "FirstName"
},
{
"no": 2,
"type": "STRING",
"length": 20,
"name": "LastName"
},
{
"no": 3,
"type": "FLOAT",
"length": 4,
"name": "Age"
},
{
"no": 4,
"type": "INTEGER",
"length": 4,
"name": "NumSeats"
}
],
"key": 3
}
@@ -1,7 +0,0 @@
1, "Purdue1"
2, "Purdue2"
3, "Purdue3"
4, "Purdue4"
5, "Purdue5"
6, "Purdue6"
7, "Purdue7"
1 1 Purdue1
2 2 Purdue2
3 3 Purdue3
4 4 Purdue4
5 5 Purdue5
6 6 Purdue6
7 7 Purdue7
@@ -1,17 +0,0 @@
{
"schema": [
{
"no": 0,
"type": "INTEGER",
"length": 4,
"name": "GroupId"
},
{
"no": 1,
"type": "STRING",
"length": 10,
"name": "GroupName"
}
],
"key": 0
}
@@ -1,10 +0,0 @@
1," ""Purdue1"""
2," ""Purdue2"""
3," ""Purdue3"""
4," ""Purdue4"""
5," ""Purdue5"""
6," ""Purdue6"""
7," ""Purdue7"""
8," ""Purdue8"""
9," ""Purdue9"""
10," ""Purdue10"""
1 1 "Purdue1"
2 2 "Purdue2"
3 3 "Purdue3"
4 4 "Purdue4"
5 5 "Purdue5"
6 6 "Purdue6"
7 7 "Purdue7"
8 8 "Purdue8"
9 9 "Purdue9"
10 10 "Purdue10"
@@ -1,17 +0,0 @@
{
"schema": [
{
"no": 0,
"type": "INTEGER",
"length": 4,
"name": "GroupId"
},
{
"no": 1,
"type": "STRING",
"length": 10,
"name": "GroupName"
}
],
"key": 0
}
@@ -1,12 +0,0 @@
3, 5, "2/10/2006", "2/13/2006"
1, 2, "2/12/2006", "2/14/2006"
9, 1, "2/15/2006", "2/15/2006"
5, 7, "2/14/2006", "2/18/2006"
1, 3, "2/15/2006", "2/16/2006"
2, 6, "2/17/2006", "2/20/2006"
3, 4, "2/18/2006", "2/19/2006"
4, 1, "2/19/2006", "2/19/2006"
2, 7, "2/18/2006", "2/23/2006"
8, 5, "2/20/2006", "2/22/2006"
3, 2, "2/24/2006", "2/26/2006"
6, 6, "2/25/2006", "2/26/2006"
1 3 5 2/10/2006 2/13/2006
2 1 2 2/12/2006 2/14/2006
3 9 1 2/15/2006 2/15/2006
4 5 7 2/14/2006 2/18/2006
5 1 3 2/15/2006 2/16/2006
6 2 6 2/17/2006 2/20/2006
7 3 4 2/18/2006 2/19/2006
8 4 1 2/19/2006 2/19/2006
9 2 7 2/18/2006 2/23/2006
10 8 5 2/20/2006 2/22/2006
11 3 2 2/24/2006 2/26/2006
12 6 6 2/25/2006 2/26/2006
@@ -1,29 +0,0 @@
{
"schema": [
{
"no": 0,
"type": "INTEGER",
"length": 4,
"name": "DriverId"
},
{
"no": 1,
"type": "INTEGER",
"length": 4,
"name": "GroupId"
},
{
"no": 2,
"type": "STRING",
"length": 10,
"name": "FromDate"
},
{
"no": 3,
"type": "STRING",
"length": 10,
"name": "ToDate"
}
],
"key": 1
}
File diff suppressed because it is too large Load Diff
@@ -1,29 +0,0 @@
{
"schema": [
{
"no": 0,
"type": "INTEGER",
"length": 4,
"name": "DriverId"
},
{
"no": 1,
"type": "INTEGER",
"length": 4,
"name": "GroupId"
},
{
"no": 2,
"type": "STRING",
"length": 10,
"name": "FromDate"
},
{
"no": 3,
"type": "STRING",
"length": 10,
"name": "ToDate"
}
],
"key": 1
}