private Builder initDerivedAttributes()

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