Search in sources :

Example 1 with EncodedCQCounter

use of org.apache.phoenix.schema.PTable.EncodedCQCounter in project phoenix by apache.

the class MetaDataEndpointImpl method getTable.

private PTable getTable(RegionScanner scanner, long clientTimeStamp, long tableTimeStamp) throws IOException, SQLException {
    List<Cell> results = Lists.newArrayList();
    scanner.next(results);
    if (results.isEmpty()) {
        return null;
    }
    Cell[] tableKeyValues = new Cell[TABLE_KV_COLUMNS.size()];
    Cell[] colKeyValues = new Cell[COLUMN_KV_COLUMNS.size()];
    // Create PTable based on KeyValues from scan
    Cell keyValue = results.get(0);
    byte[] keyBuffer = keyValue.getRowArray();
    int keyLength = keyValue.getRowLength();
    int keyOffset = keyValue.getRowOffset();
    PName tenantId = newPName(keyBuffer, keyOffset, keyLength);
    int tenantIdLength = (tenantId == null) ? 0 : tenantId.getBytes().length;
    if (tenantIdLength == 0) {
        tenantId = null;
    }
    PName schemaName = newPName(keyBuffer, keyOffset + tenantIdLength + 1, keyLength);
    int schemaNameLength = schemaName.getBytes().length;
    int tableNameLength = keyLength - schemaNameLength - 1 - tenantIdLength - 1;
    byte[] tableNameBytes = new byte[tableNameLength];
    System.arraycopy(keyBuffer, keyOffset + schemaNameLength + 1 + tenantIdLength + 1, tableNameBytes, 0, tableNameLength);
    PName tableName = PNameFactory.newName(tableNameBytes);
    int offset = tenantIdLength + schemaNameLength + tableNameLength + 3;
    // This will prevent the client from continually looking for the current
    // table when we know that there will never be one since we disallow updates
    // unless the table is the latest
    // If we already have a table newer than the one we just found and
    // the client timestamp is less that the existing table time stamp,
    // bump up the timeStamp to right before the client time stamp, since
    // we know it can't possibly change.
    long timeStamp = keyValue.getTimestamp();
    // long timeStamp = tableTimeStamp > keyValue.getTimestamp() &&
    // clientTimeStamp < tableTimeStamp
    // ? clientTimeStamp-1
    // : keyValue.getTimestamp();
    int i = 0;
    int j = 0;
    while (i < results.size() && j < TABLE_KV_COLUMNS.size()) {
        Cell kv = results.get(i);
        Cell searchKv = TABLE_KV_COLUMNS.get(j);
        int cmp = Bytes.compareTo(kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength(), searchKv.getQualifierArray(), searchKv.getQualifierOffset(), searchKv.getQualifierLength());
        if (cmp == 0) {
            // Find max timestamp of table
            timeStamp = Math.max(timeStamp, kv.getTimestamp());
            // header row
            tableKeyValues[j++] = kv;
            i++;
        } else if (cmp > 0) {
            timeStamp = Math.max(timeStamp, kv.getTimestamp());
            tableKeyValues[j++] = null;
        } else {
            // shouldn't happen - means unexpected KV in system table header row
            i++;
        }
    }
    // TABLE_TYPE, TABLE_SEQ_NUM and COLUMN_COUNT are required.
    if (tableKeyValues[TABLE_TYPE_INDEX] == null || tableKeyValues[TABLE_SEQ_NUM_INDEX] == null || tableKeyValues[COLUMN_COUNT_INDEX] == null) {
        throw new IllegalStateException("Didn't find expected key values for table row in metadata row");
    }
    Cell tableTypeKv = tableKeyValues[TABLE_TYPE_INDEX];
    PTableType tableType = PTableType.fromSerializedValue(tableTypeKv.getValueArray()[tableTypeKv.getValueOffset()]);
    Cell tableSeqNumKv = tableKeyValues[TABLE_SEQ_NUM_INDEX];
    long tableSeqNum = PLong.INSTANCE.getCodec().decodeLong(tableSeqNumKv.getValueArray(), tableSeqNumKv.getValueOffset(), SortOrder.getDefault());
    Cell columnCountKv = tableKeyValues[COLUMN_COUNT_INDEX];
    int columnCount = PInteger.INSTANCE.getCodec().decodeInt(columnCountKv.getValueArray(), columnCountKv.getValueOffset(), SortOrder.getDefault());
    Cell pkNameKv = tableKeyValues[PK_NAME_INDEX];
    PName pkName = pkNameKv != null ? newPName(pkNameKv.getValueArray(), pkNameKv.getValueOffset(), pkNameKv.getValueLength()) : null;
    Cell saltBucketNumKv = tableKeyValues[SALT_BUCKETS_INDEX];
    Integer saltBucketNum = saltBucketNumKv != null ? (Integer) PInteger.INSTANCE.getCodec().decodeInt(saltBucketNumKv.getValueArray(), saltBucketNumKv.getValueOffset(), SortOrder.getDefault()) : null;
    if (saltBucketNum != null && saltBucketNum.intValue() == 0) {
        // Zero salt buckets means not salted
        saltBucketNum = null;
    }
    Cell dataTableNameKv = tableKeyValues[DATA_TABLE_NAME_INDEX];
    PName dataTableName = dataTableNameKv != null ? newPName(dataTableNameKv.getValueArray(), dataTableNameKv.getValueOffset(), dataTableNameKv.getValueLength()) : null;
    Cell indexStateKv = tableKeyValues[INDEX_STATE_INDEX];
    PIndexState indexState = indexStateKv == null ? null : PIndexState.fromSerializedValue(indexStateKv.getValueArray()[indexStateKv.getValueOffset()]);
    Cell immutableRowsKv = tableKeyValues[IMMUTABLE_ROWS_INDEX];
    boolean isImmutableRows = immutableRowsKv == null ? false : (Boolean) PBoolean.INSTANCE.toObject(immutableRowsKv.getValueArray(), immutableRowsKv.getValueOffset(), immutableRowsKv.getValueLength());
    Cell defaultFamilyNameKv = tableKeyValues[DEFAULT_COLUMN_FAMILY_INDEX];
    PName defaultFamilyName = defaultFamilyNameKv != null ? newPName(defaultFamilyNameKv.getValueArray(), defaultFamilyNameKv.getValueOffset(), defaultFamilyNameKv.getValueLength()) : null;
    Cell viewStatementKv = tableKeyValues[VIEW_STATEMENT_INDEX];
    String viewStatement = viewStatementKv != null ? (String) PVarchar.INSTANCE.toObject(viewStatementKv.getValueArray(), viewStatementKv.getValueOffset(), viewStatementKv.getValueLength()) : null;
    Cell disableWALKv = tableKeyValues[DISABLE_WAL_INDEX];
    boolean disableWAL = disableWALKv == null ? PTable.DEFAULT_DISABLE_WAL : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(disableWALKv.getValueArray(), disableWALKv.getValueOffset(), disableWALKv.getValueLength()));
    Cell multiTenantKv = tableKeyValues[MULTI_TENANT_INDEX];
    boolean multiTenant = multiTenantKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(multiTenantKv.getValueArray(), multiTenantKv.getValueOffset(), multiTenantKv.getValueLength()));
    Cell storeNullsKv = tableKeyValues[STORE_NULLS_INDEX];
    boolean storeNulls = storeNullsKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(storeNullsKv.getValueArray(), storeNullsKv.getValueOffset(), storeNullsKv.getValueLength()));
    Cell transactionalKv = tableKeyValues[TRANSACTIONAL_INDEX];
    boolean transactional = transactionalKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(transactionalKv.getValueArray(), transactionalKv.getValueOffset(), transactionalKv.getValueLength()));
    Cell viewTypeKv = tableKeyValues[VIEW_TYPE_INDEX];
    ViewType viewType = viewTypeKv == null ? null : ViewType.fromSerializedValue(viewTypeKv.getValueArray()[viewTypeKv.getValueOffset()]);
    Cell viewIndexIdKv = tableKeyValues[VIEW_INDEX_ID_INDEX];
    Short viewIndexId = viewIndexIdKv == null ? null : (Short) MetaDataUtil.getViewIndexIdDataType().getCodec().decodeShort(viewIndexIdKv.getValueArray(), viewIndexIdKv.getValueOffset(), SortOrder.getDefault());
    Cell indexTypeKv = tableKeyValues[INDEX_TYPE_INDEX];
    IndexType indexType = indexTypeKv == null ? null : IndexType.fromSerializedValue(indexTypeKv.getValueArray()[indexTypeKv.getValueOffset()]);
    Cell baseColumnCountKv = tableKeyValues[BASE_COLUMN_COUNT_INDEX];
    int baseColumnCount = baseColumnCountKv == null ? 0 : PInteger.INSTANCE.getCodec().decodeInt(baseColumnCountKv.getValueArray(), baseColumnCountKv.getValueOffset(), SortOrder.getDefault());
    Cell rowKeyOrderOptimizableKv = tableKeyValues[ROW_KEY_ORDER_OPTIMIZABLE_INDEX];
    boolean rowKeyOrderOptimizable = rowKeyOrderOptimizableKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(rowKeyOrderOptimizableKv.getValueArray(), rowKeyOrderOptimizableKv.getValueOffset(), rowKeyOrderOptimizableKv.getValueLength()));
    Cell updateCacheFrequencyKv = tableKeyValues[UPDATE_CACHE_FREQUENCY_INDEX];
    long updateCacheFrequency = updateCacheFrequencyKv == null ? 0 : PLong.INSTANCE.getCodec().decodeLong(updateCacheFrequencyKv.getValueArray(), updateCacheFrequencyKv.getValueOffset(), SortOrder.getDefault());
    Cell indexDisableTimestampKv = tableKeyValues[INDEX_DISABLE_TIMESTAMP];
    long indexDisableTimestamp = indexDisableTimestampKv == null ? 0L : PLong.INSTANCE.getCodec().decodeLong(indexDisableTimestampKv.getValueArray(), indexDisableTimestampKv.getValueOffset(), SortOrder.getDefault());
    Cell isNamespaceMappedKv = tableKeyValues[IS_NAMESPACE_MAPPED_INDEX];
    boolean isNamespaceMapped = isNamespaceMappedKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(isNamespaceMappedKv.getValueArray(), isNamespaceMappedKv.getValueOffset(), isNamespaceMappedKv.getValueLength()));
    Cell autoPartitionSeqKv = tableKeyValues[AUTO_PARTITION_SEQ_INDEX];
    String autoPartitionSeq = autoPartitionSeqKv != null ? (String) PVarchar.INSTANCE.toObject(autoPartitionSeqKv.getValueArray(), autoPartitionSeqKv.getValueOffset(), autoPartitionSeqKv.getValueLength()) : null;
    Cell isAppendOnlySchemaKv = tableKeyValues[APPEND_ONLY_SCHEMA_INDEX];
    boolean isAppendOnlySchema = isAppendOnlySchemaKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(isAppendOnlySchemaKv.getValueArray(), isAppendOnlySchemaKv.getValueOffset(), isAppendOnlySchemaKv.getValueLength()));
    Cell storageSchemeKv = tableKeyValues[STORAGE_SCHEME_INDEX];
    //TODO: change this once we start having other values for storage schemes
    ImmutableStorageScheme storageScheme = storageSchemeKv == null ? ImmutableStorageScheme.ONE_CELL_PER_COLUMN : ImmutableStorageScheme.fromSerializedValue((byte) PTinyint.INSTANCE.toObject(storageSchemeKv.getValueArray(), storageSchemeKv.getValueOffset(), storageSchemeKv.getValueLength()));
    Cell encodingSchemeKv = tableKeyValues[QUALIFIER_ENCODING_SCHEME_INDEX];
    QualifierEncodingScheme encodingScheme = encodingSchemeKv == null ? QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : QualifierEncodingScheme.fromSerializedValue((byte) PTinyint.INSTANCE.toObject(encodingSchemeKv.getValueArray(), encodingSchemeKv.getValueOffset(), encodingSchemeKv.getValueLength()));
    Cell useStatsForParallelizationKv = tableKeyValues[USE_STATS_FOR_PARALLELIZATION_INDEX];
    boolean useStatsForParallelization = useStatsForParallelizationKv == null ? true : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(useStatsForParallelizationKv.getValueArray(), useStatsForParallelizationKv.getValueOffset(), useStatsForParallelizationKv.getValueLength()));
    List<PColumn> columns = Lists.newArrayListWithExpectedSize(columnCount);
    List<PTable> indexes = Lists.newArrayList();
    List<PName> physicalTables = Lists.newArrayList();
    PName parentTableName = tableType == INDEX ? dataTableName : null;
    PName parentSchemaName = tableType == INDEX ? schemaName : null;
    EncodedCQCounter cqCounter = (!EncodedColumnsUtil.usesEncodedColumnNames(encodingScheme) || tableType == PTableType.VIEW) ? PTable.EncodedCQCounter.NULL_COUNTER : new EncodedCQCounter();
    while (true) {
        results.clear();
        scanner.next(results);
        if (results.isEmpty()) {
            break;
        }
        Cell colKv = results.get(LINK_TYPE_INDEX);
        int colKeyLength = colKv.getRowLength();
        PName colName = newPName(colKv.getRowArray(), colKv.getRowOffset() + offset, colKeyLength - offset);
        int colKeyOffset = offset + colName.getBytes().length + 1;
        PName famName = newPName(colKv.getRowArray(), colKv.getRowOffset() + colKeyOffset, colKeyLength - colKeyOffset);
        if (isQualifierCounterKV(colKv)) {
            Integer value = PInteger.INSTANCE.getCodec().decodeInt(colKv.getValueArray(), colKv.getValueOffset(), SortOrder.ASC);
            cqCounter.setValue(famName.getString(), value);
        } else if (Bytes.compareTo(LINK_TYPE_BYTES, 0, LINK_TYPE_BYTES.length, colKv.getQualifierArray(), colKv.getQualifierOffset(), colKv.getQualifierLength()) == 0) {
            LinkType linkType = LinkType.fromSerializedValue(colKv.getValueArray()[colKv.getValueOffset()]);
            if (linkType == LinkType.INDEX_TABLE) {
                addIndexToTable(tenantId, schemaName, famName, tableName, clientTimeStamp, indexes);
            } else if (linkType == LinkType.PHYSICAL_TABLE) {
                physicalTables.add(famName);
            } else if (linkType == LinkType.PARENT_TABLE) {
                parentTableName = PNameFactory.newName(SchemaUtil.getTableNameFromFullName(famName.getBytes()));
                parentSchemaName = PNameFactory.newName(SchemaUtil.getSchemaNameFromFullName(famName.getBytes()));
            }
        } else {
            addColumnToTable(results, colName, famName, colKeyValues, columns, saltBucketNum != null);
        }
    }
    // server while holding this lock is a bad idea and likely to cause contention.
    return PTableImpl.makePTable(tenantId, schemaName, tableName, tableType, indexState, timeStamp, tableSeqNum, pkName, saltBucketNum, columns, parentSchemaName, parentTableName, indexes, isImmutableRows, physicalTables, defaultFamilyName, viewStatement, disableWAL, multiTenant, storeNulls, viewType, viewIndexId, indexType, rowKeyOrderOptimizable, transactional, updateCacheFrequency, baseColumnCount, indexDisableTimestamp, isNamespaceMapped, autoPartitionSeq, isAppendOnlySchema, storageScheme, encodingScheme, cqCounter, useStatsForParallelization);
}
Also used : ByteString(com.google.protobuf.ByteString) PTable(org.apache.phoenix.schema.PTable) PColumn(org.apache.phoenix.schema.PColumn) QualifierEncodingScheme(org.apache.phoenix.schema.PTable.QualifierEncodingScheme) ImmutableStorageScheme(org.apache.phoenix.schema.PTable.ImmutableStorageScheme) IndexType(org.apache.phoenix.schema.PTable.IndexType) Cell(org.apache.hadoop.hbase.Cell) PIndexState(org.apache.phoenix.schema.PIndexState) PTableType(org.apache.phoenix.schema.PTableType) PTinyint(org.apache.phoenix.schema.types.PTinyint) PSmallint(org.apache.phoenix.schema.types.PSmallint) PInteger(org.apache.phoenix.schema.types.PInteger) EncodedCQCounter(org.apache.phoenix.schema.PTable.EncodedCQCounter) PName(org.apache.phoenix.schema.PName) LinkType(org.apache.phoenix.schema.PTable.LinkType) ViewType(org.apache.phoenix.schema.PTable.ViewType)

