| /* |
| * 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.DriverManager; |
| import java.sql.SQLException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import javax.annotation.Nonnull; |
| |
| 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.io.ImmutableBytesWritable; |
| 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.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.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 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 Map<KVColumnFamilyQualifier, PColumn> kvColumnsByQualifiers; |
| 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 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; |
| private boolean isNamespaceMapped; |
| private String autoPartitionSeqName; |
| private boolean isAppendOnlySchema; |
| private ImmutableStorageScheme immutableStorageScheme; |
| private QualifierEncodingScheme qualifierEncodingScheme; |
| private EncodedCQCounter encodedCQCounter; |
| |
| public PTableImpl() { |
| this.indexes = Collections.emptyList(); |
| this.physicalNames = Collections.emptyList(); |
| this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA; |
| } |
| |
| // Constructor used at table creation time |
| public PTableImpl(PName tenantId, String schemaName, String tableName, long timestamp, List<PColumnFamily> families, boolean isNamespaceMapped) { |
| 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(); |
| this.isNamespaceMapped = isNamespaceMapped; |
| } |
| |
| public PTableImpl(PName tenantId, String schemaName, String tableName, long timestamp, List<PColumnFamily> families, boolean isNamespaceMapped, ImmutableStorageScheme storageScheme, QualifierEncodingScheme encodingScheme) { // 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(); |
| this.isNamespaceMapped = isNamespaceMapped; |
| this.immutableStorageScheme = storageScheme; |
| this.qualifierEncodingScheme = encodingScheme; |
| } |
| |
| // For indexes stored in shared physical tables |
| public PTableImpl(PName tenantId, PName schemaName, PName tableName, long timestamp, List<PColumnFamily> families, |
| List<PColumn> columns, List<PName> physicalNames, Short viewIndexId, boolean multiTenant, boolean isNamespaceMpped, ImmutableStorageScheme storageScheme, QualifierEncodingScheme qualifierEncodingScheme, |
| EncodedCQCounter encodedCQCounter) throws SQLException { |
| 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; |
| init(tenantId, this.schemaName, this.tableName, PTableType.INDEX, state, timeStamp, sequenceNumber, pkName, bucketNum, columns, |
| this.schemaName, parentTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName, |
| null, disableWAL, multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable, |
| isTransactional, updateCacheFrequency, indexDisableTimestamp, isNamespaceMpped, null, false, storageScheme, qualifierEncodingScheme, encodedCQCounter); |
| } |
| |
| 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.getParentSchemaName(), table.getViewStatement()); |
| } |
| |
| public static PTable makePTable(PTable index, PName indexName, String viewStatement, long updateCacheFrequency, PName tenantId) throws SQLException { |
| return Objects.equal(viewStatement, index.getViewStatement()) ? index : makePTable(index, indexName, index.getTimeStamp(), Lists.newArrayList(index.getPhysicalName()), index.getIndexes(), viewStatement, updateCacheFrequency, tenantId); |
| } |
| |
| public static PTableImpl makePTable(PTable table, PName tableName, long timeStamp, List<PName> physicalNames, List<PTable> indexes, String viewStatement, long updateCacheFrequency, PName tenantId) throws SQLException { |
| return new PTableImpl( |
| tenantId, table.getSchemaName(), tableName, table.getType(), table.getIndexState(), timeStamp, |
| table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table), table.getParentSchemaName(), table.getParentTableName(), |
| indexes, table.isImmutableRows(), physicalNames, table.getDefaultFamilyName(), viewStatement, |
| table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(), |
| table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), updateCacheFrequency, |
| table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter()); |
| } |
| |
| 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.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), |
| table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter()); |
| } |
| |
| public static PTableImpl makePTable(PTable table, Collection<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.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), |
| table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter()); |
| } |
| |
| public static PTableImpl makePTable(PTable table, Collection<PColumn> columns, PName defaultFamily) 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(), defaultFamily, table.getViewStatement(), |
| table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(), |
| table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), |
| table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter()); |
| } |
| |
| public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, Collection<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.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), |
| table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter()); |
| } |
| |
| public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, Collection<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.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), |
| table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter()); |
| } |
| |
| public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, Collection<PColumn> columns, boolean isImmutableRows, boolean isWalDisabled, |
| boolean isMultitenant, boolean storeNulls, boolean isTransactional, long updateCacheFrequency, boolean isNamespaceMapped) 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.getBaseColumnCount(), table.rowKeyOrderOptimizable(), isTransactional, updateCacheFrequency, table.getIndexDisableTimestamp(), |
| isNamespaceMapped, table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter()); |
| } |
| |
| 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.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), |
| table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter()); |
| } |
| |
| 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.getBaseColumnCount(), rowKeyOrderOptimizable, table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), |
| table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter()); |
| } |
| |
| public static PTableImpl makePTable(PTable table) 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.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), |
| table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter()); |
| } |
| |
| public static PTableImpl makePTable(PName tenantId, PName schemaName, PName tableName, PTableType type, |
| PIndexState state, long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum, |
| Collection<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, boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme, QualifierEncodingScheme qualifierEncodingScheme, EncodedCQCounter encodedCQCounter) 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, QueryConstants.BASE_TABLE_BASE_COLUMN_COUNT, rowKeyOrderOptimizable, isTransactional, |
| updateCacheFrequency,indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema, storageScheme, qualifierEncodingScheme, encodedCQCounter); |
| } |
| |
| public static PTableImpl makePTable(PName tenantId, PName schemaName, PName tableName, PTableType type, |
| PIndexState state, long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum, |
| Collection<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, |
| int baseColumnCount, long indexDisableTimestamp, boolean isNamespaceMapped, |
| String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme, QualifierEncodingScheme qualifierEncodingScheme, EncodedCQCounter encodedCQCounter) |
| 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, baseColumnCount, rowKeyOrderOptimizable, isTransactional, updateCacheFrequency, |
| indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema, storageScheme, qualifierEncodingScheme, encodedCQCounter); |
| } |
| |
| private PTableImpl(PName tenantId, PName schemaName, PName tableName, PTableType type, PIndexState state, |
| long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum, Collection<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, |
| int baseColumnCount, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency, |
| long indexDisableTimestamp, boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme, |
| QualifierEncodingScheme qualifierEncodingScheme, EncodedCQCounter encodedCQCounter) throws SQLException { |
| init(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName, bucketNum, columns, |
| parentSchemaName, parentTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName, |
| viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable, |
| isTransactional, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema, storageScheme, |
| qualifierEncodingScheme, encodedCQCounter); |
| } |
| |
| @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, Collection<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 , int baseColumnCount, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency, long indexDisableTimestamp, |
| boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme, QualifierEncodingScheme qualifierEncodingScheme, |
| EncodedCQCounter encodedCQCounter) 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.rowKeyOrderOptimizable = rowKeyOrderOptimizable; |
| this.updateCacheFrequency = updateCacheFrequency; |
| this.isNamespaceMapped = isNamespaceMapped; |
| this.autoPartitionSeqName = autoPartitionSeqName; |
| this.isAppendOnlySchema = 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. |
| this.immutableStorageScheme = storageScheme == null ? ImmutableStorageScheme.ONE_CELL_PER_COLUMN : storageScheme; |
| this.qualifierEncodingScheme = qualifierEncodingScheme == null ? QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : qualifierEncodingScheme; |
| List<PColumn> pkColumns; |
| PColumn[] allColumns; |
| |
| this.columnsByName = ArrayListMultimap.create(columns.size(), 1); |
| this.kvColumnsByQualifiers = Maps.newHashMapWithExpectedSize(columns.size()); |
| 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 (PColumn column : columns) { |
| 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(schemaName.getString(), name.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 (kvColumnsByQualifiers.get(info) != null) { |
| throw new ColumnAlreadyExistsException(schemaName.getString(), |
| name.getString(), columnName); |
| } |
| kvColumnsByQualifiers.put(info, column); |
| } |
| } |
| 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()]; |
| 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!=null ? parentSchemaName.getString() : null, 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; |
| this.encodedCQCounter = encodedCQCounter; |
| } |
| |
| @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) { |
| 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); |
| } |
| |
| @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) { |
| throw new ColumnNotFoundException("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; |
| |
| public 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); |
| 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, kvBuilder.buildPut(keyPtr, |
| colFamilyPtr, QueryConstants.SINGLE_KEYVALUE_COLUMN_QUALIFIER_BYTES_PTR, ts, ptr)); |
| } |
| setValues = put; |
| } |
| // 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, 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, kvBuilder.buildPut(keyPtr, |
| column.getFamilyName().getBytesPtr(), qualifierPtr, |
| 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 put = new Put(key); |
| if (families.isEmpty()) { |
| put.add(SchemaUtil.getEmptyColumnFamily(PTableImpl.this), TransactionFactory.getTransactionFactory().getTransactionContext().getFamilyDeleteMarker(), ts, |
| HConstants.EMPTY_BYTE_ARRAY); |
| } else { |
| for (PColumnFamily colFamily : families) { |
| put.add(colFamily.getName().getBytes(), TransactionFactory.getTransactionFactory().getTransactionContext().getFamilyDeleteMarker(), ts, |
| HConstants.EMPTY_BYTE_ARRAY); |
| } |
| } |
| deleteRow = put; |
| } 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() { |
| // 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() { |
| return SchemaUtil.getPhysicalHBaseTableName(physicalNames.isEmpty() ? getName() : physicalNames.get(0), |
| isNamespaceMapped, type); |
| } |
| |
| @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(); |
| 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(); |
| 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(); |
| } |
| boolean isNamespaceMapped=false; |
| if (table.hasIsNamespaceMapped()) { |
| isNamespaceMapped = table.getIsNamespaceMapped(); |
| } |
| String autoParititonSeqName = null; |
| if (table.hasAutoParititonSeqName()) { |
| autoParititonSeqName = 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 = null; |
| 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()); |
| } |
| } |
| } |
| |
| try { |
| PTableImpl result = new PTableImpl(); |
| result.init(tenantId, schemaName, tableName, tableType, indexState, timeStamp, sequenceNumber, pkName, |
| (bucketNum == NO_SALTING) ? null : bucketNum, columns, parentSchemaName, parentTableName, indexes, |
| isImmutableRows, physicalNames, defaultFamilyName, viewStatement, disableWAL, |
| multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable, |
| isTransactional, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoParititonSeqName, |
| isAppendOnlySchema, storageScheme, qualifierEncodingScheme, encodedColumnQualifierCounter); |
| 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()); |
| // 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()); |
| builder.setTransactional(table.isTransactional()); |
| 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()))); |
| } |
| 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()); |
| 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()})); |
| } |
| 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 boolean isTransactional() { |
| return isTransactional; |
| } |
| |
| @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; |
| } |
| |
| 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; |
| } |
| |
| } |
| } |