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;
}