in phoenix-core-client/src/main/java/org/apache/phoenix/schema/PTableImpl.java [736:936]
private Builder initDerivedAttributes() throws SQLException {
checkTenantId(this.tenantId);
Preconditions.checkNotNull(this.schemaName);
Preconditions.checkNotNull(this.tableName);
Preconditions.checkNotNull(this.columns);
Preconditions.checkNotNull(this.indexes);
Preconditions.checkNotNull(this.physicalNames);
//hasColumnsRequiringUpgrade and rowKeyOrderOptimizable are booleans and can never be
// null, so no need to check them
PName fullName = PNameFactory.newName(SchemaUtil.getTableName(
this.schemaName.getString(), this.tableName.getString()));
int estimatedSize = SizedUtil.OBJECT_SIZE * 2 + 23 * SizedUtil.POINTER_SIZE +
4 * SizedUtil.INT_SIZE + 2 * SizedUtil.LONG_SIZE + 2 * SizedUtil.INT_OBJECT_SIZE +
PNameFactory.getEstimatedSize(this.tenantId) +
PNameFactory.getEstimatedSize(this.schemaName) +
PNameFactory.getEstimatedSize(this.tableName) +
PNameFactory.getEstimatedSize(this.pkName) +
PNameFactory.getEstimatedSize(this.parentTableName) +
PNameFactory.getEstimatedSize(this.defaultFamilyName);
int numPKColumns = 0;
List<PColumn> pkColumns;
PColumn[] allColumns;
if (this.bucketNum != null) {
// Add salt column to allColumns and pkColumns, but don't add to
// columnsByName, since it should not be addressable via name.
allColumns = new PColumn[this.columns.size()+1];
allColumns[SALTING_COLUMN.getPosition()] = SALTING_COLUMN;
pkColumns = Lists.newArrayListWithExpectedSize(this.columns.size()+1);
++numPKColumns;
} else {
allColumns = new PColumn[this.columns.size()];
pkColumns = Lists.newArrayListWithExpectedSize(this.columns.size());
}
// Must do this as with the new method of storing diffs, we just care about
// ordinal position relative order and not the true ordinal value itself.
List<PColumn> sortedColumns = Lists.newArrayList(this.columns);
Collections.sort(sortedColumns, new Comparator<PColumn>() {
@Override
public int compare(PColumn o1, PColumn o2) {
return Integer.compare(o1.getPosition(), o2.getPosition());
}
});
// With the new uncovered index code, we pass the data table columns to the index
// PTable. This wreaks havoc with the code used disambiguate column qualifiers.
// localColumns only holds the actual columns of the table, and not external references
List<PColumn> localColumns = new ArrayList<>(this.columns.size());
//TODO should we just pass the global indexref columns separately instead ?
for (PColumn column : sortedColumns) {
if (!(column instanceof ProjectedColumn && ((ProjectedColumn) column)
.getSourceColumnRef() instanceof IndexUncoveredDataColumnRef)) {
localColumns.add(column);
}
}
int position = 0;
if (this.bucketNum != null) {
position = 1;
}
ListMultimap<String, PColumn> populateColumnsByName =
ArrayListMultimap.create(this.columns.size(), 1);
for (PColumn column : sortedColumns) {
allColumns[position] = column;
position++;
PName familyName = column.getFamilyName();
if (familyName == null) {
++numPKColumns;
}
String columnName = column.getName().getString();
if (populateColumnsByName.put(columnName, column)) {
int count = 0;
for (PColumn dupColumn : populateColumnsByName.get(columnName)) {
if (Objects.equal(familyName, dupColumn.getFamilyName())) {
count++;
if (count > 1) {
throw new ColumnAlreadyExistsException(this.schemaName.getString(),
fullName.getString(), columnName);
}
}
}
}
}
Map<KVColumnFamilyQualifier, PColumn> populateKvColumnsByQualifiers =
Maps.newHashMapWithExpectedSize(localColumns.size());
for (PColumn column : localColumns) {
byte[] cq = column.getColumnQualifierBytes();
String cf = column.getFamilyName() != null ?
column.getFamilyName().getString() : null;
if (cf != null && cq != null) {
KVColumnFamilyQualifier info = new KVColumnFamilyQualifier(cf, cq);
if (populateKvColumnsByQualifiers.get(info) != null) {
throw new ColumnAlreadyExistsException(this.schemaName.getString(),
fullName.getString(), column.getName().getString());
}
populateKvColumnsByQualifiers.put(info, column);
}
}
estimatedSize += SizedUtil.sizeOfMap(allColumns.length, SizedUtil.POINTER_SIZE,
SizedUtil.sizeOfArrayList(1)); // for multi-map
estimatedSize += SizedUtil.sizeOfMap(numPKColumns) +
SizedUtil.sizeOfMap(allColumns.length);
RowKeySchemaBuilder builder = new RowKeySchemaBuilder(numPKColumns);
// Two pass so that column order in column families matches overall column order
// and to ensure that column family order is constant
int maxExpectedSize = allColumns.length - numPKColumns;
// Maintain iteration order so that column families are ordered as they are listed
Map<PName, List<PColumn>> familyMap = Maps.newLinkedHashMap();
PColumn rowTimestampCol = null;
boolean hasColsRequiringUpgrade = false;
for (PColumn column : allColumns) {
PName familyName = column.getFamilyName();
if (familyName == null) {
hasColsRequiringUpgrade |=
(column.getSortOrder() == SortOrder.DESC
&& (!column.getDataType().isFixedWidth()
|| column.getDataType() == PChar.INSTANCE
|| column.getDataType() == PFloat.INSTANCE
|| column.getDataType() == PDouble.INSTANCE
|| column.getDataType() == PBinary.INSTANCE) )
|| (column.getSortOrder() == SortOrder.ASC
&& column.getDataType() == PBinary.INSTANCE
&& column.getMaxLength() != null
&& column.getMaxLength() > 1);
pkColumns.add(column);
if (column.isRowTimestamp()) {
rowTimestampCol = column;
}
estimatedSize += column.getEstimatedSize(); // PK columns
builder.addField(column, column.isNullable(), column.getSortOrder());
}
}
for (PColumn column : localColumns) {
PName familyName = column.getFamilyName();
if (familyName != null) {
List<PColumn> columnsInFamily = familyMap.get(familyName);
if (columnsInFamily == null) {
columnsInFamily = Lists.newArrayListWithExpectedSize(maxExpectedSize);
familyMap.put(familyName, columnsInFamily);
}
columnsInFamily.add(column);
}
}
int rowTimestampColPos;
if (rowTimestampCol != null) {
rowTimestampColPos = pkColumns.indexOf(rowTimestampCol);
} else {
rowTimestampColPos = -1;
}
Iterator<Map.Entry<PName,List<PColumn>>> iterator = familyMap.entrySet().iterator();
PColumnFamily[] families = new PColumnFamily[familyMap.size()];
ImmutableMap.Builder<String, PColumnFamily> familyByString = ImmutableMap.builder();
ImmutableSortedMap.Builder<byte[], PColumnFamily> familyByBytes = ImmutableSortedMap
.orderedBy(Bytes.BYTES_COMPARATOR);
for (int i = 0; i < families.length; i++) {
Map.Entry<PName,List<PColumn>> entry = iterator.next();
PColumnFamily family = new PColumnFamilyImpl(entry.getKey(), entry.getValue());
families[i] = family;
familyByString.put(family.getName().getString(), family);
familyByBytes.put(family.getName().getBytes(), family);
estimatedSize += family.getEstimatedSize();
}
estimatedSize += SizedUtil.sizeOfArrayList(families.length);
estimatedSize += SizedUtil.sizeOfMap(families.length) * 2;
for (PTable index : this.indexes) {
estimatedSize += index.getEstimatedSize();
}
if (transformingNewTable!=null) {
estimatedSize += transformingNewTable.getEstimatedSize();
}
estimatedSize += PNameFactory.getEstimatedSize(this.parentName);
for (PName physicalName : this.physicalNames) {
estimatedSize += physicalName.getEstimatedSize();
}
// Populate the derived fields and return the builder
return this.setName(fullName)
.setKey(new PTableKey(this.tenantId, fullName.getString()))
.setParentName(this.parentTableName == null ? null :
PNameFactory.newName(SchemaUtil.getTableName(
this.parentSchemaName != null ?
this.parentSchemaName.getString() : null,
this.parentTableName.getString())))
.setColumnsByName(populateColumnsByName)
.setKvColumnsByQualifiers(populateKvColumnsByQualifiers)
.setAllColumns(ImmutableList.copyOf(allColumns))
.setHasColumnsRequiringUpgrade(hasColsRequiringUpgrade
| this.hasColumnsRequiringUpgrade)
.setPkColumns(ImmutableList.copyOf(pkColumns))
.setRowTimestampColPos(rowTimestampColPos)
// after hasDescVarLengthColumns is calculated
.setRowKeySchema(builder.rowKeyOrderOptimizable(
this.rowKeyOrderOptimizable || !this.hasColumnsRequiringUpgrade)
.build())
.setFamilies(ImmutableList.copyOf(families))
.setFamilyByBytes(familyByBytes.build())
.setFamilyByString(familyByString.build())
.setEstimatedSize(estimatedSize + this.rowKeySchema.getEstimatedSize());
}