package database.table.internals;
import database.table.orderby.OrderBy;
import database.table.where.Where;
import java.sql.ResultSet;
import java.util.*;
/**
* Author: Koushik Sen (ksen@cs.berkeley.edu)
* Date: 7/2/12
* Time: 10:18 AM
*/
public class TableImpl implements Table {
private String name;
private String[] columnNames;
private int[] columnTypes;
private boolean[] isPrimary;
private boolean[] isUnique;
private boolean[] isNonNull;
private ForeignKey[] foreignKeys;
private List<Row> rows;
public TableImpl(String name, String[] columnNames) {
this.name = name;
this.columnNames = columnNames;
rows = new LinkedList<Row>();
}
public TableImpl(
String name,
String[] columnNames,
int[] columnTypes,
boolean[] primary,
boolean[] unique,
boolean[] nonNull,
ForeignKey[] foreignKeys) {
this.name = name;
this.columnNames = columnNames;
this.columnTypes = columnTypes;
this.foreignKeys = foreignKeys;
this.isPrimary = primary;
this.isUnique = unique;
this.isNonNull = nonNull;
rows = new LinkedList<Row>();
}
public void insert(Row row) {
ConsistencyChecker.checkRow(this, row);
rows.add(row);
}
public void insert(String[] columns, Object[] values) {
assert (columns.length == values.length);
Row row = new Row();
for (int i = 0; i < columns.length; i++) {
String column = columns[i];
row.put(column, values[i]);
}
ConsistencyChecker.checkRow(this, row);
rows.add(row);
}
public void insert(Object[] values) {
assert (columnNames.length == values.length);
Row row = new Row();
for (int i = 0; i < columnNames.length; i++) {
String column = columnNames[i];
row.put(column, values[i]);
}
ConsistencyChecker.checkRow(this, row);
rows.add(row);
}
public void insertNoCheck(Object[] values) {
assert (columnNames.length == values.length);
Row row = new Row();
for (int i = 0; i < columnNames.length; i++) {
String column = columnNames[i];
row.put(column, values[i]);
}
rows.add(row);
}
public TableIterator iterator() {
return new TableIterator(rows.listIterator());
}
public int delete(Where where) {
int ret = 0;
TableIterator iterator = new TableIterator(rows.listIterator());
Row[] tmp = new Row[1];
while (iterator.hasNext()) {
Row row = iterator.next();
tmp[0] = row;
if (where.where(tmp)) {
ret++;
iterator.remove();
}
}
return ret;
}
public int update(Where where) {
int ret = 0;
for (Row row : rows) {
if (where.modify(row)) {
ConsistencyChecker.checkRow(this, row);
ret++;
}
}
return ret;
}
public Table select(Where where, String[][] selectColumns, Table[] fromOther) {
int nTables = 1;
if (fromOther != null) {
nTables += fromOther.length;
}
int nRows = 0;
ArrayList<String> columns = new ArrayList<String>();
for (int i = 0; i < selectColumns.length; i++) {
if (selectColumns[i] != null) {
nRows += selectColumns[i].length;
for (int j = 0; j < selectColumns[i].length; j++) {
if (columns.contains(selectColumns[i][j])) {
throw new RuntimeException("Duplicate column name in select " + selectColumns[i][j]);
}
columns.add(selectColumns[i][j]);
}
}
}
String[] tmp = new String[columns.size()];
int l = 0;
for (String next : columns) {
tmp[l] = next;
l++;
}
Table ret = TableFactory.create(tmp);
TableIterator[] iterators = new TableIterator[nTables];
while (hasNext(iterators)) {
Row[] rows = next(iterators, this, fromOther);
if (where.where(rows)) {
ret.insert(doSelectColumns(nRows, selectColumns, rows));
}
}
return ret;
}
public ResultSet getResultSet() {
return new ResultSetImpl(new TableIterator(rows.listIterator()));
}
public String getName() {
return name;
}
public String[] getColumnNames() {
return columnNames;
}
public int[] getColumnTypes() {
return columnTypes;
}
public boolean[] getPrimaries() {
return isPrimary;
}
public boolean[] getUniques() {
return isUnique;
}
public boolean[] getNonNulls() {
return isNonNull;
}
public ForeignKey[] getForeignKeys() {
return foreignKeys;
}
public void orderBy(OrderBy orderBy) {
Collections.sort(rows, orderBy.getComparator());
}
public int size() {
return rows.size();
}
public Object value() {
if (columnNames.length != 1) {
throw new RuntimeException("Table " + name + " must have one column.");
}
if (rows.size() != 1) {
throw new RuntimeException("Table " + name + " must have one row.");
}
return rows.get(0).get(columnNames[0]);
}
public boolean in(Object o) {
return any(
o,
new Predicate() {
public boolean predicate(Object o, Object value) {
if (o == null) {
if (value == null) return true;
} else {
if (o.equals(value)) return true;
}
return false; //To change body of implemented methods use File | Settings | File Templates.
}
});
}
public boolean any(Object o, Predicate p) {
if (columnNames.length != 1) {
throw new RuntimeException("Table " + name + " must have one column.");
}
TableIterator iter = iterator();
while (iter.hasNext()) {
Row row = iter.next();
Object value = row.get(columnNames[0]);
if (p.predicate(o, value)) return true;
}
return false;
}
public void setForeignKeys(ForeignKey[] fkeys) {
this.foreignKeys = fkeys;
}
private Object[] doSelectColumns(int nCols, String[][] selectColumns, Row[] rows) {
Object[] ret = new Object[nCols];
int k = 0;
for (int i = 0; i < selectColumns.length; i++) {
if (selectColumns[i] != null) {
for (int j = 0; j < selectColumns[i].length; j++) {
ret[k] = rows[i].get(selectColumns[i][j]);
k++;
}
}
}
return ret;
}
private static Row[] next(TableIterator[] iterators, Table table, Table[] fromOther) {
Row[] ret = new Row[iterators.length];
boolean first = true;
for (int i = iterators.length - 1; i >= 0; i--) {
if (iterators[i] == null || (first && !iterators[i].hasNext())) {
if (i == 0) {
iterators[i] = table.iterator();
} else {
iterators[i] = fromOther[i - 1].iterator();
}
ret[i] = iterators[i].next();
} else if (first) {
first = false;
ret[i] = iterators[i].next();
} else {
iterators[i].previous();
ret[i] = iterators[i].next();
}
}
return ret;
}
private static boolean hasNext(TableIterator[] iterators) {
for (int i = 0; i < iterators.length; i++) {
if (iterators[i] == null || iterators[i].hasNext()) return true;
}
return false;
}
}