com.clickzetta.platform.common.Schema Maven / Gradle / Ivy
Show all versions of clickzetta-java Show documentation
package com.clickzetta.platform.common;
import com.clickzetta.platform.operator.Bytes;
import com.clickzetta.platform.operator.PartialRow;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import org.apache.kudu.KuduCommon.DataType;
import java.util.*;
public class Schema {
/**
* Mapping of column index to column.
*/
private final List columnsByIndex;
/**
* The primary key columns. (sortColumns + keyColumns)
*/
private final List primaryKeyColumns = new ArrayList<>();
/**
* The primary key columns.
*/
private final List keyColumns = new ArrayList<>();
/**
* The primary key columns.
*/
private final List sortColumns = new ArrayList<>();
/**
* Mapping of column name to index.
*/
private final Map columnsByName;
/**
* Mapping of column ID to index, or null if the schema does not have assigned column IDs.
*/
private final Map columnsById;
/**
* Mapping of column name to column ID, or null if the schema does not have assigned column IDs.
*/
private final Map columnIdByName;
/**
* Mapping of var length column index to all var length columns offset.
* or null if the schema does not have var length column.
*
* Varchar | String | Binary.
*/
private final int[] varLengthColumnOffsetToAllVarCharColumns;
/**
* Mapping of column index to backing byte array offset.
*/
private final int[] columnOffsets;
/**
* Mapping of column name to index with case Insensitive.
* such as. column1 will be COLUMN1 or column1.
*/
private final Map columnsByNameWithCase;
private final int varLengthColumnCount;
private final int rowSize;
private final boolean hasNullableColumns;
private final int isDeletedIndex;
private static final int NO_IS_DELETED_INDEX = -1;
public Schema(List columns,
List keyColumns,
List sortColumns) {
this(columns, null, keyColumns, sortColumns);
}
private Schema(List columns,
List columnIds,
List keyColumns,
List sortColumns) {
boolean hasColumnIds = columnIds != null;
if (hasColumnIds && columns.size() != columnIds.size()) {
throw new IllegalArgumentException(
"Schema must be constructed with all column IDs, or none.");
}
// add sort columns & key columns.
this.keyColumns.addAll(keyColumns);
this.sortColumns.addAll(sortColumns);
this.columnsByIndex = ImmutableList.copyOf(columns);
int varLenCnt = 0;
this.columnOffsets = new int[columns.size()];
this.columnsByName = new HashMap<>(columns.size());
this.columnsByNameWithCase = new HashMap<>(columns.size() * 2);
this.columnsById = hasColumnIds ? new HashMap<>(columnIds.size()) : null;
this.columnIdByName = hasColumnIds ? new HashMap<>(columnIds.size()) : null;
this.varLengthColumnOffsetToAllVarCharColumns = new int[columns.size()];
int offset = 0;
boolean hasNulls = false;
int isDeletedIndex = NO_IS_DELETED_INDEX;
for (int index = 0; index < columns.size(); index++) {
final ColumnSchema column = columns.get(index);
if (column.isKey()) {
primaryKeyColumns.add(column);
}
hasNulls |= column.isNullable();
columnOffsets[index] = offset;
offset += column.getTypeSize();
if (this.columnsByName.put(column.getName(), index) != null) {
throw new IllegalArgumentException(
String.format("Column names must be unique: %s", columns));
}
// only used for case senstive match when use row.setValue.
this.columnsByNameWithCase.put(column.getName().toLowerCase(), index);
this.columnsByNameWithCase.put(column.getName().toUpperCase(), index);
if (column.getType() == Type.STRING || column.getType() == Type.BINARY ||
column.getType() == Type.VARCHAR) {
this.varLengthColumnOffsetToAllVarCharColumns[index] = varLenCnt;
varLenCnt++;
}
if (hasColumnIds) {
if (this.columnsById.put(columnIds.get(index), index) != null) {
throw new IllegalArgumentException(
String.format("Column IDs must be unique: %s", columnIds));
}
if (this.columnIdByName.put(column.getName(), columnIds.get(index)) != null) {
throw new IllegalArgumentException(
String.format("Column names must be unique: %s", columnIds));
}
}
if (column.getWireType() == DataType.IS_DELETED) {
isDeletedIndex = index;
}
}
this.varLengthColumnCount = varLenCnt;
this.rowSize = getRowSize(this.columnsByIndex);
this.hasNullableColumns = hasNulls;
this.isDeletedIndex = isDeletedIndex;
}
public List getColumns() {
return this.columnsByIndex;
}
public int getVarLengthColumnCount() {
return this.varLengthColumnCount;
}
public int getVarLengthColumnOffsetToAllVarCharColumns(int columnIndex) {
return this.varLengthColumnOffsetToAllVarCharColumns[columnIndex];
}
public int getRowSize() {
return this.rowSize;
}
private static int getRowSize(List columns) {
int totalSize = 0;
boolean hasNullables = false;
for (ColumnSchema column : columns) {
totalSize += column.getTypeSize();
hasNullables |= column.isNullable();
}
if (hasNullables) {
totalSize += Bytes.getBitSetSize(columns.size());
}
return totalSize;
}
public int getColumnOffset(int idx) {
return this.columnOffsets[idx];
}
public boolean hasColumn(String columnName) {
return this.columnsByName.containsKey(columnName) ||
this.columnsByNameWithCase.containsKey(columnName);
}
public int getColumnIndex(String columnName) {
Integer index = this.columnsByName.get(columnName);
if (index == null) {
index = this.columnsByNameWithCase.get(columnName.toLowerCase()) != null ?
this.columnsByNameWithCase.get(columnName.toLowerCase()) :
this.columnsByNameWithCase.get(columnName.toUpperCase());
}
if (index == null) {
throw new IllegalArgumentException(
String.format("Unknown column: %s", columnName));
}
return index;
}
public int getColumnIndex(int columnId) {
if (!hasColumnIds()) {
throw new IllegalStateException("Schema does not have Column IDs");
}
Integer index = this.columnsById.get(columnId);
if (index == null) {
throw new IllegalArgumentException(
String.format("Unknown column id: %s", columnId));
}
return index;
}
public ColumnSchema getColumnByIndex(int idx) {
return this.columnsByIndex.get(idx);
}
public ColumnSchema getColumn(String columnName) {
return columnsByIndex.get(getColumnIndex(columnName));
}
public int getColumnCount() {
return this.columnsByIndex.size();
}
public int getPrimaryKeyColumnCount() {
return this.primaryKeyColumns.size();
}
public List getPrimaryKeyColumns() {
return primaryKeyColumns;
}
public List getKeyColumns() {
return keyColumns;
}
public List getSortColumns() {
return sortColumns;
}
public Map getPrimaryKeyIndexMap() {
Map map = new LinkedHashMap<>();
for (int i = 0; i < primaryKeyColumns.size(); i++) {
map.put(primaryKeyColumns.get(i).getName(), Long.valueOf(Integer.toString(i)));
}
return map;
}
public Map getKeyIndexMap() {
Map map = new LinkedHashMap<>();
for (int i = 0; i < keyColumns.size(); i++) {
map.put(keyColumns.get(i).getName(), Long.valueOf(Integer.toString(i)));
}
return map;
}
public Map getSortIndexMap() {
Map map = new LinkedHashMap<>();
for (int i = 0; i < sortColumns.size(); i++) {
map.put(sortColumns.get(i).getName(), Long.valueOf(Integer.toString(i)));
}
return map;
}
public Schema getRowKeyProjection() {
return new Schema(primaryKeyColumns, keyColumns, sortColumns);
}
public boolean hasNullableColumns() {
return this.hasNullableColumns;
}
public boolean hasColumnIds() {
return columnsById != null;
}
public int getColumnId(String columnName) {
return columnIdByName.get(columnName);
}
public PartialRow newPartialRow() {
return new PartialRow(this);
}
public boolean hasIsDeleted() {
return isDeletedIndex != NO_IS_DELETED_INDEX;
}
public int getIsDeletedIndex() {
Preconditions.checkState(hasIsDeleted(), "Schema doesn't have an IS_DELETED columns");
return isDeletedIndex;
}
@Override
public String toString() {
return "Schema{" +
"columnsByIndex=" + columnsByIndex +
", primaryKeyColumns=" + primaryKeyColumns +
", keyColumns=" + keyColumns +
", sortColumns=" + sortColumns +
", columnsByName=" + columnsByName +
", columnsById=" + columnsById +
", columnIdByName=" + columnIdByName +
", columnOffsets=" + Arrays.toString(columnOffsets) +
", varLengthColumnCount=" + varLengthColumnCount +
", rowSize=" + rowSize +
", hasNullableColumns=" + hasNullableColumns +
", isDeletedIndex=" + isDeletedIndex +
'}';
}
}