com.clickzetta.platform.operator.PartialRow Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of clickzetta-java Show documentation
Show all versions of clickzetta-java Show documentation
The java SDK for clickzetta's Lakehouse
package com.clickzetta.platform.operator;
import com.clickzetta.platform.common.ColumnSchema;
import com.clickzetta.platform.common.ColumnTypeAttributes;
import com.clickzetta.platform.common.Schema;
import com.clickzetta.platform.common.Type;
import com.clickzetta.platform.util.DateUtil;
import com.clickzetta.platform.util.DecimalUtil;
import com.clickzetta.platform.util.StringUtil;
import com.clickzetta.platform.util.TimestampUtil;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.*;
public class PartialRow {
private final Schema schema;
private final List varLengthData;
private final byte[] rowAlloc;
private final BitSet columnsBitSet;
private final BitSet nullsBitSet;
private boolean frozen = false;
public static final byte[] EMPTY_ARRAY = new byte[0];
public int maxChangedIndex;
public PartialRow(Schema schema) {
this.schema = schema;
this.columnsBitSet = new BitSet(this.schema.getColumnCount());
this.nullsBitSet = schema.hasNullableColumns() ?
new BitSet(this.schema.getColumnCount()) : null;
this.rowAlloc = new byte[schema.getRowSize()];
this.varLengthData = Arrays.asList(new ByteBuffer[this.schema.getVarLengthColumnCount()]);
// mark max changed index.
this.maxChangedIndex = -1;
}
public PartialRow(PartialRow row) {
this.schema = row.schema;
this.maxChangedIndex = row.maxChangedIndex;
this.varLengthData = Lists.newArrayListWithCapacity(row.varLengthData.size());
for (ByteBuffer data: row.varLengthData) {
if (data == null) {
this.varLengthData.add(null);
} else {
data.reset();
// Deep copy the ByteBuffer.
ByteBuffer clone = ByteBuffer.allocate(data.remaining());
clone.put(data);
clone.flip();
clone.mark();
this.varLengthData.add(clone);
}
}
this.rowAlloc = row.rowAlloc.clone();
this.columnsBitSet = (BitSet) row.columnsBitSet.clone();
this.nullsBitSet = row.nullsBitSet == null ? null : (BitSet) row.nullsBitSet.clone();
}
public void addBoolean(int columnIndex, boolean val) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.BOOL);
rowAlloc[getPositionInRowAllocAndSetBitSet(columnIndex)] = (byte) (val ? 1 : 0);
}
public void addBoolean(String columnName, boolean val) {
addBoolean(schema.getColumnIndex(columnName), val);
}
public boolean getBoolean(String columnName) {
return getBoolean(this.schema.getColumnIndex(columnName));
}
public boolean getBoolean(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.BOOL);
checkValue(columnIndex);
byte b = rowAlloc[schema.getColumnOffset(columnIndex)];
return b == 1;
}
public void addByte(int columnIndex, byte val) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.INT8);
rowAlloc[getPositionInRowAllocAndSetBitSet(columnIndex)] = val;
}
public void addByte(String columnName, byte val) {
addByte(schema.getColumnIndex(columnName), val);
}
public byte getByte(String columnName) {
return getByte(this.schema.getColumnIndex(columnName));
}
public byte getByte(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.INT8);
checkValue(columnIndex);
return rowAlloc[schema.getColumnOffset(columnIndex)];
}
public void addShort(int columnIndex, short val) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.INT16);
Bytes.setShort(rowAlloc, val, getPositionInRowAllocAndSetBitSet(columnIndex));
}
public void addShort(String columnName, short val) {
addShort(schema.getColumnIndex(columnName), val);
}
public short getShort(String columnName) {
return getShort(this.schema.getColumnIndex(columnName));
}
public short getShort(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.INT16);
checkValue(columnIndex);
return Bytes.getShort(rowAlloc, schema.getColumnOffset(columnIndex));
}
public void addInt(int columnIndex, int val) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.INT32);
Bytes.setInt(rowAlloc, val, getPositionInRowAllocAndSetBitSet(columnIndex));
}
public void addInt(String columnName, int val) {
addInt(schema.getColumnIndex(columnName), val);
}
public int getInt(String columnName) {
return getInt(this.schema.getColumnIndex(columnName));
}
public int getInt(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.INT32);
checkValue(columnIndex);
return Bytes.getInt(rowAlloc, schema.getColumnOffset(columnIndex));
}
public void addLong(int columnIndex, long val) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.INT64, Type.UNIXTIME_MICROS);
Bytes.setLong(rowAlloc, val, getPositionInRowAllocAndSetBitSet(columnIndex));
}
public void addLong(String columnName, long val) {
addLong(schema.getColumnIndex(columnName), val);
}
public long getLong(String columnName) {
return getLong(this.schema.getColumnIndex(columnName));
}
public long getLong(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.INT64, Type.UNIXTIME_MICROS);
checkColumnExists(schema.getColumnByIndex(columnIndex));
checkValue(columnIndex);
return Bytes.getLong(rowAlloc, schema.getColumnOffset(columnIndex));
}
public void addFloat(int columnIndex, float val) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.FLOAT);
Bytes.setFloat(rowAlloc, val, getPositionInRowAllocAndSetBitSet(columnIndex));
}
public void addFloat(String columnName, float val) {
addFloat(schema.getColumnIndex(columnName), val);
}
public float getFloat(String columnName) {
return getFloat(this.schema.getColumnIndex(columnName));
}
public float getFloat(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.FLOAT);
checkValue(columnIndex);
return Bytes.getFloat(rowAlloc, schema.getColumnOffset(columnIndex));
}
public void addDouble(int columnIndex, double val) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.DOUBLE);
Bytes.setDouble(rowAlloc, val, getPositionInRowAllocAndSetBitSet(columnIndex));
}
public void addDouble(String columnName, double val) {
addDouble(schema.getColumnIndex(columnName), val);
}
public double getDouble(String columnName) {
return getDouble(this.schema.getColumnIndex(columnName));
}
public double getDouble(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.DOUBLE);
checkValue(columnIndex);
return Bytes.getDouble(rowAlloc, schema.getColumnOffset(columnIndex));
}
public void addDecimal(int columnIndex, BigDecimal val) {
checkNotFrozen();
ColumnSchema column = schema.getColumnByIndex(columnIndex);
ColumnTypeAttributes typeAttributes = column.getTypeAttributes();
checkColumn(column, Type.DECIMAL);
BigDecimal coercedVal = DecimalUtil.coerce(val,typeAttributes.getPrecision(),
typeAttributes.getScale());
Bytes.setBigDecimal(rowAlloc, coercedVal, typeAttributes.getPrecision(),
getPositionInRowAllocAndSetBitSet(columnIndex));
}
public void addDecimal(String columnName, BigDecimal val) {
addDecimal(schema.getColumnIndex(columnName), val);
}
public BigDecimal getDecimal(String columnName) {
return getDecimal(this.schema.getColumnIndex(columnName));
}
public BigDecimal getDecimal(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.DECIMAL);
checkColumnExists(schema.getColumnByIndex(columnIndex));
checkValue(columnIndex);
ColumnSchema column = schema.getColumnByIndex(columnIndex);
ColumnTypeAttributes typeAttributes = column.getTypeAttributes();
return Bytes.getDecimal(rowAlloc, schema.getColumnOffset(columnIndex),
typeAttributes.getPrecision(), typeAttributes.getScale());
}
public void addTimestamp(int columnIndex, Timestamp val) {
checkNotFrozen();
ColumnSchema column = schema.getColumnByIndex(columnIndex);
checkColumn(column, Type.UNIXTIME_MICROS);
long micros = TimestampUtil.timestampToMicros(val);
Bytes.setLong(rowAlloc, micros, getPositionInRowAllocAndSetBitSet(columnIndex));
}
public void addTimestamp(String columnName, Timestamp val) {
addTimestamp(schema.getColumnIndex(columnName), val);
}
public Timestamp getTimestamp(String columnName) {
return getTimestamp(this.schema.getColumnIndex(columnName));
}
public Timestamp getTimestamp(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.UNIXTIME_MICROS);
checkColumnExists(schema.getColumnByIndex(columnIndex));
checkValue(columnIndex);
long micros = Bytes.getLong(rowAlloc, schema.getColumnOffset(columnIndex));
return TimestampUtil.microsToTimestamp(micros);
}
public void addDate(int columnIndex, Date val) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.DATE);
int days = DateUtil.sqlDateToEpochDays(val);
Bytes.setInt(rowAlloc, days, getPositionInRowAllocAndSetBitSet(columnIndex));
}
public void addDate(String columnName, Date val) {
addDate(schema.getColumnIndex(columnName), val);
}
public Date getDate(String columnName) {
return getDate(this.schema.getColumnIndex(columnName));
}
public Date getDate(int columnIndex) {
checkColumnExists(schema.getColumnByIndex(columnIndex));
checkColumn(schema.getColumnByIndex(columnIndex), Type.DATE);
checkValue(columnIndex);
int days = Bytes.getInt(rowAlloc, schema.getColumnOffset(columnIndex));
return DateUtil.epochDaysToSqlDate(days);
}
public void addString(int columnIndex, String val) {
addStringUtf8(columnIndex, Bytes.fromString(val));
}
public void addString(String columnName, String val) {
addStringUtf8(columnName, Bytes.fromString(val));
}
public void addVarchar(int columnIndex, String val) {
ColumnSchema column = schema.getColumnByIndex(columnIndex);
checkColumn(column, Type.VARCHAR);
checkNotFrozen();
int length = column.getTypeAttributes().getLength();
if (length < val.length()) {
val = val.substring(0, length);
}
byte[] bytes = Bytes.fromString(val);
addVarLengthData(columnIndex, bytes);
}
public void addVarchar(String columnName, String val) {
addVarchar(schema.getColumnIndex(columnName), val);
}
public String getString(String columnName) {
return getString(this.schema.getColumnIndex(columnName));
}
public String getString(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.STRING);
checkValue(columnIndex);
return new String(getVarLengthData(columnIndex).array(), StandardCharsets.UTF_8);
}
public String getVarchar(String columnName) {
return getVarchar(this.schema.getColumnIndex(columnName));
}
public String getVarchar(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.VARCHAR);
checkValue(columnIndex);
return new String(getVarLengthData(columnIndex).array(), StandardCharsets.UTF_8);
}
public void addStringUtf8(int columnIndex, byte[] val) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.STRING);
addVarLengthData(columnIndex, val);
}
public void addStringUtf8(String columnName, byte[] val) {
addStringUtf8(schema.getColumnIndex(columnName), val);
}
public void addBinary(int columnIndex, byte[] val) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.BINARY);
addVarLengthData(columnIndex, val);
}
public void addBinary(int columnIndex, ByteBuffer value) {
checkNotFrozen();
checkColumn(schema.getColumnByIndex(columnIndex), Type.BINARY);
addVarLengthData(columnIndex, value);
}
public void addBinary(String columnName, byte[] val) {
addBinary(schema.getColumnIndex(columnName), val);
}
public void addBinary(String columnName, ByteBuffer value) {
addBinary(schema.getColumnIndex(columnName), value);
}
public byte[] getBinaryCopy(String columnName) {
return getBinaryCopy(this.schema.getColumnIndex(columnName));
}
public byte[] getBinaryCopy(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.BINARY);
checkValue(columnIndex);
byte[] data = getVarLengthData(columnIndex).array();
byte[] ret = new byte[data.length];
System.arraycopy(data, 0, ret, 0, data.length);
return ret;
}
public ByteBuffer getBinary(String columnName) {
return getBinary(this.schema.getColumnIndex(columnName));
}
public ByteBuffer getBinary(int columnIndex) {
checkColumn(schema.getColumnByIndex(columnIndex), Type.BINARY);
checkValue(columnIndex);
return getVarLengthData(columnIndex);
}
private void addVarLengthData(int columnIndex, byte[] val) {
addVarLengthData(columnIndex, ByteBuffer.wrap(val));
}
private void addVarLengthData(int columnIndex, ByteBuffer val) {
ByteBuffer duplicate = val.duplicate();
duplicate.mark();
varLengthData.set(this.schema.getVarLengthColumnOffsetToAllVarCharColumns(columnIndex), duplicate);
getPositionInRowAllocAndSetBitSet(columnIndex);
}
List getVarLengthData() {
return varLengthData;
}
private ByteBuffer getVarLengthData(int columnIndex) {
return varLengthData.get(this.schema.getVarLengthColumnOffsetToAllVarCharColumns(columnIndex)).duplicate();
}
public void setNull(String columnName) {
setNull(this.schema.getColumnIndex(columnName));
}
public void setNull(int columnIndex) {
assert nullsBitSet != null;
ColumnSchema column = schema.getColumnByIndex(columnIndex);
checkNotFrozen();
checkColumnExists(column);
if (!column.isNullable()) {
throw new IllegalArgumentException(column.getName() + " cannot be set to null");
}
columnsBitSet.set(columnIndex);
nullsBitSet.set(columnIndex);
}
public boolean isNull(String columnName) {
return isNull(this.schema.getColumnIndex(columnName));
}
public boolean isNull(int columnIndex) {
checkColumnExists(schema.getColumnByIndex(columnIndex));
return schema.getColumnByIndex(columnIndex).isNullable() && isSetToNull(columnIndex);
}
public void addObject(String columnName, Object val) {
addObject(this.schema.getColumnIndex(columnName), val);
}
public void addObject(int columnIndex, Object val) {
checkNotFrozen();
ColumnSchema col = schema.getColumnByIndex(columnIndex);
checkColumnExists(col);
maxChangedIndex = Math.max(maxChangedIndex, columnIndex);
try {
if (val == null) {
setNull(columnIndex);
return;
}
switch (col.getType()) {
case BOOL:
addBoolean(columnIndex, (Boolean) val);
break;
case INT8:
addByte(columnIndex, (Byte) val);
break;
case INT16:
addShort(columnIndex, (Short) val);
break;
case INT32:
addInt(columnIndex, (Integer) val);
break;
case INT64:
addLong(columnIndex, (Long) val);
break;
case UNIXTIME_MICROS:
if (val instanceof Timestamp) {
addTimestamp(columnIndex, (Timestamp) val);
} else {
addLong(columnIndex, (Long) val);
}
break;
case FLOAT:
addFloat(columnIndex, (Float) val);
break;
case DOUBLE:
addDouble(columnIndex, (Double) val);
break;
case STRING:
addString(columnIndex, (String) val);
break;
case VARCHAR:
addVarchar(columnIndex, (String) val);
break;
case DATE:
if (val instanceof Integer) {
val = DateUtil.epochDaysToSqlDate((int) val);
}
addDate(columnIndex, (Date) val);
break;
case BINARY:
if (val instanceof byte[]) {
addBinary(columnIndex, (byte[]) val);
} else {
addBinary(columnIndex, (ByteBuffer) val);
}
break;
case DECIMAL:
addDecimal(columnIndex, (BigDecimal) val);
break;
default:
throw new IllegalArgumentException("Unsupported column type: " + col.getType());
}
} catch (ClassCastException e) {
throw new IllegalArgumentException(
"Value type does not match column type " + col.getType() +
" for column " + col.getName());
}
}
public Object getObject(String columnName) {
return getObject(this.schema.getColumnIndex(columnName));
}
public Object getObject(int columnIndex) {
checkColumnExists(schema.getColumnByIndex(columnIndex));
if (isNull(columnIndex) || !isSet(columnIndex)) {
return null;
}
Type type = schema.getColumnByIndex(columnIndex).getType();
switch (type) {
case BOOL: return getBoolean(columnIndex);
case INT8: return getByte(columnIndex);
case INT16: return getShort(columnIndex);
case INT32: return getInt(columnIndex);
case INT64: return getLong(columnIndex);
case DATE: return getDate(columnIndex);
case UNIXTIME_MICROS: return getTimestamp(columnIndex);
case FLOAT: return getFloat(columnIndex);
case DOUBLE: return getDouble(columnIndex);
case VARCHAR: return getVarchar(columnIndex);
case STRING: return getString(columnIndex);
case BINARY: return getBinaryCopy(columnIndex);
case DECIMAL: return getDecimal(columnIndex);
default: throw new UnsupportedOperationException("Unsupported type: " + type);
}
}
private void checkColumn(ColumnSchema column, Type... types) {
checkColumnExists(column);
for (Type type : types) {
if (column.getType().equals(type)) {
return;
}
}
throw new IllegalArgumentException(String.format("%s isn't %s, it's %s", column.getName(),
Arrays.toString(types), column.getType().getName()));
}
private void checkColumnExists(ColumnSchema column) {
if (column == null) {
throw new IllegalArgumentException("Column name isn't present in the table's schema");
}
}
private void checkValue(int columnIndex) {
if (!isSet(columnIndex)) {
throw new IllegalArgumentException("Column value is not set");
}
if (isNull(columnIndex)) {
throw new IllegalArgumentException("Column value is null");
}
}
private void checkNotFrozen() {
if (frozen) {
throw new IllegalStateException("This row was already applied and cannot be modified.");
}
}
private int getPositionInRowAllocAndSetBitSet(int columnIndex) {
columnsBitSet.set(columnIndex);
return schema.getColumnOffset(columnIndex);
}
public boolean isSet(String columnName) {
return isSet(this.schema.getColumnIndex(columnName));
}
public boolean isSet(int columnIndex) {
checkColumnExists(schema.getColumnByIndex(columnIndex));
return this.columnsBitSet.get(columnIndex);
}
boolean isSetToNull(int column) {
if (this.nullsBitSet == null) {
return false;
}
return this.nullsBitSet.get(column);
}
public byte[] encodePrimaryKey() {
return KeyEncoder.encodePrimaryKey(this);
}
@Override
public String toString() {
int numCols = schema.getColumnCount();
StringBuilder sb = new StringBuilder();
sb.append('(');
boolean first = true;
for (int idx = 0; idx < numCols; ++idx) {
if (!columnsBitSet.get(idx)) {
continue;
}
if (first) {
first = false;
} else {
sb.append(", ");
}
ColumnSchema col = schema.getColumnByIndex(idx);
sb.append(col.getType().getName());
if (col.getTypeAttributes() != null) {
sb.append(col.getTypeAttributes().toStringForType(col.getType()));
}
sb.append(' ');
sb.append(col.getName());
sb.append('=');
appendCellValueDebugString(idx, sb);
}
sb.append(')');
return sb.toString();
}
public String stringifyRowKey() {
int numRowKeys = schema.getPrimaryKeyColumnCount();
List idxs = new ArrayList<>(numRowKeys);
for (int i = 0; i < numRowKeys; i++) {
idxs.add(i);
}
StringBuilder sb = new StringBuilder();
sb.append("(");
appendDebugString(idxs, sb);
sb.append(")");
return sb.toString();
}
void appendDebugString(List idxs, StringBuilder sb) {
boolean first = true;
for (int idx : idxs) {
if (first) {
first = false;
} else {
sb.append(", ");
}
ColumnSchema col = schema.getColumnByIndex(idx);
sb.append(col.getType().getName());
sb.append(' ');
sb.append(col.getName());
sb.append('=');
appendCellValueDebugString(idx, sb);
}
}
void appendShortDebugString(List idxs, StringBuilder sb) {
boolean first = true;
for (int idx : idxs) {
if (first) {
first = false;
} else {
sb.append(", ");
}
appendCellValueDebugString(idx, sb);
}
}
void appendCellValueDebugString(Integer idx, StringBuilder sb) {
ColumnSchema col = schema.getColumnByIndex(idx);
Preconditions.checkState(columnsBitSet.get(idx), "Column %s is not set", col.getName());
if (nullsBitSet != null && nullsBitSet.get(idx)) {
sb.append("NULL");
return;
}
switch (col.getType()) {
case BOOL:
sb.append(Bytes.getBoolean(rowAlloc, schema.getColumnOffset(idx)));
return;
case INT8:
sb.append(Bytes.getByte(rowAlloc, schema.getColumnOffset(idx)));
return;
case INT16:
sb.append(Bytes.getShort(rowAlloc, schema.getColumnOffset(idx)));
return;
case INT32:
sb.append(Bytes.getInt(rowAlloc, schema.getColumnOffset(idx)));
return;
case INT64:
sb.append(Bytes.getLong(rowAlloc, schema.getColumnOffset(idx)));
return;
case DATE:
sb.append(DateUtil.epochDaysToDateString(
Bytes.getInt(rowAlloc, schema.getColumnOffset(idx))));
return;
case UNIXTIME_MICROS:
sb.append(TimestampUtil.timestampToString(
Bytes.getLong(rowAlloc, schema.getColumnOffset(idx))));
return;
case FLOAT:
sb.append(Bytes.getFloat(rowAlloc, schema.getColumnOffset(idx)));
return;
case DOUBLE:
sb.append(Bytes.getDouble(rowAlloc, schema.getColumnOffset(idx)));
return;
case DECIMAL:
ColumnTypeAttributes typeAttributes = col.getTypeAttributes();
sb.append(Bytes.getDecimal(rowAlloc, schema.getColumnOffset(idx),
typeAttributes.getPrecision(), typeAttributes.getScale()));
return;
case VARCHAR:
case BINARY:
case STRING:
ByteBuffer value = getVarLengthData().get(this.schema.getVarLengthColumnOffsetToAllVarCharColumns(idx)).duplicate();
value.reset(); // Make sure we start at the beginning.
byte[] data = new byte[value.limit() - value.position()];
value.get(data);
if (col.getType() == Type.STRING || col.getType() == Type.VARCHAR) {
sb.append('"');
StringUtil.appendEscapedSQLString(Bytes.getString(data), sb);
sb.append('"');
} else {
sb.append(Bytes.pretty(data));
}
return;
default:
throw new RuntimeException("unreachable");
}
}
void setMin(int index) {
ColumnSchema column = schema.getColumnByIndex(index);
Type type = column.getType();
switch (type) {
case BOOL:
addBoolean(index, false);
break;
case INT8:
addByte(index, Byte.MIN_VALUE);
break;
case INT16:
addShort(index, Short.MIN_VALUE);
break;
case INT32:
addInt(index, Integer.MIN_VALUE);
break;
case DATE:
addDate(index, DateUtil.epochDaysToSqlDate(DateUtil.MIN_DATE_VALUE));
break;
case INT64:
case UNIXTIME_MICROS:
addLong(index, Long.MIN_VALUE);
break;
case FLOAT:
addFloat(index, -Float.MAX_VALUE);
break;
case DOUBLE:
addDouble(index, -Double.MAX_VALUE);
break;
case DECIMAL:
ColumnTypeAttributes typeAttributes = column.getTypeAttributes();
addDecimal(index,
DecimalUtil.minValue(typeAttributes.getPrecision(), typeAttributes.getScale()));
break;
case STRING:
addStringUtf8(index, EMPTY_ARRAY);
break;
case BINARY:
addBinary(index, EMPTY_ARRAY);
break;
case VARCHAR:
addVarchar(index, "");
break;
default:
throw new RuntimeException("unreachable");
}
}
void setRaw(int index, byte[] value) {
ColumnSchema column = schema.getColumnByIndex(index);
Type type = column.getType();
switch (type) {
case BOOL:
case INT8:
case INT16:
case INT32:
case INT64:
case DATE:
case UNIXTIME_MICROS:
case FLOAT:
case DOUBLE:
case DECIMAL: {
Preconditions.checkArgument(value.length == column.getTypeSize());
System.arraycopy(value, 0, rowAlloc,
getPositionInRowAllocAndSetBitSet(index), value.length);
break;
}
case VARCHAR:
case STRING:
case BINARY: {
addVarLengthData(index, value);
break;
}
default:
throw new RuntimeException("unreachable");
}
}
boolean incrementColumn(int index) {
ColumnSchema column = schema.getColumnByIndex(index);
Type type = column.getType();
Preconditions.checkState(isSet(index));
int offset = schema.getColumnOffset(index);
switch (type) {
case BOOL: {
boolean isFalse = rowAlloc[offset] == 0;
rowAlloc[offset] = 1;
return isFalse;
}
case INT8: {
byte existing = rowAlloc[offset];
if (existing == Byte.MAX_VALUE) {
return false;
}
rowAlloc[offset] = (byte) (existing + 1);
return true;
}
case INT16: {
short existing = Bytes.getShort(rowAlloc, offset);
if (existing == Short.MAX_VALUE) {
return false;
}
Bytes.setShort(rowAlloc, (short) (existing + 1), offset);
return true;
}
case INT32: {
int existing = Bytes.getInt(rowAlloc, offset);
if (existing == Integer.MAX_VALUE) {
return false;
}
Bytes.setInt(rowAlloc, existing + 1, offset);
return true;
}
case DATE: {
int existing = Bytes.getInt(rowAlloc, offset);
if (existing == DateUtil.MAX_DATE_VALUE) {
return false;
}
Bytes.setInt(rowAlloc, existing + 1, offset);
return true;
}
case INT64:
case UNIXTIME_MICROS: {
long existing = Bytes.getLong(rowAlloc, offset);
if (existing == Long.MAX_VALUE) {
return false;
}
Bytes.setLong(rowAlloc, existing + 1, offset);
return true;
}
case FLOAT: {
float existing = Bytes.getFloat(rowAlloc, offset);
float incremented = Math.nextAfter(existing, Float.POSITIVE_INFINITY);
if (existing == incremented) {
return false;
}
Bytes.setFloat(rowAlloc, incremented, offset);
return true;
}
case DOUBLE: {
double existing = Bytes.getDouble(rowAlloc, offset);
double incremented = Math.nextAfter(existing, Double.POSITIVE_INFINITY);
if (existing == incremented) {
return false;
}
Bytes.setDouble(rowAlloc, incremented, offset);
return true;
}
case DECIMAL: {
int precision = column.getTypeAttributes().getPrecision();
int scale = column.getTypeAttributes().getScale();
BigDecimal existing = Bytes.getDecimal(rowAlloc, offset, precision, scale);
BigDecimal max = DecimalUtil.maxValue(precision, scale);
if (existing.equals(max)) {
return false;
}
BigDecimal smallest = DecimalUtil.smallestValue(scale);
Bytes.setBigDecimal(rowAlloc, existing.add(smallest), precision, offset);
return true;
}
case VARCHAR:
case STRING:
case BINARY: {
ByteBuffer data = varLengthData.get(this.schema.getVarLengthColumnOffsetToAllVarCharColumns(index));
data.reset();
int len = data.limit() - data.position();
byte[] incremented = new byte[len + 1];
System.arraycopy(data.array(), data.arrayOffset() + data.position(), incremented, 0, len);
addVarLengthData(index, incremented);
return true;
}
default:
throw new RuntimeException("unreachable");
}
}
static boolean isIncremented(PartialRow lower, PartialRow upper, List indexes) {
boolean equals = false;
ListIterator iter = indexes.listIterator(indexes.size());
while (iter.hasPrevious()) {
int index = iter.previous();
if (equals) {
if (isCellEqual(lower, upper, index)) {
continue;
}
return false;
}
if (!lower.isSet(index) && !upper.isSet(index)) {
continue;
}
if (!isCellIncremented(lower, upper, index)) {
return false;
}
equals = true;
}
return equals;
}
private static boolean isCellEqual(PartialRow a, PartialRow b, int index) {
Preconditions.checkArgument(a.getSchema().equals(b.getSchema()));
Preconditions.checkArgument(a.getSchema().getColumnByIndex(index).isKey());
Preconditions.checkArgument(a.isSet(index));
Preconditions.checkArgument(b.isSet(index));
ColumnSchema column = a.getSchema().getColumnByIndex(index);
Type type = column.getType();
int offset = a.getSchema().getColumnOffset(index);
switch (type) {
case BOOL:
case INT8:
return a.rowAlloc[offset] == b.rowAlloc[offset];
case INT16:
return Bytes.getShort(a.rowAlloc, offset) == Bytes.getShort(b.rowAlloc, offset);
case DATE:
case INT32:
return Bytes.getInt(a.rowAlloc, offset) == Bytes.getInt(b.rowAlloc, offset);
case INT64:
case UNIXTIME_MICROS:
return Bytes.getLong(a.rowAlloc, offset) == Bytes.getLong(b.rowAlloc, offset);
case FLOAT:
return Bytes.getFloat(a.rowAlloc, offset) == Bytes.getFloat(b.rowAlloc, offset);
case DOUBLE:
return Bytes.getDouble(a.rowAlloc, offset) == Bytes.getDouble(b.rowAlloc, offset);
case DECIMAL:
ColumnTypeAttributes typeAttributes = column.getTypeAttributes();
int precision = typeAttributes.getPrecision();
int scale = typeAttributes.getScale();
return Bytes.getDecimal(a.rowAlloc, offset, precision, scale)
.equals(Bytes.getDecimal(b.rowAlloc, offset, precision, scale));
case VARCHAR:
case STRING:
case BINARY: {
ByteBuffer dataA = a.varLengthData.get(a.schema.getVarLengthColumnOffsetToAllVarCharColumns(index)).duplicate();
ByteBuffer dataB = b.varLengthData.get(b.schema.getVarLengthColumnOffsetToAllVarCharColumns(index)).duplicate();
dataA.reset();
dataB.reset();
int lenA = dataA.limit() - dataA.position();
int lenB = dataB.limit() - dataB.position();
if (lenA != lenB) {
return false;
}
for (int i = 0; i < lenA; i++) {
if (dataA.get(dataA.position() + i) != dataB.get(dataB.position() + i)) {
return false;
}
}
return true;
}
default:
throw new RuntimeException("unreachable");
}
}
private static boolean isCellIncremented(PartialRow lower, PartialRow upper, int index) {
Preconditions.checkArgument(lower.getSchema().equals(upper.getSchema()));
Preconditions.checkArgument(lower.getSchema().getColumnByIndex(index).isKey());
Preconditions.checkArgument(lower.isSet(index));
Preconditions.checkArgument(upper.isSet(index));
ColumnSchema column = lower.getSchema().getColumnByIndex(index);
Type type = column.getType();
int offset = lower.getSchema().getColumnOffset(index);
switch (type) {
case BOOL:
return lower.rowAlloc[offset] + 1 == upper.rowAlloc[offset];
case INT8: {
byte val = lower.rowAlloc[offset];
return val != Byte.MAX_VALUE && val + 1 == upper.rowAlloc[offset];
}
case INT16: {
short val = Bytes.getShort(lower.rowAlloc, offset);
return val != Short.MAX_VALUE && val + 1 == Bytes.getShort(upper.rowAlloc, offset);
}
case INT32: {
int val = Bytes.getInt(lower.rowAlloc, offset);
return val != Integer.MAX_VALUE && val + 1 == Bytes.getInt(upper.rowAlloc, offset);
}
case DATE: {
int val = Bytes.getInt(lower.rowAlloc, offset);
return val != DateUtil.MAX_DATE_VALUE && val + 1 == Bytes.getInt(upper.rowAlloc, offset);
}
case INT64:
case UNIXTIME_MICROS: {
long val = Bytes.getLong(lower.rowAlloc, offset);
return val != Long.MAX_VALUE && val + 1 == Bytes.getLong(upper.rowAlloc, offset);
}
case FLOAT: {
float val = Bytes.getFloat(lower.rowAlloc, offset);
return val != Float.POSITIVE_INFINITY &&
Math.nextAfter(val, Float.POSITIVE_INFINITY) ==
Bytes.getFloat(upper.rowAlloc, offset);
}
case DOUBLE: {
double val = Bytes.getDouble(lower.rowAlloc, offset);
return val != Double.POSITIVE_INFINITY &&
Math.nextAfter(val, Double.POSITIVE_INFINITY) ==
Bytes.getDouble(upper.rowAlloc, offset);
}
case DECIMAL: {
ColumnTypeAttributes typeAttributes = column.getTypeAttributes();
int precision = typeAttributes.getPrecision();
int scale = typeAttributes.getScale();
BigDecimal val = Bytes.getDecimal(lower.rowAlloc, offset, precision, scale);
BigDecimal smallestVal = DecimalUtil.smallestValue(scale);
return val.add(smallestVal).equals(
Bytes.getDecimal(upper.rowAlloc, offset, precision, scale));
}
case VARCHAR:
case STRING:
case BINARY: {
// Check that b is 1 byte bigger than a, the extra byte is 0, and the other bytes are equal.
ByteBuffer dataA = lower.varLengthData.get(lower.schema.getVarLengthColumnOffsetToAllVarCharColumns(index)).duplicate();
ByteBuffer dataB = upper.varLengthData.get(upper.schema.getVarLengthColumnOffsetToAllVarCharColumns(index)).duplicate();
dataA.reset();
dataB.reset();
int lenA = dataA.limit() - dataA.position();
int lenB = dataB.limit() - dataB.position();
if (lenA == Integer.MAX_VALUE ||
lenA + 1 != lenB ||
dataB.get(dataB.limit() - 1) != 0) {
return false;
}
for (int i = 0; i < lenA; i++) {
if (dataA.get(dataA.position() + i) != dataB.get(dataB.position() + i)) {
return false;
}
}
return true;
}
default:
throw new RuntimeException("unreachable");
}
}
public Schema getSchema() {
return schema;
}
public byte[] getRowAlloc() {
return rowAlloc;
}
BitSet getColumnsBitSet() {
return columnsBitSet;
}
BitSet getNullsBitSet() {
return nullsBitSet;
}
void freeze() {
this.frozen = true;
}
public void reset() {
this.columnsBitSet.clear();
if (this.nullsBitSet != null) {
this.nullsBitSet.clear();
}
Arrays.fill(this.rowAlloc, (byte) 0);
for (ByteBuffer buffer : this.varLengthData) {
buffer.clear();
}
// mark max changed index.
this.maxChangedIndex = -1;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy