package edu.washington.escience.myria.storage;
import com.google.common.base.Preconditions;
import edu.washington.escience.myria.Schema;
import edu.washington.escience.myria.Type;
import edu.washington.escience.myria.column.builder.ColumnBuilder;
/**
* Utility functions for dealing with tuples.
*/
public final class TupleUtils {
/** Utility class cannot be instantiated. */
private TupleUtils() {}
/**
* Copy the specified from a {@link ReadableColumn} to a {@link AppendableTable}.
*
* @param from the source of the value
* @param fromRow the row of the source value
* @param to the destination of the value
*/
public static void copyValue(
final ReadableColumn from, final int fromRow, final ColumnBuilder<?> to) {
Type t = from.getType();
switch (t) {
case BOOLEAN_TYPE:
to.appendBoolean(from.getBoolean(fromRow));
break;
case DATETIME_TYPE:
to.appendDateTime(from.getDateTime(fromRow));
break;
case DOUBLE_TYPE:
to.appendDouble(from.getDouble(fromRow));
break;
case FLOAT_TYPE:
to.appendFloat(from.getFloat(fromRow));
break;
case INT_TYPE:
to.appendInt(from.getInt(fromRow));
break;
case LONG_TYPE:
to.appendLong(from.getLong(fromRow));
break;
case STRING_TYPE:
to.appendString(from.getString(fromRow));
break;
case BLOB_TYPE:
to.appendBlob(from.getBlob(fromRow));
break;
}
}
/**
* Copy the specified from a {@link ReadableColumn} to a {@link AppendableTable}.
*
* @param from the source of the value
* @param fromRow the row of the source value
* @param to the destination of the value
* @param toColumn the destination column
*/
public static void copyValue(
final ReadableColumn from, final int fromRow, final AppendableTable to, final int toColumn) {
Type t = from.getType();
switch (t) {
case BOOLEAN_TYPE:
to.putBoolean(toColumn, from.getBoolean(fromRow));
break;
case DATETIME_TYPE:
to.putDateTime(toColumn, from.getDateTime(fromRow));
break;
case DOUBLE_TYPE:
to.putDouble(toColumn, from.getDouble(fromRow));
break;
case FLOAT_TYPE:
to.putFloat(toColumn, from.getFloat(fromRow));
break;
case INT_TYPE:
to.putInt(toColumn, from.getInt(fromRow));
break;
case LONG_TYPE:
to.putLong(toColumn, from.getLong(fromRow));
break;
case STRING_TYPE:
to.putString(toColumn, from.getString(fromRow));
break;
case BLOB_TYPE:
to.putBlob(toColumn, from.getBlob(fromRow));
break;
}
}
/**
* Copy the specified from a {@link ReadableTable} to a {@link ColumnBuilder}.
*
* @param from the source of the value
* @param fromColumn the column of the source value
* @param fromRow the row of the source value
* @param to the destination of the value
* @param toColumn the destination column
*/
public static void copyValue(
final ReadableTable from,
final int fromColumn,
final int fromRow,
final ColumnBuilder<?> to,
final int toColumn) {
Type t = from.getSchema().getColumnType(fromColumn);
switch (t) {
case BOOLEAN_TYPE:
to.appendBoolean(from.getBoolean(fromColumn, fromRow));
break;
case DATETIME_TYPE:
to.appendDateTime(from.getDateTime(fromColumn, fromRow));
break;
case DOUBLE_TYPE:
to.appendDouble(from.getDouble(fromColumn, fromRow));
break;
case FLOAT_TYPE:
to.appendFloat(from.getFloat(fromColumn, fromRow));
break;
case INT_TYPE:
to.appendInt(from.getInt(fromColumn, fromRow));
break;
case LONG_TYPE:
to.appendLong(from.getLong(fromColumn, fromRow));
break;
case STRING_TYPE:
to.appendString(from.getString(fromColumn, fromRow));
break;
case BLOB_TYPE:
to.appendBlob(from.getBlob(fromColumn, fromRow));
break;
}
}
/**
* Copy the specified from a {@link ReadableTable} to a {@link AppendableTable}.
*
* @param from the source of the value
* @param fromColumn the column of the source value
* @param fromRow the row of the source value
* @param to the destination of the value
* @param toColumn the destination column
*/
public static void copyValue(
final ReadableTable from,
final int fromColumn,
final int fromRow,
final AppendableTable to,
final int toColumn) {
Type t = from.getSchema().getColumnType(fromColumn);
switch (t) {
case BOOLEAN_TYPE:
to.putBoolean(toColumn, from.getBoolean(fromColumn, fromRow));
break;
case DATETIME_TYPE:
to.putDateTime(toColumn, from.getDateTime(fromColumn, fromRow));
break;
case DOUBLE_TYPE:
to.putDouble(toColumn, from.getDouble(fromColumn, fromRow));
break;
case FLOAT_TYPE:
to.putFloat(toColumn, from.getFloat(fromColumn, fromRow));
break;
case INT_TYPE:
to.putInt(toColumn, from.getInt(fromColumn, fromRow));
break;
case LONG_TYPE:
to.putLong(toColumn, from.getLong(fromColumn, fromRow));
break;
case STRING_TYPE:
to.putString(toColumn, from.getString(fromColumn, fromRow));
break;
case BLOB_TYPE:
to.putBlob(toColumn, from.getBlob(fromColumn, fromRow));
break;
}
}
/**
* @param table1 the table that cell 1 is in
* @param column1 column number of cell 1
* @param row1 row number of cell 1
* @param table2 the table that cell 2 is in
* @param column2 column number of cell 2
* @param row2 row number of cell 2
* @return comparison result
*/
public static int cellCompare(
final ReadableTable table1,
final int column1,
final int row1,
final ReadableTable table2,
final int column2,
final int row2) {
Preconditions.checkArgument(
table1.getSchema().getColumnType(column1).equals(table2.getSchema().getColumnType(column2)),
"The types of comparing cells are not matched.");
switch (table1.getSchema().getColumnType(column1)) {
case BOOLEAN_TYPE:
return Type.compareRaw(table1.getBoolean(column1, row1), table2.getBoolean(column2, row2));
case DOUBLE_TYPE:
return Type.compareRaw(table1.getDouble(column1, row1), table2.getDouble(column2, row2));
case FLOAT_TYPE:
return Type.compareRaw(table1.getFloat(column1, row1), table2.getFloat(column2, row2));
case INT_TYPE:
return Type.compareRaw(table1.getInt(column1, row1), table2.getInt(column2, row2));
case LONG_TYPE:
return Type.compareRaw(table1.getLong(column1, row1), table2.getLong(column2, row2));
case STRING_TYPE:
return Type.compareRaw(table1.getString(column1, row1), table2.getString(column2, row2));
case DATETIME_TYPE:
return Type.compareRaw(
table1.getDateTime(column1, row1), table2.getDateTime(column2, row2));
case BLOB_TYPE:
return Type.compareRaw(table1.getBlob(column1, row1), table2.getBlob(column2, row2));
}
throw new IllegalStateException("Invalid type.");
}
/**
* Compares a whole tuple with a tuple from another batch. The columns from the two compare indexes are compared in
* order.
*
* @param table1 the first table
* @param compareIndexes1 the columns from this table that should be compared with the column of the other table
* @param rowIdx1 row in this table
* @param table2 other table
* @param compareIndexes2 the columns from the other TB that should be compared with the column of this table
* @param rowIdx2 row in other table
* @param ascending true if the column is ordered ascending
* @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater
* than the second
*/
public static int tupleCompare(
final ReadableTable table1,
final int[] compareIndexes1,
final int rowIdx1,
final ReadableTable table2,
final int[] compareIndexes2,
final int rowIdx2,
final boolean[] ascending) {
for (int i = 0; i < compareIndexes1.length; i++) {
int compared =
TupleUtils.cellCompare(
table1, compareIndexes1[i], rowIdx1, table2, compareIndexes2[i], rowIdx2);
if (compared != 0) {
if (!ascending[i]) {
return -compared;
} else {
return compared;
}
}
}
return 0;
}
/**
* Same as {@link #tupleCompare(ReadableTable, int[], int, ReadableTable, int[], int, boolean[])} but comparison
* within the same table.
*
* @param table the table that compared cells is in
* @param columnCompareIndexes the columns from this TB that should be compared with the column of the other table
* @param rowIdx row in this table
* @param rowIdx2 row in this table that should be compared to the first one
* @param ascending true if the column is ordered ascending
* @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater
* than the second
*/
public static int tupleCompare(
final ReadableTable table,
final int[] columnCompareIndexes,
final int rowIdx,
final int rowIdx2,
final boolean[] ascending) {
return tupleCompare(
table, columnCompareIndexes, rowIdx, table, columnCompareIndexes, rowIdx2, ascending);
}
/**
* Check if two tuples are equal on given columns.
*
* @param table1 the table holding the first tuple
* @param compareColumns1 the comparing list of columns of the first tuple
* @param row1 row index of the first tuple
* @param table2 the table holding the second tuple
* @param compareColumns2 the comparing list of columns of the second tuple
* @param row2 row index of the second tuple
*
* @return true if equals.
*/
public static boolean tupleEquals(
final ReadableTable table1,
final int[] compareColumns1,
final int row1,
final ReadableTable table2,
final int[] compareColumns2,
final int row2) {
if (compareColumns1.length != compareColumns2.length) {
return false;
}
for (int i = 0; i < compareColumns1.length; ++i) {
switch (table1.getSchema().getColumnType(compareColumns1[i])) {
case BOOLEAN_TYPE:
if (table1.getBoolean(compareColumns1[i], row1)
!= table2.getBoolean(compareColumns2[i], row2)) {
return false;
}
break;
case DOUBLE_TYPE:
if (table1.getDouble(compareColumns1[i], row1)
!= table2.getDouble(compareColumns2[i], row2)) {
return false;
}
break;
case FLOAT_TYPE:
if (table1.getFloat(compareColumns1[i], row1)
!= table2.getFloat(compareColumns2[i], row2)) {
return false;
}
break;
case INT_TYPE:
if (table1.getInt(compareColumns1[i], row1) != table2.getInt(compareColumns2[i], row2)) {
return false;
}
break;
case LONG_TYPE:
if (table1.getLong(compareColumns1[i], row1)
!= table2.getLong(compareColumns2[i], row2)) {
return false;
}
break;
case STRING_TYPE:
if (!table1
.getString(compareColumns1[i], row1)
.equals(table2.getString(compareColumns2[i], row2))) {
return false;
}
break;
case DATETIME_TYPE:
if (!table1
.getDateTime(compareColumns1[i], row1)
.equals(table2.getDateTime(compareColumns2[i], row2))) {
return false;
}
break;
case BLOB_TYPE:
if (!table1
.getBlob(compareColumns1[i], row1)
.equals(table2.getBlob(compareColumns2[i], row2))) {
return false;
}
}
}
return true;
}
/**
* Compare a tuple against another tuple on all columns.
*
* @param table1 the table holding the comparing tuple
* @param row1 row index of the tuple in table1 to compare
* @param table2 the table holding the tuple to compare against
* @param row2 row index of the tuple in table2 to compare against
* @return true if equals
*/
public static boolean tupleEquals(
final ReadableTable table1, final int row1, final ReadableTable table2, final int row2) {
if (table1.numColumns() != table2.numColumns()) {
return false;
}
for (int i = 0; i < table1.numColumns(); ++i) {
switch (table1.getSchema().getColumnType(i)) {
case BOOLEAN_TYPE:
if (table1.getBoolean(i, row1) != table2.getBoolean(i, row2)) {
return false;
}
break;
case DOUBLE_TYPE:
if (table1.getDouble(i, row1) != table2.getDouble(i, row2)) {
return false;
}
break;
case FLOAT_TYPE:
if (table1.getFloat(i, row1) != table2.getFloat(i, row2)) {
return false;
}
break;
case INT_TYPE:
if (table1.getInt(i, row1) != table2.getInt(i, row2)) {
return false;
}
break;
case LONG_TYPE:
if (table1.getLong(i, row1) != table2.getLong(i, row2)) {
return false;
}
break;
case STRING_TYPE:
if (!table1.getString(i, row1).equals(table2.getString(i, row2))) {
return false;
}
break;
case DATETIME_TYPE:
if (!table1.getDateTime(i, row1).equals(table2.getDateTime(i, row2))) {
return false;
}
break;
case BLOB_TYPE:
if (!table1.getBlob(i, row1).equals(table2.getBlob(i, row2))) {
return false;
}
break;
}
}
return true;
}
/**
* Compare a tuple on given columns with all columns of another tuple.
*
* @param table1 the table holding comparing tuple
* @param compareColumns the columns of the comparing tuple in table1
* @param row1 row index of the comparing tuple in table1
* @param table2 the table holding the tuple to compare with
* @param index row index of the tuple to compare with in table2
*
* @return true if equals
*/
public static boolean tupleEquals(
final ReadableTable table1,
final int[] compareColumns,
final int row1,
final ReadableTable table2,
final int index) {
if (compareColumns.length != table2.numColumns()) {
return false;
}
for (int i = 0; i < compareColumns.length; ++i) {
switch (table1.getSchema().getColumnType(compareColumns[i])) {
case BOOLEAN_TYPE:
if (table1.getBoolean(compareColumns[i], row1) != table2.getBoolean(i, index)) {
return false;
}
break;
case DOUBLE_TYPE:
if (table1.getDouble(compareColumns[i], row1) != table2.getDouble(i, index)) {
return false;
}
break;
case FLOAT_TYPE:
if (table1.getFloat(compareColumns[i], row1) != table2.getFloat(i, index)) {
return false;
}
break;
case INT_TYPE:
if (table1.getInt(compareColumns[i], row1) != table2.getInt(i, index)) {
return false;
}
break;
case LONG_TYPE:
if (table1.getLong(compareColumns[i], row1) != table2.getLong(i, index)) {
return false;
}
break;
case STRING_TYPE:
if (!table1.getString(compareColumns[i], row1).equals(table2.getString(i, index))) {
return false;
}
break;
case DATETIME_TYPE:
if (!table1.getDateTime(compareColumns[i], row1).equals(table2.getDateTime(i, index))) {
return false;
}
break;
case BLOB_TYPE:
if (!table1.getBlob(compareColumns[i], row1).equals(table2.getBlob(i, index))) {
return false;
}
break;
}
}
return true;
}
/**
* batch size for tuple batch depending on schema.
* @param schema of tuplebatch
* @return batchsize.
*/
public static int getBatchSize(Schema schema) {
int batchSize = 1000 * 10;
if (schema.getColumnTypes().indexOf(Type.BLOB_TYPE) >= 0) batchSize = 1;
return batchSize;
}
/**
* batch size for column depending upon type.
* @param type of column.
* @return batchsize.
*/
public static int getBatchSize(Type type) {
int batchSize = 1000 * 10;
if (type == Type.BLOB_TYPE) batchSize = 1;
return batchSize;
}
}