Example 2 with EncodedCQCounter

use of org.apache.phoenix.schema.PTable.EncodedCQCounter in project phoenix by apache.

the class AlterTableIT method testMetadataForMutableTable.

@Test
public void testMetadataForMutableTable() throws Exception {
    String schemaName = "XYZ";
    String baseTableName = generateUniqueName();
    String viewName = generateUniqueName();
    String fullTableName = schemaName + "." + baseTableName;
    String fullViewName = schemaName + "." + viewName;
    try (Connection conn = DriverManager.getConnection(getUrl())) {
        PhoenixConnection phxConn = conn.unwrap(PhoenixConnection.class);
        conn.createStatement().execute("CREATE TABLE IF NOT EXISTS " + fullTableName + " (" + " ID char(1) NOT NULL," + " COL1 integer NOT NULL," + " COL2 bigint NOT NULL," + " KV1 VARCHAR" + " CONSTRAINT NAME_PK PRIMARY KEY (ID, COL1, COL2)" + " ) " + tableDDLOptions);
        PTable baseTable = phxConn.getTable(new PTableKey(phxConn.getTenantId(), fullTableName));
        long initBaseTableSeqNumber = baseTable.getSequenceNumber();
        // assert that the client side cache is updated.
        EncodedCQCounter cqCounter = baseTable.getEncodedCQCounter();
        assertEquals(columnEncoded ? (Integer) (ENCODED_CQ_COUNTER_INITIAL_VALUE + 1) : null, cqCounter.getNextQualifier(QueryConstants.DEFAULT_COLUMN_FAMILY));
        // assert that the server side metadata is updated correctly.
        assertEncodedCQCounter(DEFAULT_COLUMN_FAMILY, schemaName, baseTableName, ENCODED_CQ_COUNTER_INITIAL_VALUE + 1);
        assertEncodedCQValue(DEFAULT_COLUMN_FAMILY, "KV1", schemaName, baseTableName, ENCODED_CQ_COUNTER_INITIAL_VALUE);
        assertSequenceNumber(schemaName, baseTableName, initBaseTableSeqNumber);
        // now create a view and validate client and server side metadata
        String viewDDL = "CREATE VIEW " + fullViewName + " ( VIEW_COL1 INTEGER, A.VIEW_COL2 VARCHAR ) AS SELECT * FROM " + fullTableName;
        conn.createStatement().execute(viewDDL);
        baseTable = phxConn.getTable(new PTableKey(phxConn.getTenantId(), fullTableName));
        PTable view = phxConn.getTable(new PTableKey(phxConn.getTenantId(), fullViewName));
        // verify that the client side cache is updated. Base table's cq counters should be updated.
        assertEquals(columnEncoded ? (Integer) (ENCODED_CQ_COUNTER_INITIAL_VALUE + 3) : null, baseTable.getEncodedCQCounter().getNextQualifier(DEFAULT_COLUMN_FAMILY));
        assertNull("A view should always have the null cq counter", view.getEncodedCQCounter().getNextQualifier(DEFAULT_COLUMN_FAMILY));
        // assert that the server side metadata for the base table and the view is also updated correctly.
        assertEncodedCQCounter(DEFAULT_COLUMN_FAMILY, schemaName, baseTableName, ENCODED_CQ_COUNTER_INITIAL_VALUE + 3);
        assertEncodedCQValue(DEFAULT_COLUMN_FAMILY, "VIEW_COL1", schemaName, viewName, ENCODED_CQ_COUNTER_INITIAL_VALUE + 1);
        assertEncodedCQValue("A", "VIEW_COL2", schemaName, viewName, ENCODED_CQ_COUNTER_INITIAL_VALUE + 2);
        assertSequenceNumber(schemaName, baseTableName, initBaseTableSeqNumber + (columnEncoded ? 1 : 0));
        assertSequenceNumber(schemaName, viewName, PTable.INITIAL_SEQ_NUM);
    }
}
Also used : PhoenixConnection(org.apache.phoenix.jdbc.PhoenixConnection) EncodedCQCounter(org.apache.phoenix.schema.PTable.EncodedCQCounter) Connection(java.sql.Connection) PhoenixConnection(org.apache.phoenix.jdbc.PhoenixConnection) TestUtil.closeConnection(org.apache.phoenix.util.TestUtil.closeConnection) PTableKey(org.apache.phoenix.schema.PTableKey) PTable(org.apache.phoenix.schema.PTable) BaseTest(org.apache.phoenix.query.BaseTest) Test(org.junit.Test)

Example 3 with EncodedCQCounter

use of org.apache.phoenix.schema.PTable.EncodedCQCounter in project phoenix by apache.

the class MetaDataEndpointImpl method getTable.

