blob: dd6dcccc449f4897a11759fb00553c0c1a33429b [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.coprocessor.ScanRegionObserver.DYNAMIC_COLUMN_METADATA_STORED_FOR_MUTATION;
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.jdbc.PhoenixDatabaseMetaData.APPEND_ONLY_SCHEMA;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.AUTO_PARTITION_SEQ;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.COLUMN_ENCODED_BYTES;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.DISABLE_WAL;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ENCODING_SCHEME;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.GUIDE_POSTS_WIDTH;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IMMUTABLE_ROWS;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.DEFAULT_COLUMN_FAMILY_NAME;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IMMUTABLE_STORAGE_SCHEME;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MULTI_TENANT;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SALT_BUCKETS;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TRANSACTIONAL;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TRANSACTION_PROVIDER;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.UPDATE_CACHE_FREQUENCY;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.USE_STATS_FOR_PARALLELIZATION;
import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_COLUMN_ENCODED_BYTES;
import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_IMMUTABLE_STORAGE_SCHEME;
import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_MULTI_TENANT;
import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_SALT_BUCKETS;
import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_TRANSACTIONAL;
import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_TRANSACTION_PROVIDER;
import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_UPDATE_CACHE_FREQUENCY;
import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_USE_STATS_FOR_PARALLELIZATION;
import static org.apache.phoenix.schema.SaltingUtil.SALTING_COLUMN;
import static org.apache.phoenix.schema.TableProperty.DEFAULT_COLUMN_FAMILY;
import static org.apache.phoenix.schema.types.PDataType.TRUE_BYTES;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_NOT_DEFINED;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MIN_PHOENIX_TTL_HWM;
import java.io.IOException;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nonnull;
import com.google.common.annotations.VisibleForTesting;
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.Increment;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress;
import org.apache.hadoop.hbase.util.ByteStringer;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.phoenix.compile.ExpressionCompiler;
import org.apache.phoenix.compile.StatementContext;
import org.apache.phoenix.coprocessor.generated.DynamicColumnMetaDataProtos;
import org.apache.phoenix.coprocessor.generated.PTableProtos;
import org.apache.phoenix.exception.DataExceedsCapacityException;
import org.apache.phoenix.expression.Expression;
import org.apache.phoenix.expression.LiteralExpression;
import org.apache.phoenix.expression.SingleCellConstructorExpression;
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.jdbc.PhoenixStatement;
import org.apache.phoenix.parse.ParseNode;
import org.apache.phoenix.parse.SQLParser;
import org.apache.phoenix.protobuf.ProtobufUtil;
import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.schema.RowKeySchema.RowKeySchemaBuilder;
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.transaction.TransactionFactory;
import org.apache.phoenix.util.ByteUtil;
import org.apache.phoenix.util.EncodedColumnsUtil;
import org.apache.phoenix.util.MetaDataUtil;
import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.SchemaUtil;
import org.apache.phoenix.util.SizedUtil;
import org.apache.phoenix.util.TrustedByteArrayOutputStream;
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;
/**
*
* 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 static final int VIEW_MODIFIED_UPDATE_CACHE_FREQUENCY_BIT_SET_POS = 0;
private static final int VIEW_MODIFIED_USE_STATS_FOR_PARALLELIZATION_BIT_SET_POS = 1;
private static final int VIEW_MODIFIED_PHOENIX_TTL_BIT_SET_POS = 2;
private IndexMaintainer indexMaintainer;
private ImmutableBytesWritable indexMaintainersPtr;
private final PTableKey key;
private final PName name;
private final PName schemaName;
private final PName tableName;
private final PName tenantId;
private final PTableType type;
private final PIndexState state;
private final long sequenceNumber;
private final long timeStamp;
private final long indexDisableTimestamp;
// Have MultiMap for String->PColumn (may need family qualifier)
private final List<PColumn> pkColumns;
private final List<PColumn> allColumns;
// columns that were inherited from a parent table but that were dropped in the view
private final List<PColumn> excludedColumns;
private final List<PColumnFamily> families;
private final Map<byte[], PColumnFamily> familyByBytes;
private final Map<String, PColumnFamily> familyByString;
private final ListMultimap<String, PColumn> columnsByName;
private final Map<KVColumnFamilyQualifier, PColumn> kvColumnsByQualifiers;
private final PName pkName;
private final Integer bucketNum;
private final RowKeySchema rowKeySchema;
// Indexes associated with this table.
private final List<PTable> indexes;
// Data table name that the index is created on.
private final PName parentName;
private final PName parentSchemaName;
private final PName parentTableName;
private final List<PName> physicalNames;
private final boolean isImmutableRows;
private final PName defaultFamilyName;
private final String viewStatement;
private final boolean disableWAL;
private final boolean multiTenant;
private final boolean storeNulls;
private final TransactionFactory.Provider transactionProvider;
private final ViewType viewType;
private final PDataType viewIndexIdType;
private final Long viewIndexId;
private final int estimatedSize;
private final IndexType indexType;
private final int baseColumnCount;
private final boolean rowKeyOrderOptimizable; // TODO: remove when required that tables have been upgrade for PHOENIX-2067
private final boolean hasColumnsRequiringUpgrade; // TODO: remove when required that tables have been upgrade for PHOENIX-2067
private final int rowTimestampColPos;
private final long updateCacheFrequency;
private final boolean isNamespaceMapped;
private final String autoPartitionSeqName;
private final boolean isAppendOnlySchema;
private final ImmutableStorageScheme immutableStorageScheme;
private final QualifierEncodingScheme qualifierEncodingScheme;
private final EncodedCQCounter encodedCQCounter;
private final Boolean useStatsForParallelization;
private final long phoenixTTL;
private final long phoenixTTLHighWaterMark;
private final BitSet viewModifiedPropSet;
private Map<String, String> propertyValues;
public static class Builder {
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;
private List<PColumn> pkColumns;
private List<PColumn> allColumns;
private List<PColumn> excludedColumns;
private List<PColumnFamily> families;
private Map<byte[], PColumnFamily> familyByBytes;
private Map<String, PColumnFamily> familyByString;
private ListMultimap<String, PColumn> columnsByName;
private Map<KVColumnFamilyQualifier, PColumn> kvColumnsByQualifiers;
private PName pkName;
private Integer bucketNum;
private RowKeySchema rowKeySchema;
private List<PTable> indexes;
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 TransactionFactory.Provider transactionProvider;
private ViewType viewType;
private PDataType viewIndexIdType;
private Long viewIndexId;
private int estimatedSize;
private IndexType indexType;
private int baseColumnCount;
private boolean rowKeyOrderOptimizable;
private boolean hasColumnsRequiringUpgrade;
private int rowTimestampColPos;
private long updateCacheFrequency;
private boolean isNamespaceMapped;
private String autoPartitionSeqName;
private boolean isAppendOnlySchema;
private ImmutableStorageScheme immutableStorageScheme;
private QualifierEncodingScheme qualifierEncodingScheme;
private EncodedCQCounter encodedCQCounter;
private Boolean useStatsForParallelization;
private long phoenixTTL;
private long phoenixTTLHighWaterMark;
private Map<String, String> propertyValues = new HashMap<>();
// Used to denote which properties a view has explicitly modified
private BitSet viewModifiedPropSet = new BitSet(3);
// Optionally set columns for the builder, but not for the actual PTable
private Collection<PColumn> columns;
public Builder setKey(PTableKey key) {
this.key = key;
return this;
}
public Builder setName(PName name) {
this.name = name;
return this;
}
public Builder setSchemaName(PName schemaName) {
this.schemaName = schemaName;
return this;
}
public Builder setTableName(PName tableName) {
this.tableName = tableName;
return this;
}
public Builder setTenantId(PName tenantId) {
this.tenantId = tenantId;
return this;
}
public Builder setType(PTableType type) {
this.type = type;
return this;
}
public Builder setState(PIndexState state) {
this.state = state;
return this;
}
public Builder setSequenceNumber(long sequenceNumber) {
this.sequenceNumber = sequenceNumber;
return this;
}
public Builder setTimeStamp(long timeStamp) {
this.timeStamp = timeStamp;
return this;
}
public Builder setIndexDisableTimestamp(long indexDisableTimestamp) {
this.indexDisableTimestamp = indexDisableTimestamp;
return this;
}
public Builder setPkColumns(List<PColumn> pkColumns) {
this.pkColumns = pkColumns;
return this;
}
public Builder setAllColumns(List<PColumn> allColumns) {
this.allColumns = allColumns;
return this;
}
public Builder setExcludedColumns(List<PColumn> excludedColumns) {
this.excludedColumns = excludedColumns;
return this;
}
public Builder setFamilyAttributes(List<PColumnFamily> families) {
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;
return this;
}
public Builder setFamilies(List<PColumnFamily> families) {
this.families = families;
return this;
}
public Builder setFamilyByBytes(Map<byte[], PColumnFamily> familyByBytes) {
this.familyByBytes = familyByBytes;
return this;
}
public Builder setFamilyByString(Map<String, PColumnFamily> familyByString) {
this.familyByString = familyByString;
return this;
}
public Builder setColumnsByName(ListMultimap<String, PColumn> columnsByName) {
this.columnsByName = columnsByName;
return this;
}
public Builder setKvColumnsByQualifiers(Map<KVColumnFamilyQualifier, PColumn> kvColumnsByQualifiers) {
this.kvColumnsByQualifiers = kvColumnsByQualifiers;
return this;
}
public Builder setPkName(PName pkName) {
this.pkName = pkName;
return this;
}
public Builder setBucketNum(Integer bucketNum) {
if(bucketNum!=null) {
propertyValues.put(SALT_BUCKETS, String.valueOf(bucketNum));
}
this.bucketNum = bucketNum;
return this;
}
public Builder setRowKeySchema(RowKeySchema rowKeySchema) {
this.rowKeySchema = rowKeySchema;
return this;
}
public Builder setIndexes(List<PTable> indexes) {
this.indexes = indexes;
return this;
}
public Builder setParentName(PName parentName) {
this.parentName = parentName;
return this;
}
public Builder setParentSchemaName(PName parentSchemaName) {
this.parentSchemaName = parentSchemaName;
return this;
}
public Builder setParentTableName(PName parentTableName) {
this.parentTableName = parentTableName;
return this;
}
public Builder setPhysicalNames(List<PName> physicalNames) {
this.physicalNames = physicalNames;
return this;
}
public Builder setImmutableRows(boolean immutableRows) {
propertyValues.put(IMMUTABLE_ROWS, String.valueOf(immutableRows));
isImmutableRows = immutableRows;
return this;
}
public Builder setIndexMaintainer(IndexMaintainer indexMaintainer) {
this.indexMaintainer = indexMaintainer;
return this;
}
public Builder setIndexMaintainersPtr(ImmutableBytesWritable indexMaintainersPtr) {
this.indexMaintainersPtr = indexMaintainersPtr;
return this;
}
public Builder setDefaultFamilyName(PName defaultFamilyName) {
if (defaultFamilyName != null){
propertyValues.put(DEFAULT_COLUMN_FAMILY_NAME, defaultFamilyName.getString());
}
this.defaultFamilyName = defaultFamilyName;
return this;
}
public Builder setViewStatement(String viewStatement) {
this.viewStatement = viewStatement;
return this;
}
public Builder setDisableWAL(boolean disableWAL) {
propertyValues.put(DISABLE_WAL, String.valueOf(disableWAL));
this.disableWAL = disableWAL;
return this;
}
public Builder setMultiTenant(boolean multiTenant) {
propertyValues.put(MULTI_TENANT, String.valueOf(multiTenant));
this.multiTenant = multiTenant;
return this;
}
public Builder setStoreNulls(boolean storeNulls) {
this.storeNulls = storeNulls;
return this;
}
public Builder setTransactionProvider(TransactionFactory.Provider transactionProvider) {
if(transactionProvider != null) {
propertyValues.put(TRANSACTION_PROVIDER, String.valueOf(transactionProvider));
}
this.transactionProvider = transactionProvider;
return this;
}
public Builder setViewType(ViewType viewType) {
this.viewType = viewType;
return this;
}
public Builder setViewIndexIdType(PDataType viewIndexIdType) {
this.viewIndexIdType = viewIndexIdType;
return this;
}
public Builder setViewIndexId(Long viewIndexId) {
this.viewIndexId = viewIndexId;
return this;
}
public Builder setEstimatedSize(int estimatedSize) {
this.estimatedSize = estimatedSize;
return this;
}
public Builder setIndexType(IndexType indexType) {
this.indexType = indexType;
return this;
}
public Builder setBaseColumnCount(int baseColumnCount) {
this.baseColumnCount = baseColumnCount;
return this;
}
public Builder setRowKeyOrderOptimizable(boolean rowKeyOrderOptimizable) {
this.rowKeyOrderOptimizable = rowKeyOrderOptimizable;
return this;
}
public Builder setHasColumnsRequiringUpgrade(boolean hasColumnsRequiringUpgrade) {
this.hasColumnsRequiringUpgrade = hasColumnsRequiringUpgrade;
return this;
}
public Builder setRowTimestampColPos(int rowTimestampColPos) {
this.rowTimestampColPos = rowTimestampColPos;
return this;
}
public Builder setUpdateCacheFrequency(long updateCacheFrequency) {
propertyValues.put(UPDATE_CACHE_FREQUENCY, String.valueOf(updateCacheFrequency));
this.updateCacheFrequency = updateCacheFrequency;
return this;
}
public Builder setNamespaceMapped(boolean namespaceMapped) {
isNamespaceMapped = namespaceMapped;
return this;
}
public Builder setAutoPartitionSeqName(String autoPartitionSeqName) {
propertyValues.put(AUTO_PARTITION_SEQ, autoPartitionSeqName);
this.autoPartitionSeqName = autoPartitionSeqName;
return this;
}
public Builder setAppendOnlySchema(boolean appendOnlySchema) {
propertyValues.put(APPEND_ONLY_SCHEMA, String.valueOf(appendOnlySchema));
isAppendOnlySchema = appendOnlySchema;
return this;
}
public Builder setImmutableStorageScheme(ImmutableStorageScheme immutableStorageScheme) {
propertyValues.put(IMMUTABLE_STORAGE_SCHEME, immutableStorageScheme.toString());
this.immutableStorageScheme = immutableStorageScheme;
return this;
}
public Builder setQualifierEncodingScheme(QualifierEncodingScheme qualifierEncodingScheme) {
propertyValues.put(ENCODING_SCHEME, qualifierEncodingScheme.toString());
this.qualifierEncodingScheme = qualifierEncodingScheme;
return this;
}
public Builder setEncodedCQCounter(EncodedCQCounter encodedCQCounter) {
this.encodedCQCounter = encodedCQCounter;
return this;
}
public Builder setUseStatsForParallelization(Boolean useStatsForParallelization) {
if(useStatsForParallelization!=null) {
propertyValues.put(USE_STATS_FOR_PARALLELIZATION, String.valueOf(useStatsForParallelization));
}
this.useStatsForParallelization = useStatsForParallelization;
return this;
}
public Builder setViewModifiedUpdateCacheFrequency(boolean modified) {
this.viewModifiedPropSet.set(VIEW_MODIFIED_UPDATE_CACHE_FREQUENCY_BIT_SET_POS,
modified);
return this;
}
public Builder setViewModifiedUseStatsForParallelization(boolean modified) {
this.viewModifiedPropSet.set(VIEW_MODIFIED_USE_STATS_FOR_PARALLELIZATION_BIT_SET_POS,
modified);
return this;
}
public Builder setPhoenixTTL(long phoenixTTL) {
this.phoenixTTL = phoenixTTL;
return this;
}
public Builder setPhoenixTTLHighWaterMark(long phoenixTTLHighWaterMark) {
this.phoenixTTLHighWaterMark = phoenixTTLHighWaterMark;
return this;
}
public Builder setViewModifiedPhoenixTTL(boolean modified) {
this.viewModifiedPropSet.set(VIEW_MODIFIED_PHOENIX_TTL_BIT_SET_POS,
modified);
return this;
}
/**
* Note: When set in the builder, we must call {@link Builder#initDerivedAttributes()}
* before building the PTable in order to correctly populate other attributes of the PTable
* @param columns PColumns to be set in the builder
* @return PTableImpl.Builder object
*/
public Builder setColumns(Collection<PColumn> columns) {
this.columns = columns;
return this;
}
/**
* Populate derivable attributes of the PTable
* @return PTableImpl.Builder object
* @throws SQLException
*/
private Builder initDerivedAttributes() throws SQLException {
checkTenantId(this.tenantId);
Preconditions.checkNotNull(this.schemaName);
Preconditions.checkNotNull(this.tableName);
Preconditions.checkNotNull(this.columns);
Preconditions.checkNotNull(this.indexes);
Preconditions.checkNotNull(this.physicalNames);
Preconditions.checkNotNull(this.hasColumnsRequiringUpgrade);
Preconditions.checkNotNull(this.rowKeyOrderOptimizable);
PName fullName = PNameFactory.newName(SchemaUtil.getTableName(
this.schemaName.getString(), this.tableName.getString()));
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(this.tenantId) +
PNameFactory.getEstimatedSize(this.schemaName) +
PNameFactory.getEstimatedSize(this.tableName) +
PNameFactory.getEstimatedSize(this.pkName) +
PNameFactory.getEstimatedSize(this.parentTableName) +
PNameFactory.getEstimatedSize(this.defaultFamilyName);
int numPKColumns = 0;
List<PColumn> pkColumns;
PColumn[] allColumns;
if (this.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[this.columns.size()+1];
allColumns[SALTING_COLUMN.getPosition()] = SALTING_COLUMN;
pkColumns = Lists.newArrayListWithExpectedSize(this.columns.size()+1);
++numPKColumns;
} else {
allColumns = new PColumn[this.columns.size()];
pkColumns = Lists.newArrayListWithExpectedSize(this.columns.size());
}
// Must do this as with the new method of storing diffs, we just care about
// ordinal position relative order and not the true ordinal value itself.
List<PColumn> sortedColumns = Lists.newArrayList(this.columns);
Collections.sort(sortedColumns, new Comparator<PColumn>() {
@Override
public int compare(PColumn o1, PColumn o2) {
return Integer.valueOf(o1.getPosition()).compareTo(o2.getPosition());
}
});
int position = 0;
if (this.bucketNum != null) {
position = 1;
}
ListMultimap<String, PColumn> populateColumnsByName =
ArrayListMultimap.create(this.columns.size(), 1);
Map<KVColumnFamilyQualifier, PColumn> populateKvColumnsByQualifiers =
Maps.newHashMapWithExpectedSize(this.columns.size());
for (PColumn column : sortedColumns) {
allColumns[position] = column;
position++;
PName familyName = column.getFamilyName();
if (familyName == null) {
++numPKColumns;
}
String columnName = column.getName().getString();
if (populateColumnsByName.put(columnName, column)) {
int count = 0;
for (PColumn dupColumn : populateColumnsByName.get(columnName)) {
if (Objects.equal(familyName, dupColumn.getFamilyName())) {
count++;
if (count > 1) {
throw new ColumnAlreadyExistsException(this.schemaName.getString(),
fullName.getString(), columnName);
}
}
}
}
byte[] cq = column.getColumnQualifierBytes();
String cf = column.getFamilyName() != null ?
column.getFamilyName().getString() : null;
if (cf != null && cq != null) {
KVColumnFamilyQualifier info = new KVColumnFamilyQualifier(cf, cq);
if (populateKvColumnsByQualifiers.get(info) != null) {
throw new ColumnAlreadyExistsException(this.schemaName.getString(),
fullName.getString(), columnName);
}
populateKvColumnsByQualifiers.put(info, column);
}
}
estimatedSize += SizedUtil.sizeOfMap(allColumns.length, SizedUtil.POINTER_SIZE,
SizedUtil.sizeOfArrayList(1)); // for multi-map
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;
boolean hasColsRequiringUpgrade = false;
for (PColumn column : allColumns) {
PName familyName = column.getFamilyName();
if (familyName == null) {
hasColsRequiringUpgrade |=
(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);
}
}
int rowTimestampColPos;
if (rowTimestampCol != null) {
rowTimestampColPos = pkColumns.indexOf(rowTimestampCol);
} else {
rowTimestampColPos = -1;
}
Iterator<Map.Entry<PName,List<PColumn>>> iterator = familyMap.entrySet().iterator();
PColumnFamily[] families = new PColumnFamily[familyMap.size()];
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();
}
estimatedSize += SizedUtil.sizeOfArrayList(families.length);
estimatedSize += SizedUtil.sizeOfMap(families.length) * 2;
for (PTable index : this.indexes) {
estimatedSize += index.getEstimatedSize();
}
estimatedSize += PNameFactory.getEstimatedSize(this.parentName);
for (PName physicalName : this.physicalNames) {
estimatedSize += physicalName.getEstimatedSize();
}
// Populate the derived fields and return the builder
return this.setName(fullName)
.setKey(new PTableKey(this.tenantId, fullName.getString()))
.setParentName(this.parentTableName == null ? null :
PNameFactory.newName(SchemaUtil.getTableName(
this.parentSchemaName != null ?
this.parentSchemaName.getString() : null,
this.parentTableName.getString())))
.setColumnsByName(populateColumnsByName)
.setKvColumnsByQualifiers(populateKvColumnsByQualifiers)
.setAllColumns(ImmutableList.copyOf(allColumns))
.setHasColumnsRequiringUpgrade(hasColsRequiringUpgrade
| this.hasColumnsRequiringUpgrade)
.setPkColumns(ImmutableList.copyOf(pkColumns))
.setRowTimestampColPos(rowTimestampColPos)
// after hasDescVarLengthColumns is calculated
.setRowKeySchema(builder.rowKeyOrderOptimizable(
this.rowKeyOrderOptimizable || !this.hasColumnsRequiringUpgrade)
.build())
.setFamilies(ImmutableList.copyOf(families))
.setFamilyByBytes(familyByBytes.build())
.setFamilyByString(familyByString.build())
.setEstimatedSize(estimatedSize + this.rowKeySchema.getEstimatedSize());
}
public PTableImpl build() throws SQLException {
// Note that we call initDerivedAttributes to populate derivable attributes if
// this.columns is set in the PTableImpl.Builder object
return (this.columns == null) ? new PTableImpl(this) :
new PTableImpl(this.initDerivedAttributes());
}
}
@VisibleForTesting
PTableImpl() {
this(new PTableImpl.Builder()
.setIndexes(Collections.<PTable>emptyList())
.setPhysicalNames(Collections.<PName>emptyList())
.setRowKeySchema(RowKeySchema.EMPTY_SCHEMA));
}
// Private constructor used by the builder
private PTableImpl(Builder builder) {
this.key = builder.key;
this.name = builder.name;
this.schemaName = builder.schemaName;
this.tableName = builder.tableName;
this.tenantId = builder.tenantId;
this.type = builder.type;
this.state = builder.state;
this.sequenceNumber = builder.sequenceNumber;
this.timeStamp = builder.timeStamp;
this.indexDisableTimestamp = builder.indexDisableTimestamp;
this.pkColumns = builder.pkColumns;
this.allColumns = builder.allColumns;
this.excludedColumns = builder.excludedColumns;
this.families = builder.families;
this.familyByBytes = builder.familyByBytes;
this.familyByString = builder.familyByString;
this.columnsByName = builder.columnsByName;
this.kvColumnsByQualifiers = builder.kvColumnsByQualifiers;
this.pkName = builder.pkName;
this.bucketNum = builder.bucketNum;
this.rowKeySchema = builder.rowKeySchema;
this.indexes = builder.indexes;
this.parentName = builder.parentName;
this.parentSchemaName = builder.parentSchemaName;
this.parentTableName = builder.parentTableName;
this.physicalNames = builder.physicalNames;
this.isImmutableRows = builder.isImmutableRows;
this.indexMaintainer = builder.indexMaintainer;
this.indexMaintainersPtr = builder.indexMaintainersPtr;
this.defaultFamilyName = builder.defaultFamilyName;
this.viewStatement = builder.viewStatement;
this.disableWAL = builder.disableWAL;
this.multiTenant = builder.multiTenant;
this.storeNulls = builder.storeNulls;
this.transactionProvider = builder.transactionProvider;
this.viewType = builder.viewType;
this.viewIndexIdType = builder.viewIndexIdType;
this.viewIndexId = builder.viewIndexId;
this.estimatedSize = builder.estimatedSize;
this.indexType = builder.indexType;
this.baseColumnCount = builder.baseColumnCount;
this.rowKeyOrderOptimizable = builder.rowKeyOrderOptimizable;
this.hasColumnsRequiringUpgrade = builder.hasColumnsRequiringUpgrade;
this.rowTimestampColPos = builder.rowTimestampColPos;
this.updateCacheFrequency = builder.updateCacheFrequency;
this.isNamespaceMapped = builder.isNamespaceMapped;
this.autoPartitionSeqName = builder.autoPartitionSeqName;
this.isAppendOnlySchema = builder.isAppendOnlySchema;
this.immutableStorageScheme = builder.immutableStorageScheme;
this.qualifierEncodingScheme = builder.qualifierEncodingScheme;
this.encodedCQCounter = builder.encodedCQCounter;
this.useStatsForParallelization = builder.useStatsForParallelization;
this.phoenixTTL = builder.phoenixTTL;
this.phoenixTTLHighWaterMark = builder.phoenixTTLHighWaterMark;
this.viewModifiedPropSet = builder.viewModifiedPropSet;
this.propertyValues = builder.propertyValues;
}
// 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 == null ? Collections.<PColumn> emptyList() :
(table.getBucketNum() == null ? table.getColumns() :
table.getColumns().subList(1, table.getColumns().size()));
}
/**
* Get a PTableImpl.Builder from an existing PTable and set the builder columns
* @param table Original PTable
* @param columns Columns to set in the builder for the new PTable to be constructed
* @return PTable builder object based on an existing PTable
*/
public static PTableImpl.Builder builderWithColumns(PTable table, Collection<PColumn> columns) {
return builderFromExisting(table).setColumns(columns);
}
/**
* Get a PTableImpl.Builder from an existing PTable
* @param table Original PTable
*/
private static PTableImpl.Builder builderFromExisting(PTable table) {
return new PTableImpl.Builder()
.setType(table.getType())
.setState(table.getIndexState())
.setTimeStamp(table.getTimeStamp())
.setIndexDisableTimestamp(table.getIndexDisableTimestamp())
.setSequenceNumber(table.getSequenceNumber())
.setImmutableRows(table.isImmutableRows())
.setViewStatement(table.getViewStatement())
.setDisableWAL(table.isWALDisabled())
.setMultiTenant(table.isMultiTenant())
.setStoreNulls(table.getStoreNulls())
.setViewType(table.getViewType())
.setViewIndexIdType(table.getviewIndexIdType())
.setViewIndexId(table.getViewIndexId())
.setIndexType(table.getIndexType())
.setTransactionProvider(table.getTransactionProvider())
.setUpdateCacheFrequency(table.getUpdateCacheFrequency())
.setNamespaceMapped(table.isNamespaceMapped())
.setAutoPartitionSeqName(table.getAutoPartitionSeqName())
.setAppendOnlySchema(table.isAppendOnlySchema())
.setImmutableStorageScheme(table.getImmutableStorageScheme() == null ?
ImmutableStorageScheme.ONE_CELL_PER_COLUMN : table.getImmutableStorageScheme())
.setQualifierEncodingScheme(table.getEncodingScheme() == null ?
QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : table.getEncodingScheme())
.setBaseColumnCount(table.getBaseColumnCount())
.setEncodedCQCounter(table.getEncodedCQCounter())
.setUseStatsForParallelization(table.useStatsForParallelization())
.setExcludedColumns(table.getExcludedColumns() == null ?
ImmutableList.<PColumn>of() : ImmutableList.copyOf(table.getExcludedColumns()))
.setTenantId(table.getTenantId())
.setSchemaName(table.getSchemaName())
.setTableName(table.getTableName())
.setPkName(table.getPKName())
.setDefaultFamilyName(table.getDefaultFamilyName())
.setRowKeyOrderOptimizable(table.rowKeyOrderOptimizable())
.setBucketNum(table.getBucketNum())
.setIndexes(table.getIndexes() == null ?
Collections.<PTable>emptyList() : table.getIndexes())
.setParentSchemaName(table.getParentSchemaName())
.setParentTableName(table.getParentTableName())
.setPhysicalNames(table.getPhysicalNames() == null ?
ImmutableList.<PName>of() : ImmutableList.copyOf(table.getPhysicalNames()))
.setViewModifiedUseStatsForParallelization(table
.hasViewModifiedUseStatsForParallelization())
.setViewModifiedUpdateCacheFrequency(table.hasViewModifiedUpdateCacheFrequency())
.setViewModifiedPhoenixTTL(table.hasViewModifiedPhoenixTTL())
.setPhoenixTTL(table.getPhoenixTTL())
.setPhoenixTTLHighWaterMark(table.getPhoenixTTLHighWaterMark());
}
@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;
}
public static void checkTenantId(PName tenantId) {
// tenantId should be null or not empty
Preconditions.checkArgument(tenantId == null || tenantId.getBytes().length > 0);
}
@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) {
List<PColumn> columns = getPKColumns();
int nValues = values.length;
while (nValues > 0 && (values[nValues-1] == null || values[nValues-1].length == 0)) {
nValues--;
}
for (PColumn column : columns) {
if (column.getExpressionStr() != null) {
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);
}
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) {
if (column.getExpressionStr() != null) {
try {
String url = PhoenixRuntime.JDBC_PROTOCOL
+ PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR
+ PhoenixRuntime.CONNECTIONLESS;
PhoenixConnection conn = DriverManager.getConnection(url)
.unwrap(PhoenixConnection.class);
StatementContext context =
new StatementContext(new PhoenixStatement(conn));
ExpressionCompiler compiler = new ExpressionCompiler(context);
ParseNode defaultParseNode =
new SQLParser(column.getExpressionStr()).parseExpression();
Expression defaultExpression = defaultParseNode.accept(compiler);
defaultExpression.evaluate(null, key);
column.getDataType().coerceBytes(key, null,
defaultExpression.getDataType(),
defaultExpression.getMaxLength(), defaultExpression.getScale(),
defaultExpression.getSortOrder(),
column.getMaxLength(), column.getScale(),
column.getSortOrder());
byteValue = ByteUtil.copyKeyBytesIfNecessary(key);
} catch (SQLException e) { // should not be possible
throw new ConstraintViolationException(name.getString() + "."
+ column.getName().getString()
+ " failed to compile default value expression of "
+ column.getExpressionStr());
}
}
else {
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();
Integer scale = column.getScale();
key.set(byteValue);
if (!type.isSizeCompatible(key, null, type, sortOrder, null, null, maxLength, scale)) {
throw new DataExceedsCapacityException(name.getString() + "." + column.getName().getString() + " may not exceed " + maxLength + " (" + SchemaUtil.toString(type, byteValue) + ")");
}
key.set(byteValue);
type.pad(key, maxLength, sortOrder);
byteValue = ByteUtil.copyKeyBytesIfNecessary(key);
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, boolean hasOnDupKey, byte[]... values) {
PRow row = new PRowImpl(builder, key, ts, getBucketNum(), hasOnDupKey);
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,
boolean hasOnDupKey, byte[]... values) {
return newRow(builder, ts, key, 0, hasOnDupKey, values);
}
@Override
public PRow newRow(KeyValueBuilder builder, ImmutableBytesWritable key, boolean hasOnDupKey, byte[]... values) {
return newRow(builder, HConstants.LATEST_TIMESTAMP, key, hasOnDupKey, values);
}
@Override
public PColumn getColumnForColumnName(String name) throws ColumnNotFoundException, AmbiguousColumnException {
List<PColumn> columns = columnsByName.get(name);
int size = columns.size();
if (size == 0) {
String schemaNameStr = schemaName==null?null:schemaName.getString();
String tableNameStr = tableName==null?null:tableName.getString();
throw new ColumnNotFoundException(schemaNameStr, tableNameStr, null, 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);
}
@Override
public PColumn getColumnForColumnQualifier(byte[] cf, byte[] cq) throws ColumnNotFoundException, AmbiguousColumnException {
Preconditions.checkNotNull(cq);
if (!EncodedColumnsUtil.usesEncodedColumnNames(this) || cf == null) {
String columnName = (String)PVarchar.INSTANCE.toObject(cq);
return getColumnForColumnName(columnName);
} else {
String family = (String)PVarchar.INSTANCE.toObject(cf);
PColumn col = kvColumnsByQualifiers.get(new KVColumnFamilyQualifier(family, cq));
if (col == null) {
String schemaNameStr = schemaName==null?null:schemaName.getString();
String tableNameStr = tableName==null?null:tableName.getString();
throw new ColumnNotFoundException(schemaNameStr, tableNameStr, null,
"No column found for column qualifier " + qualifierEncodingScheme.decode(cq));
}
return col;
}
}
/**
*
* 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 Mutation setValues;
private Delete unsetValues;
private Mutation deleteRow;
private final long ts;
private final boolean hasOnDupKey;
// map from column name to value
private Map<PColumn, byte[]> columnToValueMap;
// Map from the column family name to the list of dynamic columns in that column family.
// If there are no dynamic columns in a column family, the key for that column family
// will not exist in the map, rather than the corresponding value being an empty list.
private Map<String, List<PColumn>> colFamToDynamicColumnsMapping;
PRowImpl(KeyValueBuilder kvBuilder, ImmutableBytesWritable key, long ts, Integer bucketNum, boolean hasOnDupKey) {
this.kvBuilder = kvBuilder;
this.ts = ts;
this.hasOnDupKey = hasOnDupKey;
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);
}
this.columnToValueMap = Maps.newHashMapWithExpectedSize(1);
this.colFamToDynamicColumnsMapping = Maps.newHashMapWithExpectedSize(1);
newMutations();
}
private void newMutations() {
Mutation put = this.hasOnDupKey ? new Increment(this.key) : 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 {
// store all columns for a given column family in a single cell instead of one column per cell in order to improve write performance
if (immutableStorageScheme != null && immutableStorageScheme != ImmutableStorageScheme.ONE_CELL_PER_COLUMN) {
Put put = new Put(this.key);
if (isWALDisabled()) {
put.setDurability(Durability.SKIP_WAL);
}
// the setValues Put contains one cell per column, we need to convert it to a Put that contains a cell with all columns for a given column family
for (PColumnFamily family : families) {
byte[] columnFamily = family.getName().getBytes();
Collection<PColumn> columns = family.getColumns();
int maxEncodedColumnQualifier = Integer.MIN_VALUE;
for (PColumn column : columns) {
int qualifier = qualifierEncodingScheme.decode(column.getColumnQualifierBytes());
maxEncodedColumnQualifier = Math.max(maxEncodedColumnQualifier, qualifier);
}
Expression[] colValues = EncodedColumnsUtil.createColumnExpressionArray(maxEncodedColumnQualifier);
for (PColumn column : columns) {
if (columnToValueMap.containsKey(column)) {
int colIndex = qualifierEncodingScheme.decode(column.getColumnQualifierBytes())-QueryConstants.ENCODED_CQ_COUNTER_INITIAL_VALUE+1;
colValues[colIndex] = new LiteralExpression(columnToValueMap.get(column));
}
}
List<Expression> children = Arrays.asList(colValues);
// we use SingleCellConstructorExpression to serialize all the columns into a single byte[]
SingleCellConstructorExpression singleCellConstructorExpression = new SingleCellConstructorExpression(immutableStorageScheme, children);
ImmutableBytesWritable ptr = new ImmutableBytesWritable();
singleCellConstructorExpression.evaluate(null, ptr);
ImmutableBytesPtr colFamilyPtr = new ImmutableBytesPtr(columnFamily);
addQuietly(put, kvBuilder.buildPut(keyPtr,
colFamilyPtr, QueryConstants.SINGLE_KEYVALUE_COLUMN_QUALIFIER_BYTES_PTR, ts, ptr));
}
// Preserve the attributes of the original mutation
Map<String, byte[]> attrsMap = setValues.getAttributesMap();
setValues = put;
for (String attrKey : attrsMap.keySet()) {
setValues.setAttribute(attrKey, attrsMap.get(attrKey));
}
}
// 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), so instead add a KV that is always empty. This allows us to imitate SQL semantics given the
// way HBase works.
Pair<byte[], byte[]> emptyKvInfo = EncodedColumnsUtil.getEmptyKeyValueInfo(PTableImpl.this);
addQuietly(setValues, kvBuilder.buildPut(keyPtr,
SchemaUtil.getEmptyColumnFamilyPtr(PTableImpl.this),
new ImmutableBytesPtr(emptyKvInfo.getFirst()), ts,
new ImmutableBytesPtr(emptyKvInfo.getSecond())));
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();
break;
}
}
}
}
@Override
public void setValue(PColumn column, byte[] byteValue) {
deleteRow = null;
byte[] family = column.getFamilyName().getBytes();
byte[] qualifier = column.getColumnQualifierBytes();
ImmutableBytesPtr qualifierPtr = new ImmutableBytesPtr(qualifier);
PDataType<?> type = column.getDataType();
// Check null, since some types have no byte representation for null
if (byteValue == null) {
byteValue = ByteUtil.EMPTY_BYTE_ARRAY;
}
boolean isNull = type.isNull(byteValue);
if (isNull && !column.isNullable()) {
throw new ConstraintViolationException(name.getString() + "." + column.getName().getString() +
" may not be null");
} else if (isNull && PTableImpl.this.isImmutableRows() && column.getExpressionStr() == null) {
// Store nulls for immutable tables otherwise default value would be used
removeIfPresent(setValues, family, qualifier);
removeIfPresent(unsetValues, family, qualifier);
} else if (isNull && !getStoreNulls() && !this.hasOnDupKey && column.getExpressionStr() == null) {
// Cannot use column delete marker when row has ON DUPLICATE KEY clause
// because we cannot change a Delete mutation to a Put mutation in the
// case of updates occurring due to the execution of the clause.
removeIfPresent(setValues, family, qualifier);
deleteQuietly(unsetValues, kvBuilder, kvBuilder.buildDeleteColumns(keyPtr, column
.getFamilyName().getBytesPtr(), qualifierPtr, ts));
} else {
ImmutableBytesWritable ptr = new ImmutableBytesWritable(byteValue);
Integer maxLength = column.getMaxLength();
Integer scale = column.getScale();
SortOrder sortOrder = column.getSortOrder();
if (!type.isSizeCompatible(ptr, null, type, sortOrder, null, null, maxLength, scale)) {
throw new DataExceedsCapacityException(name.getString() + "." + column.getName().getString() +
" may not exceed " + maxLength + " (" + SchemaUtil.toString(type, byteValue) + ")");
}
ptr.set(byteValue);
type.pad(ptr, maxLength, sortOrder);
removeIfPresent(unsetValues, family, qualifier);
// store all columns for a given column family in a single cell instead of one column per cell in order to improve write performance
// we don't need to do anything with unsetValues as it is only used when storeNulls is false, storeNulls is always true when storeColsInSingleCell is true
if (immutableStorageScheme == ImmutableStorageScheme.SINGLE_CELL_ARRAY_WITH_OFFSETS) {
columnToValueMap.put(column, ptr.get());
}
else {
removeIfPresent(unsetValues, family, qualifier);
addQuietly(setValues, kvBuilder.buildPut(keyPtr,
column.getFamilyName().getBytesPtr(), qualifierPtr,
ts, ptr));
}
String fam = Bytes.toString(family);
if (column.isDynamic()) {
if (!this.colFamToDynamicColumnsMapping.containsKey(fam)) {
this.colFamToDynamicColumnsMapping.put(fam, new ArrayList<PColumn>());
}
this.colFamToDynamicColumnsMapping.get(fam).add(column);
}
}
}
/**
* Add attributes to the Put mutations indicating that we need to add shadow cells to Puts
* to store dynamic column metadata. See
* {@link org.apache.phoenix.coprocessor.ScanRegionObserver#preBatchMutate(ObserverContext,
* MiniBatchOperationInProgress)}
*/
public boolean setAttributesForDynamicColumnsIfReqd() {
if (this.colFamToDynamicColumnsMapping == null ||
this.colFamToDynamicColumnsMapping.isEmpty()) {
return false;
}
boolean attrsForDynColsSet = false;
for (Entry<String, List<PColumn>> colFamToDynColsList :
this.colFamToDynamicColumnsMapping.entrySet()) {
DynamicColumnMetaDataProtos.DynamicColumnMetaData.Builder builder =
DynamicColumnMetaDataProtos.DynamicColumnMetaData.newBuilder();
for (PColumn dynCol : colFamToDynColsList.getValue()) {
builder.addDynamicColumns(PColumnImpl.toProto(dynCol));
}
if (builder.getDynamicColumnsCount() != 0) {
// The attribute key is the column family name and the value is the
// serialized list of dynamic columns
setValues.setAttribute(colFamToDynColsList.getKey(),
builder.build().toByteArray());
attrsForDynColsSet = true;
}
}
return attrsForDynColsSet;
}
@Override public void setAttributeToProcessDynamicColumnsMetadata() {
setValues.setAttribute(DYNAMIC_COLUMN_METADATA_STORED_FOR_MUTATION, TRUE_BYTES);
}
@SuppressWarnings("deprecation")
@Override
public void delete() {
newMutations();
Delete delete = new Delete(key);
if (families.isEmpty()) {
delete.addFamily(SchemaUtil.getEmptyColumnFamily(PTableImpl.this), ts);
} else {
for (PColumnFamily colFamily : families) {
delete.addFamily(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) {
String schemaNameStr = schemaName==null?null:schemaName.getString();
String tableNameStr = tableName==null?null:tableName.getString();
throw new ColumnFamilyNotFoundException(schemaNameStr, tableNameStr, familyName);
}
return family;
}
@Override
public PColumnFamily getColumnFamily(byte[] familyBytes) throws ColumnFamilyNotFoundException {
PColumnFamily family = familyByBytes.get(familyBytes);
if (family == null) {
String familyName = Bytes.toString(familyBytes);
String schemaNameStr = schemaName==null?null:schemaName.getString();
String tableNameStr = tableName==null?null:tableName.getString();
throw new ColumnFamilyNotFoundException(schemaNameStr, tableNameStr, familyName);
}
return family;
}
@Override
public List<PColumn> getColumns() {
return allColumns;
}
@Override
public List<PColumn> getExcludedColumns() {
return excludedColumns;
}
@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) {
String schemaNameStr = schemaName==null?null:schemaName.getString();
String tableNameStr = tableName==null?null:tableName.getString();
throw new ColumnNotFoundException(schemaNameStr, tableNameStr, null, name);
}
if (size > 1) {
do {
PColumn column = columns.get(--size);
if (column.getFamilyName() == null) {
return column;
}
} while (size > 0);
String schemaNameStr = schemaName==null?null:schemaName.getString();
String tableNameStr = tableName==null?null:tableName.getString();
throw new ColumnNotFoundException(schemaNameStr, tableNameStr, null, 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() {
// a view on a table will not have a parent name but will have a physical table name (which is the parent)
return (type!=PTableType.VIEW || parentName!=null) ? parentTableName :
PNameFactory.newName(SchemaUtil.getTableNameFromFullName(getPhysicalName().getBytes()));
}
@Override
public PName getParentName() {
// a view on a table will not have a parent name but will have a physical table name (which is the parent)
return (type!=PTableType.VIEW || parentName!=null) ? parentName : getPhysicalName();
}
@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() {
if (physicalNames.isEmpty()) {
return SchemaUtil.getPhysicalHBaseTableName(schemaName, tableName, isNamespaceMapped);
} else {
return PNameFactory.newName(physicalNames.get(0).getBytes());
}
}
@Override
public List<PName> getPhysicalNames() {
return !physicalNames.isEmpty() ? physicalNames : Lists.newArrayList(getPhysicalName());
}
@Override
public PName getDefaultFamilyName() {
return defaultFamilyName;
}
@Override
public String getViewStatement() {
return viewStatement;
}
@Override
public boolean isWALDisabled() {
return disableWAL;
}
@Override
public Long getViewIndexId() {
return viewIndexId;
}
@Override
public PDataType getviewIndexIdType() {
return viewIndexIdType;
}
@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) {
if (table==null)
return null;
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());
}
Long viewIndexId = null;
if (table.hasViewIndexId()) {
viewIndexId = table.getViewIndexId();
}
PDataType viewIndexIdType = table.hasViewIndexIdType()
? PDataType.fromTypeId(table.getViewIndexIdType())
: MetaDataUtil.getLegacyViewIndexIdDataType();
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();
PName parentSchemaName = null;
PName parentTableName = null;
if (table.hasParentNameBytes()) {
parentSchemaName = PNameFactory.newName(SchemaUtil.getSchemaNameFromFullName((table.getParentNameBytes().toByteArray())));
parentTableName = PNameFactory.newName(SchemaUtil.getTableNameFromFullName(table.getParentNameBytes().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();
TransactionFactory.Provider transactionProvider = null;
if (table.hasTransactionProvider()) {
transactionProvider = TransactionFactory.Provider.fromCode(table.getTransactionProvider());
} else if (table.hasTransactional()) {
// For backward compatibility prior to transactionProvider field
transactionProvider = TransactionFactory.Provider.TEPHRA;
}
ViewType viewType = null;
String viewStatement = null;
if (tableType == PTableType.VIEW) {
viewType = ViewType.fromSerializedValue(table.getViewType().toByteArray()[0]);
}
if(table.hasViewStatement()){
viewStatement = (String) PVarchar.INSTANCE.toObject(table.getViewStatement().toByteArray());
}
List<PName> 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();
}
boolean isNamespaceMapped=false;
if (table.hasIsNamespaceMapped()) {
isNamespaceMapped = table.getIsNamespaceMapped();
}
String autoPartitionSeqName = null;
if (table.hasAutoParititonSeqName()) {
autoPartitionSeqName = table.getAutoParititonSeqName();
}
boolean isAppendOnlySchema = false;
if (table.hasIsAppendOnlySchema()) {
isAppendOnlySchema = table.getIsAppendOnlySchema();
}
// For backward compatibility. Clients older than 4.10 will always have non-encoded immutable tables.
ImmutableStorageScheme storageScheme = ImmutableStorageScheme.ONE_CELL_PER_COLUMN;
if (table.hasStorageScheme()) {
storageScheme = ImmutableStorageScheme.fromSerializedValue(table.getStorageScheme().toByteArray()[0]);
}
// For backward compatibility. Clients older than 4.10 will always have non-encoded qualifiers.
QualifierEncodingScheme qualifierEncodingScheme = QualifierEncodingScheme.NON_ENCODED_QUALIFIERS;
if (table.hasEncodingScheme()) {
qualifierEncodingScheme = QualifierEncodingScheme.fromSerializedValue(table.getEncodingScheme().toByteArray()[0]);
}
EncodedCQCounter encodedColumnQualifierCounter;
if ((!EncodedColumnsUtil.usesEncodedColumnNames(qualifierEncodingScheme) || tableType == PTableType.VIEW)) {
encodedColumnQualifierCounter = PTable.EncodedCQCounter.NULL_COUNTER;
}
else {
encodedColumnQualifierCounter = new EncodedCQCounter();
if (table.getEncodedCQCountersList() != null) {
for (org.apache.phoenix.coprocessor.generated.PTableProtos.EncodedCQCounter cqCounterFromProto : table.getEncodedCQCountersList()) {
encodedColumnQualifierCounter.setValue(cqCounterFromProto.getColFamily(), cqCounterFromProto.getCounter());
}
}
}
Boolean useStatsForParallelization = null;
if (table.hasUseStatsForParallelization()) {
useStatsForParallelization = table.getUseStatsForParallelization();
}
long phoenixTTL = PHOENIX_TTL_NOT_DEFINED;
if (table.hasPhoenixTTL()) {
phoenixTTL = table.getPhoenixTTL();
}
long phoenixTTLHighWaterMark = MIN_PHOENIX_TTL_HWM;
if (table.hasPhoenixTTLHighWaterMark()) {
phoenixTTLHighWaterMark = table.getPhoenixTTLHighWaterMark();
}
// for older clients just use the value of the properties that are set on the view
boolean viewModifiedUpdateCacheFrequency = true;
boolean viewModifiedUseStatsForParallelization = true;
boolean viewModifiedPhoenixTTL = true;
if (table.hasViewModifiedUpdateCacheFrequency()) {
viewModifiedUpdateCacheFrequency = table.getViewModifiedUpdateCacheFrequency();
}
if (table.hasViewModifiedUseStatsForParallelization()) {
viewModifiedUseStatsForParallelization = table.getViewModifiedUseStatsForParallelization();
}
if (table.hasViewModifiedPhoenixTTL()) {
viewModifiedPhoenixTTL = table.getViewModifiedPhoenixTTL();
}
try {
return new PTableImpl.Builder()
.setType(tableType)
.setState(indexState)
.setTimeStamp(timeStamp)
.setIndexDisableTimestamp(indexDisableTimestamp)
.setSequenceNumber(sequenceNumber)
.setImmutableRows(isImmutableRows)
.setViewStatement(viewStatement)
.setDisableWAL(disableWAL)
.setMultiTenant(multiTenant)
.setStoreNulls(storeNulls)
.setViewType(viewType)
.setViewIndexIdType(viewIndexIdType)
.setViewIndexId(viewIndexId)
.setIndexType(indexType)
.setTransactionProvider(transactionProvider)
.setUpdateCacheFrequency(updateCacheFrequency)
.setNamespaceMapped(isNamespaceMapped)
.setAutoPartitionSeqName(autoPartitionSeqName)
.setAppendOnlySchema(isAppendOnlySchema)
// null check for backward compatibility and sanity. If any of the two below is null,
// then it means the table is a non-encoded table.
.setImmutableStorageScheme(storageScheme == null ?
ImmutableStorageScheme.ONE_CELL_PER_COLUMN : storageScheme)
.setQualifierEncodingScheme(qualifierEncodingScheme == null ?
QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : qualifierEncodingScheme)
.setBaseColumnCount(baseColumnCount)
.setEncodedCQCounter(encodedColumnQualifierCounter)
.setUseStatsForParallelization(useStatsForParallelization)
.setPhoenixTTL(phoenixTTL)
.setPhoenixTTLHighWaterMark(phoenixTTLHighWaterMark)
.setExcludedColumns(ImmutableList.<PColumn>of())
.setTenantId(tenantId)
.setSchemaName(schemaName)
.setTableName(tableName)
.setPkName(pkName)
.setDefaultFamilyName(defaultFamilyName)
.setRowKeyOrderOptimizable(rowKeyOrderOptimizable)
.setBucketNum((bucketNum == NO_SALTING) ? null : bucketNum)
.setIndexes(indexes == null ? Collections.<PTable>emptyList() : indexes)
.setParentSchemaName(parentSchemaName)
.setParentTableName(parentTableName)
.setPhysicalNames(physicalNames == null ?
ImmutableList.<PName>of() : ImmutableList.copyOf(physicalNames))
.setColumns(columns)
.setViewModifiedUpdateCacheFrequency(viewModifiedUpdateCacheFrequency)
.setViewModifiedUseStatsForParallelization(viewModifiedUseStatsForParallelization)
.setViewModifiedPhoenixTTL(viewModifiedPhoenixTTL)
.build();
} 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());
builder.setViewIndexIdType(table.getviewIndexIdType().getSqlType());
}
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());
// TODO remove this field in 5.0 release
if (table.getParentName() != null) {
builder.setDataTableNameBytes(ByteStringer.wrap(table.getParentTableName().getBytes()));
}
if (table.getParentName() !=null) {
builder.setParentNameBytes(ByteStringer.wrap(table.getParentName().getBytes()));
}
if (table.getDefaultFamilyName()!= null) {
builder.setDefaultFamilyName(ByteStringer.wrap(table.getDefaultFamilyName().getBytes()));
}
builder.setDisableWAL(table.isWALDisabled());
builder.setMultiTenant(table.isMultiTenant());
builder.setStoreNulls(table.getStoreNulls());
if (table.getTransactionProvider() != null) {
builder.setTransactionProvider(table.getTransactionProvider().getCode());
}
if(table.getType() == PTableType.VIEW){
builder.setViewType(ByteStringer.wrap(new byte[]{table.getViewType().getSerializedValue()}));
}
if(table.getViewStatement()!=null){
builder.setViewStatement(ByteStringer.wrap(PVarchar.INSTANCE.toBytes(table.getViewStatement())));
}
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());
builder.setIsNamespaceMapped(table.isNamespaceMapped());
if (table.getAutoPartitionSeqName() != null) {
builder.setAutoParititonSeqName(table.getAutoPartitionSeqName());
}
builder.setIsAppendOnlySchema(table.isAppendOnlySchema());
if (table.getImmutableStorageScheme() != null) {
builder.setStorageScheme(ByteStringer.wrap(new byte[]{table.getImmutableStorageScheme().getSerializedMetadataValue()}));
}
if (table.getEncodedCQCounter() != null) {
Map<String, Integer> values = table.getEncodedCQCounter().values();
for (Entry<String, Integer> cqCounter : values.entrySet()) {
org.apache.phoenix.coprocessor.generated.PTableProtos.EncodedCQCounter.Builder cqBuilder = org.apache.phoenix.coprocessor.generated.PTableProtos.EncodedCQCounter.newBuilder();
cqBuilder.setColFamily(cqCounter.getKey());
cqBuilder.setCounter(cqCounter.getValue());
builder.addEncodedCQCounters(cqBuilder.build());
}
}
if (table.getEncodingScheme() != null) {
builder.setEncodingScheme(ByteStringer.wrap(new byte[]{table.getEncodingScheme().getSerializedMetadataValue()}));
}
if (table.useStatsForParallelization() != null) {
builder.setUseStatsForParallelization(table.useStatsForParallelization());
}
builder.setPhoenixTTL(table.getPhoenixTTL());
builder.setPhoenixTTLHighWaterMark(table.getPhoenixTTLHighWaterMark());
builder.setViewModifiedUpdateCacheFrequency(table.hasViewModifiedUpdateCacheFrequency());
builder.setViewModifiedUseStatsForParallelization(table.hasViewModifiedUseStatsForParallelization());
builder.setViewModifiedPhoenixTTL(table.hasViewModifiedPhoenixTTL());
return builder.build();
}
@Override
public PTableKey getKey() {
return key;
}
@Override
public PName getParentSchemaName() {
// a view on a table will not have a parent name but will have a physical table name (which is the parent)
return (type!=PTableType.VIEW || parentName!=null) ? parentSchemaName :
PNameFactory.newName(SchemaUtil.getSchemaNameFromFullName(getPhysicalName().getBytes()));
}
@Override
public TransactionFactory.Provider getTransactionProvider() {
return transactionProvider;
}
@Override
public final boolean isTransactional() {
return transactionProvider != null;
}
@Override
public int getBaseColumnCount() {
return baseColumnCount;
}
@Override
public boolean rowKeyOrderOptimizable() {
return rowKeyOrderOptimizable || !hasColumnsRequiringUpgrade;
}
@Override
public int getRowTimestampColPos() {
return rowTimestampColPos;
}
@Override
public boolean isNamespaceMapped() {
return isNamespaceMapped;
}
@Override
public String getAutoPartitionSeqName() {
return autoPartitionSeqName;
}
@Override
public boolean isAppendOnlySchema() {
return isAppendOnlySchema;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (! (obj instanceof PTable)) return false;
PTable other = (PTable) obj;
if (key == null) {
if (other.getKey() != null) return false;
} else if (!key.equals(other.getKey())) return false;
return true;
}
@Override
public ImmutableStorageScheme getImmutableStorageScheme() {
return immutableStorageScheme;
}
@Override
public EncodedCQCounter getEncodedCQCounter() {
return encodedCQCounter;
}
@Override
public QualifierEncodingScheme getEncodingScheme() {
return qualifierEncodingScheme;
}
@Override
public Boolean useStatsForParallelization() {
return useStatsForParallelization;
}
@Override
public long getPhoenixTTL() {
return phoenixTTL;
}
@Override
public long getPhoenixTTLHighWaterMark() {
return phoenixTTLHighWaterMark;
}
@Override public boolean hasViewModifiedUpdateCacheFrequency() {
return viewModifiedPropSet.get(VIEW_MODIFIED_UPDATE_CACHE_FREQUENCY_BIT_SET_POS);
}
@Override public boolean hasViewModifiedUseStatsForParallelization() {
return viewModifiedPropSet.get(VIEW_MODIFIED_USE_STATS_FOR_PARALLELIZATION_BIT_SET_POS);
}
@Override public boolean hasViewModifiedPhoenixTTL() {
return viewModifiedPropSet.get(VIEW_MODIFIED_PHOENIX_TTL_BIT_SET_POS);
}
private static final class KVColumnFamilyQualifier {
@Nonnull
private final String colFamilyName;
@Nonnull
private final byte[] colQualifier;
public KVColumnFamilyQualifier(String colFamilyName, byte[] colQualifier) {
Preconditions.checkArgument(colFamilyName != null && colQualifier != null,
"None of the arguments, column family name or column qualifier can be null");
this.colFamilyName = colFamilyName;
this.colQualifier = colQualifier;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + colFamilyName.hashCode();
result = prime * result + Arrays.hashCode(colQualifier);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
KVColumnFamilyQualifier other = (KVColumnFamilyQualifier) obj;
if (!colFamilyName.equals(other.colFamilyName)) return false;
if (!Arrays.equals(colQualifier, other.colQualifier)) return false;
return true;
}
}
@Override
public Map<String, String> getPropertyValues() {
return Collections.unmodifiableMap(propertyValues);
}
@Override
public Map<String, String> getDefaultPropertyValues() {
Map<String, String> map = new HashMap<>();
map.put(DISABLE_WAL, String.valueOf(DEFAULT_DISABLE_WAL));
map.put(IMMUTABLE_ROWS, String.valueOf(DEFAULT_IMMUTABLE_ROWS));
map.put(TRANSACTION_PROVIDER, DEFAULT_TRANSACTION_PROVIDER);
map.put(IMMUTABLE_STORAGE_SCHEME, DEFAULT_IMMUTABLE_STORAGE_SCHEME);
map.put(COLUMN_ENCODED_BYTES, String.valueOf(DEFAULT_COLUMN_ENCODED_BYTES));
map.put(UPDATE_CACHE_FREQUENCY, String.valueOf(DEFAULT_UPDATE_CACHE_FREQUENCY));
map.put(USE_STATS_FOR_PARALLELIZATION, String.valueOf(DEFAULT_USE_STATS_FOR_PARALLELIZATION));
map.put(TRANSACTIONAL, String.valueOf(DEFAULT_TRANSACTIONAL));
map.put(MULTI_TENANT, String.valueOf(DEFAULT_MULTI_TENANT));
map.put(SALT_BUCKETS, String.valueOf(DEFAULT_SALT_BUCKETS));
map.put(DEFAULT_COLUMN_FAMILY_NAME, String.valueOf(DEFAULT_COLUMN_FAMILY));
return Collections.unmodifiableMap(map);
}
}