Search in sources :

Example 6 with MetaDataMutationResult

use of org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult in project phoenix by apache.

the class ConnectionlessQueryServicesImpl method updateIndexState.

@Override
public MetaDataMutationResult updateIndexState(List<Mutation> tableMetadata, String parentTableName) throws SQLException {
    byte[][] rowKeyMetadata = new byte[3][];
    SchemaUtil.getVarChars(tableMetadata.get(0).getRow(), rowKeyMetadata);
    Mutation m = MetaDataUtil.getTableHeaderRow(tableMetadata);
    ImmutableBytesWritable ptr = new ImmutableBytesWritable();
    if (!MetaDataUtil.getMutationValue(m, INDEX_STATE_BYTES, kvBuilder, ptr)) {
        throw new IllegalStateException();
    }
    PIndexState newState = PIndexState.fromSerializedValue(ptr.get()[ptr.getOffset()]);
    byte[] tenantIdBytes = rowKeyMetadata[PhoenixDatabaseMetaData.TENANT_ID_INDEX];
    String schemaName = Bytes.toString(rowKeyMetadata[PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX]);
    String indexName = Bytes.toString(rowKeyMetadata[PhoenixDatabaseMetaData.TABLE_NAME_INDEX]);
    String indexTableName = SchemaUtil.getTableName(schemaName, indexName);
    PName tenantId = tenantIdBytes.length == 0 ? null : PNameFactory.newName(tenantIdBytes);
    PTable index = metaData.getTableRef(new PTableKey(tenantId, indexTableName)).getTable();
    index = PTableImpl.makePTable(index, newState == PIndexState.USABLE ? PIndexState.ACTIVE : newState == PIndexState.UNUSABLE ? PIndexState.INACTIVE : newState);
    return new MetaDataMutationResult(MutationCode.TABLE_ALREADY_EXISTS, 0, index);
}
Also used : ImmutableBytesWritable(org.apache.hadoop.hbase.io.ImmutableBytesWritable) PIndexState(org.apache.phoenix.schema.PIndexState) PName(org.apache.phoenix.schema.PName) Mutation(org.apache.hadoop.hbase.client.Mutation) PTableKey(org.apache.phoenix.schema.PTableKey) MetaDataMutationResult(org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult) PTable(org.apache.phoenix.schema.PTable)

Example 7 with MetaDataMutationResult

use of org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult in project phoenix by apache.

the class ConnectionlessQueryServicesImpl method getFunctions.

@Override
public MetaDataMutationResult getFunctions(PName tenantId, List<Pair<byte[], Long>> functionNameAndTimeStampPairs, long clientTimestamp) throws SQLException {
    List<PFunction> functions = new ArrayList<PFunction>(functionNameAndTimeStampPairs.size());
    for (Pair<byte[], Long> functionInfo : functionNameAndTimeStampPairs) {
        try {
            PFunction function2 = metaData.getFunction(new PTableKey(tenantId, Bytes.toString(functionInfo.getFirst())));
            functions.add(function2);
        } catch (FunctionNotFoundException e) {
            return new MetaDataMutationResult(MutationCode.FUNCTION_NOT_FOUND, 0, null);
        }
    }
    if (functions.isEmpty()) {
        return null;
    }
    return new MetaDataMutationResult(MutationCode.FUNCTION_ALREADY_EXISTS, 0, functions, true);
}
Also used : FunctionNotFoundException(org.apache.phoenix.schema.FunctionNotFoundException) PFunction(org.apache.phoenix.parse.PFunction) ArrayList(java.util.ArrayList) PTableKey(org.apache.phoenix.schema.PTableKey) MetaDataMutationResult(org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult)

Example 8 with MetaDataMutationResult

use of org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult in project phoenix by apache.

the class ConnectionQueryServicesImpl method dropFunction.

