moved p3
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
bin/
|
||||
.DS_Store
|
||||
@@ -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.
@@ -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,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,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,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,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
|
||||
}
|
||||
Reference in New Issue
Block a user