package org.hsqldb.navigator;
import java.util.Comparator;
import java.util.TreeMap;
import org.hsqldb.QueryExpression;
import org.hsqldb.QuerySpecification;
import org.hsqldb.Row;
import org.hsqldb.Session;
import org.hsqldb.SortAndSlice;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.index.Index;
import org.hsqldb.lib.ArraySort;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.LongKeyHashMap;
import org.hsqldb.result.ResultMetaData;
import org.hsqldb.rowio.RowInputInterface;
import org.hsqldb.rowio.RowOutputInterface;
public class RowSetNavigatorData extends RowSetNavigator
implements Comparator<Object[]> {
public static final Object[][] emptyTable = new Object[0][];
private Object[][] dataTable = emptyTable;
int visibleColumnCount;
boolean isAggregate;
boolean isSimpleAggregate;
Object[] simpleAggregateData;
boolean reindexTable;
Index mainIndex;
Index fullIndex;
Index orderIndex;
Index groupIndex;
Index idIndex;
TreeMap<Object[], Object[]> rowMap;
LongKeyHashMap idMap;
RowSetNavigatorData(Session session) {
this.session = session;
}
public RowSetNavigatorData(Session session, QuerySpecification select) {
this.session = session;
this.rangePosition = select.resultRangePosition;
visibleColumnCount = select.getColumnCount();
isSimpleAggregate = select.isAggregated && !select.isGrouped;
mainIndex = select.mainIndex;
fullIndex = select.fullIndex;
orderIndex = select.orderIndex;
if (select.isGrouped) {
mainIndex = select.groupIndex;
rowMap = new TreeMap<Object[], Object[]>(this);
}
if (select.idIndex != null) {
idMap = new LongKeyHashMap();
}
}
public RowSetNavigatorData(Session session,
QueryExpression queryExpression) {
this.session = session;
mainIndex = queryExpression.mainIndex;
fullIndex = queryExpression.fullIndex;
orderIndex = queryExpression.orderIndex;
visibleColumnCount = queryExpression.getColumnCount();
}
public RowSetNavigatorData(Session session, RowSetNavigator navigator) {
this.session = session;
setCapacity(navigator.size);
while (navigator.next()) {
add(navigator.getCurrent());
}
}
public void sortFull(Session session) {
mainIndex = fullIndex;
ArraySort.sort(dataTable, size, this);
reset();
}
public void sortOrder(Session session) {
if (orderIndex != null) {
mainIndex = orderIndex;
ArraySort.sort(dataTable, size, this);
}
reset();
}
public void sortOrderUnion(Session session, SortAndSlice sortAndSlice) {
if (sortAndSlice.index != null) {
mainIndex = sortAndSlice.index;
ArraySort.sort(dataTable, size, this);
reset();
}
}
public void add(Object[] data) {
ensureCapacity();
dataTable[size] = data;
size++;
if (rowMap != null) {
rowMap.put(data, data);
}
if (idMap != null) {
Long id = (Long) data[visibleColumnCount];
idMap.put(id.longValue(), data);
}
}
public boolean addRow(Row row) {
throw Error.runtimeError(ErrorCode.U_S0500, "RowSetNavigatorData");
}
public void update(Object[] oldData, Object[] newData) {
}
void addAdjusted(Object[] data, int[] columnMap) {
data = projectData(data, columnMap);
add(data);
}
void insertAdjusted(Object[] data, int[] columnMap) {
projectData(data, columnMap);
insert(data);
}
Object[] projectData(Object[] data, int[] columnMap) {
if (columnMap == null) {
data = (Object[]) ArrayUtil.resizeArrayIfDifferent(data,
visibleColumnCount);
} else {
Object[] newData = new Object[visibleColumnCount];
ArrayUtil.projectRow(data, columnMap, newData);
data = newData;
}
return data;
}
void insert(Object[] data) {
ensureCapacity();
System.arraycopy(dataTable, currentPos, dataTable, currentPos + 1,
size - currentPos);
dataTable[currentPos] = data;
size++;
}
public void release() {
this.dataTable = emptyTable;
this.size = 0;
reset();
isClosed = true;
}
public void clear() {
this.dataTable = emptyTable;
this.size = 0;
reset();
}
public boolean absolute(int position) {
return super.absolute(position);
}
public Object[] getCurrent() {
if (currentPos < 0 || currentPos >= size) {
return null;
}
return dataTable[currentPos];
}
public Row getCurrentRow() {
throw Error.runtimeError(ErrorCode.U_S0500, "RowSetNavigatorData");
}
public Object[] getNextRowData() {
return next() ? getCurrent()
: null;
}
public boolean next() {
return super.next();
}
public void removeCurrent() {
System.arraycopy(dataTable, currentPos + 1, dataTable, currentPos,
size - currentPos - 1);
dataTable[size - 1] = null;
currentPos--;
size--;
}
public void reset() {
super.reset();
}
public boolean isMemory() {
return true;
}
public void read(RowInputInterface in, ResultMetaData meta) {}
public void write(RowOutputInterface out, ResultMetaData meta) {
reset();
out.writeLong(id);
out.writeInt(size);
out.writeInt(0);
out.writeInt(size);
while (next()) {
Object[] data = getCurrent();
out.writeData(meta.getExtendedColumnCount(), meta.columnTypes,
data, null, null);
}
reset();
}
public Object[] getData(long rowId) {
return (Object[]) idMap.get(rowId);
}
public void copy(RowIterator other, int[] rightColumnIndexes) {
while (other.next()) {
Object[] currentData = other.getCurrent();
addAdjusted(currentData, rightColumnIndexes);
}
}
public void union(Session session, RowSetNavigatorData other) {
Object[] currentData;
removeDuplicates(session);
other.removeDuplicates(session);
mainIndex = fullIndex;
while (other.next()) {
currentData = other.getCurrent();
int position = ArraySort.searchFirst(dataTable, 0, size,
currentData, this);
if (position < 0) {
position = -position - 1;
currentPos = position;
insert(currentData);
}
}
reset();
}
public void unionAll(Session session, RowSetNavigatorData other) {
mainIndex = fullIndex;
other.reset();
while (other.next()) {
Object[] currentData = other.getCurrent();
add(currentData);
}
reset();
}
public void intersect(Session session, RowSetNavigatorData other) {
removeDuplicates(session);
other.sortFull(session);
while (next()) {
Object[] currentData = getCurrent();
boolean hasRow = other.containsRow(currentData);
if (!hasRow) {
removeCurrent();
}
}
reset();
}
public void intersectAll(Session session, RowSetNavigatorData other) {
Object[] compareData = null;
RowIterator it;
Object[] otherData = null;
sortFull(session);
other.sortFull(session);
it = fullIndex.emptyIterator();
while (next()) {
Object[] currentData = getCurrent();
boolean newGroup =
compareData == null
|| fullIndex.compareRowNonUnique(
session, currentData, compareData,
visibleColumnCount) != 0;
if (newGroup) {
compareData = currentData;
it = other.findFirstRow(currentData);
}
if (it.next()) {
otherData = it.getCurrent();
if (fullIndex.compareRowNonUnique(
session, currentData, otherData,
visibleColumnCount) == 0) {
continue;
}
}
removeCurrent();
}
reset();
}
public void except(Session session, RowSetNavigatorData other) {
removeDuplicates(session);
other.sortFull(session);
while (next()) {
Object[] currentData = getCurrent();
boolean hasRow = other.containsRow(currentData);
if (hasRow) {
removeCurrent();
}
}
reset();
}
public void exceptAll(Session session, RowSetNavigatorData other) {
Object[] compareData = null;
RowIterator it;
Object[] otherData = null;
sortFull(session);
other.sortFull(session);
it = fullIndex.emptyIterator();
while (next()) {
Object[] currentData = getCurrent();
boolean newGroup =
compareData == null
|| fullIndex.compareRowNonUnique(
session, currentData, compareData,
fullIndex.getColumnCount()) != 0;
if (newGroup) {
compareData = currentData;
it = other.findFirstRow(currentData);
}
if (it.next()) {
otherData = it.getCurrent();
if (fullIndex.compareRowNonUnique(
session, currentData, otherData,
fullIndex.getColumnCount()) == 0) {
removeCurrent();
}
}
}
reset();
}
public boolean hasUniqueNotNullRows(Session session) {
sortFull(session);
reset();
Object[] lastRowData = null;
while (next()) {
Object[] currentData = getCurrent();
if (hasNull(currentData)) {
continue;
}
if (lastRowData != null
&& fullIndex.compareRow(session, lastRowData, currentData)
== 0) {
return false;
} else {
lastRowData = currentData;
}
}
return true;
}
public void removeDuplicates(Session session) {
sortFull(session);
reset();
int lastRowPos = -1;
Object[] lastRowData = null;
while (next()) {
Object[] currentData = getCurrent();
if (lastRowData == null) {
lastRowPos = currentPos;
lastRowData = currentData;
continue;
}
if (fullIndex.compareRow(session, lastRowData, currentData) != 0) {
lastRowPos++;
lastRowData = currentData;
dataTable[lastRowPos] = currentData;
}
}
for (int i = lastRowPos + 1; i < size; i++) {
dataTable[i] = null;
}
super.size = lastRowPos + 1;
reset();
}
public void trim(int limitstart, int limitcount) {
if (size == 0) {
return;
}
if (limitstart >= size) {
clear();
return;
}
if (limitstart != 0) {
reset();
for (int i = 0; i < limitstart; i++) {
next();
removeCurrent();
}
}
if (limitcount >= size) {
return;
}
reset();
for (int i = 0; i < limitcount; i++) {
next();
}
while (next()) {
removeCurrent();
}
reset();
}
boolean hasNull(Object[] data) {
for (int i = 0; i < visibleColumnCount; i++) {
if (data[i] == null) {
return true;
}
}
return false;
}
public Object[] getGroupData(Object[] data) {
if (isSimpleAggregate) {
if (simpleAggregateData == null) {
simpleAggregateData = data;
return null;
}
return simpleAggregateData;
}
return rowMap.get(data);
}
boolean containsRow(Object[] data) {
int position = ArraySort.searchFirst(dataTable, 0, size, data, this);
return position >= 0;
}
RowIterator findFirstRow(Object[] data) {
int position = ArraySort.searchFirst(dataTable, 0, size, data, this);
if (position < 0) {
position = size;
} else {
position--;
}
return new DataIterator(position);
}
void getBlock(int offset) {
}
private void setCapacity(int newSize) {
if (size > dataTable.length) {
dataTable = new Object[newSize][];
}
}
private void ensureCapacity() {
if (size == dataTable.length) {
int newSize = size == 0 ? 4
: size * 2;
Object[][] newTable = new Object[newSize][];
System.arraycopy(dataTable, 0, newTable, 0, size);
dataTable = newTable;
}
}
void implement() {
throw Error.error(ErrorCode.U_S0500, "RSND");
}
class DataIterator implements RowIterator {
int pos;
DataIterator(int position) {
pos = position;
}
public Object getField(int col) {
if (pos < size) {
return dataTable[pos][col];
} else {
return null;
}
}
public boolean next() {
if (pos < size - 1) {
pos++;
return true;
}
return false;
}
public Row getCurrentRow() {
return null;
}
public Object[] getCurrent() {
if (pos < size) {
return dataTable[pos];
} else {
return null;
}
}
public void removeCurrent() {}
public void release() {}
public long getRowId() {
return 0L;
}
}
public int compare(Object[] a, Object[] b) {
return mainIndex.compareRow((Session) session, a, b);
}
}