@Override
public MetaDataMutationResult dropFunction(final List<Mutation> functionData, final boolean ifExists) throws SQLException {
    byte[][] rowKeyMetadata = new byte[2][];
    byte[] key = functionData.get(0).getRow();
    SchemaUtil.getVarChars(key, rowKeyMetadata);
    byte[] tenantIdBytes = rowKeyMetadata[PhoenixDatabaseMetaData.TENANT_ID_INDEX];
    byte[] functionBytes = rowKeyMetadata[PhoenixDatabaseMetaData.FUNTION_NAME_INDEX];
    byte[] functionKey = SchemaUtil.getFunctionKey(tenantIdBytes, functionBytes);
    final MetaDataMutationResult result = metaDataCoprocessorExec(functionKey, new Batch.Call<MetaDataService, MetaDataResponse>() {

        @Override
        public MetaDataResponse call(MetaDataService instance) throws IOException {
            ServerRpcController controller = new ServerRpcController();
            BlockingRpcCallback<MetaDataResponse> rpcCallback = new BlockingRpcCallback<MetaDataResponse>();
            DropFunctionRequest.Builder builder = DropFunctionRequest.newBuilder();
            for (Mutation m : functionData) {
                MutationProto mp = ProtobufUtil.toProto(m);
                builder.addTableMetadataMutations(mp.toByteString());
            }
            builder.setIfExists(ifExists);
            builder.setClientVersion(VersionUtil.encodeVersion(PHOENIX_MAJOR_VERSION, PHOENIX_MINOR_VERSION, PHOENIX_PATCH_NUMBER));
            instance.dropFunction(controller, builder.build(), rpcCallback);
            if (controller.getFailedOn() != null) {
                throw controller.getFailedOn();
            }
            return rpcCallback.get();
        }
    }, PhoenixDatabaseMetaData.SYSTEM_FUNCTION_NAME_BYTES);
    return result;
}
Also used : MetaDataResponse(org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse) KeyValueBuilder(org.apache.phoenix.hbase.index.util.KeyValueBuilder) NonTxIndexBuilder(org.apache.phoenix.hbase.index.covered.NonTxIndexBuilder) ThreadFactoryBuilder(com.google.common.util.concurrent.ThreadFactoryBuilder) PhoenixIndexBuilder(org.apache.phoenix.index.PhoenixIndexBuilder) IOException(java.io.IOException) PhoenixIOException(org.apache.phoenix.exception.PhoenixIOException) ServerRpcController(org.apache.hadoop.hbase.ipc.ServerRpcController) MutationProto(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto) MetaDataService(org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataService) Batch(org.apache.hadoop.hbase.client.coprocessor.Batch) BlockingRpcCallback(org.apache.hadoop.hbase.ipc.BlockingRpcCallback) Mutation(org.apache.hadoop.hbase.client.Mutation) MetaDataMutationResult(org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult)

Example 9 with MetaDataMutationResult

use of org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult in project phoenix by apache.

the class PhoenixRuntime method getTable.

/**
     * 
     * @param conn
     * @param name requires a pre-normalized table name or a pre-normalized schema and table name
     * @return
     * @throws SQLException
     */
public static PTable getTable(Connection conn, String name) throws SQLException {
    PTable table = null;
    PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
    try {
        table = pconn.getTable(new PTableKey(pconn.getTenantId(), name));
    } catch (TableNotFoundException e) {
        String schemaName = SchemaUtil.getSchemaNameFromFullName(name);
        String tableName = SchemaUtil.getTableNameFromFullName(name);
        MetaDataMutationResult result = new MetaDataClient(pconn).updateCache(schemaName, tableName);
        if (result.getMutationCode() != MutationCode.TABLE_ALREADY_EXISTS) {
            throw e;
        }
        table = result.getTable();
    }
    return table;
}
Also used : MetaDataClient(org.apache.phoenix.schema.MetaDataClient) TableNotFoundException(org.apache.phoenix.schema.TableNotFoundException) PhoenixConnection(org.apache.phoenix.jdbc.PhoenixConnection) PTableKey(org.apache.phoenix.schema.PTableKey) MetaDataMutationResult(org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult) PTable(org.apache.phoenix.schema.PTable)

Example 10 with MetaDataMutationResult