private PTable getTable(RegionScanner scanner, long clientTimeStamp, long tableTimeStamp, int clientVersion) throws IOException, SQLException {
    List<Cell> results = Lists.newArrayList();
    scanner.next(results);
    if (results.isEmpty()) {
        return null;
    }
    Cell[] tableKeyValues = new Cell[TABLE_KV_COLUMNS.size()];
    Cell[] colKeyValues = new Cell[COLUMN_KV_COLUMNS.size()];
    // Create PTable based on KeyValues from scan
    Cell keyValue = results.get(0);
    byte[] keyBuffer = keyValue.getRowArray();
    int keyLength = keyValue.getRowLength();
    int keyOffset = keyValue.getRowOffset();
    PName tenantId = newPName(keyBuffer, keyOffset, keyLength);
    int tenantIdLength = (tenantId == null) ? 0 : tenantId.getBytes().length;
    if (tenantIdLength == 0) {
        tenantId = null;
    }
    PName schemaName = newPName(keyBuffer, keyOffset + tenantIdLength + 1, keyLength);
    int schemaNameLength = schemaName.getBytes().length;
    int tableNameLength = keyLength - schemaNameLength - 1 - tenantIdLength - 1;
    byte[] tableNameBytes = new byte[tableNameLength];
    System.arraycopy(keyBuffer, keyOffset + schemaNameLength + 1 + tenantIdLength + 1, tableNameBytes, 0, tableNameLength);
    PName tableName = PNameFactory.newName(tableNameBytes);
    int offset = tenantIdLength + schemaNameLength + tableNameLength + 3;
    // This will prevent the client from continually looking for the current
    // table when we know that there will never be one since we disallow updates
    // unless the table is the latest
    // If we already have a table newer than the one we just found and
    // the client timestamp is less that the existing table time stamp,
    // bump up the timeStamp to right before the client time stamp, since
    // we know it can't possibly change.
    long timeStamp = keyValue.getTimestamp();
    // long timeStamp = tableTimeStamp > keyValue.getTimestamp() &&
    // clientTimeStamp < tableTimeStamp
    // ? clientTimeStamp-1
    // : keyValue.getTimestamp();
    int i = 0;
    int j = 0;
    while (i < results.size() && j < TABLE_KV_COLUMNS.size()) {
        Cell kv = results.get(i);
        Cell searchKv = TABLE_KV_COLUMNS.get(j);
        int cmp = Bytes.compareTo(kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength(), searchKv.getQualifierArray(), searchKv.getQualifierOffset(), searchKv.getQualifierLength());
        if (cmp == 0) {
            // Find max timestamp of table
            timeStamp = Math.max(timeStamp, kv.getTimestamp());
            // header row
            tableKeyValues[j++] = kv;
            i++;
        } else if (cmp > 0) {
            timeStamp = Math.max(timeStamp, kv.getTimestamp());
            tableKeyValues[j++] = null;
        } else {
            // shouldn't happen - means unexpected KV in system table header row
            i++;
        }
    }
    // TABLE_TYPE, TABLE_SEQ_NUM and COLUMN_COUNT are required.
    if (tableKeyValues[TABLE_TYPE_INDEX] == null || tableKeyValues[TABLE_SEQ_NUM_INDEX] == null || tableKeyValues[COLUMN_COUNT_INDEX] == null) {
        throw new IllegalStateException("Didn't find expected key values for table row in metadata row");
    }
    Cell tableTypeKv = tableKeyValues[TABLE_TYPE_INDEX];
    PTableType tableType = PTableType.fromSerializedValue(tableTypeKv.getValueArray()[tableTypeKv.getValueOffset()]);
    Cell tableSeqNumKv = tableKeyValues[TABLE_SEQ_NUM_INDEX];
    long tableSeqNum = PLong.INSTANCE.getCodec().decodeLong(tableSeqNumKv.getValueArray(), tableSeqNumKv.getValueOffset(), SortOrder.getDefault());
    Cell columnCountKv = tableKeyValues[COLUMN_COUNT_INDEX];
    int columnCount = PInteger.INSTANCE.getCodec().decodeInt(columnCountKv.getValueArray(), columnCountKv.getValueOffset(), SortOrder.getDefault());
    Cell pkNameKv = tableKeyValues[PK_NAME_INDEX];
    PName pkName = pkNameKv != null ? newPName(pkNameKv.getValueArray(), pkNameKv.getValueOffset(), pkNameKv.getValueLength()) : null;
    Cell saltBucketNumKv = tableKeyValues[SALT_BUCKETS_INDEX];
    Integer saltBucketNum = saltBucketNumKv != null ? (Integer) PInteger.INSTANCE.getCodec().decodeInt(saltBucketNumKv.getValueArray(), saltBucketNumKv.getValueOffset(), SortOrder.getDefault()) : null;
    if (saltBucketNum != null && saltBucketNum.intValue() == 0) {
        // Zero salt buckets means not salted
        saltBucketNum = null;
    }
    Cell dataTableNameKv = tableKeyValues[DATA_TABLE_NAME_INDEX];
    PName dataTableName = dataTableNameKv != null ? newPName(dataTableNameKv.getValueArray(), dataTableNameKv.getValueOffset(), dataTableNameKv.getValueLength()) : null;
    Cell indexStateKv = tableKeyValues[INDEX_STATE_INDEX];
    PIndexState indexState = indexStateKv == null ? null : PIndexState.fromSerializedValue(indexStateKv.getValueArray()[indexStateKv.getValueOffset()]);
    // the value in those versions) since the client won't have this index state in its enum.
    if (indexState == PIndexState.PENDING_ACTIVE && clientVersion < PhoenixDatabaseMetaData.MIN_PENDING_ACTIVE_INDEX) {
        indexState = PIndexState.ACTIVE;
    }
    // since the client won't have this index state in its enum.
    if (indexState == PIndexState.PENDING_DISABLE && clientVersion < PhoenixDatabaseMetaData.MIN_PENDING_DISABLE_INDEX) {
        // note: for older clients, we have to rely on the rebuilder to transition PENDING_DISABLE -> DISABLE
        indexState = PIndexState.DISABLE;
    }
    Cell immutableRowsKv = tableKeyValues[IMMUTABLE_ROWS_INDEX];
    boolean isImmutableRows = immutableRowsKv == null ? false : (Boolean) PBoolean.INSTANCE.toObject(immutableRowsKv.getValueArray(), immutableRowsKv.getValueOffset(), immutableRowsKv.getValueLength());
    Cell defaultFamilyNameKv = tableKeyValues[DEFAULT_COLUMN_FAMILY_INDEX];
    PName defaultFamilyName = defaultFamilyNameKv != null ? newPName(defaultFamilyNameKv.getValueArray(), defaultFamilyNameKv.getValueOffset(), defaultFamilyNameKv.getValueLength()) : null;
    Cell viewStatementKv = tableKeyValues[VIEW_STATEMENT_INDEX];
    String viewStatement = viewStatementKv != null ? (String) PVarchar.INSTANCE.toObject(viewStatementKv.getValueArray(), viewStatementKv.getValueOffset(), viewStatementKv.getValueLength()) : null;
    Cell disableWALKv = tableKeyValues[DISABLE_WAL_INDEX];
    boolean disableWAL = disableWALKv == null ? PTable.DEFAULT_DISABLE_WAL : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(disableWALKv.getValueArray(), disableWALKv.getValueOffset(), disableWALKv.getValueLength()));
    Cell multiTenantKv = tableKeyValues[MULTI_TENANT_INDEX];
    boolean multiTenant = multiTenantKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(multiTenantKv.getValueArray(), multiTenantKv.getValueOffset(), multiTenantKv.getValueLength()));
    Cell storeNullsKv = tableKeyValues[STORE_NULLS_INDEX];
    boolean storeNulls = storeNullsKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(storeNullsKv.getValueArray(), storeNullsKv.getValueOffset(), storeNullsKv.getValueLength()));
    Cell transactionalKv = tableKeyValues[TRANSACTIONAL_INDEX];
    boolean transactional = transactionalKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(transactionalKv.getValueArray(), transactionalKv.getValueOffset(), transactionalKv.getValueLength()));
    Cell viewTypeKv = tableKeyValues[VIEW_TYPE_INDEX];
    ViewType viewType = viewTypeKv == null ? null : ViewType.fromSerializedValue(viewTypeKv.getValueArray()[viewTypeKv.getValueOffset()]);
    Cell viewIndexIdKv = tableKeyValues[VIEW_INDEX_ID_INDEX];
    Short viewIndexId = viewIndexIdKv == null ? null : (Short) MetaDataUtil.getViewIndexIdDataType().getCodec().decodeShort(viewIndexIdKv.getValueArray(), viewIndexIdKv.getValueOffset(), SortOrder.getDefault());
    Cell indexTypeKv = tableKeyValues[INDEX_TYPE_INDEX];
    IndexType indexType = indexTypeKv == null ? null : IndexType.fromSerializedValue(indexTypeKv.getValueArray()[indexTypeKv.getValueOffset()]);
    Cell baseColumnCountKv = tableKeyValues[BASE_COLUMN_COUNT_INDEX];
    int baseColumnCount = baseColumnCountKv == null ? 0 : PInteger.INSTANCE.getCodec().decodeInt(baseColumnCountKv.getValueArray(), baseColumnCountKv.getValueOffset(), SortOrder.getDefault());
    Cell rowKeyOrderOptimizableKv = tableKeyValues[ROW_KEY_ORDER_OPTIMIZABLE_INDEX];
    boolean rowKeyOrderOptimizable = rowKeyOrderOptimizableKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(rowKeyOrderOptimizableKv.getValueArray(), rowKeyOrderOptimizableKv.getValueOffset(), rowKeyOrderOptimizableKv.getValueLength()));
    Cell updateCacheFrequencyKv = tableKeyValues[UPDATE_CACHE_FREQUENCY_INDEX];
    long updateCacheFrequency = updateCacheFrequencyKv == null ? 0 : PLong.INSTANCE.getCodec().decodeLong(updateCacheFrequencyKv.getValueArray(), updateCacheFrequencyKv.getValueOffset(), SortOrder.getDefault());
    Cell indexDisableTimestampKv = tableKeyValues[INDEX_DISABLE_TIMESTAMP];
    long indexDisableTimestamp = indexDisableTimestampKv == null ? 0L : PLong.INSTANCE.getCodec().decodeLong(indexDisableTimestampKv.getValueArray(), indexDisableTimestampKv.getValueOffset(), SortOrder.getDefault());
    Cell isNamespaceMappedKv = tableKeyValues[IS_NAMESPACE_MAPPED_INDEX];
    boolean isNamespaceMapped = isNamespaceMappedKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(isNamespaceMappedKv.getValueArray(), isNamespaceMappedKv.getValueOffset(), isNamespaceMappedKv.getValueLength()));
    Cell autoPartitionSeqKv = tableKeyValues[AUTO_PARTITION_SEQ_INDEX];
    String autoPartitionSeq = autoPartitionSeqKv != null ? (String) PVarchar.INSTANCE.toObject(autoPartitionSeqKv.getValueArray(), autoPartitionSeqKv.getValueOffset(), autoPartitionSeqKv.getValueLength()) : null;
    Cell isAppendOnlySchemaKv = tableKeyValues[APPEND_ONLY_SCHEMA_INDEX];
    boolean isAppendOnlySchema = isAppendOnlySchemaKv == null ? false : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(isAppendOnlySchemaKv.getValueArray(), isAppendOnlySchemaKv.getValueOffset(), isAppendOnlySchemaKv.getValueLength()));
    Cell storageSchemeKv = tableKeyValues[STORAGE_SCHEME_INDEX];
    // TODO: change this once we start having other values for storage schemes
    ImmutableStorageScheme storageScheme = storageSchemeKv == null ? ImmutableStorageScheme.ONE_CELL_PER_COLUMN : ImmutableStorageScheme.fromSerializedValue((byte) PTinyint.INSTANCE.toObject(storageSchemeKv.getValueArray(), storageSchemeKv.getValueOffset(), storageSchemeKv.getValueLength()));
    Cell encodingSchemeKv = tableKeyValues[QUALIFIER_ENCODING_SCHEME_INDEX];
    QualifierEncodingScheme encodingScheme = encodingSchemeKv == null ? QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : QualifierEncodingScheme.fromSerializedValue((byte) PTinyint.INSTANCE.toObject(encodingSchemeKv.getValueArray(), encodingSchemeKv.getValueOffset(), encodingSchemeKv.getValueLength()));
    Cell useStatsForParallelizationKv = tableKeyValues[USE_STATS_FOR_PARALLELIZATION_INDEX];
    Boolean useStatsForParallelization = useStatsForParallelizationKv == null ? null : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(useStatsForParallelizationKv.getValueArray(), useStatsForParallelizationKv.getValueOffset(), useStatsForParallelizationKv.getValueLength()));
    List<PColumn> columns = Lists.newArrayListWithExpectedSize(columnCount);
    List<PTable> indexes = Lists.newArrayList();
    List<PName> physicalTables = Lists.newArrayList();
    PName parentTableName = tableType == INDEX ? dataTableName : null;
    PName parentSchemaName = tableType == INDEX ? schemaName : null;
    EncodedCQCounter cqCounter = (!EncodedColumnsUtil.usesEncodedColumnNames(encodingScheme) || tableType == PTableType.VIEW) ? PTable.EncodedCQCounter.NULL_COUNTER : new EncodedCQCounter();
    while (true) {
        results.clear();
        scanner.next(results);
        if (results.isEmpty()) {
            break;
        }
        Cell colKv = results.get(LINK_TYPE_INDEX);
        int colKeyLength = colKv.getRowLength();
        PName colName = newPName(colKv.getRowArray(), colKv.getRowOffset() + offset, colKeyLength - offset);
        int colKeyOffset = offset + colName.getBytes().length + 1;
        PName famName = newPName(colKv.getRowArray(), colKv.getRowOffset() + colKeyOffset, colKeyLength - colKeyOffset);
        if (isQualifierCounterKV(colKv)) {
            Integer value = PInteger.INSTANCE.getCodec().decodeInt(colKv.getValueArray(), colKv.getValueOffset(), SortOrder.ASC);
            cqCounter.setValue(famName.getString(), value);
        } else if (Bytes.compareTo(LINK_TYPE_BYTES, 0, LINK_TYPE_BYTES.length, colKv.getQualifierArray(), colKv.getQualifierOffset(), colKv.getQualifierLength()) == 0) {
            LinkType linkType = LinkType.fromSerializedValue(colKv.getValueArray()[colKv.getValueOffset()]);
            if (linkType == LinkType.INDEX_TABLE) {
                addIndexToTable(tenantId, schemaName, famName, tableName, clientTimeStamp, indexes, clientVersion);
            } else if (linkType == LinkType.PHYSICAL_TABLE) {
                physicalTables.add(famName);
            } else if (linkType == LinkType.PARENT_TABLE) {
                parentTableName = PNameFactory.newName(SchemaUtil.getTableNameFromFullName(famName.getBytes()));
                parentSchemaName = PNameFactory.newName(SchemaUtil.getSchemaNameFromFullName(famName.getBytes()));
            }
        } else {
            addColumnToTable(results, colName, famName, colKeyValues, columns, saltBucketNum != null);
        }
    }
    // server while holding this lock is a bad idea and likely to cause contention.
    return PTableImpl.makePTable(tenantId, schemaName, tableName, tableType, indexState, timeStamp, tableSeqNum, pkName, saltBucketNum, columns, parentSchemaName, parentTableName, indexes, isImmutableRows, physicalTables, defaultFamilyName, viewStatement, disableWAL, multiTenant, storeNulls, viewType, viewIndexId, indexType, rowKeyOrderOptimizable, transactional, updateCacheFrequency, baseColumnCount, indexDisableTimestamp, isNamespaceMapped, autoPartitionSeq, isAppendOnlySchema, storageScheme, encodingScheme, cqCounter, useStatsForParallelization);
}
Also used : ByteString(com.google.protobuf.ByteString) PTable(org.apache.phoenix.schema.PTable) PColumn(org.apache.phoenix.schema.PColumn) QualifierEncodingScheme(org.apache.phoenix.schema.PTable.QualifierEncodingScheme) ImmutableStorageScheme(org.apache.phoenix.schema.PTable.ImmutableStorageScheme) IndexType(org.apache.phoenix.schema.PTable.IndexType) PBoolean(org.apache.phoenix.schema.types.PBoolean) Cell(org.apache.hadoop.hbase.Cell) PIndexState(org.apache.phoenix.schema.PIndexState) PTableType(org.apache.phoenix.schema.PTableType) PTinyint(org.apache.phoenix.schema.types.PTinyint) PSmallint(org.apache.phoenix.schema.types.PSmallint) PInteger(org.apache.phoenix.schema.types.PInteger) EncodedCQCounter(org.apache.phoenix.schema.PTable.EncodedCQCounter) PName(org.apache.phoenix.schema.PName) LinkType(org.apache.phoenix.schema.PTable.LinkType) ViewType(org.apache.phoenix.schema.PTable.ViewType)

