blob: bb90c16e56bebca7f3aa82ada75f90a2a22655f0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.phoenix.schema;
import static org.apache.phoenix.hbase.index.util.KeyValueBuilder.addQuietly;
import static org.apache.phoenix.hbase.index.util.KeyValueBuilder.deleteQuietly;
import static org.apache.phoenix.schema.SaltingUtil.SALTING_COLUMN;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.util.ByteStringer;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.coprocessor.generated.PGuidePostsProtos;
import org.apache.phoenix.coprocessor.generated.PGuidePostsProtos.PGuidePosts;
import org.apache.phoenix.coprocessor.generated.PTableProtos;
import org.apache.phoenix.exception.DataExceedsCapacityException;
import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr;
import org.apache.phoenix.hbase.index.util.KeyValueBuilder;
import org.apache.phoenix.index.IndexMaintainer;
import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.protobuf.ProtobufUtil;
import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.schema.RowKeySchema.RowKeySchemaBuilder;
import org.apache.phoenix.schema.stats.GuidePostsInfo;
import org.apache.phoenix.schema.stats.PTableStats;
import org.apache.phoenix.schema.stats.PTableStatsImpl;
import org.apache.phoenix.schema.types.PBinary;
import org.apache.phoenix.schema.types.PChar;
import org.apache.phoenix.schema.types.PDataType;
import org.apache.phoenix.schema.types.PDouble;
import org.apache.phoenix.schema.types.PFloat;
import org.apache.phoenix.schema.types.PVarchar;
import org.apache.phoenix.util.ByteUtil;
import org.apache.phoenix.util.SchemaUtil;
import org.apache.phoenix.util.SizedUtil;
import org.apache.phoenix.util.StringUtil;
import org.apache.phoenix.util.TrustedByteArrayOutputStream;
import co.cask.tephra.TxConstants;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.protobuf.HBaseZeroCopyByteString;
import com.sun.istack.NotNull;
/**
*
* Base class for PTable implementors. Provides abstraction for
* storing data in a single column (ColumnLayout.SINGLE) or in
* multiple columns (ColumnLayout.MULTI).
*
*
* @since 0.1
*/
public class PTableImpl implements PTable {
private static final Integer NO_SALTING = -1;
private PTableKey key;
private PName name;
private PName schemaName = PName.EMPTY_NAME;
private PName tableName = PName.EMPTY_NAME;
private PName tenantId;
private PTableType type;
private PIndexState state;
private long sequenceNumber;
private long timeStamp;
private long indexDisableTimestamp;
// Have MultiMap for String->PColumn (may need family qualifier)
private List<PColumn> pkColumns;
private List<PColumn> allColumns;
private List<PColumnFamily> families;
private Map<byte[], PColumnFamily> familyByBytes;
private Map<String, PColumnFamily> familyByString;
private ListMultimap<String,PColumn> columnsByName;
private PName pkName;
private Integer bucketNum;
private RowKeySchema rowKeySchema;
// Indexes associated with this table.
private List<PTable> indexes;
// Data table name that the index is created on.
private PName parentName;
private PName parentSchemaName;
private PName parentTableName;
private List<PName> physicalNames;
private boolean isImmutableRows;
private IndexMaintainer indexMaintainer;
private ImmutableBytesWritable indexMaintainersPtr;
private PName defaultFamilyName;
private String viewStatement;
private boolean disableWAL;
private boolean multiTenant;
private boolean storeNulls;
private boolean isTransactional;
private ViewType viewType;
private Short viewIndexId;
private int estimatedSize;
private IndexType indexType;
private PTableStats tableStats = PTableStats.EMPTY_STATS;
private int baseColumnCount;
private boolean rowKeyOrderOptimizable; // TODO: remove when required that tables have been upgrade for PHOENIX-2067
private boolean hasColumnsRequiringUpgrade; // TODO: remove when required that tables have been upgrade for PHOENIX-2067
private int rowTimestampColPos;
private long updateCacheFrequency;
public PTableImpl() {
this.indexes = Collections.emptyList();
this.physicalNames = Collections.emptyList();
this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA;
}
public PTableImpl(PName tenantId, String schemaName, String tableName, long timestamp, List<PColumnFamily> families) { // For base table of mapped VIEW
Preconditions.checkArgument(tenantId==null || tenantId.getBytes().length > 0); // tenantId should be null or not empty
this.tenantId = tenantId;
this.name = PNameFactory.newName(SchemaUtil.getTableName(schemaName, tableName));
this.key = new PTableKey(tenantId, name.getString());
this.schemaName = PNameFactory.newName(schemaName);
this.tableName = PNameFactory.newName(tableName);
this.type = PTableType.VIEW;
this.viewType = ViewType.MAPPED;
this.timeStamp = timestamp;
this.pkColumns = this.allColumns = Collections.emptyList();
this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA;
this.indexes = Collections.emptyList();
this.familyByBytes = Maps.newHashMapWithExpectedSize(families.size());
this.familyByString = Maps.newHashMapWithExpectedSize(families.size());
for (PColumnFamily family : families) {
familyByBytes.put(family.getName().getBytes(), family);
familyByString.put(family.getName().getString(), family);
}
this.families = families;
this.physicalNames = Collections.emptyList();
}
public PTableImpl(long timeStamp) { // For delete marker
this(timeStamp, false);
}
public PTableImpl(long timeStamp, boolean isIndex) { // For index delete marker
if (isIndex) {
this.type = PTableType.INDEX;
this.state = PIndexState.INACTIVE;
} else {
this.type = PTableType.TABLE;
}
this.timeStamp = timeStamp;
this.pkColumns = this.allColumns = Collections.emptyList();
this.families = Collections.emptyList();
this.familyByBytes = Collections.emptyMap();
this.familyByString = Collections.emptyMap();
this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA;
this.indexes = Collections.emptyList();
this.physicalNames = Collections.emptyList();;
}
// When cloning table, ignore the salt column as it will be added back in the constructor
public static List<PColumn> getColumnsToClone(PTable table) {
return table.getBucketNum() == null ? table.getColumns() : table.getColumns().subList(1, table.getColumns().size());
}
public static PTableImpl makePTable(PTable table, long timeStamp, List<PTable> indexes) throws SQLException {
return makePTable(table, timeStamp, indexes, table.getSchemaName(), table.getViewStatement());
}
public static PTable makePTable(PTable table, String viewStatement) throws SQLException {
return Objects.equal(viewStatement, table.getViewStatement()) ? table : makePTable(table, table.getTimeStamp(), table.getIndexes(), table.getSchemaName(), viewStatement);
}
public static PTableImpl makePTable(PTable table, long timeStamp, List<PTable> indexes, PName parentSchemaName, String viewStatement) throws SQLException {
return new PTableImpl(
table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), timeStamp,
table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table), parentSchemaName, table.getParentTableName(),
indexes, table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), viewStatement,
table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp());
}
public static PTableImpl makePTable(PTable table, List<PColumn> columns) throws SQLException {
return new PTableImpl(
table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), table.getTimeStamp(),
table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
table.getIndexes(), table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp());
}
public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, List<PColumn> columns) throws SQLException {
return new PTableImpl(
table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), timeStamp,
sequenceNumber, table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(), table.isWALDisabled(),
table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(), table.getTableStats(),
table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp());
}
public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, List<PColumn> columns, boolean isImmutableRows) throws SQLException {
return new PTableImpl(
table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), timeStamp,
sequenceNumber, table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
table.getIndexes(), isImmutableRows, table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(),
table.getIndexType(), table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp());
}
public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, List<PColumn> columns, boolean isImmutableRows, boolean isWalDisabled,
boolean isMultitenant, boolean storeNulls, boolean isTransactional, long updateCacheFrequency) throws SQLException {
return new PTableImpl(
table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), timeStamp,
sequenceNumber, table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
table.getIndexes(), isImmutableRows, table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
isWalDisabled, isMultitenant, storeNulls, table.getViewType(), table.getViewIndexId(), table.getIndexType(), table.getTableStats(),
table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), isTransactional, updateCacheFrequency, table.getIndexDisableTimestamp());
}
public static PTableImpl makePTable(PTable table, PIndexState state) throws SQLException {
return new PTableImpl(
table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), state, table.getTimeStamp(),
table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table),
table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp());
}
public static PTableImpl makePTable(PTable table, boolean rowKeyOrderOptimizable) throws SQLException {
return new PTableImpl(
table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), table.getTimeStamp(),
table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table),
table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(), table.getTableStats(),
table.getBaseColumnCount(), rowKeyOrderOptimizable, table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp());
}
public static PTableImpl makePTable(PTable table, PTableStats stats) throws SQLException {
return new PTableImpl(
table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), table.getTimeStamp(),
table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table),
table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(), stats,
table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp());
}
public static PTableImpl makePTable(PName tenantId, PName schemaName, PName tableName, PTableType type,
PIndexState state, long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum,
List<PColumn> columns, PName dataSchemaName, PName dataTableName, List<PTable> indexes,
boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression,
boolean disableWAL, boolean multiTenant, boolean storeNulls, ViewType viewType, Short viewIndexId,
IndexType indexType, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency,
long indexDisableTimestamp) throws SQLException {
return new PTableImpl(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName, bucketNum, columns, dataSchemaName,
dataTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName,
viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexId,
indexType, PTableStats.EMPTY_STATS, QueryConstants.BASE_TABLE_BASE_COLUMN_COUNT, rowKeyOrderOptimizable, isTransactional,
updateCacheFrequency,indexDisableTimestamp);
}
public static PTableImpl makePTable(PName tenantId, PName schemaName, PName tableName, PTableType type,
PIndexState state, long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum,
List<PColumn> columns, PName dataSchemaName, PName dataTableName, List<PTable> indexes,
boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression,
boolean disableWAL, boolean multiTenant, boolean storeNulls, ViewType viewType, Short viewIndexId,
IndexType indexType, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency,
@NotNull PTableStats stats, int baseColumnCount, long indexDisableTimestamp)
throws SQLException {
return new PTableImpl(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName,
bucketNum, columns, dataSchemaName, dataTableName, indexes, isImmutableRows, physicalNames,
defaultFamilyName, viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexId,
indexType, stats, baseColumnCount, rowKeyOrderOptimizable, isTransactional, updateCacheFrequency, indexDisableTimestamp);
}
private PTableImpl(PName tenantId, PName schemaName, PName tableName, PTableType type, PIndexState state,
long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum, List<PColumn> columns,
PName parentSchemaName, PName parentTableName, List<PTable> indexes, boolean isImmutableRows,
List<PName> physicalNames, PName defaultFamilyName, String viewExpression, boolean disableWAL, boolean multiTenant,
boolean storeNulls, ViewType viewType, Short viewIndexId, IndexType indexType,
PTableStats stats, int baseColumnCount, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency, long indexDisableTimestamp) throws SQLException {
init(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName, bucketNum, columns,
stats, schemaName, parentTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName,
viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable,
isTransactional, updateCacheFrequency, indexDisableTimestamp);
}
@Override
public long getUpdateCacheFrequency() {
return updateCacheFrequency;
}
@Override
public boolean isMultiTenant() {
return multiTenant;
}
@Override
public boolean getStoreNulls() {
return storeNulls;
}
@Override
public ViewType getViewType() {
return viewType;
}
@Override
public int getEstimatedSize() {
return estimatedSize;
}
private void init(PName tenantId, PName schemaName, PName tableName, PTableType type, PIndexState state, long timeStamp, long sequenceNumber,
PName pkName, Integer bucketNum, List<PColumn> columns, PTableStats stats, PName parentSchemaName, PName parentTableName,
List<PTable> indexes, boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression, boolean disableWAL,
boolean multiTenant, boolean storeNulls, ViewType viewType, Short viewIndexId,
IndexType indexType , int baseColumnCount, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency, long indexDisableTimestamp) throws SQLException {
Preconditions.checkNotNull(schemaName);
Preconditions.checkArgument(tenantId==null || tenantId.getBytes().length > 0); // tenantId should be null or not empty
int estimatedSize = SizedUtil.OBJECT_SIZE * 2 + 23 * SizedUtil.POINTER_SIZE + 4 * SizedUtil.INT_SIZE + 2 * SizedUtil.LONG_SIZE + 2 * SizedUtil.INT_OBJECT_SIZE +
PNameFactory.getEstimatedSize(tenantId) +
PNameFactory.getEstimatedSize(schemaName) +
PNameFactory.getEstimatedSize(tableName) +
PNameFactory.getEstimatedSize(pkName) +
PNameFactory.getEstimatedSize(parentTableName) +
PNameFactory.getEstimatedSize(defaultFamilyName);
this.tenantId = tenantId;
this.schemaName = schemaName;
this.tableName = tableName;
this.name = PNameFactory.newName(SchemaUtil.getTableName(schemaName.getString(), tableName.getString()));
this.key = new PTableKey(tenantId, name.getString());
this.type = type;
this.state = state;
this.timeStamp = timeStamp;
this.indexDisableTimestamp = indexDisableTimestamp;
this.sequenceNumber = sequenceNumber;
this.pkName = pkName;
this.isImmutableRows = isImmutableRows;
this.defaultFamilyName = defaultFamilyName;
this.viewStatement = viewExpression;
this.disableWAL = disableWAL;
this.multiTenant = multiTenant;
this.storeNulls = storeNulls;
this.viewType = viewType;
this.viewIndexId = viewIndexId;
this.indexType = indexType;
this.isTransactional = isTransactional;
this.tableStats = stats;
this.rowKeyOrderOptimizable = rowKeyOrderOptimizable;
this.updateCacheFrequency = updateCacheFrequency;
List<PColumn> pkColumns;
PColumn[] allColumns;
this.columnsByName = ArrayListMultimap.create(columns.size(), 1);
int numPKColumns = 0;
if (bucketNum != null) {
// Add salt column to allColumns and pkColumns, but don't add to
// columnsByName, since it should not be addressable via name.
allColumns = new PColumn[columns.size()+1];
allColumns[SALTING_COLUMN.getPosition()] = SALTING_COLUMN;
pkColumns = Lists.newArrayListWithExpectedSize(columns.size()+1);
++numPKColumns;
} else {
allColumns = new PColumn[columns.size()];
pkColumns = Lists.newArrayListWithExpectedSize(columns.size());
}
for (int i = 0; i < columns.size(); i++) {
PColumn column = columns.get(i);
allColumns[column.getPosition()] = column;
PName familyName = column.getFamilyName();
if (familyName == null) {
++numPKColumns;
}
String columnName = column.getName().getString();
if (columnsByName.put(columnName, column)) {
int count = 0;
for (PColumn dupColumn : columnsByName.get(columnName)) {
if (Objects.equal(familyName, dupColumn.getFamilyName())) {
count++;
if (count > 1) {
throw new ColumnAlreadyExistsException(null, name.getString(), columnName);
}
}
}
}
}
estimatedSize += SizedUtil.sizeOfMap(allColumns.length, SizedUtil.POINTER_SIZE, SizedUtil.sizeOfArrayList(1)); // for multi-map
this.bucketNum = bucketNum;
this.allColumns = ImmutableList.copyOf(allColumns);
estimatedSize += SizedUtil.sizeOfMap(numPKColumns) + SizedUtil.sizeOfMap(allColumns.length);
RowKeySchemaBuilder builder = new RowKeySchemaBuilder(numPKColumns);
// Two pass so that column order in column families matches overall column order
// and to ensure that column family order is constant
int maxExpectedSize = allColumns.length - numPKColumns;
// Maintain iteration order so that column families are ordered as they are listed
Map<PName, List<PColumn>> familyMap = Maps.newLinkedHashMap();
PColumn rowTimestampCol = null;
for (PColumn column : allColumns) {
PName familyName = column.getFamilyName();
if (familyName == null) {
hasColumnsRequiringUpgrade |=
( column.getSortOrder() == SortOrder.DESC
&& (!column.getDataType().isFixedWidth()
|| column.getDataType() == PChar.INSTANCE
|| column.getDataType() == PFloat.INSTANCE
|| column.getDataType() == PDouble.INSTANCE
|| column.getDataType() == PBinary.INSTANCE) )
|| (column.getSortOrder() == SortOrder.ASC && column.getDataType() == PBinary.INSTANCE && column.getMaxLength() != null && column.getMaxLength() > 1);
pkColumns.add(column);
if (column.isRowTimestamp()) {
rowTimestampCol = column;
}
}
if (familyName == null) {
estimatedSize += column.getEstimatedSize(); // PK columns
builder.addField(column, column.isNullable(), column.getSortOrder());
} else {
List<PColumn> columnsInFamily = familyMap.get(familyName);
if (columnsInFamily == null) {
columnsInFamily = Lists.newArrayListWithExpectedSize(maxExpectedSize);
familyMap.put(familyName, columnsInFamily);
}
columnsInFamily.add(column);
}
}
this.pkColumns = ImmutableList.copyOf(pkColumns);
if (rowTimestampCol != null) {
this.rowTimestampColPos = this.pkColumns.indexOf(rowTimestampCol);
} else {
this.rowTimestampColPos = -1;
}
builder.rowKeyOrderOptimizable(this.rowKeyOrderOptimizable()); // after hasDescVarLengthColumns is calculated
this.rowKeySchema = builder.build();
estimatedSize += rowKeySchema.getEstimatedSize();
Iterator<Map.Entry<PName,List<PColumn>>> iterator = familyMap.entrySet().iterator();
PColumnFamily[] families = new PColumnFamily[familyMap.size()];
estimatedSize += this.tableStats.getEstimatedSize();
ImmutableMap.Builder<String, PColumnFamily> familyByString = ImmutableMap.builder();
ImmutableSortedMap.Builder<byte[], PColumnFamily> familyByBytes = ImmutableSortedMap
.orderedBy(Bytes.BYTES_COMPARATOR);
for (int i = 0; i < families.length; i++) {
Map.Entry<PName,List<PColumn>> entry = iterator.next();
PColumnFamily family = new PColumnFamilyImpl(entry.getKey(), entry.getValue());
families[i] = family;
familyByString.put(family.getName().getString(), family);
familyByBytes.put(family.getName().getBytes(), family);
estimatedSize += family.getEstimatedSize();
}
this.families = ImmutableList.copyOf(families);
this.familyByBytes = familyByBytes.build();
this.familyByString = familyByString.build();
estimatedSize += SizedUtil.sizeOfArrayList(families.length);
estimatedSize += SizedUtil.sizeOfMap(families.length) * 2;
this.indexes = indexes == null ? Collections.<PTable>emptyList() : indexes;
for (PTable index : this.indexes) {
estimatedSize += index.getEstimatedSize();
}
this.parentSchemaName = parentSchemaName;
this.parentTableName = parentTableName;
this.parentName = parentTableName == null ? null : PNameFactory.newName(SchemaUtil.getTableName(
parentSchemaName.getString(), parentTableName.getString()));
estimatedSize += PNameFactory.getEstimatedSize(this.parentName);
this.physicalNames = physicalNames == null ? ImmutableList.<PName>of() : ImmutableList.copyOf(physicalNames);
for (PName name : this.physicalNames) {
estimatedSize += name.getEstimatedSize();
}
this.estimatedSize = estimatedSize;
this.baseColumnCount = baseColumnCount;
}
@Override
public boolean isImmutableRows() {
return isImmutableRows;
}
@Override
public String toString() {
return name.getString();
}
@Override
public List<PColumn> getPKColumns() {
return pkColumns;
}
@Override
public final PName getName() {
return name;
}
@Override
public final PName getSchemaName() {
return schemaName;
}
@Override
public final PName getTableName() {
return tableName;
}
@Override
public final PTableType getType() {
return type;
}
@Override
public final List<PColumnFamily> getColumnFamilies() {
return families;
}
@Override
public int newKey(ImmutableBytesWritable key, byte[][] values) {
int nValues = values.length;
while (nValues > 0 && (values[nValues-1] == null || values[nValues-1].length == 0)) {
nValues--;
}
int i = 0;
TrustedByteArrayOutputStream os = new TrustedByteArrayOutputStream(SchemaUtil.estimateKeyLength(this));
try {
Integer bucketNum = this.getBucketNum();
if (bucketNum != null) {
// Write place holder for salt byte
i++;
os.write(QueryConstants.SEPARATOR_BYTE_ARRAY);
}
List<PColumn> columns = getPKColumns();
int nColumns = columns.size();
PDataType type = null;
SortOrder sortOrder = null;
boolean wasNull = false;
while (i < nValues && i < nColumns) {
// Separate variable length column values in key with zero byte
if (type != null && !type.isFixedWidth()) {
os.write(SchemaUtil.getSeparatorByte(rowKeyOrderOptimizable(), wasNull, sortOrder));
}
PColumn column = columns.get(i);
sortOrder = column.getSortOrder();
type = column.getDataType();
// This will throw if the value is null and the type doesn't allow null
byte[] byteValue = values[i++];
if (byteValue == null) {
byteValue = ByteUtil.EMPTY_BYTE_ARRAY;
}
wasNull = byteValue.length == 0;
// An empty byte array return value means null. Do this,
// since a type may have muliple representations of null.
// For example, VARCHAR treats both null and an empty string
// as null. This way we don't need to leak that part of the
// implementation outside of PDataType by checking the value
// here.
if (byteValue.length == 0 && !column.isNullable()) {
throw new ConstraintViolationException(name.getString() + "." + column.getName().getString() + " may not be null");
}
Integer maxLength = column.getMaxLength();
if (maxLength != null && type.isFixedWidth() && byteValue.length < maxLength) {
if (rowKeyOrderOptimizable()) {
key.set(byteValue);
type.pad(key, maxLength, sortOrder);
byteValue = ByteUtil.copyKeyBytesIfNecessary(key);
} else {
// TODO: remove this incorrect code and move StringUtil.padChar() to TestUtil
// once we require tables to have been upgraded
byteValue = StringUtil.padChar(byteValue, maxLength);
}
} else if (maxLength != null && !type.isArrayType() && byteValue.length > maxLength) {
throw new DataExceedsCapacityException(name.getString() + "." + column.getName().getString() + " may not exceed " + maxLength + " bytes (" + SchemaUtil.toString(type, byteValue) + ")");
}
os.write(byteValue, 0, byteValue.length);
}
// Need trailing byte for DESC columns
if (type != null && !type.isFixedWidth() && SchemaUtil.getSeparatorByte(rowKeyOrderOptimizable(), wasNull, sortOrder) == QueryConstants.DESC_SEPARATOR_BYTE) {
os.write(QueryConstants.DESC_SEPARATOR_BYTE);
}
// If some non null pk values aren't set, then throw
if (i < nColumns) {
PColumn column = columns.get(i);
if (column.getDataType().isFixedWidth() || !column.isNullable()) {
throw new ConstraintViolationException(name.getString() + "." + column.getName().getString() + " may not be null");
}
}
if (nValues == 0) {
throw new ConstraintViolationException("Primary key may not be null ("+ name.getString() + ")");
}
byte[] buf = os.getBuffer();
int size = os.size();
if (bucketNum != null) {
buf[0] = SaltingUtil.getSaltingByte(buf, 1, size-1, bucketNum);
}
key.set(buf,0,size);
return i;
} finally {
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e); // Impossible
}
}
}
private PRow newRow(KeyValueBuilder builder, long ts, ImmutableBytesWritable key, int i, byte[]... values) {
PRow row = new PRowImpl(builder, key, ts, getBucketNum());
if (i < values.length) {
for (PColumnFamily family : getColumnFamilies()) {
for (PColumn column : family.getColumns()) {
row.setValue(column, values[i++]);
if (i == values.length)
return row;
}
}
}
return row;
}
@Override
public PRow newRow(KeyValueBuilder builder, long ts, ImmutableBytesWritable key,
byte[]... values) {
return newRow(builder, ts, key, 0, values);
}
@Override
public PRow newRow(KeyValueBuilder builder, ImmutableBytesWritable key, byte[]... values) {
return newRow(builder, HConstants.LATEST_TIMESTAMP, key, values);
}
@Override
public PColumn getColumn(String name) throws ColumnNotFoundException, AmbiguousColumnException {
List<PColumn> columns = columnsByName.get(name);
int size = columns.size();
if (size == 0) {
throw new ColumnNotFoundException(name);
}
if (size > 1) {
for (PColumn column : columns) {
if (column.getFamilyName() == null || QueryConstants.DEFAULT_COLUMN_FAMILY.equals(column.getFamilyName().getString())) {
// Allow ambiguity with PK column or column in the default column family,
// since a PK column cannot be prefixed and a user would not know how to
// prefix a column in the default column family.
return column;
}
}
throw new AmbiguousColumnException(name);
}
return columns.get(0);
}
/**
*
* PRow implementation for ColumnLayout.MULTI mode which stores column
* values across multiple hbase columns.
*
*
* @since 0.1
*/
private class PRowImpl implements PRow {
private final byte[] key;
private final ImmutableBytesWritable keyPtr;
// default to the generic builder, and only override when we know on the client
private final KeyValueBuilder kvBuilder;
private Put setValues;
private Delete unsetValues;
private Mutation deleteRow;
private final long ts;
public PRowImpl(KeyValueBuilder kvBuilder, ImmutableBytesWritable key, long ts, Integer bucketNum) {
this.kvBuilder = kvBuilder;
this.ts = ts;
if (bucketNum != null) {
this.key = SaltingUtil.getSaltedKey(key, bucketNum);
this.keyPtr = new ImmutableBytesPtr(this.key);
} else {
this.keyPtr = new ImmutableBytesPtr(key);
this.key = ByteUtil.copyKeyBytesIfNecessary(key);
}
newMutations();
}
private void newMutations() {
Put put = new Put(this.key);
Delete delete = new Delete(this.key);
if (isWALDisabled()) {
put.setDurability(Durability.SKIP_WAL);
delete.setDurability(Durability.SKIP_WAL);
}
this.setValues = put;
this.unsetValues = delete;
}
@Override
public List<Mutation> toRowMutations() {
List<Mutation> mutations = new ArrayList<Mutation>(3);
if (deleteRow != null) {
// Include only deleteRow mutation if present because it takes precedence over all others
mutations.add(deleteRow);
} else {
// Because we cannot enforce a not null constraint on a KV column (since we don't know if the row exists when
// we upsert it), se instead add a KV that is always emtpy. This allows us to imitate SQL semantics given the
// way HBase works.
addQuietly(setValues, kvBuilder, kvBuilder.buildPut(keyPtr,
SchemaUtil.getEmptyColumnFamilyPtr(PTableImpl.this),
QueryConstants.EMPTY_COLUMN_BYTES_PTR, ts,
QueryConstants.EMPTY_COLUMN_VALUE_BYTES_PTR));
mutations.add(setValues);
if (!unsetValues.isEmpty()) {
mutations.add(unsetValues);
}
}
return mutations;
}
private void removeIfPresent(Mutation m, byte[] family, byte[] qualifier) {
Map<byte[],List<Cell>> familyMap = m.getFamilyCellMap();
List<Cell> kvs = familyMap.get(family);
if (kvs != null) {
Iterator<Cell> iterator = kvs.iterator();
while (iterator.hasNext()) {
Cell kv = iterator.next();
if (Bytes.compareTo(kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength(),
qualifier, 0, qualifier.length) == 0) {
iterator.remove();
}
}
}
}
@Override
public void setValue(PColumn column, Object value) {
byte[] byteValue = value == null ? ByteUtil.EMPTY_BYTE_ARRAY : column.getDataType().toBytes(value);
setValue(column, byteValue);
}
@Override
public void setValue(PColumn column, byte[] byteValue) {
deleteRow = null;
byte[] family = column.getFamilyName().getBytes();
byte[] qualifier = column.getName().getBytes();
PDataType type = column.getDataType();
// Check null, since some types have no byte representation for null
boolean isNull = type.isNull(byteValue);
if (isNull && !getStoreNulls()) {
if (!column.isNullable()) {
throw new ConstraintViolationException(name.getString() + "." + column.getName().getString() + " may not be null");
}
removeIfPresent(setValues, family, qualifier);
deleteQuietly(unsetValues, kvBuilder, kvBuilder.buildDeleteColumns(keyPtr, column
.getFamilyName().getBytesPtr(), column.getName().getBytesPtr(), ts));
} else {
ImmutableBytesWritable ptr = new ImmutableBytesWritable(byteValue == null ?
HConstants.EMPTY_BYTE_ARRAY : byteValue);
Integer maxLength = column.getMaxLength();
if (!isNull && type.isFixedWidth() && maxLength != null) {
if (ptr.getLength() < maxLength) {
type.pad(ptr, maxLength, column.getSortOrder());
} else if (ptr.getLength() > maxLength) {
throw new DataExceedsCapacityException(name.getString() + "." + column.getName().getString() + " may not exceed " + maxLength + " bytes (" + type.toObject(byteValue) + ")");
}
}
removeIfPresent(unsetValues, family, qualifier);
addQuietly(setValues, kvBuilder, kvBuilder.buildPut(keyPtr,
column.getFamilyName().getBytesPtr(), column.getName().getBytesPtr(),
ts, ptr));
}
}
@SuppressWarnings("deprecation")
@Override
public void delete() {
newMutations();
// we're using the Tephra column family delete marker here to prevent the translation
// of deletes to puts by the Tephra's TransactionProcessor
if (PTableImpl.this.isTransactional()) {
Put delete = new Put(key);
for (PColumnFamily colFamily : families) {
delete.add(colFamily.getName().getBytes(), TxConstants.FAMILY_DELETE_QUALIFIER, ts,
HConstants.EMPTY_BYTE_ARRAY);
}
deleteRow = delete;
} else {
Delete delete = new Delete(key);
for (PColumnFamily colFamily : families) {
delete.deleteFamily(colFamily.getName().getBytes(), ts);
}
deleteRow = delete;
}
if (isWALDisabled()) {
deleteRow.setDurability(Durability.SKIP_WAL);
}
}
}
@Override
public PColumnFamily getColumnFamily(String familyName) throws ColumnFamilyNotFoundException {
PColumnFamily family = familyByString.get(familyName);
if (family == null) {
throw new ColumnFamilyNotFoundException(familyName);
}
return family;
}
@Override
public PColumnFamily getColumnFamily(byte[] familyBytes) throws ColumnFamilyNotFoundException {
PColumnFamily family = familyByBytes.get(familyBytes);
if (family == null) {
String familyName = Bytes.toString(familyBytes);
throw new ColumnFamilyNotFoundException(familyName);
}
return family;
}
@Override
public List<PColumn> getColumns() {
return allColumns;
}
@Override
public long getSequenceNumber() {
return sequenceNumber;
}
@Override
public long getTimeStamp() {
return timeStamp;
}
@Override
public long getIndexDisableTimestamp() {
return indexDisableTimestamp;
}
@Override
public PColumn getPKColumn(String name) throws ColumnNotFoundException {
List<PColumn> columns = columnsByName.get(name);
int size = columns.size();
if (size == 0) {
throw new ColumnNotFoundException(name);
}
if (size > 1) {
do {
PColumn column = columns.get(--size);
if (column.getFamilyName() == null) {
return column;
}
} while (size > 0);
throw new ColumnNotFoundException(name);
}
return columns.get(0);
}
@Override
public PName getPKName() {
return pkName;
}
@Override
public RowKeySchema getRowKeySchema() {
return rowKeySchema;
}
@Override
public Integer getBucketNum() {
return bucketNum;
}
@Override
public List<PTable> getIndexes() {
return indexes;
}
@Override
public PIndexState getIndexState() {
return state;
}
@Override
public PName getParentTableName() {
return parentTableName;
}
@Override
public PName getParentName() {
return parentName;
}
@Override
public synchronized IndexMaintainer getIndexMaintainer(PTable dataTable, PhoenixConnection connection) {
if (indexMaintainer == null) {
indexMaintainer = IndexMaintainer.create(dataTable, this, connection);
}
return indexMaintainer;
}
@Override
public synchronized boolean getIndexMaintainers(ImmutableBytesWritable ptr, PhoenixConnection connection) {
if (indexMaintainersPtr == null || indexMaintainersPtr.getLength()==0) {
indexMaintainersPtr = new ImmutableBytesWritable();
if (indexes.isEmpty()) {
indexMaintainersPtr.set(ByteUtil.EMPTY_BYTE_ARRAY);
} else {
IndexMaintainer.serialize(this, indexMaintainersPtr, connection);
}
}
ptr.set(indexMaintainersPtr.get(), indexMaintainersPtr.getOffset(), indexMaintainersPtr.getLength());
return indexMaintainersPtr.getLength() > 0;
}
@Override
public PName getPhysicalName() {
return physicalNames.isEmpty() ? getName() : physicalNames.get(0);
}
@Override
public List<PName> getPhysicalNames() {
return physicalNames;
}
@Override
public PName getDefaultFamilyName() {
return defaultFamilyName;
}
@Override
public String getViewStatement() {
return viewStatement;
}
@Override
public boolean isWALDisabled() {
return disableWAL;
}
@Override
public Short getViewIndexId() {
return viewIndexId;
}
@Override
public PName getTenantId() {
return tenantId;
}
@Override
public IndexType getIndexType() {
return indexType;
}
/**
* Construct a PTable instance from ProtoBuffered PTable instance
* @param table
*/
public static PTable createFromProto(PTableProtos.PTable table) {
PName tenantId = null;
if(table.hasTenantId()){
tenantId = PNameFactory.newName(table.getTenantId().toByteArray());
}
PName schemaName = PNameFactory.newName(table.getSchemaNameBytes().toByteArray());
PName tableName = PNameFactory.newName(table.getTableNameBytes().toByteArray());
PTableType tableType = PTableType.values()[table.getTableType().ordinal()];
PIndexState indexState = null;
if (table.hasIndexState()) {
indexState = PIndexState.fromSerializedValue(table.getIndexState());
}
Short viewIndexId = null;
if(table.hasViewIndexId()){
viewIndexId = (short)table.getViewIndexId();
}
IndexType indexType = IndexType.getDefault();
if(table.hasIndexType()){
indexType = IndexType.fromSerializedValue(table.getIndexType().toByteArray()[0]);
}
long sequenceNumber = table.getSequenceNumber();
long timeStamp = table.getTimeStamp();
long indexDisableTimestamp = table.getIndexDisableTimestamp();
PName pkName = null;
if (table.hasPkNameBytes()) {
pkName = PNameFactory.newName(table.getPkNameBytes().toByteArray());
}
int bucketNum = table.getBucketNum();
List<PColumn> columns = Lists.newArrayListWithExpectedSize(table.getColumnsCount());
for (PTableProtos.PColumn curPColumnProto : table.getColumnsList()) {
columns.add(PColumnImpl.createFromProto(curPColumnProto));
}
List<PTable> indexes = Lists.newArrayListWithExpectedSize(table.getIndexesCount());
for (PTableProtos.PTable curPTableProto : table.getIndexesList()) {
indexes.add(createFromProto(curPTableProto));
}
boolean isImmutableRows = table.getIsImmutableRows();
SortedMap<byte[], GuidePostsInfo> tableGuidePosts = new TreeMap<byte[], GuidePostsInfo>(Bytes.BYTES_COMPARATOR);
for (PTableProtos.PTableStats pTableStatsProto : table.getGuidePostsList()) {
PGuidePosts pGuidePosts = pTableStatsProto.getPGuidePosts();
int maxLength = pGuidePosts.getMaxLength();
int guidePostsCount = pGuidePosts.getEncodedGuidePostsCount();
GuidePostsInfo info = new GuidePostsInfo(pGuidePosts.getByteCountsList(),
new ImmutableBytesWritable(
HBaseZeroCopyByteString.zeroCopyGetBytes(pGuidePosts.getEncodedGuidePosts())),
pGuidePosts.getRowCountsList(), maxLength, guidePostsCount);
tableGuidePosts.put(pTableStatsProto.getKey().toByteArray(), info);
}
PTableStats stats = new PTableStatsImpl(tableGuidePosts, table.getStatsTimeStamp());
PName dataTableName = null;
if (table.hasDataTableNameBytes()) {
dataTableName = PNameFactory.newName(table.getDataTableNameBytes().toByteArray());
}
PName defaultFamilyName = null;
if (table.hasDefaultFamilyName()) {
defaultFamilyName = PNameFactory.newName(table.getDefaultFamilyName().toByteArray());
}
boolean disableWAL = table.getDisableWAL();
boolean multiTenant = table.getMultiTenant();
boolean storeNulls = table.getStoreNulls();
boolean isTransactional = table.getTransactional();
ViewType viewType = null;
String viewStatement = null;
List<PName> physicalNames = Collections.emptyList();
if (tableType == PTableType.VIEW) {
viewType = ViewType.fromSerializedValue(table.getViewType().toByteArray()[0]);
if(table.hasViewStatement()){
viewStatement = (String) PVarchar.INSTANCE.toObject(table.getViewStatement().toByteArray());
}
}
if (tableType == PTableType.VIEW || viewIndexId != null) {
physicalNames = Lists.newArrayListWithExpectedSize(table.getPhysicalNamesCount());
for(int i = 0; i < table.getPhysicalNamesCount(); i++){
physicalNames.add(PNameFactory.newName(table.getPhysicalNames(i).toByteArray()));
}
}
int baseColumnCount = -1;
if (table.hasBaseColumnCount()) {
baseColumnCount = table.getBaseColumnCount();
}
boolean rowKeyOrderOptimizable = false;
if (table.hasRowKeyOrderOptimizable()) {
rowKeyOrderOptimizable = table.getRowKeyOrderOptimizable();
}
long updateCacheFrequency = 0;
if (table.hasUpdateCacheFrequency()) {
updateCacheFrequency = table.getUpdateCacheFrequency();
}
try {
PTableImpl result = new PTableImpl();
result.init(tenantId, schemaName, tableName, tableType, indexState, timeStamp, sequenceNumber, pkName,
(bucketNum == NO_SALTING) ? null : bucketNum, columns, stats, schemaName,dataTableName, indexes,
isImmutableRows, physicalNames, defaultFamilyName, viewStatement, disableWAL,
multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable,
isTransactional, updateCacheFrequency, indexDisableTimestamp);
return result;
} catch (SQLException e) {
throw new RuntimeException(e); // Impossible
}
}
public static PTableProtos.PTable toProto(PTable table) {
PTableProtos.PTable.Builder builder = PTableProtos.PTable.newBuilder();
if(table.getTenantId() != null){
builder.setTenantId(ByteStringer.wrap(table.getTenantId().getBytes()));
}
builder.setSchemaNameBytes(ByteStringer.wrap(table.getSchemaName().getBytes()));
builder.setTableNameBytes(ByteStringer.wrap(table.getTableName().getBytes()));
builder.setTableType(ProtobufUtil.toPTableTypeProto(table.getType()));
if (table.getType() == PTableType.INDEX) {
if(table.getIndexState() != null) {
builder.setIndexState(table.getIndexState().getSerializedValue());
}
if(table.getViewIndexId() != null) {
builder.setViewIndexId(table.getViewIndexId());
}
if(table.getIndexType() != null) {
builder.setIndexType(ByteStringer.wrap(new byte[]{table.getIndexType().getSerializedValue()}));
}
}
builder.setSequenceNumber(table.getSequenceNumber());
builder.setTimeStamp(table.getTimeStamp());
PName tmp = table.getPKName();
if (tmp != null) {
builder.setPkNameBytes(ByteStringer.wrap(tmp.getBytes()));
}
Integer bucketNum = table.getBucketNum();
int offset = 0;
if(bucketNum == null){
builder.setBucketNum(NO_SALTING);
} else {
offset = 1;
builder.setBucketNum(bucketNum);
}
List<PColumn> columns = table.getColumns();
int columnSize = columns.size();
for (int i = offset; i < columnSize; i++) {
PColumn column = columns.get(i);
builder.addColumns(PColumnImpl.toProto(column));
}
List<PTable> indexes = table.getIndexes();
for (PTable curIndex : indexes) {
builder.addIndexes(toProto(curIndex));
}
builder.setIsImmutableRows(table.isImmutableRows());
for (Map.Entry<byte[], GuidePostsInfo> entry : table.getTableStats().getGuidePosts().entrySet()) {
PTableProtos.PTableStats.Builder statsBuilder = PTableProtos.PTableStats.newBuilder();
statsBuilder.setKey(ByteStringer.wrap(entry.getKey()));
statsBuilder.setGuidePostsCount(entry.getValue().getGuidePostsCount());
PGuidePostsProtos.PGuidePosts.Builder guidePstsBuilder = PGuidePostsProtos.PGuidePosts.newBuilder();
guidePstsBuilder.setEncodedGuidePosts(ByteStringer.wrap(entry.getValue().getGuidePosts().get()));
guidePstsBuilder.addAllByteCounts(entry.getValue().getByteCounts());
guidePstsBuilder.addAllRowCounts(entry.getValue().getRowCounts());
guidePstsBuilder.setMaxLength(entry.getValue().getMaxLength());
guidePstsBuilder.setEncodedGuidePostsCount(entry.getValue().getGuidePostsCount());
statsBuilder.setPGuidePosts(guidePstsBuilder);
builder.addGuidePosts(statsBuilder.build());
}
builder.setStatsTimeStamp(table.getTableStats().getTimestamp());
if (table.getParentName() != null) {
builder.setDataTableNameBytes(ByteStringer.wrap(table.getParentTableName().getBytes()));
}
if (table.getDefaultFamilyName()!= null) {
builder.setDefaultFamilyName(ByteStringer.wrap(table.getDefaultFamilyName().getBytes()));
}
builder.setDisableWAL(table.isWALDisabled());
builder.setMultiTenant(table.isMultiTenant());
builder.setStoreNulls(table.getStoreNulls());
builder.setTransactional(table.isTransactional());
if(table.getType() == PTableType.VIEW){
builder.setViewType(ByteStringer.wrap(new byte[]{table.getViewType().getSerializedValue()}));
builder.setViewStatement(ByteStringer.wrap(PVarchar.INSTANCE.toBytes(table.getViewStatement())));
}
if(table.getType() == PTableType.VIEW || table.getViewIndexId() != null){
for (int i = 0; i < table.getPhysicalNames().size(); i++) {
builder.addPhysicalNames(ByteStringer.wrap(table.getPhysicalNames().get(i).getBytes()));
}
}
builder.setBaseColumnCount(table.getBaseColumnCount());
builder.setRowKeyOrderOptimizable(table.rowKeyOrderOptimizable());
builder.setUpdateCacheFrequency(table.getUpdateCacheFrequency());
builder.setIndexDisableTimestamp(table.getIndexDisableTimestamp());
return builder.build();
}
@Override
public PTableKey getKey() {
return key;
}
@Override
public PTableStats getTableStats() {
return tableStats;
}
@Override
public PName getParentSchemaName() {
return parentSchemaName;
}
@Override
public boolean isTransactional() {
return isTransactional;
}
public int getBaseColumnCount() {
return baseColumnCount;
}
@Override
public boolean rowKeyOrderOptimizable() {
return rowKeyOrderOptimizable || !hasColumnsRequiringUpgrade;
}
@Override
public int getRowTimestampColPos() {
return rowTimestampColPos;
}
}