package database.table.commands; import database.table.from.From; import database.table.groupby.GroupBy; import database.table.having.Having; import database.table.internals.*; import database.table.operations.Operations; import database.table.orderby.OrderBy; import database.table.select.Select; import database.table.where.Where; import java.util.LinkedList; /** * Author: Koushik Sen (ksen@cs.berkeley.edu) */ public class SelectCommand { private Select select; private From from; private Where where; private GroupBy groupBy; private Having having; private OrderBy orderBy; private boolean isDistinct; public SelectCommand( Select select, From from, Where where, GroupBy groupBy, Having having, OrderBy orderBy, boolean distinct) { this.select = select; this.from = from; this.where = where; this.groupBy = groupBy; this.having = having; this.orderBy = orderBy; isDistinct = distinct; } class Pair { ArrayBasedTuple tuple; Row row; Pair(ArrayBasedTuple tuple, Row row) { this.tuple = tuple; this.row = row; } } public Table execute() { Table[] tables = from.tables(); int nTables = tables.length; String[] selectAs = select.selectAs(); Table ret = TableFactory.create(selectAs); TableIterator[] iterators = new TableIterator[nTables]; LinkedList<Pair> groups = new LinkedList<Pair>(); while (hasNext(iterators)) { boolean insert = false; Row[] rows = next(iterators, tables); if (where.where(rows)) { ArrayBasedTuple group = new ArrayBasedTuple(groupBy.groupBy(rows)); Row row = null; for (Pair tmp : groups) { if (tmp.tuple.equals(group)) { row = tmp.row; break; } } if (row == null) { row = new Row(); insert = true; groups.add(new Pair(group, row)); } Operations[] operations = select.select(); int i = 0; if (selectAs.length != operations.length) { throw new RuntimeException( "In Select selectAs and select returns different length arrays"); } for (String columnName : selectAs) { row.put(columnName, operations[i].apply(row.get(columnName), rows)); i++; } if (insert && having.having(row)) { boolean exists = false; if (isDistinct) { TableIterator iter = ret.iterator(); while (iter.hasNext()) { Row next = iter.next(); if (next.equals(row)) { exists = true; } } } if (!exists) { ret.insert(row); } } } } if (orderBy != null) { ret.orderBy(orderBy); } return ret; } private static Row[] next(TableIterator[] iterators, Table[] tables) { 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())) { iterators[i] = tables[i].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; } }