Example 4 with EncodedCQCounter

use of org.apache.phoenix.schema.PTable.EncodedCQCounter in project phoenix by apache.

the class TupleProjectionCompiler method createProjectedTable.

public static PTable createProjectedTable(TableRef tableRef, List<ColumnRef> sourceColumnRefs, boolean retainPKColumns) throws SQLException {
    PTable table = tableRef.getTable();
    List<PColumn> projectedColumns = new ArrayList<PColumn>();
    int position = table.getBucketNum() != null ? 1 : 0;
    for (int i = retainPKColumns ? position : 0; i < sourceColumnRefs.size(); i++) {
        ColumnRef sourceColumnRef = sourceColumnRefs.get(i);
        PColumn sourceColumn = sourceColumnRef.getColumn();
        String colName = sourceColumn.getName().getString();
        String aliasedName = tableRef.getTableAlias() == null ? SchemaUtil.getColumnName(table.getName().getString(), colName) : SchemaUtil.getColumnName(tableRef.getTableAlias(), colName);
        PName familyName = SchemaUtil.isPKColumn(sourceColumn) ? (retainPKColumns ? null : PNameFactory.newName(VALUE_COLUMN_FAMILY)) : sourceColumn.getFamilyName();
        // If we're not retaining the PK columns, then we should switch columns to be nullable
        PColumn column = new ProjectedColumn(PNameFactory.newName(aliasedName), familyName, position++, sourceColumn.isNullable(), sourceColumnRef, sourceColumn.getColumnQualifierBytes());
        projectedColumns.add(column);
    }
    EncodedCQCounter cqCounter = EncodedCQCounter.NULL_COUNTER;
    if (EncodedColumnsUtil.usesEncodedColumnNames(table)) {
        cqCounter = EncodedCQCounter.copy(table.getEncodedCQCounter());
    }
    return PTableImpl.makePTable(table.getTenantId(), PROJECTED_TABLE_SCHEMA, table.getName(), PTableType.PROJECTED, null, table.getTimeStamp(), table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), projectedColumns, null, null, Collections.<PTable>emptyList(), table.isImmutableRows(), Collections.<PName>emptyList(), null, null, table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), null, table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), cqCounter, table.useStatsForParallelization());
}
Also used : PColumn(org.apache.phoenix.schema.PColumn) EncodedCQCounter(org.apache.phoenix.schema.PTable.EncodedCQCounter) PName(org.apache.phoenix.schema.PName) ArrayList(java.util.ArrayList) ColumnRef(org.apache.phoenix.schema.ColumnRef) LocalIndexDataColumnRef(org.apache.phoenix.schema.LocalIndexDataColumnRef) PTable(org.apache.phoenix.schema.PTable) ProjectedColumn(org.apache.phoenix.schema.ProjectedColumn)

Example 5 with EncodedCQCounter

use of org.apache.phoenix.schema.PTable.EncodedCQCounter in project phoenix by apache.

the class MetaDataClient method createTableInternal.

