public static PTable addDerivedColumnsFromParent()

in phoenix-core-client/src/main/java/org/apache/phoenix/util/ViewUtil.java [698:865]


    public static PTable addDerivedColumnsFromParent(PhoenixConnection connection,
        PTable view, PTable parentTable,
        boolean recalculateBaseColumnCount)
            throws SQLException {
        // combine columns for view and view indexes
        boolean hasIndexId = view.getViewIndexId() != null;
        boolean isSalted = view.getBucketNum() != null;
        boolean isDiverged = isDivergedView(view);
        boolean isDivergedViewCreatedPre4_15 = isDiverged;
        List<PColumn> allColumns = Lists.newArrayList();
        List<PColumn> excludedColumns = Lists.newArrayList();
        // add my own columns first in reverse order
        List<PColumn> myColumns = view.getColumns();
        // skip salted column as it will be created automatically
        myColumns = myColumns.subList(isSalted ? 1 : 0, myColumns.size());
        for (int i = myColumns.size() - 1; i >= 0; i--) {
            PColumn pColumn = myColumns.get(i);
            if (pColumn.isExcluded()) {
                // Diverged views created pre-4.15 will not have EXCLUDED_COLUMN linking rows
                isDivergedViewCreatedPre4_15 = false;
                excludedColumns.add(pColumn);
            }
            allColumns.add(pColumn);
        }

        // initialize map from with indexed expression to list of required data columns
        // then remove the data columns that have not been dropped, so that we get the columns that
        // have been dropped
        Map<PColumn, List<String>> indexRequiredDroppedDataColMap =
                Maps.newHashMapWithExpectedSize(view.getColumns().size());
        if (hasIndexId) {
            int indexPosOffset = (isSalted ? 1 : 0) + (view.isMultiTenant() ? 1 : 0) + 1;
            ColumnNameTrackingExpressionCompiler expressionCompiler =
                    new ColumnNameTrackingExpressionCompiler();
            for (int i = indexPosOffset; i < view.getPKColumns().size(); i++) {
                PColumn indexColumn = view.getPKColumns().get(i);
                try {
                    expressionCompiler.reset();
                    String expressionStr = IndexUtil.getIndexColumnExpressionStr(indexColumn);
                    ParseNode parseNode = SQLParser.parseCondition(expressionStr);
                    parseNode.accept(expressionCompiler);
                    indexRequiredDroppedDataColMap.put(indexColumn,
                            Lists.newArrayList(expressionCompiler.getDataColumnNames()));
                } catch (SQLException e) {
                    throw new RuntimeException(e); // Impossible
                }
            }
        }

        long maxTableTimestamp = view.getTimeStamp();
        long maxDDLTimestamp = view.getLastDDLTimestamp() != null ? view.getLastDDLTimestamp() : 0L;
        int numPKCols = view.getPKColumns().size();
        // set the final table timestamp and DDL timestamp as the respective max timestamps of the
        // view/view index or its ancestors
        maxTableTimestamp = Math.max(maxTableTimestamp, parentTable.getTimeStamp());
        //Diverged views no longer inherit ddl timestamps from their ancestors because they don't
        // inherit column changes
        maxDDLTimestamp = Math.max(maxDDLTimestamp,
            parentTable.getLastDDLTimestamp() != null ? parentTable.getLastDDLTimestamp() : 0L);

        if (hasIndexId) {
            // add all pk columns of parent tables to indexes
            // skip salted column as it will be added from the base table columns
            int startIndex = parentTable.getBucketNum() != null ? 1 : 0;
            for (int index=startIndex; index<parentTable.getPKColumns().size(); index++) {
                PColumn pkColumn = parentTable.getPKColumns().get(index);
                // don't add the salt column of ancestor tables for view indexes, or deleted columns
                // or constant columns from the view where statement
                if (pkColumn.equals(SaltingUtil.SALTING_COLUMN) || pkColumn.isExcluded()
                        || pkColumn.getViewConstant()!=null) {
                    continue;
                }
                pkColumn = IndexUtil.getIndexPKColumn(++numPKCols, pkColumn);
                int existingColumnIndex = allColumns.indexOf(pkColumn);
                if (existingColumnIndex == -1) {
                    allColumns.add(0, pkColumn);
                }
            }
            for (int j = 0; j < parentTable.getColumns().size(); j++) {
                PColumn tableColumn = parentTable.getColumns().get(j);
                if (tableColumn.isExcluded()) {
                    continue;
                }
                String dataColumnName = tableColumn.getName().getString();
                // remove from list of columns since it has not been dropped
                for (Map.Entry<PColumn, List<String>> entry : indexRequiredDroppedDataColMap
                        .entrySet()) {
                    entry.getValue().remove(dataColumnName);
                }
            }
        } else if (!isDivergedViewCreatedPre4_15) {
            // For diverged views created by a pre-4.15 client, we don't need to inherit columns
            // from its ancestors
            inheritColumnsFromParent(view, parentTable, isDiverged, excludedColumns, allColumns);
        }
        // at this point indexRequiredDroppedDataColMap only contain the columns required by a view
        // index that have dropped
        for (Map.Entry<PColumn, List<String>> entry : indexRequiredDroppedDataColMap.entrySet()) {
            if (!entry.getValue().isEmpty()) {
                PColumn indexColumnToBeDropped = entry.getKey();
                if (SchemaUtil.isPKColumn(indexColumnToBeDropped)) {
                    // if an indexed column was dropped in an ancestor then we
                    // cannot use this index an more
                    // TODO figure out a way to actually drop this view index
                    return null;
                } else {
                    allColumns.remove(indexColumnToBeDropped);
                }
            }
        }

        List<PColumn> columnsToAdd = Lists.newArrayList();
        int position = isSalted ? 1 : 0;
        // allColumns contains the columns in the reverse order
        for (int i = allColumns.size() - 1; i >= 0; i--) {
            PColumn column = allColumns.get(i);
            if (view.getColumns().contains(column)) {
                // for views this column is not derived from an ancestor
                columnsToAdd.add(new PColumnImpl(column, position++));
            } else {
                columnsToAdd.add(new PColumnImpl(column, true, position++));
            }
        }
        // we need to include the salt column when setting the base table column count in order to
        // maintain b/w compatibility
        int baseTableColumnCount = view.getBaseColumnCount();
        if (recalculateBaseColumnCount) {
            baseTableColumnCount = isDiverged ?
                QueryConstants.DIVERGED_VIEW_BASE_COLUMN_COUNT :
                columnsToAdd.size() - myColumns.size() + (isSalted ? 1 : 0);
        }
        // Inherit view-modifiable properties from the parent table/view if the current view has
        // not previously modified this property
        long updateCacheFreq = (view.getType() != PTableType.VIEW ||
                view.hasViewModifiedUpdateCacheFrequency()) ?
                view.getUpdateCacheFrequency() : parentTable.getUpdateCacheFrequency();
        Boolean useStatsForParallelization = (view.getType() != PTableType.VIEW ||
                view.hasViewModifiedUseStatsForParallelization()) ?
                view.useStatsForParallelization() : parentTable.useStatsForParallelization();

        // When creating a PTable for views or view indexes, use the baseTable PTable for attributes
        // inherited from the physical base table.
        // if a TableProperty is not valid on a view we set it to the base table value
        // if a TableProperty is valid on a view and is not mutable on a view we set it to the base
        // table value
        // if a TableProperty is valid on a view and is mutable on a view, we use the value set
        // on the view if the view had previously modified the property, otherwise we propagate the
        // value from the base table (see PHOENIX-4763)
        PTable pTable = PTableImpl.builderWithColumns(view, columnsToAdd)
                .setImmutableRows(parentTable.isImmutableRows())
                .setDisableWAL(parentTable.isWALDisabled())
                .setMultiTenant(parentTable.isMultiTenant())
                .setStoreNulls(parentTable.getStoreNulls())
                .setTransactionProvider(parentTable.getTransactionProvider())
                .setAutoPartitionSeqName(parentTable.getAutoPartitionSeqName())
                .setAppendOnlySchema(parentTable.isAppendOnlySchema())
                .setBaseColumnCount(baseTableColumnCount)
                .setBaseTableLogicalName(parentTable.getBaseTableLogicalName())
                .setTimeStamp(maxTableTimestamp)
                .setExcludedColumns(ImmutableList.copyOf(excludedColumns))
                .setUpdateCacheFrequency(updateCacheFreq)
                .setUseStatsForParallelization(useStatsForParallelization)
                .setLastDDLTimestamp(maxDDLTimestamp)
                .build();
        pTable = WhereConstantParser.addViewInfoToPColumnsIfNeeded(pTable);

        return pTable;
    }