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