private PTable createTableInternal(CreateTableStatement statement, byte[][] splits, final PTable parent, String viewStatement, ViewType viewType, final byte[][] viewColumnConstants, final BitSet isViewColumnReferenced, boolean allocateIndexId, IndexType indexType, Date asyncCreatedDate, Map<String, Object> tableProps, Map<String, Object> commonFamilyProps) throws SQLException {
    final PTableType tableType = statement.getTableType();
    boolean wasAutoCommit = connection.getAutoCommit();
    connection.rollback();
    try {
        connection.setAutoCommit(false);
        List<Mutation> tableMetaData = Lists.newArrayListWithExpectedSize(statement.getColumnDefs().size() + 3);
        TableName tableNameNode = statement.getTableName();
        final String schemaName = connection.getSchema() != null && tableNameNode.getSchemaName() == null ? connection.getSchema() : tableNameNode.getSchemaName();
        final String tableName = tableNameNode.getTableName();
        String parentTableName = null;
        PName tenantId = connection.getTenantId();
        String tenantIdStr = tenantId == null ? null : tenantId.getString();
        Long scn = connection.getSCN();
        long clientTimeStamp = scn == null ? HConstants.LATEST_TIMESTAMP : scn;
        boolean multiTenant = false;
        boolean storeNulls = false;
        boolean transactional = (parent != null) ? parent.isTransactional() : false;
        Integer saltBucketNum = null;
        String defaultFamilyName = null;
        boolean isImmutableRows = false;
        boolean isAppendOnlySchema = false;
        List<PName> physicalNames = Collections.emptyList();
        boolean addSaltColumn = false;
        boolean rowKeyOrderOptimizable = true;
        Long timestamp = null;
        boolean isNamespaceMapped = parent == null ? SchemaUtil.isNamespaceMappingEnabled(tableType, connection.getQueryServices().getProps()) : parent.isNamespaceMapped();
        boolean isLocalIndex = indexType == IndexType.LOCAL;
        QualifierEncodingScheme encodingScheme = NON_ENCODED_QUALIFIERS;
        ImmutableStorageScheme immutableStorageScheme = ONE_CELL_PER_COLUMN;
        if (parent != null && tableType == PTableType.INDEX) {
            timestamp = TransactionUtil.getTableTimestamp(connection, transactional);
            storeNulls = parent.getStoreNulls();
            isImmutableRows = parent.isImmutableRows();
            isAppendOnlySchema = parent.isAppendOnlySchema();
            // from the table to the index, though.
            if (isLocalIndex || (parent.getType() == PTableType.VIEW && parent.getViewType() != ViewType.MAPPED)) {
                PName physicalName = parent.getPhysicalName();
                saltBucketNum = parent.getBucketNum();
                addSaltColumn = (saltBucketNum != null && !isLocalIndex);
                defaultFamilyName = parent.getDefaultFamilyName() == null ? null : parent.getDefaultFamilyName().getString();
                if (isLocalIndex) {
                    defaultFamilyName = parent.getDefaultFamilyName() == null ? QueryConstants.DEFAULT_LOCAL_INDEX_COLUMN_FAMILY : IndexUtil.getLocalIndexColumnFamily(parent.getDefaultFamilyName().getString());
                    saltBucketNum = null;
                    // Set physical name of local index table
                    physicalNames = Collections.singletonList(PNameFactory.newName(physicalName.getBytes()));
                } else {
                    defaultFamilyName = parent.getDefaultFamilyName() == null ? QueryConstants.DEFAULT_COLUMN_FAMILY : parent.getDefaultFamilyName().getString();
                    // Set physical name of view index table
                    physicalNames = Collections.singletonList(PNameFactory.newName(MetaDataUtil.getViewIndexPhysicalName(physicalName.getBytes())));
                }
            }
            multiTenant = parent.isMultiTenant();
            storeNulls = parent.getStoreNulls();
            parentTableName = parent.getTableName().getString();
            // Pass through data table sequence number so we can check it hasn't changed
            PreparedStatement incrementStatement = connection.prepareStatement(INCREMENT_SEQ_NUM);
            incrementStatement.setString(1, tenantIdStr);
            incrementStatement.setString(2, schemaName);
            incrementStatement.setString(3, parentTableName);
            incrementStatement.setLong(4, parent.getSequenceNumber());
            incrementStatement.execute();
            // Get list of mutations and add to table meta data that will be passed to server
            // to guarantee order. This row will always end up last
            tableMetaData.addAll(connection.getMutationState().toMutations(timestamp).next().getSecond());
            connection.rollback();
            // Add row linking from data table row to index table row
            PreparedStatement linkStatement = connection.prepareStatement(CREATE_LINK);
            linkStatement.setString(1, tenantIdStr);
            linkStatement.setString(2, schemaName);
            linkStatement.setString(3, parentTableName);
            linkStatement.setString(4, tableName);
            linkStatement.setByte(5, LinkType.INDEX_TABLE.getSerializedValue());
            linkStatement.setLong(6, parent.getSequenceNumber());
            linkStatement.setString(7, PTableType.INDEX.getSerializedValue());
            linkStatement.execute();
        }
        PrimaryKeyConstraint pkConstraint = statement.getPrimaryKeyConstraint();
        String pkName = null;
        List<Pair<ColumnName, SortOrder>> pkColumnsNames = Collections.<Pair<ColumnName, SortOrder>>emptyList();
        Iterator<Pair<ColumnName, SortOrder>> pkColumnsIterator = Collections.emptyIterator();
        if (pkConstraint != null) {
            pkColumnsNames = pkConstraint.getColumnNames();
            pkColumnsIterator = pkColumnsNames.iterator();
            pkName = pkConstraint.getName();
        }
        // This tells Phoenix that you're managing the index maintenance yourself.
        if (tableType != PTableType.INDEX && (tableType != PTableType.VIEW || viewType == ViewType.MAPPED)) {
            // TODO remove TableProperty.IMMUTABLE_ROWS at the next major release
            Boolean isImmutableRowsProp = statement.immutableRows() != null ? statement.immutableRows() : (Boolean) TableProperty.IMMUTABLE_ROWS.getValue(tableProps);
            if (isImmutableRowsProp == null) {
                isImmutableRows = connection.getQueryServices().getProps().getBoolean(QueryServices.IMMUTABLE_ROWS_ATTRIB, QueryServicesOptions.DEFAULT_IMMUTABLE_ROWS);
            } else {
                isImmutableRows = isImmutableRowsProp;
            }
        }
        if (tableType == PTableType.TABLE) {
            Boolean isAppendOnlySchemaProp = (Boolean) TableProperty.APPEND_ONLY_SCHEMA.getValue(tableProps);
            isAppendOnlySchema = isAppendOnlySchemaProp != null ? isAppendOnlySchemaProp : false;
        }
        // Can't set any of these on views or shared indexes on views
        if (tableType != PTableType.VIEW && !allocateIndexId) {
            saltBucketNum = (Integer) TableProperty.SALT_BUCKETS.getValue(tableProps);
            if (saltBucketNum != null) {
                if (saltBucketNum < 0 || saltBucketNum > SaltingUtil.MAX_BUCKET_NUM) {
                    throw new SQLExceptionInfo.Builder(SQLExceptionCode.INVALID_BUCKET_NUM).build().buildException();
                }
            }
            // Salt the index table if the data table is salted
            if (saltBucketNum == null) {
                if (parent != null) {
                    saltBucketNum = parent.getBucketNum();
                }
            } else if (saltBucketNum.intValue() == 0) {
                // Provides a way for an index to not be salted if its data table is salted
                saltBucketNum = null;
            }
            addSaltColumn = (saltBucketNum != null);
        }
        // Can't set MULTI_TENANT or DEFAULT_COLUMN_FAMILY_NAME on an INDEX or a non mapped VIEW
        if (tableType != PTableType.INDEX && (tableType != PTableType.VIEW || viewType == ViewType.MAPPED)) {
            Boolean multiTenantProp = (Boolean) tableProps.get(PhoenixDatabaseMetaData.MULTI_TENANT);
            multiTenant = Boolean.TRUE.equals(multiTenantProp);
            defaultFamilyName = (String) TableProperty.DEFAULT_COLUMN_FAMILY.getValue(tableProps);
        }
        boolean disableWAL = false;
        Boolean disableWALProp = (Boolean) TableProperty.DISABLE_WAL.getValue(tableProps);
        if (disableWALProp != null) {
            disableWAL = disableWALProp;
        }
        long updateCacheFrequency = connection.getQueryServices().getProps().getLong(QueryServices.DEFAULT_UPDATE_CACHE_FREQUENCY_ATRRIB, QueryServicesOptions.DEFAULT_UPDATE_CACHE_FREQUENCY);
        Long updateCacheFrequencyProp = (Long) TableProperty.UPDATE_CACHE_FREQUENCY.getValue(tableProps);
        if (updateCacheFrequencyProp != null) {
            updateCacheFrequency = updateCacheFrequencyProp;
        }
        String autoPartitionSeq = (String) TableProperty.AUTO_PARTITION_SEQ.getValue(tableProps);
        Long guidePostsWidth = (Long) TableProperty.GUIDE_POSTS_WIDTH.getValue(tableProps);
        // We only allow setting guide post width for a base table
        if (guidePostsWidth != null && tableType != PTableType.TABLE) {
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_SET_GUIDE_POST_WIDTH).setSchemaName(schemaName).setTableName(tableName).build().buildException();
        }
        Boolean storeNullsProp = (Boolean) TableProperty.STORE_NULLS.getValue(tableProps);
        if (storeNullsProp == null) {
            if (parent == null) {
                storeNulls = connection.getQueryServices().getProps().getBoolean(QueryServices.DEFAULT_STORE_NULLS_ATTRIB, QueryServicesOptions.DEFAULT_STORE_NULLS);
                tableProps.put(PhoenixDatabaseMetaData.STORE_NULLS, Boolean.valueOf(storeNulls));
            }
        } else {
            storeNulls = storeNullsProp;
        }
        Boolean transactionalProp = (Boolean) TableProperty.TRANSACTIONAL.getValue(tableProps);
        if (transactionalProp != null && parent != null) {
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.ONLY_TABLE_MAY_BE_DECLARED_TRANSACTIONAL).setSchemaName(schemaName).setTableName(tableName).build().buildException();
        }
        if (parent == null) {
            if (transactionalProp == null) {
                transactional = connection.getQueryServices().getProps().getBoolean(QueryServices.DEFAULT_TABLE_ISTRANSACTIONAL_ATTRIB, QueryServicesOptions.DEFAULT_TABLE_ISTRANSACTIONAL);
            } else {
                transactional = transactionalProp;
            }
        }
        boolean transactionsEnabled = connection.getQueryServices().getProps().getBoolean(QueryServices.TRANSACTIONS_ENABLED, QueryServicesOptions.DEFAULT_TRANSACTIONS_ENABLED);
        // can't create a transactional table if transactions are not enabled
        if (!transactionsEnabled && transactional) {
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_CREATE_TXN_TABLE_IF_TXNS_DISABLED).setSchemaName(schemaName).setTableName(tableName).build().buildException();
        }
        // can't create a transactional table if it has a row timestamp column
        if (pkConstraint.getNumColumnsWithRowTimestamp() > 0 && transactional) {
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_CREATE_TXN_TABLE_WITH_ROW_TIMESTAMP).setSchemaName(schemaName).setTableName(tableName).build().buildException();
        }
        // Put potentially inferred value into tableProps as it's used by the createTable call below
        // to determine which coprocessors to install on the new table.
        tableProps.put(PhoenixDatabaseMetaData.TRANSACTIONAL, transactional);
        if (transactional) {
            // If TTL set, use Tephra TTL property name instead
            Object ttl = commonFamilyProps.remove(HColumnDescriptor.TTL);
            if (ttl != null) {
                commonFamilyProps.put(PhoenixTransactionContext.PROPERTY_TTL, ttl);
            }
        }
        Boolean useStatsForParallelizationProp = (Boolean) TableProperty.USE_STATS_FOR_PARALLELIZATION.getValue(tableProps);
        boolean sharedTable = statement.getTableType() == PTableType.VIEW || allocateIndexId;
        if (transactional) {
            // maintenance code being able to see the prior state to update the rows correctly.
            if (Boolean.FALSE.equals(storeNullsProp)) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.STORE_NULLS_MUST_BE_TRUE_FOR_TRANSACTIONAL).setSchemaName(schemaName).setTableName(tableName).build().buildException();
            }
            // Force STORE_NULLS to true when transactional as Tephra cannot deal with column deletes
            storeNulls = true;
            tableProps.put(PhoenixDatabaseMetaData.STORE_NULLS, Boolean.TRUE);
            if (!sharedTable) {
                Integer maxVersionsProp = (Integer) commonFamilyProps.get(HConstants.VERSIONS);
                if (maxVersionsProp == null) {
                    if (parent != null) {
                        HTableDescriptor desc = connection.getQueryServices().getTableDescriptor(parent.getPhysicalName().getBytes());
                        if (desc != null) {
                            maxVersionsProp = desc.getFamily(SchemaUtil.getEmptyColumnFamily(parent)).getMaxVersions();
                        }
                    }
                    if (maxVersionsProp == null) {
                        maxVersionsProp = connection.getQueryServices().getProps().getInt(QueryServices.MAX_VERSIONS_TRANSACTIONAL_ATTRIB, QueryServicesOptions.DEFAULT_MAX_VERSIONS_TRANSACTIONAL);
                    }
                    commonFamilyProps.put(HConstants.VERSIONS, maxVersionsProp);
                }
            }
        }
        timestamp = timestamp == null ? TransactionUtil.getTableTimestamp(connection, transactional) : timestamp;
        // Delay this check as it is supported to have IMMUTABLE_ROWS and SALT_BUCKETS defined on views
        if (sharedTable) {
            if (tableProps.get(PhoenixDatabaseMetaData.DEFAULT_COLUMN_FAMILY_NAME) != null) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.DEFAULT_COLUMN_FAMILY_ON_SHARED_TABLE).setSchemaName(schemaName).setTableName(tableName).build().buildException();
            }
            if (SchemaUtil.hasHTableDescriptorProps(tableProps)) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.VIEW_WITH_PROPERTIES).build().buildException();
            }
        }
        List<ColumnDef> colDefs = statement.getColumnDefs();
        LinkedHashMap<PColumn, PColumn> columns;
        LinkedHashSet<PColumn> pkColumns;
        if (tenantId != null && !sharedTable) {
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_CREATE_TENANT_SPECIFIC_TABLE).setSchemaName(schemaName).setTableName(tableName).build().buildException();
        }
        if (autoPartitionSeq != null) {
            int autoPartitionColIndex = multiTenant ? 1 : 0;
            PDataType dataType = colDefs.get(autoPartitionColIndex).getDataType();
            if (!PLong.INSTANCE.isCastableTo(dataType)) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.SEQUENCE_NOT_CASTABLE_TO_AUTO_PARTITION_ID_COLUMN).setSchemaName(schemaName).setTableName(tableName).build().buildException();
            }
        }
        if (tableType == PTableType.VIEW) {
            physicalNames = Collections.singletonList(PNameFactory.newName(parent.getPhysicalName().getString()));
            if (viewType == ViewType.MAPPED) {
                columns = Maps.newLinkedHashMap();
                pkColumns = newLinkedHashSetWithExpectedSize(colDefs.size());
            } else {
                // Propagate property values to VIEW.
                // TODO: formalize the known set of these properties
                // Manually transfer the ROW_KEY_ORDER_OPTIMIZABLE_BYTES from parent as we don't
                // want to add this hacky flag to the schema (see PHOENIX-2067).
                rowKeyOrderOptimizable = parent.rowKeyOrderOptimizable();
                if (rowKeyOrderOptimizable) {
                    UpgradeUtil.addRowKeyOrderOptimizableCell(tableMetaData, SchemaUtil.getTableKey(tenantIdStr, schemaName, tableName), clientTimeStamp);
                }
                multiTenant = parent.isMultiTenant();
                saltBucketNum = parent.getBucketNum();
                isAppendOnlySchema = parent.isAppendOnlySchema();
                isImmutableRows = parent.isImmutableRows();
                if (updateCacheFrequencyProp == null) {
                    // set to the parent value if the property is not set on the view
                    updateCacheFrequency = parent.getUpdateCacheFrequency();
                }
                disableWAL = (disableWALProp == null ? parent.isWALDisabled() : disableWALProp);
                defaultFamilyName = parent.getDefaultFamilyName() == null ? null : parent.getDefaultFamilyName().getString();
                List<PColumn> allColumns = parent.getColumns();
                if (saltBucketNum != null) {
                    // Don't include salt column in columns, as it should not have it when created
                    allColumns = allColumns.subList(1, allColumns.size());
                }
                columns = new LinkedHashMap<PColumn, PColumn>(allColumns.size() + colDefs.size());
                for (PColumn column : allColumns) {
                    columns.put(column, column);
                }
                pkColumns = newLinkedHashSet(parent.getPKColumns());
                // Add row linking view to its parent
                PreparedStatement linkStatement = connection.prepareStatement(CREATE_VIEW_LINK);
                linkStatement.setString(1, tenantIdStr);
                linkStatement.setString(2, schemaName);
                linkStatement.setString(3, tableName);
                linkStatement.setString(4, parent.getName().getString());
                linkStatement.setByte(5, LinkType.PARENT_TABLE.getSerializedValue());
                linkStatement.setString(6, parent.getTenantId() == null ? null : parent.getTenantId().getString());
                linkStatement.execute();
                // Add row linking parent to view
                linkStatement = connection.prepareStatement(CREATE_CHILD_LINK);
                linkStatement.setString(1, parent.getTenantId() == null ? null : parent.getTenantId().getString());
                linkStatement.setString(2, parent.getSchemaName() == null ? null : parent.getSchemaName().getString());
                linkStatement.setString(3, parent.getTableName().getString());
                linkStatement.setString(4, tenantIdStr);
                linkStatement.setString(5, SchemaUtil.getTableName(schemaName, tableName));
                linkStatement.setByte(6, LinkType.CHILD_TABLE.getSerializedValue());
                linkStatement.execute();
            }
        } else {
            columns = new LinkedHashMap<PColumn, PColumn>(colDefs.size());
            // in case salted
            pkColumns = newLinkedHashSetWithExpectedSize(colDefs.size() + 1);
        }
        // fail because it looks like there's always a view associated with it.
        if (!physicalNames.isEmpty()) {
            // Otherwise, we end up with a self-referencing link and then cannot ever drop the view.
            if (viewType != ViewType.MAPPED || (!physicalNames.get(0).getString().equals(SchemaUtil.getTableName(schemaName, tableName)) && !physicalNames.get(0).getString().equals(SchemaUtil.getPhysicalHBaseTableName(schemaName, tableName, isNamespaceMapped).getString()))) {
                // Add row linking from data table row to physical table row
                PreparedStatement linkStatement = connection.prepareStatement(CREATE_LINK);
                for (PName physicalName : physicalNames) {
                    linkStatement.setString(1, tenantIdStr);
                    linkStatement.setString(2, schemaName);
                    linkStatement.setString(3, tableName);
                    linkStatement.setString(4, physicalName.getString());
                    linkStatement.setByte(5, LinkType.PHYSICAL_TABLE.getSerializedValue());
                    if (tableType == PTableType.VIEW) {
                        PTable physicalTable = connection.getTable(new PTableKey(null, physicalName.getString().replace(QueryConstants.NAMESPACE_SEPARATOR, QueryConstants.NAME_SEPARATOR)));
                        linkStatement.setLong(6, physicalTable.getSequenceNumber());
                        linkStatement.setString(7, null);
                    } else {
                        linkStatement.setLong(6, parent.getSequenceNumber());
                        linkStatement.setString(7, PTableType.INDEX.getSerializedValue());
                    }
                    linkStatement.execute();
                }
                tableMetaData.addAll(connection.getMutationState().toMutations(timestamp).next().getSecond());
                connection.rollback();
            }
        }
        Map<String, PName> familyNames = Maps.newLinkedHashMap();
        boolean rowTimeStampColumnAlreadyFound = false;
        int positionOffset = columns.size();
        if (saltBucketNum != null) {
            positionOffset++;
            if (addSaltColumn) {
                pkColumns.add(SaltingUtil.SALTING_COLUMN);
            }
        }
        int pkPositionOffset = pkColumns.size();
        int position = positionOffset;
        EncodedCQCounter cqCounter = NULL_COUNTER;
        PTable viewPhysicalTable = null;
        if (tableType == PTableType.VIEW) {
            /*
                 * We can't control what column qualifiers are used in HTable mapped to Phoenix views. So we are not
                 * able to encode column names.
                 */
            if (viewType != MAPPED) {
                /*
                     * For regular phoenix views, use the storage scheme of the physical table since they all share the
                     * the same HTable. Views always use the base table's column qualifier counter for doling out
                     * encoded column qualifier.
                     */
                viewPhysicalTable = PhoenixRuntime.getTable(connection, physicalNames.get(0).getString());
                immutableStorageScheme = viewPhysicalTable.getImmutableStorageScheme();
                encodingScheme = viewPhysicalTable.getEncodingScheme();
                if (EncodedColumnsUtil.usesEncodedColumnNames(viewPhysicalTable)) {
                    cqCounter = viewPhysicalTable.getEncodedCQCounter();
                }
            }
        } else // System tables have hard-coded column qualifiers. So we can't use column encoding for them.
        if (!SchemaUtil.isSystemTable(Bytes.toBytes(SchemaUtil.getTableName(schemaName, tableName)))) {
            /*
                 * Indexes inherit the storage scheme of the parent data tables. Otherwise, we always attempt to 
                 * create tables with encoded column names. 
                 * 
                 * Also of note is the case with shared indexes i.e. local indexes and view indexes. In these cases, 
                 * column qualifiers for covered columns don't have to be unique because rows of the logical indexes are 
                 * partitioned by the virtue of indexId present in the row key. As such, different shared indexes can use
                 * potentially overlapping column qualifiers.
                 * 
                 */
            if (parent != null) {
                encodingScheme = parent.getEncodingScheme();
                immutableStorageScheme = parent.getImmutableStorageScheme();
            } else {
                Byte encodingSchemeSerializedByte = (Byte) TableProperty.COLUMN_ENCODED_BYTES.getValue(tableProps);
                if (encodingSchemeSerializedByte == null) {
                    encodingSchemeSerializedByte = (byte) connection.getQueryServices().getProps().getInt(QueryServices.DEFAULT_COLUMN_ENCODED_BYTES_ATRRIB, QueryServicesOptions.DEFAULT_COLUMN_ENCODED_BYTES);
                }
                encodingScheme = QualifierEncodingScheme.fromSerializedValue(encodingSchemeSerializedByte);
                if (isImmutableRows) {
                    immutableStorageScheme = (ImmutableStorageScheme) TableProperty.IMMUTABLE_STORAGE_SCHEME.getValue(tableProps);
                    if (immutableStorageScheme == null) {
                        if (multiTenant) {
                            immutableStorageScheme = ImmutableStorageScheme.valueOf(connection.getQueryServices().getProps().get(QueryServices.DEFAULT_MULTITENANT_IMMUTABLE_STORAGE_SCHEME_ATTRIB, QueryServicesOptions.DEFAULT_MULTITENANT_IMMUTABLE_STORAGE_SCHEME));
                        } else {
                            immutableStorageScheme = ImmutableStorageScheme.valueOf(connection.getQueryServices().getProps().get(QueryServices.DEFAULT_IMMUTABLE_STORAGE_SCHEME_ATTRIB, QueryServicesOptions.DEFAULT_IMMUTABLE_STORAGE_SCHEME));
                        }
                    }
                    if (immutableStorageScheme != ONE_CELL_PER_COLUMN && encodingScheme == NON_ENCODED_QUALIFIERS) {
                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.INVALID_IMMUTABLE_STORAGE_SCHEME_AND_COLUMN_QUALIFIER_BYTES).setSchemaName(schemaName).setTableName(tableName).build().buildException();
                    }
                }
            }
            cqCounter = encodingScheme != NON_ENCODED_QUALIFIERS ? new EncodedCQCounter() : NULL_COUNTER;
        }
        Map<String, Integer> changedCqCounters = new HashMap<>(colDefs.size());
        boolean wasPKDefined = false;
        for (ColumnDef colDef : colDefs) {
            rowTimeStampColumnAlreadyFound = checkAndValidateRowTimestampCol(colDef, pkConstraint, rowTimeStampColumnAlreadyFound, tableType);
            if (colDef.isPK()) {
                // i.e. the column is declared as CREATE TABLE COLNAME DATATYPE PRIMARY KEY...
                if (wasPKDefined) {
                    throw new SQLExceptionInfo.Builder(SQLExceptionCode.PRIMARY_KEY_ALREADY_EXISTS).setColumnName(colDef.getColumnDefName().getColumnName()).build().buildException();
                }
                wasPKDefined = true;
            } else {
                // do not allow setting NOT-NULL constraint on non-primary columns.
                if (!colDef.isNull() && !isImmutableRows && (wasPKDefined || !isPkColumn(pkConstraint, colDef))) {
                    throw new SQLExceptionInfo.Builder(SQLExceptionCode.KEY_VALUE_NOT_NULL).setSchemaName(schemaName).setTableName(tableName).setColumnName(colDef.getColumnDefName().getColumnName()).build().buildException();
                }
            }
            ColumnName columnDefName = colDef.getColumnDefName();
            String colDefFamily = columnDefName.getFamilyName();
            boolean isPkColumn = isPkColumn(pkConstraint, colDef);
            String cqCounterFamily = null;
            if (!isPkColumn) {
                if (immutableStorageScheme == SINGLE_CELL_ARRAY_WITH_OFFSETS && encodingScheme != NON_ENCODED_QUALIFIERS) {
                    // For this scheme we track column qualifier counters at the column family level.
                    cqCounterFamily = colDefFamily != null ? colDefFamily : (defaultFamilyName != null ? defaultFamilyName : DEFAULT_COLUMN_FAMILY);
                } else {
                    // For other schemes, column qualifier counters are tracked using the default column family.
                    cqCounterFamily = defaultFamilyName != null ? defaultFamilyName : DEFAULT_COLUMN_FAMILY;
                }
            }
            Integer encodedCQ = isPkColumn ? null : cqCounter.getNextQualifier(cqCounterFamily);
            byte[] columnQualifierBytes = null;
            try {
                columnQualifierBytes = EncodedColumnsUtil.getColumnQualifierBytes(columnDefName.getColumnName(), encodedCQ, encodingScheme, isPkColumn);
            } catch (QualifierOutOfRangeException e) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.MAX_COLUMNS_EXCEEDED).setSchemaName(schemaName).setTableName(tableName).build().buildException();
            }
            PColumn column = newColumn(position++, colDef, pkConstraint, defaultFamilyName, false, columnQualifierBytes, isImmutableRows);
            if (cqCounter.increment(cqCounterFamily)) {
                changedCqCounters.put(cqCounterFamily, cqCounter.getNextQualifier(cqCounterFamily));
            }
            if (SchemaUtil.isPKColumn(column)) {
                // TODO: remove this constraint?
                if (pkColumnsIterator.hasNext() && !column.getName().getString().equals(pkColumnsIterator.next().getFirst().getColumnName())) {
                    throw new SQLExceptionInfo.Builder(SQLExceptionCode.PRIMARY_KEY_OUT_OF_ORDER).setSchemaName(schemaName).setTableName(tableName).setColumnName(column.getName().getString()).build().buildException();
                }
                if (tableType == PTableType.VIEW && viewType != ViewType.MAPPED) {
                    throwIfLastPKOfParentIsFixedLength(parent, schemaName, tableName, colDef);
                }
                if (!pkColumns.add(column)) {
                    throw new ColumnAlreadyExistsException(schemaName, tableName, column.getName().getString());
                }
            }
            if (columns.put(column, column) != null) {
                throw new ColumnAlreadyExistsException(schemaName, tableName, column.getName().getString());
            }
            if ((colDef.getDataType() == PVarbinary.INSTANCE || colDef.getDataType().isArrayType()) && SchemaUtil.isPKColumn(column) && pkColumnsIterator.hasNext()) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.VARBINARY_IN_ROW_KEY).setSchemaName(schemaName).setTableName(tableName).setColumnName(column.getName().getString()).build().buildException();
            }
            if (column.getFamilyName() != null) {
                familyNames.put(IndexUtil.getActualColumnFamilyName(column.getFamilyName().getString()), column.getFamilyName());
            }
        }
        // We need a PK definition for a TABLE or mapped VIEW
        if (!wasPKDefined && pkColumnsNames.isEmpty() && tableType != PTableType.VIEW && viewType != ViewType.MAPPED) {
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.PRIMARY_KEY_MISSING).setSchemaName(schemaName).setTableName(tableName).build().buildException();
        }
        if (!pkColumnsNames.isEmpty() && pkColumnsNames.size() != pkColumns.size() - pkPositionOffset) {
            // Then a column name in the primary key constraint wasn't resolved
            Iterator<Pair<ColumnName, SortOrder>> pkColumnNamesIterator = pkColumnsNames.iterator();
            while (pkColumnNamesIterator.hasNext()) {
                ColumnName colName = pkColumnNamesIterator.next().getFirst();
                ColumnDef colDef = findColumnDefOrNull(colDefs, colName);
                if (colDef == null) {
                    throw new ColumnNotFoundException(schemaName, tableName, null, colName.getColumnName());
                }
                if (colDef.getColumnDefName().getFamilyName() != null) {
                    throw new SQLExceptionInfo.Builder(SQLExceptionCode.PRIMARY_KEY_WITH_FAMILY_NAME).setSchemaName(schemaName).setTableName(tableName).setColumnName(colDef.getColumnDefName().getColumnName()).setFamilyName(colDef.getColumnDefName().getFamilyName()).build().buildException();
                }
            }
            // The above should actually find the specific one, but just in case...
            throw new SQLExceptionInfo.Builder(SQLExceptionCode.INVALID_PRIMARY_KEY_CONSTRAINT).setSchemaName(schemaName).setTableName(tableName).build().buildException();
        }
        List<Pair<byte[], Map<String, Object>>> familyPropList = Lists.newArrayListWithExpectedSize(familyNames.size());
        if (!statement.getProps().isEmpty()) {
            for (String familyName : statement.getProps().keySet()) {
                if (!familyName.equals(QueryConstants.ALL_FAMILY_PROPERTIES_KEY)) {
                    if (familyNames.get(familyName) == null) {
                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.PROPERTIES_FOR_FAMILY).setFamilyName(familyName).build().buildException();
                    } else if (statement.getTableType() == PTableType.VIEW) {
                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.VIEW_WITH_PROPERTIES).build().buildException();
                    }
                }
            }
        }
        throwIfInsufficientColumns(schemaName, tableName, pkColumns, saltBucketNum != null, multiTenant);
        for (PName familyName : familyNames.values()) {
            String fam = familyName.getString();
            Collection<Pair<String, Object>> props = statement.getProps().get(IndexUtil.getActualColumnFamilyName(fam));
            if (props.isEmpty()) {
                familyPropList.add(new Pair<byte[], Map<String, Object>>(familyName.getBytes(), commonFamilyProps));
            } else {
                Map<String, Object> combinedFamilyProps = Maps.newHashMapWithExpectedSize(props.size() + commonFamilyProps.size());
                combinedFamilyProps.putAll(commonFamilyProps);
                for (Pair<String, Object> prop : props) {
                    // i.e. it can't be column family specific.
                    if (!familyName.equals(QueryConstants.ALL_FAMILY_PROPERTIES_KEY) && prop.getFirst().equals(TTL)) {
                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.COLUMN_FAMILY_NOT_ALLOWED_FOR_TTL).build().buildException();
                    }
                    combinedFamilyProps.put(prop.getFirst(), prop.getSecond());
                }
                familyPropList.add(new Pair<byte[], Map<String, Object>>(familyName.getBytes(), combinedFamilyProps));
            }
        }
        if (familyNames.isEmpty()) {
            // if there are no family names, use the default column family name. This also takes care of the case when
            // the table ddl has only PK cols present (which means familyNames is empty).
            byte[] cf = defaultFamilyName == null ? (!isLocalIndex ? QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES : QueryConstants.DEFAULT_LOCAL_INDEX_COLUMN_FAMILY_BYTES) : Bytes.toBytes(defaultFamilyName);
            familyPropList.add(new Pair<byte[], Map<String, Object>>(cf, commonFamilyProps));
        }
        // Bootstrapping for our SYSTEM.TABLE that creates itself before it exists
        if (SchemaUtil.isMetaTable(schemaName, tableName)) {
            // TODO: what about stats for system catalog?
            PName newSchemaName = PNameFactory.newName(schemaName);
            // Column names and qualifiers and hardcoded for system tables.
            PTable table = PTableImpl.makePTable(tenantId, newSchemaName, PNameFactory.newName(tableName), tableType, null, MetaDataProtocol.MIN_TABLE_TIMESTAMP, PTable.INITIAL_SEQ_NUM, PNameFactory.newName(QueryConstants.SYSTEM_TABLE_PK_NAME), null, columns.values(), null, null, Collections.<PTable>emptyList(), isImmutableRows, Collections.<PName>emptyList(), defaultFamilyName == null ? null : PNameFactory.newName(defaultFamilyName), null, Boolean.TRUE.equals(disableWAL), false, false, null, null, indexType, true, false, 0, 0L, isNamespaceMapped, autoPartitionSeq, isAppendOnlySchema, ONE_CELL_PER_COLUMN, NON_ENCODED_QUALIFIERS, PTable.EncodedCQCounter.NULL_COUNTER, true);
            connection.addTable(table, MetaDataProtocol.MIN_TABLE_TIMESTAMP);
        }
        // Update column qualifier counters
        if (EncodedColumnsUtil.usesEncodedColumnNames(encodingScheme)) {
            // Store the encoded column counter for phoenix entities that have their own hbase
            // tables i.e. base tables and indexes.
            String schemaNameToUse = tableType == VIEW ? viewPhysicalTable.getSchemaName().getString() : schemaName;
            String tableNameToUse = tableType == VIEW ? viewPhysicalTable.getTableName().getString() : tableName;
            boolean sharedIndex = tableType == PTableType.INDEX && (indexType == IndexType.LOCAL || parent.getType() == PTableType.VIEW);
            // For local indexes and indexes on views, pass on the the tenant id since all their meta-data rows have
            // tenant ids in there.
            String tenantIdToUse = connection.getTenantId() != null && sharedIndex ? connection.getTenantId().getString() : null;
            // too since we want clients to get the latest PTable of the base table.
            for (Entry<String, Integer> entry : changedCqCounters.entrySet()) {
                try (PreparedStatement linkStatement = connection.prepareStatement(UPDATE_ENCODED_COLUMN_COUNTER)) {
                    linkStatement.setString(1, tenantIdToUse);
                    linkStatement.setString(2, schemaNameToUse);
                    linkStatement.setString(3, tableNameToUse);
                    linkStatement.setString(4, entry.getKey());
                    linkStatement.setInt(5, entry.getValue());
                    linkStatement.execute();
                }
            }
            if (tableType == VIEW && !changedCqCounters.isEmpty()) {
                PreparedStatement incrementStatement = connection.prepareStatement(INCREMENT_SEQ_NUM);
                incrementStatement.setString(1, null);
                incrementStatement.setString(2, viewPhysicalTable.getSchemaName().getString());
                incrementStatement.setString(3, viewPhysicalTable.getTableName().getString());
                incrementStatement.setLong(4, viewPhysicalTable.getSequenceNumber() + 1);
                incrementStatement.execute();
            }
            if (connection.getMutationState().toMutations(timestamp).hasNext()) {
                tableMetaData.addAll(connection.getMutationState().toMutations(timestamp).next().getSecond());
                connection.rollback();
            }
        }
        short nextKeySeq = 0;
        List<Mutation> columnMetadata = Lists.newArrayListWithExpectedSize(columns.size());
        try (PreparedStatement colUpsert = connection.prepareStatement(INSERT_COLUMN_CREATE_TABLE)) {
            for (Map.Entry<PColumn, PColumn> entry : columns.entrySet()) {
                PColumn column = entry.getValue();
                final int columnPosition = column.getPosition();
                // set the autoPartition column attributes
                if (parent != null && parent.getAutoPartitionSeqName() != null && parent.getPKColumns().get(MetaDataUtil.getAutoPartitionColIndex(parent)).equals(column)) {
                    entry.setValue(column = new DelegateColumn(column) {

                        @Override
                        public byte[] getViewConstant() {
                            // will be set correctly on the server
                            return QueryConstants.EMPTY_COLUMN_VALUE_BYTES;
                        }

                        @Override
                        public boolean isViewReferenced() {
                            return true;
                        }
                    });
                } else if (isViewColumnReferenced != null) {
                    if (viewColumnConstants != null && columnPosition < viewColumnConstants.length) {
                        entry.setValue(column = new DelegateColumn(column) {

                            @Override
                            public byte[] getViewConstant() {
                                return viewColumnConstants[columnPosition];
                            }

                            @Override
                            public boolean isViewReferenced() {
                                return isViewColumnReferenced.get(columnPosition);
                            }
                        });
                    } else {
                        entry.setValue(column = new DelegateColumn(column) {

                            @Override
                            public boolean isViewReferenced() {
                                return isViewColumnReferenced.get(columnPosition);
                            }
                        });
                    }
                }
                Short keySeq = SchemaUtil.isPKColumn(column) ? ++nextKeySeq : null;
                addColumnMutation(schemaName, tableName, column, colUpsert, parentTableName, pkName, keySeq, saltBucketNum != null);
                columnMetadata.addAll(connection.getMutationState().toMutations(timestamp).next().getSecond());
                connection.rollback();
            }
        }
        // add the columns in reverse order since we reverse the list later
        Collections.reverse(columnMetadata);
        tableMetaData.addAll(columnMetadata);
        String dataTableName = parent == null || tableType == PTableType.VIEW ? null : parent.getTableName().getString();
        PIndexState indexState = parent == null || tableType == PTableType.VIEW ? null : PIndexState.BUILDING;
        PreparedStatement tableUpsert = connection.prepareStatement(CREATE_TABLE);
        tableUpsert.setString(1, tenantIdStr);
        tableUpsert.setString(2, schemaName);
        tableUpsert.setString(3, tableName);
        tableUpsert.setString(4, tableType.getSerializedValue());
        tableUpsert.setLong(5, PTable.INITIAL_SEQ_NUM);
        tableUpsert.setInt(6, position);
        if (saltBucketNum != null) {
            tableUpsert.setInt(7, saltBucketNum);
        } else {
            tableUpsert.setNull(7, Types.INTEGER);
        }
        tableUpsert.setString(8, pkName);
        tableUpsert.setString(9, dataTableName);
        tableUpsert.setString(10, indexState == null ? null : indexState.getSerializedValue());
        tableUpsert.setBoolean(11, isImmutableRows);
        tableUpsert.setString(12, defaultFamilyName);
        if (parent != null && parent.getAutoPartitionSeqName() != null && viewStatement == null) {
            // set to non-null value so that we will generate a Put that
            // will be set correctly on the server
            tableUpsert.setString(13, QueryConstants.EMPTY_COLUMN_VALUE);
        } else {
            tableUpsert.setString(13, viewStatement);
        }
        tableUpsert.setBoolean(14, disableWAL);
        tableUpsert.setBoolean(15, multiTenant);
        if (viewType == null) {
            tableUpsert.setNull(16, Types.TINYINT);
        } else {
            tableUpsert.setByte(16, viewType.getSerializedValue());
        }
        if (indexType == null) {
            tableUpsert.setNull(17, Types.TINYINT);
        } else {
            tableUpsert.setByte(17, indexType.getSerializedValue());
        }
        tableUpsert.setBoolean(18, storeNulls);
        if (parent != null && tableType == PTableType.VIEW) {
            tableUpsert.setInt(19, parent.getColumns().size());
        } else {
            tableUpsert.setInt(19, BASE_TABLE_BASE_COLUMN_COUNT);
        }
        tableUpsert.setBoolean(20, transactional);
        tableUpsert.setLong(21, updateCacheFrequency);
        tableUpsert.setBoolean(22, isNamespaceMapped);
        if (autoPartitionSeq == null) {
            tableUpsert.setNull(23, Types.VARCHAR);
        } else {
            tableUpsert.setString(23, autoPartitionSeq);
        }
        tableUpsert.setBoolean(24, isAppendOnlySchema);
        if (guidePostsWidth == null) {
            tableUpsert.setNull(25, Types.BIGINT);
        } else {
            tableUpsert.setLong(25, guidePostsWidth);
        }
        tableUpsert.setByte(26, immutableStorageScheme.getSerializedMetadataValue());
        tableUpsert.setByte(27, encodingScheme.getSerializedMetadataValue());
        if (useStatsForParallelizationProp == null) {
            tableUpsert.setNull(28, Types.BOOLEAN);
        } else {
            tableUpsert.setBoolean(28, useStatsForParallelizationProp);
        }
        tableUpsert.execute();
        if (asyncCreatedDate != null) {
            PreparedStatement setAsync = connection.prepareStatement(SET_ASYNC_CREATED_DATE);
            setAsync.setString(1, tenantIdStr);
            setAsync.setString(2, schemaName);
            setAsync.setString(3, tableName);
            setAsync.setDate(4, asyncCreatedDate);
            setAsync.execute();
        }
        tableMetaData.addAll(connection.getMutationState().toMutations(timestamp).next().getSecond());
        connection.rollback();
        /*
             * The table metadata must be in the following order:
             * 1) table header row
             * 2) ordered column rows
             * 3) parent table header row
             */
        Collections.reverse(tableMetaData);
        if (indexType != IndexType.LOCAL) {
            splits = SchemaUtil.processSplits(splits, pkColumns, saltBucketNum, connection.getQueryServices().getProps().getBoolean(QueryServices.FORCE_ROW_KEY_ORDER_ATTRIB, QueryServicesOptions.DEFAULT_FORCE_ROW_KEY_ORDER));
        }
        MetaDataMutationResult result = connection.getQueryServices().createTable(tableMetaData, viewType == ViewType.MAPPED || allocateIndexId ? physicalNames.get(0).getBytes() : null, tableType, tableProps, familyPropList, splits, isNamespaceMapped, allocateIndexId);
        MutationCode code = result.getMutationCode();
        switch(code) {
            case TABLE_ALREADY_EXISTS:
                if (result.getTable() != null) {
                    // Can happen for transactional table that already exists as HBase table
                    addTableToCache(result);
                }
                if (!statement.ifNotExists()) {
                    throw new TableAlreadyExistsException(schemaName, tableName, result.getTable());
                }
                return null;
            case PARENT_TABLE_NOT_FOUND:
                throw new TableNotFoundException(schemaName, parent.getName().getString());
            case NEWER_TABLE_FOUND:
                // it to this connection as we can't see it.
                if (!statement.ifNotExists()) {
                    throw new NewerTableAlreadyExistsException(schemaName, tableName, result.getTable());
                }
            case UNALLOWED_TABLE_MUTATION:
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_MUTATE_TABLE).setSchemaName(schemaName).setTableName(tableName).build().buildException();
            case CONCURRENT_TABLE_MUTATION:
                addTableToCache(result);
                throw new ConcurrentTableMutationException(schemaName, tableName);
            case AUTO_PARTITION_SEQUENCE_NOT_FOUND:
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.AUTO_PARTITION_SEQUENCE_UNDEFINED).setSchemaName(schemaName).setTableName(tableName).build().buildException();
            case CANNOT_COERCE_AUTO_PARTITION_ID:
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_COERCE_AUTO_PARTITION_ID).setSchemaName(schemaName).setTableName(tableName).build().buildException();
            case TOO_MANY_INDEXES:
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.TOO_MANY_INDEXES).setSchemaName(SchemaUtil.getSchemaNameFromFullName(parent.getPhysicalName().getString())).setTableName(SchemaUtil.getTableNameFromFullName(parent.getPhysicalName().getString())).build().buildException();
            default:
                // set the view statement and relevant partition column attributes correctly
                if (parent != null && parent.getAutoPartitionSeqName() != null) {
                    final PColumn autoPartitionCol = parent.getPKColumns().get(MetaDataUtil.getAutoPartitionColIndex(parent));
                    final Long autoPartitionNum = Long.valueOf(result.getAutoPartitionNum());
                    columns.put(autoPartitionCol, new DelegateColumn(autoPartitionCol) {

                        @Override
                        public byte[] getViewConstant() {
                            PDataType dataType = autoPartitionCol.getDataType();
                            Object val = dataType.toObject(autoPartitionNum, PLong.INSTANCE);
                            byte[] bytes = new byte[dataType.getByteSize() + 1];
                            dataType.toBytes(val, bytes, 0);
                            return bytes;
                        }

                        @Override
                        public boolean isViewReferenced() {
                            return true;
                        }
                    });
                    String viewPartitionClause = QueryUtil.getViewPartitionClause(MetaDataUtil.getAutoPartitionColumnName(parent), autoPartitionNum);
                    if (viewStatement != null) {
                        viewStatement = viewStatement + " AND " + viewPartitionClause;
                    } else {
                        viewStatement = QueryUtil.getViewStatement(parent.getSchemaName().getString(), parent.getTableName().getString(), viewPartitionClause);
                    }
                }
                PName newSchemaName = PNameFactory.newName(schemaName);
                /*
                 * It doesn't hurt for the PTable of views to have the cqCounter. However, views always rely on the
                 * parent table's counter to dole out encoded column qualifiers. So setting the counter as NULL_COUNTER
                 * for extra safety.
                 */
                EncodedCQCounter cqCounterToBe = tableType == PTableType.VIEW ? NULL_COUNTER : cqCounter;
                PTable table = PTableImpl.makePTable(tenantId, newSchemaName, PNameFactory.newName(tableName), tableType, indexState, timestamp != null ? timestamp : result.getMutationTime(), PTable.INITIAL_SEQ_NUM, pkName == null ? null : PNameFactory.newName(pkName), saltBucketNum, columns.values(), parent == null ? null : parent.getSchemaName(), parent == null ? null : parent.getTableName(), Collections.<PTable>emptyList(), isImmutableRows, physicalNames, defaultFamilyName == null ? null : PNameFactory.newName(defaultFamilyName), viewStatement, Boolean.TRUE.equals(disableWAL), multiTenant, storeNulls, viewType, result.getViewIndexId(), indexType, rowKeyOrderOptimizable, transactional, updateCacheFrequency, 0L, isNamespaceMapped, autoPartitionSeq, isAppendOnlySchema, immutableStorageScheme, encodingScheme, cqCounterToBe, useStatsForParallelizationProp);
                result = new MetaDataMutationResult(code, result.getMutationTime(), table, true);
                addTableToCache(result);
                return table;
        }
    } finally {
        connection.setAutoCommit(wasAutoCommit);
    }
}
Also used : LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) PDataType(org.apache.phoenix.schema.types.PDataType) SQLExceptionInfo(org.apache.phoenix.exception.SQLExceptionInfo) ColumnDef(org.apache.phoenix.parse.ColumnDef) PrimaryKeyConstraint(org.apache.phoenix.parse.PrimaryKeyConstraint) TableName(org.apache.phoenix.parse.TableName) PUnsignedLong(org.apache.phoenix.schema.types.PUnsignedLong) PLong(org.apache.phoenix.schema.types.PLong) Mutation(org.apache.hadoop.hbase.client.Mutation) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) QualifierOutOfRangeException(org.apache.phoenix.schema.PTable.QualifierEncodingScheme.QualifierOutOfRangeException) QualifierEncodingScheme(org.apache.phoenix.schema.PTable.QualifierEncodingScheme) ImmutableStorageScheme(org.apache.phoenix.schema.PTable.ImmutableStorageScheme) MetaDataMutationResult(org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult) Pair(org.apache.hadoop.hbase.util.Pair) PreparedStatement(java.sql.PreparedStatement) IndexKeyConstraint(org.apache.phoenix.parse.IndexKeyConstraint) PrimaryKeyConstraint(org.apache.phoenix.parse.PrimaryKeyConstraint) ColumnDefInPkConstraint(org.apache.phoenix.parse.ColumnDefInPkConstraint) MutationCode(org.apache.phoenix.coprocessor.MetaDataProtocol.MutationCode) HTableDescriptor(org.apache.hadoop.hbase.HTableDescriptor) PInteger(org.apache.phoenix.schema.types.PInteger) ColumnName(org.apache.phoenix.parse.ColumnName) EncodedCQCounter(org.apache.phoenix.schema.PTable.EncodedCQCounter)

Aggregations

EncodedCQCounter (org.apache.phoenix.schema.PTable.EncodedCQCounter)8 PTable (org.apache.phoenix.schema.PTable)6 ImmutableStorageScheme (org.apache.phoenix.schema.PTable.ImmutableStorageScheme)4 PInteger (org.apache.phoenix.schema.types.PInteger)4 Connection (java.sql.Connection)3 PhoenixConnection (org.apache.phoenix.jdbc.PhoenixConnection)3 BaseTest (org.apache.phoenix.query.BaseTest)3 PColumn (org.apache.phoenix.schema.PColumn)3 PName (org.apache.phoenix.schema.PName)3 QualifierEncodingScheme (org.apache.phoenix.schema.PTable.QualifierEncodingScheme)3 PTableKey (org.apache.phoenix.schema.PTableKey)3 ByteString (com.google.protobuf.ByteString)2 PreparedStatement (java.sql.PreparedStatement)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 Cell (org.apache.hadoop.hbase.Cell)2 Mutation (org.apache.hadoop.hbase.client.Mutation)2 MetaDataMutationResult (org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult)2 MutationCode (org.apache.phoenix.coprocessor.MetaDataProtocol.MutationCode)2