org.apache.phoenix.util.MetaDataUtil Maven / Gradle / Ivy
Show all versions of phoenix-server-hbase-2.6
/*
* 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.util;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.*;
import static org.apache.phoenix.util.SchemaUtil.getVarChars;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.*;
import org.apache.phoenix.schema.ColumnFamilyNotFoundException;
import org.apache.phoenix.schema.ColumnNotFoundException;
import org.apache.phoenix.schema.PColumn;
import org.apache.phoenix.schema.PColumnFamily;
import org.apache.phoenix.schema.PName;
import org.apache.phoenix.schema.PNameFactory;
import org.apache.phoenix.schema.PTable;
import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.schema.SequenceKey;
import org.apache.phoenix.schema.SortOrder;
import org.apache.phoenix.schema.TableNotFoundException;
import org.apache.phoenix.schema.TableProperty;
import org.apache.phoenix.schema.types.PVarchar;
import org.apache.phoenix.thirdparty.com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.ExtendedCell;
import org.apache.hadoop.hbase.ExtendedCellBuilder;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.TagUtil;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.coprocessorclient.MetaDataProtocol;
import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.hbase.index.util.GenericKeyValueBuilder;
import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr;
import org.apache.phoenix.hbase.index.util.IndexManagementUtil;
import org.apache.phoenix.hbase.index.util.KeyValueBuilder;
import org.apache.phoenix.hbase.index.util.VersionUtil;
import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.schema.PTable.IndexType;
import org.apache.phoenix.schema.PTable.LinkType;
import org.apache.phoenix.schema.types.PBoolean;
import org.apache.phoenix.schema.types.PDataType;
import org.apache.phoenix.schema.types.PInteger;
import org.apache.phoenix.schema.types.PLong;
import org.apache.phoenix.schema.types.PSmallint;
import org.apache.phoenix.schema.types.PUnsignedTinyint;
import org.apache.phoenix.thirdparty.com.google.common.collect.ImmutableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.phoenix.thirdparty.com.google.common.collect.ImmutableList;
import org.apache.phoenix.thirdparty.com.google.common.collect.Iterables;
import org.apache.phoenix.thirdparty.com.google.common.collect.Lists;
public class MetaDataUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(MetaDataUtil.class);
public static final String VIEW_INDEX_TABLE_PREFIX = "_IDX_";
public static final String LOCAL_INDEX_TABLE_PREFIX = "_LOCAL_IDX_";
public static final String VIEW_INDEX_SEQUENCE_PREFIX = "_SEQ_";
public static final String VIEW_INDEX_SEQUENCE_NAME_PREFIX = "_ID_";
public static final byte[] VIEW_INDEX_SEQUENCE_PREFIX_BYTES = Bytes.toBytes(VIEW_INDEX_SEQUENCE_PREFIX);
public static final String VIEW_INDEX_ID_COLUMN_NAME = "_INDEX_ID";
public static final String PARENT_TABLE_KEY = "PARENT_TABLE";
public static final String IS_VIEW_INDEX_TABLE_PROP_NAME = "IS_VIEW_INDEX_TABLE";
public static final byte[] IS_VIEW_INDEX_TABLE_PROP_BYTES = Bytes.toBytes(IS_VIEW_INDEX_TABLE_PROP_NAME);
public static final String IS_LOCAL_INDEX_TABLE_PROP_NAME = "IS_LOCAL_INDEX_TABLE";
public static final byte[] IS_LOCAL_INDEX_TABLE_PROP_BYTES = Bytes.toBytes(IS_LOCAL_INDEX_TABLE_PROP_NAME);
public static final String DATA_TABLE_NAME_PROP_NAME = "DATA_TABLE_NAME";
public static final byte[] DATA_TABLE_NAME_PROP_BYTES = Bytes.toBytes(DATA_TABLE_NAME_PROP_NAME);
private static final Map ALLOWED_SERVER_CLIENT_MAJOR_VERSION =
ImmutableMap.of(
new MajorMinorVersion(5, 1), new MajorMinorVersion(4, 16)
);
// See PHOENIX-3955
public static final List SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES = ImmutableList.of(
ColumnFamilyDescriptorBuilder.TTL,
ColumnFamilyDescriptorBuilder.KEEP_DELETED_CELLS,
ColumnFamilyDescriptorBuilder.REPLICATION_SCOPE);
public static Put getLastDDLTimestampUpdate(byte[] tableHeaderRowKey,
long clientTimestamp,
long lastDDLTimestamp) {
//use client timestamp as the timestamp of the Cell, to match the other Cells that might
// be created by this DDL. But the actual value will be a _server_ timestamp
Put p = new Put(tableHeaderRowKey, clientTimestamp);
byte[] lastDDLTimestampBytes = PLong.INSTANCE.toBytes(lastDDLTimestamp);
p.addColumn(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES,
PhoenixDatabaseMetaData.LAST_DDL_TIMESTAMP_BYTES, lastDDLTimestampBytes);
return p;
}
public static Put getExternalSchemaIdUpdate(byte[] tableHeaderRowKey,
String externalSchemaId) {
//use client timestamp as the timestamp of the Cell, to match the other Cells that might
// be created by this DDL. But the actual value will be a _server_ timestamp
Put p = new Put(tableHeaderRowKey);
byte[] externalSchemaIdBytes = PVarchar.INSTANCE.toBytes(externalSchemaId);
p.addColumn(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES,
PhoenixDatabaseMetaData.EXTERNAL_SCHEMA_ID_BYTES, externalSchemaIdBytes);
return p;
}
/**
* Checks if a table is meant to be queried directly (and hence is relevant to external
* systems tracking Phoenix schema)
* @param tableType
* @return True if a table or view, false otherwise (such as for an index, system table, or
* subquery)
*/
public static boolean isTableDirectlyQueried(PTableType tableType) {
return tableType.equals(PTableType.TABLE) || tableType.equals(PTableType.VIEW);
}
public static class ClientServerCompatibility {
private int errorCode;
private boolean isCompatible;
ClientServerCompatibility() {
this.errorCode = 0;
}
public int getErrorCode() {
return this.errorCode;
}
void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public boolean getIsCompatible() {
return this.isCompatible;
}
void setCompatible(boolean isCompatible) {
this.isCompatible = isCompatible;
}
}
public static ClientServerCompatibility areClientAndServerCompatible(long serverHBaseAndPhoenixVersion) {
// As of 3.0, we allow a client and server to differ for the minor version.
// Care has to be taken to upgrade the server before the client, as otherwise
// the client may call expressions that don't yet exist on the server.
// Differing by the patch version has always been allowed.
// Only differing by the major version is not allowed.
return areClientAndServerCompatible(MetaDataUtil.decodePhoenixVersion(serverHBaseAndPhoenixVersion), MetaDataProtocol.PHOENIX_MAJOR_VERSION, MetaDataProtocol.PHOENIX_MINOR_VERSION);
}
// Default scope for testing
@VisibleForTesting
static ClientServerCompatibility areClientAndServerCompatible(int serverVersion, int clientMajorVersion, int clientMinorVersion) {
// A server and client with the same major and minor version number must be compatible.
// So it's important that we roll the PHOENIX_MAJOR_VERSION or PHOENIX_MINOR_VERSION
// when we make an incompatible change.
ClientServerCompatibility compatibility = new ClientServerCompatibility();
if (VersionUtil.encodeMinPatchVersion(clientMajorVersion, clientMinorVersion) > serverVersion) { // Client major and minor cannot be ahead of server
compatibility.setErrorCode(SQLExceptionCode.OUTDATED_JARS.getErrorCode());
compatibility.setCompatible(false);
return compatibility;
} else if (VersionUtil.encodeMaxMinorVersion(clientMajorVersion) < serverVersion) { // Client major version must at least be up to server major version
MajorMinorVersion serverMajorMinorVersion = new MajorMinorVersion(
VersionUtil.decodeMajorVersion(serverVersion),
VersionUtil.decodeMinorVersion(serverVersion));
MajorMinorVersion clientMajorMinorVersion =
new MajorMinorVersion(clientMajorVersion, clientMinorVersion);
if (!clientMajorMinorVersion.equals(
ALLOWED_SERVER_CLIENT_MAJOR_VERSION.get(serverMajorMinorVersion))) {
// Incompatible if not whitelisted by ALLOWED_SERVER_CLIENT_MAJOR_VERSION
compatibility.setErrorCode(SQLExceptionCode
.INCOMPATIBLE_CLIENT_SERVER_JAR.getErrorCode());
compatibility.setCompatible(false);
return compatibility;
}
}
compatibility.setCompatible(true);
return compatibility;
}
// Given the encoded integer representing the phoenix version in the encoded version value.
// The second byte in int would be the major version, 3rd byte minor version, and 4th byte
// patch version.
public static int decodePhoenixVersion(long version) {
return (int) ((version << Byte.SIZE * 4) >>> Byte.SIZE * 5);
}
// TODO: generalize this to use two bytes to return a SQL error code instead
public static long encodeHasIndexWALCodec(long version, boolean isValid) {
if (!isValid) {
return version | 1;
}
return version;
}
public static boolean decodeHasIndexWALCodec(long version) {
return (version & 0xF) == 0;
}
// Given the encoded integer representing the client hbase version in the encoded version value.
// The second byte in int would be the major version, 3rd byte minor version, and 4th byte
// patch version.
public static int decodeHBaseVersion(long version) {
return (int) (version >>> Byte.SIZE * 5);
}
public static String decodeHBaseVersionAsString(int version) {
int major = (version >>> Byte.SIZE * 2) & 0xFF;
int minor = (version >>> Byte.SIZE * 1) & 0xFF;
int patch = version & 0xFF;
return major + "." + minor + "." + patch;
}
// Given the encoded integer representing the phoenix version in the encoded version value.
// The second byte in int would be the major version, 3rd byte minor version, and 4th byte
// patch version.
public static boolean decodeTableNamespaceMappingEnabled(long version) {
return ((int)((version << Byte.SIZE * 3) >>> Byte.SIZE * 7) & 0x1) != 0;
}
// The first three bytes of the long encode the HBase version as major.minor.patch.
// The fourth byte is isTableNamespaceMappingEnabled
// The fifth to seventh bytes of the value encode the Phoenix version as major.minor.patch.
// The eights byte encodes whether the WAL codec is correctly installed
/**
* Encode HBase and Phoenix version along with some server-side config information such as whether WAL codec is
* installed (necessary for non transactional, mutable secondar indexing), and whether systemNamespace mapping is enabled.
*
* @param hbaseVersionStr
* @param config
* @return long value sent back during initialization of a cluster connection.
*/
public static long encodeVersion(String hbaseVersionStr, Configuration config) {
long hbaseVersion = VersionUtil.encodeVersion(hbaseVersionStr);
long isTableNamespaceMappingEnabled = SchemaUtil.isNamespaceMappingEnabled(PTableType.TABLE,
new ReadOnlyProps(config.iterator())) ? 1 : 0;
long phoenixVersion = VersionUtil.encodeVersion(MetaDataProtocol.PHOENIX_MAJOR_VERSION,
MetaDataProtocol.PHOENIX_MINOR_VERSION, MetaDataProtocol.PHOENIX_PATCH_NUMBER);
long walCodec = IndexManagementUtil.isWALEditCodecSet(config) ? 0 : 1;
long version =
// Encode HBase major, minor, patch version
(hbaseVersion << (Byte.SIZE * 5))
// Encode if table namespace mapping is enabled on the server side
// Note that we DO NOT return information on whether system tables are mapped
// on the server side
| (isTableNamespaceMappingEnabled << (Byte.SIZE * 4))
// Encode Phoenix major, minor, patch version
| (phoenixVersion << (Byte.SIZE * 1))
// Encode whether or not non transactional, mutable secondary indexing was configured properly.
| walCodec;
return version;
}
public static byte[] getTenantIdAndSchemaAndTableName(Mutation someRow) {
byte[][] rowKeyMetaData = new byte[3][];
getVarChars(someRow.getRow(), 3, rowKeyMetaData);
return ByteUtil.concat(rowKeyMetaData[0], rowKeyMetaData[1], rowKeyMetaData[2]);
}
public static byte[] getTenantIdAndSchemaAndTableName(Result result) {
byte[][] rowKeyMetaData = new byte[3][];
getVarChars(result.getRow(), 3, rowKeyMetaData);
return ByteUtil.concat(rowKeyMetaData[0], rowKeyMetaData[1], rowKeyMetaData[2]);
}
public static void getTenantIdAndSchemaAndTableName(List tableMetadata, byte[][] rowKeyMetaData) {
Mutation m = getTableHeaderRow(tableMetadata);
getVarChars(m.getRow(), 3, rowKeyMetaData);
}
public static int getBaseColumnCount(List tableMetadata) {
int result = -1;
for (Mutation mutation : tableMetadata) {
for (List cells : mutation.getFamilyCellMap().values()) {
for (Cell cell : cells) {
// compare using offsets
if (Bytes.compareTo(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength(), PhoenixDatabaseMetaData.BASE_COLUMN_COUNT_BYTES, 0,
PhoenixDatabaseMetaData.BASE_COLUMN_COUNT_BYTES.length) == 0)
if (Bytes.contains(cell.getQualifierArray(), PhoenixDatabaseMetaData.BASE_COLUMN_COUNT_BYTES)) {
result = PInteger.INSTANCE.getCodec()
.decodeInt(cell.getValueArray(), cell.getValueOffset(), SortOrder.ASC);
}
}
}
}
return result;
}
public static void mutatePutValue(Put somePut, byte[] family, byte[] qualifier, byte[] newValue) {
NavigableMap> familyCellMap = somePut.getFamilyCellMap();
List cells = familyCellMap.get(family);
List newCells = Lists.newArrayList();
if (cells != null) {
for (Cell cell : cells) {
if (Bytes.compareTo(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength(),
qualifier, 0, qualifier.length) == 0) {
Cell replacementCell = new KeyValue(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(), cell.getQualifierArray(),
cell.getQualifierOffset(), cell.getQualifierLength(), cell.getTimestamp(),
KeyValue.Type.codeToType(cell.getType().getCode()), newValue, 0, newValue.length);
newCells.add(replacementCell);
} else {
newCells.add(cell);
}
}
familyCellMap.put(family, newCells);
}
}
/**
* Iterates over the cells that are mutated by the put operation for the given column family and
* column qualifier and conditionally modifies those cells to add a tags list. We only add tags
* if the cell value does not match the passed valueArray. If we always want to add tags to
* these cells, we can pass in a null valueArray
* @param somePut Put operation
* @param family column family of the cells
* @param qualifier column qualifier of the cells
* @param cellBuilder ExtendedCellBuilder object
* @param valueArray byte array of values or null
* @param tagArray byte array of tags to add to the cells
*/
public static void conditionallyAddTagsToPutCells(Put somePut, byte[] family, byte[] qualifier,
ExtendedCellBuilder cellBuilder, byte[] valueArray, byte[] tagArray) {
NavigableMap> familyCellMap = somePut.getFamilyCellMap();
List cells = familyCellMap.get(family);
List newCells = Lists.newArrayList();
if (cells != null) {
for (Cell cell : cells) {
if (Bytes.compareTo(cell.getQualifierArray(), cell.getQualifierOffset(),
cell.getQualifierLength(), qualifier, 0, qualifier.length) == 0 &&
(valueArray == null || !CellUtil.matchingValue(cell, valueArray))) {
ExtendedCell extendedCell = cellBuilder
.setRow(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())
.setFamily(cell.getFamilyArray(), cell.getFamilyOffset(),
cell.getFamilyLength())
.setQualifier(cell.getQualifierArray(), cell.getQualifierOffset(),
cell.getQualifierLength())
.setValue(cell.getValueArray(), cell.getValueOffset(),
cell.getValueLength())
.setTimestamp(cell.getTimestamp())
.setType(cell.getType())
.setTags(TagUtil.concatTags(tagArray, cell))
.build();
// Replace existing cell with a cell that has the custom tags list
newCells.add(extendedCell);
} else {
// Add cell as is
newCells.add(cell);
}
}
familyCellMap.put(family, newCells);
}
}
public static Put cloneDeleteToPutAndAddColumn(Delete delete, byte[] family, byte[] qualifier, byte[] value) {
NavigableMap> familyCellMap = delete.getFamilyCellMap();
List cells = familyCellMap.get(family);
Cell cell = Iterables.getFirst(cells, null);
if (cell == null) {
throw new RuntimeException("Empty cells for delete for family: " + Bytes.toStringBinary(family));
}
byte[] rowArray = new byte[cell.getRowLength()];
System.arraycopy(cell.getRowArray(), cell.getRowOffset(), rowArray, 0, cell.getRowLength());
Put put = new Put(rowArray, delete.getTimestamp());
put.addColumn(family, qualifier, delete.getTimestamp(), value);
return put;
}
public static void getTenantIdAndFunctionName(List functionMetadata, byte[][] rowKeyMetaData) {
Mutation m = getTableHeaderRow(functionMetadata);
getVarChars(m.getRow(), 2, rowKeyMetaData);
}
/**
* Only return the parent table name if it has the same tenant id and schema name as the current
* table (this is only used to lock the parent table of indexes)
*/
public static byte[] getParentTableName(List tableMetadata) {
if (tableMetadata.size() == 1) {
return null;
}
byte[][] rowKeyMetaData = new byte[3][];
// get the tenantId, schema name and table name for the current table
getTenantIdAndSchemaAndTableName(tableMetadata, rowKeyMetaData);
byte[] tenantId = rowKeyMetaData[PhoenixDatabaseMetaData.TENANT_ID_INDEX];
byte[] schemaName = rowKeyMetaData[PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX];
byte[] tableName = rowKeyMetaData[PhoenixDatabaseMetaData.TABLE_NAME_INDEX];
// get the tenantId, schema name and table name for the parent table
Mutation m = getParentTableHeaderRow(tableMetadata);
getVarChars(m.getRow(), 3, rowKeyMetaData);
if (Bytes.compareTo(tenantId, rowKeyMetaData[PhoenixDatabaseMetaData.TENANT_ID_INDEX]) == 0
&& Bytes.compareTo(schemaName,
rowKeyMetaData[PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX]) == 0
&& Bytes.compareTo(tableName,
rowKeyMetaData[PhoenixDatabaseMetaData.TABLE_NAME_INDEX]) == 0) {
return null;
}
return rowKeyMetaData[PhoenixDatabaseMetaData.TABLE_NAME_INDEX];
}
public static long getSequenceNumber(Mutation tableMutation) {
List kvs = tableMutation.getFamilyCellMap().get(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES);
if (kvs != null) {
for (Cell kv : kvs) { // list is not ordered, so search. TODO: we could potentially assume the position
if (isSequenceNumber(kv)) {
return PLong.INSTANCE.getCodec().decodeLong(kv.getValueArray(), kv.getValueOffset(), SortOrder.getDefault());
}
}
}
throw new IllegalStateException();
}
public static long getSequenceNumber(List tableMetaData) {
return getSequenceNumber(getPutOnlyTableHeaderRow(tableMetaData));
}
public static boolean isSequenceNumber(Mutation m) {
boolean foundSequenceNumber = false;
for (Cell kv : m.getFamilyCellMap().get(TABLE_FAMILY_BYTES)) {
if (isSequenceNumber(kv)) {
foundSequenceNumber = true;
break;
}
}
return foundSequenceNumber;
}
public static boolean isSequenceNumber(Cell kv) {
return CellUtil.matchingQualifier(kv, PhoenixDatabaseMetaData.TABLE_SEQ_NUM_BYTES);
}
public static PTableType getTableType(List tableMetaData, KeyValueBuilder builder,
ImmutableBytesWritable value) {
if (getMutationValue(getPutOnlyTableHeaderRow(tableMetaData),
PhoenixDatabaseMetaData.TABLE_TYPE_BYTES, builder, value)) {
return PTableType.fromSerializedValue(value.get()[value.getOffset()]);
}
return null;
}
public static boolean isNameSpaceMapped(List tableMetaData, KeyValueBuilder builder,
ImmutableBytesWritable value) {
if (getMutationValue(getPutOnlyTableHeaderRow(tableMetaData),
PhoenixDatabaseMetaData.IS_NAMESPACE_MAPPED_BYTES, builder, value)) {
return (boolean)PBoolean.INSTANCE.toObject(ByteUtil.copyKeyBytesIfNecessary(value));
}
return false;
}
public static int getSaltBuckets(List tableMetaData, KeyValueBuilder builder,
ImmutableBytesWritable value) {
if (getMutationValue(getPutOnlyTableHeaderRow(tableMetaData),
PhoenixDatabaseMetaData.SALT_BUCKETS_BYTES, builder, value)) {
return PInteger.INSTANCE.getCodec().decodeInt(value, SortOrder.getDefault());
}
return 0;
}
public static long getParentSequenceNumber(List tableMetaData) {
return getSequenceNumber(getParentTableHeaderRow(tableMetaData));
}
public static Mutation getTableHeaderRow(List tableMetaData) {
return tableMetaData.get(0);
}
/**
* Get the mutation who's qualifier matches the passed key
*
* We need to pass in an {@link ImmutableBytesPtr} to pass the result back to make life easier
* when dealing with a regular {@link KeyValue} vs. a custom KeyValue as the latter may not
* support things like {@link KeyValue#getBuffer()}
* @param headerRow mutation to check
* @param key to check
* @param builder that created the {@link KeyValue KeyValues} in the {@link Mutation}
* @param ptr to point to the KeyValue's value if found
* @return true if the KeyValue was found and false otherwise
*/
public static boolean getMutationValue(Mutation headerRow, byte[] key,
KeyValueBuilder builder, ImmutableBytesWritable ptr) {
List kvs = headerRow.getFamilyCellMap().get(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES);
if (kvs != null) {
for (Cell cell : kvs) {
KeyValue kv = PhoenixKeyValueUtil.maybeCopyCell(cell);
if (builder.compareQualifier(kv, key, 0, key.length) ==0) {
builder.getValueAsPtr(kv, ptr);
return true;
}
}
}
return false;
}
public static KeyValue getMutationValue(Mutation headerRow, byte[] key,
KeyValueBuilder builder) {
List kvs = headerRow.getFamilyCellMap().get(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES);
if (kvs != null) {
for (Cell cell : kvs) {
KeyValue kv = org.apache.hadoop.hbase.KeyValueUtil.ensureKeyValue(cell);
if (builder.compareQualifier(kv, key, 0, key.length) ==0) {
return kv;
}
}
}
return null;
}
public static boolean setMutationValue(Mutation headerRow, byte[] key,
KeyValueBuilder builder, KeyValue keyValue) {
List kvs = headerRow.getFamilyCellMap().get(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES);
if (kvs != null) {
for (Cell cell : kvs) {
KeyValue kv = org.apache.hadoop.hbase.KeyValueUtil.ensureKeyValue(cell);
if (builder.compareQualifier(kv, key, 0, key.length) ==0) {
KeyValueBuilder.addQuietly(headerRow, keyValue);
return true;
}
}
}
return false;
}
public static List getTableCellsFromMutations(List tableMetaData) {
List tableCells = Lists.newArrayList();
byte[] tableKey = tableMetaData.get(0).getRow();
for (int k = 0; k < tableMetaData.size(); k++) {
Mutation m = tableMetaData.get(k);
if (Bytes.equals(m.getRow(), tableKey)) {
tableCells.addAll(getCellList(m));
}
}
return tableCells;
}
public static List> getColumnAndLinkCellsFromMutations(List tableMetaData) {
//skip the first mutation because it's the table header row with table-specific information
//all the rest of the mutations are either from linking rows or column definition rows
List> allColumnsCellList = Lists.newArrayList();
byte[] tableKey = tableMetaData.get(0).getRow();
for (int k = 1; k < tableMetaData.size(); k++) {
Mutation m = tableMetaData.get(k);
//filter out mutations for the table header row and TABLE_SEQ_NUM and parent table
//rows such as a view's column qualifier count
if (!Bytes.equals(m.getRow(), tableKey) && !(!isLinkType(m) && isSequenceNumber(m)
&& !isParentTableColumnQualifierCounter(m, tableKey))) {
List listToAdd = getCellList(m);
if (listToAdd != null && listToAdd.size() > 0) {
allColumnsCellList.add(listToAdd);
}
}
}
return allColumnsCellList;
}
private static List getCellList(Mutation m) {
List cellList = Lists.newArrayList();
for (Cell c : m.getFamilyCellMap().get(TABLE_FAMILY_BYTES)) {
//Mutations will mark NULL columns as deletes, whereas when we read
//from HBase we just won't get Cells for those columns. To use Mutation cells
//with code expecting Cells read from HBase results, we have to purge those
//Delete mutations
if (c != null && !CellUtil.isDelete(c)) {
cellList.add(c);
}
}
return cellList;
}
/**
* Returns the first Put element in tableMetaData . There could be leading Delete elements before the
* table header row
*/
public static Put getPutOnlyTableHeaderRow(List tableMetaData) {
for (Mutation m : tableMetaData) {
if (m instanceof Put) { return (Put) m; }
}
throw new IllegalStateException("No table header row found in table metadata");
}
public static Put getPutOnlyAutoPartitionColumn(PTable parentTable, List tableMetaData) {
int autoPartitionPutIndex = parentTable.isMultiTenant() ? 2: 1;
int i=0;
for (Mutation m : tableMetaData) {
if (m instanceof Put && i++==autoPartitionPutIndex) { return (Put) m; }
}
throw new IllegalStateException("No auto partition column row found in table metadata");
}
public static Mutation getParentTableHeaderRow(List tableMetaData) {
return tableMetaData.get(tableMetaData.size()-1);
}
public static long getClientTimeStamp(List tableMetadata) {
Mutation m = tableMetadata.get(0);
return getClientTimeStamp(m);
}
public static long getClientTimeStamp(Mutation m) {
Collection> kvs = m.getFamilyCellMap().values();
// Empty if Mutation is a Delete
// TODO: confirm that Delete timestamp is reset like Put
return kvs.isEmpty() ? m.getTimestamp() : kvs.iterator().next().get(0).getTimestamp();
}
public static byte[] getParentLinkKey(String tenantId, String schemaName, String tableName, String indexName) {
return ByteUtil.concat(tenantId == null ? ByteUtil.EMPTY_BYTE_ARRAY : Bytes.toBytes(tenantId), QueryConstants.SEPARATOR_BYTE_ARRAY, schemaName == null ? ByteUtil.EMPTY_BYTE_ARRAY : Bytes.toBytes(schemaName), QueryConstants.SEPARATOR_BYTE_ARRAY, Bytes.toBytes(tableName), QueryConstants.SEPARATOR_BYTE_ARRAY, QueryConstants.SEPARATOR_BYTE_ARRAY, Bytes.toBytes(indexName));
}
public static byte[] getParentLinkKey(byte[] tenantId, byte[] schemaName, byte[] tableName, byte[] indexName) {
return ByteUtil.concat(tenantId == null ? ByteUtil.EMPTY_BYTE_ARRAY : tenantId, QueryConstants.SEPARATOR_BYTE_ARRAY, schemaName == null ? ByteUtil.EMPTY_BYTE_ARRAY : schemaName, QueryConstants.SEPARATOR_BYTE_ARRAY, tableName, QueryConstants.SEPARATOR_BYTE_ARRAY, QueryConstants.SEPARATOR_BYTE_ARRAY, indexName);
}
public static byte[] getChildLinkKey(PName parentTenantId, PName parentSchemaName, PName parentTableName, PName viewTenantId, PName viewName) {
return ByteUtil.concat(parentTenantId == null ? ByteUtil.EMPTY_BYTE_ARRAY : parentTenantId.getBytes(), QueryConstants.SEPARATOR_BYTE_ARRAY,
parentSchemaName == null ? ByteUtil.EMPTY_BYTE_ARRAY : parentSchemaName.getBytes(), QueryConstants.SEPARATOR_BYTE_ARRAY,
parentTableName.getBytes(), QueryConstants.SEPARATOR_BYTE_ARRAY,
viewTenantId == null ? ByteUtil.EMPTY_BYTE_ARRAY : viewTenantId.getBytes(), QueryConstants.SEPARATOR_BYTE_ARRAY,
viewName.getBytes());
}
public static Cell getCell(List cells, byte[] cq) {
for (Cell cell : cells) {
if (Bytes.compareTo(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength(), cq, 0, cq.length) == 0) {
return cell;
}
}
return null;
}
public static boolean isMultiTenant(Mutation m, KeyValueBuilder builder, ImmutableBytesWritable ptr) {
if (getMutationValue(m, PhoenixDatabaseMetaData.MULTI_TENANT_BYTES, builder, ptr)) {
return Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(ptr));
}
return false;
}
public static boolean isTransactional(Mutation m, KeyValueBuilder builder, ImmutableBytesWritable ptr) {
if (getMutationValue(m, PhoenixDatabaseMetaData.TRANSACTIONAL_BYTES, builder, ptr)) {
return Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(ptr));
}
return false;
}
public static boolean isSalted(Mutation m, KeyValueBuilder builder, ImmutableBytesWritable ptr) {
return MetaDataUtil.getMutationValue(m, PhoenixDatabaseMetaData.SALT_BUCKETS_BYTES, builder, ptr);
}
public static byte[] getViewIndexPhysicalName(byte[] physicalTableName) {
return getIndexPhysicalName(physicalTableName, VIEW_INDEX_TABLE_PREFIX);
}
public static String getViewIndexPhysicalName(String physicalTableName) {
return getIndexPhysicalName(physicalTableName, VIEW_INDEX_TABLE_PREFIX);
}
public static String getNamespaceMappedName(PName tableName, boolean isNamespaceMapped) {
String logicalName = tableName.getString();
if (isNamespaceMapped) {
logicalName = logicalName.replace(QueryConstants.NAME_SEPARATOR, QueryConstants.NAMESPACE_SEPARATOR);
}
return logicalName;
}
public static String getViewIndexPhysicalName(PName logicalTableName, boolean isNamespaceMapped) {
String logicalName = getNamespaceMappedName(logicalTableName, isNamespaceMapped);
return getIndexPhysicalName(logicalName, VIEW_INDEX_TABLE_PREFIX);
}
private static byte[] getIndexPhysicalName(byte[] physicalTableName, String indexPrefix) {
return Bytes.toBytes(getIndexPhysicalName(Bytes.toString(physicalTableName), indexPrefix));
}
private static String getIndexPhysicalName(String physicalTableName, String indexPrefix) {
if (physicalTableName.contains(QueryConstants.NAMESPACE_SEPARATOR)) {
String schemaName = SchemaUtil.getSchemaNameFromFullName(physicalTableName,
QueryConstants.NAMESPACE_SEPARATOR);
String tableName = SchemaUtil.getTableNameFromFullName(physicalTableName,
QueryConstants.NAMESPACE_SEPARATOR);
return (schemaName + QueryConstants.NAMESPACE_SEPARATOR + indexPrefix + tableName);
}
return indexPrefix + physicalTableName;
}
public static byte[] getLocalIndexPhysicalName(byte[] physicalTableName) {
return getIndexPhysicalName(physicalTableName, LOCAL_INDEX_TABLE_PREFIX);
}
public static String getLocalIndexTableName(String tableName) {
return LOCAL_INDEX_TABLE_PREFIX + tableName;
}
public static String getLocalIndexSchemaName(String schemaName) {
return schemaName;
}
public static String getLocalIndexUserTableName(String localIndexTableName) {
if (localIndexTableName.contains(QueryConstants.NAMESPACE_SEPARATOR)) {
String schemaName = SchemaUtil.getSchemaNameFromFullName(localIndexTableName,
QueryConstants.NAMESPACE_SEPARATOR);
String tableName = SchemaUtil.getTableNameFromFullName(localIndexTableName,
QueryConstants.NAMESPACE_SEPARATOR);
String userTableName = tableName.substring(LOCAL_INDEX_TABLE_PREFIX.length());
return (schemaName + QueryConstants.NAMESPACE_SEPARATOR + userTableName);
} else {
String schemaName = SchemaUtil.getSchemaNameFromFullName(localIndexTableName);
if (!schemaName.isEmpty()) schemaName = schemaName.substring(LOCAL_INDEX_TABLE_PREFIX.length());
String tableName = localIndexTableName.substring(
(schemaName.isEmpty() ? 0 : (schemaName.length() + QueryConstants.NAME_SEPARATOR.length()))
+ LOCAL_INDEX_TABLE_PREFIX.length());
return SchemaUtil.getTableName(schemaName, tableName);
}
}
public static String getViewIndexUserTableName(String viewIndexTableName) {
if (viewIndexTableName.contains(QueryConstants.NAMESPACE_SEPARATOR)) {
String schemaName = SchemaUtil.getSchemaNameFromFullName(viewIndexTableName,
QueryConstants.NAMESPACE_SEPARATOR);
String tableName = SchemaUtil.getTableNameFromFullName(viewIndexTableName,
QueryConstants.NAMESPACE_SEPARATOR);
String userTableName = tableName.substring(VIEW_INDEX_TABLE_PREFIX.length());
return (schemaName + QueryConstants.NAMESPACE_SEPARATOR + userTableName);
} else {
String schemaName = SchemaUtil.getSchemaNameFromFullName(viewIndexTableName);
if (!schemaName.isEmpty()) schemaName = schemaName.substring(VIEW_INDEX_TABLE_PREFIX.length());
String tableName = viewIndexTableName.substring(
(schemaName.isEmpty() ? 0 : (schemaName.length() + QueryConstants.NAME_SEPARATOR.length()))
+ VIEW_INDEX_TABLE_PREFIX.length());
return SchemaUtil.getTableName(schemaName, tableName);
}
}
public static String getOldViewIndexSequenceSchemaName(PName physicalName, boolean isNamespaceMapped) {
if (!isNamespaceMapped) { return VIEW_INDEX_SEQUENCE_PREFIX + physicalName.getString(); }
return SchemaUtil.getSchemaNameFromFullName(physicalName.toString());
}
public static String getOldViewIndexSequenceName(PName physicalName, PName tenantId, boolean isNamespaceMapped) {
if (!isNamespaceMapped) { return VIEW_INDEX_SEQUENCE_NAME_PREFIX + (tenantId == null ? "" : tenantId); }
return SchemaUtil.getTableNameFromFullName(physicalName.toString()) + VIEW_INDEX_SEQUENCE_NAME_PREFIX;
}
public static SequenceKey getOldViewIndexSequenceKey(String tenantId, PName physicalName, int nSaltBuckets,
boolean isNamespaceMapped) {
// Create global sequence of the form:
// rather than tenant-specific sequence, as it makes it much easier
// to cleanup when the physical table is dropped, as we can delete
// all global sequences leading with + physical name.
String schemaName = getOldViewIndexSequenceSchemaName(physicalName, isNamespaceMapped);
String tableName = getOldViewIndexSequenceName(physicalName, PNameFactory.newName(tenantId), isNamespaceMapped);
return new SequenceKey(isNamespaceMapped ? tenantId : null, schemaName, tableName, nSaltBuckets);
}
public static String getViewIndexSequenceSchemaName(PName logicalBaseTableName, boolean isNamespaceMapped) {
if (!isNamespaceMapped) {
String baseTableName = SchemaUtil.getParentTableNameFromIndexTable(logicalBaseTableName.getString(),
MetaDataUtil.VIEW_INDEX_TABLE_PREFIX);
return SchemaUtil.getSchemaNameFromFullName(baseTableName);
} else {
return SchemaUtil.getSchemaNameFromFullName(logicalBaseTableName.toString());
}
}
public static String getViewIndexSequenceName(PName physicalName, PName tenantId, boolean isNamespaceMapped) {
return SchemaUtil.getTableNameFromFullName(physicalName.toString()) + VIEW_INDEX_SEQUENCE_NAME_PREFIX;
}
/**
*
* @param tenantId No longer used, but kept in signature for backwards compatibility
* @param physicalName Name of physical view index table
* @param nSaltBuckets Number of salt buckets
* @param isNamespaceMapped Is namespace mapping enabled
* @return SequenceKey for the ViewIndexId
*/
public static SequenceKey getViewIndexSequenceKey(String tenantId, PName physicalName, int nSaltBuckets,
boolean isNamespaceMapped) {
// Create global sequence of the form: .
// We can't use a tenant-owned or escaped sequence because of collisions,
// with other view indexes that may be global or owned by other tenants that
// also use this same physical view index table. It's also much easier
// to cleanup when the physical table is dropped, as we can delete
// all global sequences leading with + physical name.
String schemaName = getViewIndexSequenceSchemaName(physicalName, isNamespaceMapped);
String tableName = getViewIndexSequenceName(physicalName, null, isNamespaceMapped);
return new SequenceKey(null, schemaName, tableName, nSaltBuckets);
}
public static PDataType getViewIndexIdDataType() {
return PLong.INSTANCE;
}
public static PDataType getLegacyViewIndexIdDataType() {
return PSmallint.INSTANCE;
}
public static String getViewIndexIdColumnName() {
return VIEW_INDEX_ID_COLUMN_NAME;
}
public static boolean hasViewIndexTable(PhoenixConnection connection, PName physicalName) throws SQLException {
return hasViewIndexTable(connection, physicalName.getBytes());
}
public static boolean hasViewIndexTable(PhoenixConnection connection, byte[] physicalTableName)
throws SQLException {
byte[] physicalIndexName = MetaDataUtil.getViewIndexPhysicalName(physicalTableName);
try {
TableDescriptor desc = connection.getQueryServices().getTableDescriptor(physicalIndexName);
return desc != null && Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(desc.getValue(IS_VIEW_INDEX_TABLE_PROP_BYTES)));
} catch (TableNotFoundException e) {
return false;
}
}
public static boolean hasLocalIndexTable(PhoenixConnection connection, PName physicalName) throws SQLException {
return hasLocalIndexTable(connection, physicalName.getBytes());
}
public static boolean hasLocalIndexTable(PhoenixConnection connection, byte[] physicalTableName) throws SQLException {
try {
TableDescriptor desc = connection.getQueryServices().getTableDescriptor(physicalTableName);
if (desc == null ) {
return false;
}
return hasLocalIndexColumnFamily(desc);
} catch (TableNotFoundException e) {
return false;
}
}
public static boolean hasLocalIndexColumnFamily(TableDescriptor desc) {
for (ColumnFamilyDescriptor cf : desc.getColumnFamilies()) {
if (cf.getNameAsString().startsWith(QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX)) {
return true;
}
}
return false;
}
public static List getNonLocalIndexColumnFamilies(TableDescriptor desc) {
List families = new ArrayList(desc.getColumnFamilies().length);
for (ColumnFamilyDescriptor cf : desc.getColumnFamilies()) {
if (!cf.getNameAsString().startsWith(QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX)) {
families.add(cf.getName());
}
}
return families;
}
public static List getLocalIndexColumnFamilies(PhoenixConnection conn, byte[] physicalTableName) throws SQLException {
TableDescriptor desc = conn.getQueryServices().getTableDescriptor(physicalTableName);
if (desc == null ) {
return Collections.emptyList();
}
List families = new ArrayList(desc.getColumnFamilies().length / 2);
for (ColumnFamilyDescriptor cf : desc.getColumnFamilies()) {
if (cf.getNameAsString().startsWith(QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX)) {
families.add(cf.getName());
}
}
return families;
}
public static void deleteViewIndexSequences(PhoenixConnection connection, PName name, boolean isNamespaceMapped)
throws SQLException {
String schemaName = getViewIndexSequenceSchemaName(name, isNamespaceMapped);
String sequenceName = getViewIndexSequenceName(name, null, isNamespaceMapped);
String delQuery = String.format(" DELETE FROM " + PhoenixDatabaseMetaData.SYSTEM_SEQUENCE
+ " WHERE " + PhoenixDatabaseMetaData.SEQUENCE_SCHEMA + " %s AND "
+ PhoenixDatabaseMetaData.SEQUENCE_NAME + " = ? ",
schemaName.length() > 0 ? "= ? " : " IS NULL");
try (PreparedStatement delSeqStmt = connection.prepareStatement(delQuery)) {
if (schemaName.length() > 0) {
delSeqStmt.setString(1, schemaName);
delSeqStmt.setString(2, sequenceName);
} else {
delSeqStmt.setString(1, sequenceName);
}
delSeqStmt.executeUpdate();
}
}
public static boolean propertyNotAllowedToBeOutOfSync(String colFamProp) {
return SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES.contains(colFamProp);
}
public static Map getSyncedProps(ColumnFamilyDescriptor defaultCFDesc) {
Map syncedProps = new HashMap<>();
if (defaultCFDesc != null) {
for (String propToKeepInSync: SYNCED_DATA_TABLE_AND_INDEX_COL_FAM_PROPERTIES) {
syncedProps.put(propToKeepInSync, Bytes.toString(
defaultCFDesc.getValue(Bytes.toBytes(propToKeepInSync))));
}
}
return syncedProps;
}
public static Scan newTableRowsScan(byte[] key, long startTimeStamp, long stopTimeStamp){
return newTableRowsScan(key, null, startTimeStamp, stopTimeStamp);
}
public static Scan newTableRowsScan(byte[] startKey, byte[] stopKey, long startTimeStamp, long stopTimeStamp) {
Scan scan = new Scan();
ScanUtil.setTimeRange(scan, startTimeStamp, stopTimeStamp);
scan.withStartRow(startKey);
if (stopKey == null) {
stopKey = ByteUtil.concat(startKey, QueryConstants.SEPARATOR_BYTE_ARRAY);
ByteUtil.nextKey(stopKey, stopKey.length);
}
scan.withStopRow(stopKey);
return scan;
}
public static LinkType getLinkType(Mutation tableMutation) {
return getLinkType(tableMutation.getFamilyCellMap().get(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES));
}
public static LinkType getLinkType(Collection kvs) {
if (kvs != null) {
for (Cell kv : kvs) {
if (isLinkType(kv)) {
return LinkType.fromSerializedValue(PUnsignedTinyint.INSTANCE.getCodec().
decodeByte(kv.getValueArray(), kv.getValueOffset(),
SortOrder.getDefault())); }
}
}
return null;
}
public static boolean isLocalIndex(String physicalName) {
if (physicalName.contains(LOCAL_INDEX_TABLE_PREFIX)) { return true; }
return false;
}
public static boolean isLinkType(Cell kv) {
return CellUtil.matchingQualifier(kv, PhoenixDatabaseMetaData.LINK_TYPE_BYTES);
}
public static boolean isLinkType(Mutation m) {
boolean foundLinkType = false;
for (Cell kv : m.getFamilyCellMap().get(TABLE_FAMILY_BYTES)) {
if (isLinkType(kv)) {
foundLinkType = true;
break;
}
}
return foundLinkType;
}
public static boolean isParentTableColumnQualifierCounter(Mutation m, byte[] tableRow) {
boolean foundCQCounter = false;
for (Cell kv : m.getFamilyCellMap().get(TABLE_FAMILY_BYTES)) {
if (isParentTableColumnQualifierCounter(kv, tableRow)) {
foundCQCounter = true;
break;
}
}
return foundCQCounter;
}
public static boolean isParentTableColumnQualifierCounter(Cell kv, byte[] tableRow) {
byte[][] tableRowKeyMetaData = new byte[5][];
getVarChars(tableRow, tableRowKeyMetaData);
byte[] tableName = tableRowKeyMetaData[TABLE_NAME_INDEX];
byte[][] columnRowKeyMetaData = new byte[5][];
int nColumns = getVarChars(kv.getRowArray(), kv.getRowOffset(), kv.getRowLength(),
0, columnRowKeyMetaData);
if (nColumns == 5) {
byte[] columnTableName = columnRowKeyMetaData[TABLE_NAME_INDEX];
if (!Bytes.equals(tableName, columnTableName)) {
return CellUtil.matchingQualifier(kv, COLUMN_QUALIFIER_BYTES);
}
}
return false;
}
public static boolean isViewIndex(String physicalName) {
if (physicalName.contains(QueryConstants.NAMESPACE_SEPARATOR)) {
return SchemaUtil.getTableNameFromFullName(physicalName).startsWith(VIEW_INDEX_TABLE_PREFIX);
} else {
return physicalName.startsWith(VIEW_INDEX_TABLE_PREFIX);
}
}
public static String getAutoPartitionColumnName(PTable parentTable) {
List parentTableColumns = parentTable.getPKColumns();
PColumn column = parentTableColumns.get(getAutoPartitionColIndex(parentTable));
return column.getName().getString();
}
// this method should only be called on the parent table (since it has the _SALT column)
public static int getAutoPartitionColIndex(PTable parentTable) {
boolean isMultiTenant = parentTable.isMultiTenant();
boolean isSalted = parentTable.getBucketNum()!=null;
return (isMultiTenant && isSalted) ? 2 : (isMultiTenant || isSalted) ? 1 : 0;
}
public static boolean isHColumnProperty(String propName) {
return ColumnFamilyDescriptorBuilder.getDefaultValues().containsKey(propName);
}
public static boolean isHTableProperty(String propName) {
return !isHColumnProperty(propName) && !TableProperty.isPhoenixTableProperty(propName);
}
public static boolean isLocalIndexFamily(ImmutableBytesPtr cfPtr) {
return cfPtr.getLength() >= QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX_BYTES.length &&
Bytes.compareTo(cfPtr.get(), cfPtr.getOffset(), QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX_BYTES.length, QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX_BYTES, 0, QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX_BYTES.length) == 0;
}
public static boolean isLocalIndexFamily(byte[] cf) {
return Bytes.startsWith(cf, QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX_BYTES);
}
public static final byte[] getPhysicalTableRowForView(PTable view) {
byte[] physicalTableSchemaName = Bytes.toBytes(SchemaUtil.getSchemaNameFromFullName(view.getPhysicalName().getString()));
byte[] physicalTableName = Bytes.toBytes(SchemaUtil.getTableNameFromFullName(view.getPhysicalName().getString()));
return SchemaUtil.getTableKey(ByteUtil.EMPTY_BYTE_ARRAY, physicalTableSchemaName, physicalTableName);
}
/**
* Extract mutations of link type {@link PTable.LinkType#CHILD_TABLE} from the list of mutations.
* The child link mutations will be sent to SYSTEM.CHILD_LINK and other mutations to SYSTEM.CATALOG
* @param metadataMutations total list of mutations
* @return list of mutations pertaining to parent-child links
*/
public static List removeChildLinkMutations(List metadataMutations) {
List childLinkMutations = Lists.newArrayList();
Iterator iter = metadataMutations.iterator();
while (iter.hasNext()) {
Mutation m = iter.next();
for (Cell kv : m.getFamilyCellMap().get(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES)) {
// remove mutations of link type LinkType.CHILD_TABLE
if ((Bytes.compareTo(kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength(),
PhoenixDatabaseMetaData.LINK_TYPE_BYTES, 0,
PhoenixDatabaseMetaData.LINK_TYPE_BYTES.length) == 0)
&& ((Bytes.compareTo(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength(),
LinkType.CHILD_TABLE.getSerializedValueAsByteArray(), 0,
LinkType.CHILD_TABLE.getSerializedValueAsByteArray().length) == 0))) {
childLinkMutations.add(m);
iter.remove();
}
}
}
return childLinkMutations;
}
public static IndexType getIndexType(List tableMetaData, KeyValueBuilder builder,
ImmutableBytesWritable value) {
if (getMutationValue(getPutOnlyTableHeaderRow(tableMetaData), PhoenixDatabaseMetaData.INDEX_TYPE_BYTES, builder,
value)) { return IndexType.fromSerializedValue(value.get()[value.getOffset()]); }
return null;
}
/**
* Retrieve the viewIndexId datatype from create request.
*
* @see MetaDataEndpointImpl#createTable(com.google.protobuf.RpcController,
* org.apache.phoenix.coprocessor.generated.MetaDataProtos.CreateTableRequest,
* com.google.protobuf.RpcCallback)
*/
public static PDataType> getIndexDataType(List tableMetaData,
KeyValueBuilder builder, ImmutableBytesWritable value) {
if (getMutationValue(getPutOnlyTableHeaderRow(tableMetaData),
PhoenixDatabaseMetaData.VIEW_INDEX_ID_DATA_TYPE_BYTES, builder, value)) {
return PDataType.fromTypeId(
PInteger.INSTANCE.getCodec().decodeInt(value, SortOrder.getDefault()));
}
return getLegacyViewIndexIdDataType();
}
public static boolean getChangeDetectionEnabled(List tableMetaData) {
KeyValueBuilder builder = GenericKeyValueBuilder.INSTANCE;
ImmutableBytesWritable value = new ImmutableBytesWritable();
if (getMutationValue(getPutOnlyTableHeaderRow(tableMetaData),
PhoenixDatabaseMetaData.CHANGE_DETECTION_ENABLED_BYTES, builder, value)) {
return Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(value.get(),
value.getOffset(),
value.getLength()));
} else {
return false;
}
}
public static PColumn getColumn(int pkCount, byte[][] rowKeyMetaData, PTable table) throws ColumnFamilyNotFoundException, ColumnNotFoundException {
PColumn col = null;
if (pkCount > FAMILY_NAME_INDEX
&& rowKeyMetaData[PhoenixDatabaseMetaData.FAMILY_NAME_INDEX].length > 0) {
PColumnFamily family =
table.getColumnFamily(rowKeyMetaData[PhoenixDatabaseMetaData.FAMILY_NAME_INDEX]);
col =
family.getPColumnForColumnNameBytes(rowKeyMetaData[PhoenixDatabaseMetaData.COLUMN_NAME_INDEX]);
} else if (pkCount > COLUMN_NAME_INDEX
&& rowKeyMetaData[PhoenixDatabaseMetaData.COLUMN_NAME_INDEX].length > 0) {
col = table.getPKColumn(new String(
rowKeyMetaData[PhoenixDatabaseMetaData.COLUMN_NAME_INDEX], StandardCharsets.UTF_8));
}
return col;
}
public static void deleteFromStatsTable(PhoenixConnection connection,
PTable table, List physicalTableNames,
List sharedTableStates)
throws SQLException {
boolean isAutoCommit = connection.getAutoCommit();
try {
connection.setAutoCommit(true);
Set physicalTablesSet = new HashSet<>();
physicalTablesSet.add(table.getPhysicalName().getString());
for (byte[] physicalTableName:physicalTableNames) {
physicalTablesSet.add(Bytes.toString(physicalTableName));
}
for (MetaDataProtocol.SharedTableState s: sharedTableStates) {
physicalTablesSet.add(s.getPhysicalNames().get(0).getString());
}
StringBuilder buf = new StringBuilder("DELETE FROM SYSTEM.STATS WHERE PHYSICAL_NAME IN (");
for (int i = 0; i < physicalTablesSet.size(); i++) {
buf.append(" ?,");
}
buf.setCharAt(buf.length() - 1, ')');
if (table.getIndexType()==IndexType.LOCAL) {
buf.append(" AND COLUMN_FAMILY IN(");
if (table.getColumnFamilies().isEmpty()) {
buf.append("'" + QueryConstants.DEFAULT_LOCAL_INDEX_COLUMN_FAMILY + "',");
} else {
buf.append(QueryUtil.generateInListParams(table
.getColumnFamilies().size()));
}
buf.setCharAt(buf.length() - 1, ')');
}
try (PreparedStatement delStatsStmt = connection.prepareStatement(buf.toString())) {
int param = 0;
Iterator itr = physicalTablesSet.iterator();
while (itr.hasNext()) {
delStatsStmt.setString(++param, itr.next().toString());
}
if (table.getIndexType() == IndexType.LOCAL
&& !table.getColumnFamilies().isEmpty()) {
for (PColumnFamily cf : table.getColumnFamilies()) {
delStatsStmt.setString(++param, cf.getName().getString());
}
}
delStatsStmt.execute();
}
} finally {
connection.setAutoCommit(isAutoCommit);
}
}
}
| | | | | | | | | | | | | | | | |