use of org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult 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 = Iterators.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);
        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(TxConstants.PROPERTY_TTL, ttl);
            }
        }
        boolean useStatsForParallelization = true;
        Boolean useStatsForParallelizationProp = (Boolean) TableProperty.USE_STATS_FOR_PARALLELIZATION.getValue(tableProps);
        if (useStatsForParallelizationProp != null) {
            useStatsForParallelization = useStatsForParallelizationProp;
        } else {
            useStatsForParallelization = connection.getQueryServices().getProps().getBoolean(QueryServices.USE_STATS_FOR_PARALLELIZATION, QueryServicesOptions.DEFAULT_USE_STATS_FOR_PARALLELIZATION);
        }
        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))) {
                // 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 isPK = false;
        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 the hbase table already exists, then possibly encoded or non-encoded column qualifiers were used. 
                 * In this case we pursue ahead with non-encoded column qualifier scheme. If the phoenix metadata for this table already exists 
                 * then we rely on the PTable, with appropriate storage scheme, returned in the MetadataMutationResult to be updated 
                 * in the client cache. If the phoenix table metadata already doesn't exist then the non-encoded column qualifier scheme works
                 * because we cannot control the column qualifiers that were used when populating the hbase table.
                 */
            byte[] tableNameBytes = SchemaUtil.getTableNameAsBytes(schemaName, tableName);
            boolean tableExists = true;
            try {
                HTableDescriptor tableDescriptor = connection.getQueryServices().getTableDescriptor(tableNameBytes);
                if (tableDescriptor == null) {
                    // for connectionless
                    tableExists = false;
                }
            } catch (org.apache.phoenix.schema.TableNotFoundException e) {
                tableExists = false;
            }
            if (tableExists) {
                encodingScheme = NON_ENCODED_QUALIFIERS;
                immutableStorageScheme = ONE_CELL_PER_COLUMN;
            } else 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());
        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 (isPK) {
                    throw new SQLExceptionInfo.Builder(SQLExceptionCode.PRIMARY_KEY_ALREADY_EXISTS).setColumnName(colDef.getColumnDefName().getColumnName()).build().buildException();
                }
                isPK = true;
            } else {
                // do not allow setting NOT-NULL constraint on non-primary columns.
                if (Boolean.FALSE.equals(colDef.isNull()) && (isPK || (pkConstraint != null && !pkConstraint.contains(colDef.getColumnDefName())))) {
                    throw new SQLExceptionInfo.Builder(SQLExceptionCode.INVALID_NOT_NULL_CONSTRAINT).setSchemaName(schemaName).setTableName(tableName).setColumnName(colDef.getColumnDefName().getColumnName()).build().buildException();
                }
            }
            ColumnName columnDefName = colDef.getColumnDefName();
            String colDefFamily = columnDefName.getFamilyName();
            boolean isPkColumn = isPkColumn(pkConstraint, colDef, columnDefName);
            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);
            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 (!isPK && 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());
        tableUpsert.setBoolean(28, useStatsForParallelization);
        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, useStatsForParallelization);
                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

MetaDataMutationResult (org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult)36 Mutation (org.apache.hadoop.hbase.client.Mutation)20 MutationCode (org.apache.phoenix.coprocessor.MetaDataProtocol.MutationCode)15 PLong (org.apache.phoenix.schema.types.PLong)11 MutationState (org.apache.phoenix.execute.MutationState)10 PTable (org.apache.phoenix.schema.PTable)10 PUnsignedLong (org.apache.phoenix.schema.types.PUnsignedLong)9 IOException (java.io.IOException)8 BlockingRpcCallback (org.apache.hadoop.hbase.ipc.BlockingRpcCallback)8 ServerRpcController (org.apache.hadoop.hbase.ipc.ServerRpcController)8 MutationProto (org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto)8 MetaDataResponse (org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse)8 MetaDataService (org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataService)8 SQLExceptionInfo (org.apache.phoenix.exception.SQLExceptionInfo)8 PhoenixIndexBuilder (org.apache.phoenix.index.PhoenixIndexBuilder)8 TableNotFoundException (org.apache.phoenix.schema.TableNotFoundException)8 ThreadFactoryBuilder (com.google.common.util.concurrent.ThreadFactoryBuilder)7 ArrayList (java.util.ArrayList)7 HashMap (java.util.HashMap)7 Batch (org.apache.hadoop.hbase.client.coprocessor.Batch)7