private IndexMaintainer()

in phoenix-core-client/src/main/java/org/apache/phoenix/index/IndexMaintainer.java [469:704]


    private IndexMaintainer(final PTable dataTable, final PTable cdcTable, final PTable index,
            PhoenixConnection connection) throws SQLException {
        this(dataTable.getRowKeySchema(), dataTable.getBucketNum() != null);
        this.rowKeyOrderOptimizable = index.rowKeyOrderOptimizable();
        this.isMultiTenant = dataTable.isMultiTenant();
        this.viewIndexId = index.getViewIndexId() == null ? null : index.getviewIndexIdType().toBytes(index.getViewIndexId());
        this.viewIndexIdType = index.getviewIndexIdType();
        this.isLocalIndex = index.getIndexType() == IndexType.LOCAL;
        this.isUncovered = index.getIndexType() == IndexType.UNCOVERED_GLOBAL;
        this.encodingScheme = index.getEncodingScheme();
        this.isCDCIndex = CDCUtil.isCDCIndex(index);

        // null check for b/w compatibility
        this.encodingScheme = index.getEncodingScheme() == null ? QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : index.getEncodingScheme();
        this.immutableStorageScheme = index.getImmutableStorageScheme() == null ? ImmutableStorageScheme.ONE_CELL_PER_COLUMN : index.getImmutableStorageScheme();
        this.dataEncodingScheme = dataTable.getEncodingScheme() == null ? QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : dataTable.getEncodingScheme();
        this.dataImmutableStorageScheme = dataTable.getImmutableStorageScheme() == null ? ImmutableStorageScheme.ONE_CELL_PER_COLUMN : dataTable.getImmutableStorageScheme();
        this.nDataTableSaltBuckets = isDataTableSalted ? dataTable.getBucketNum() : PTable.NO_SALTING;

        byte[] indexTableName = index.getPhysicalName().getBytes();
        // Use this for the nDataSaltBuckets as we need this for local indexes
        // TODO: persist nDataSaltBuckets separately, but maintain b/w compat.
        Integer nIndexSaltBuckets = isLocalIndex ? dataTable.getBucketNum() : index.getBucketNum();
        boolean indexWALDisabled = index.isWALDisabled();
        int indexPosOffset = (index.getBucketNum() == null ? 0 : 1) + (this.isMultiTenant ? 1 : 0) + (this.viewIndexId == null ? 0 : 1);
        int nIndexColumns = index.getColumns().size() - indexPosOffset;
        int nIndexPKColumns = index.getPKColumns().size() - indexPosOffset;
        // number of expressions that are indexed that are not present in the row key of the data table
        int indexedExpressionCount = 0;
        for (int i = indexPosOffset; i<index.getPKColumns().size();i++) {
        	PColumn indexColumn = index.getPKColumns().get(i);
        	String indexColumnName = indexColumn.getName().getString();
            String dataFamilyName = IndexUtil.getDataColumnFamilyName(indexColumnName);
            String dataColumnName = IndexUtil.getDataColumnName(indexColumnName);
            try {
                PColumn dataColumn = dataFamilyName.equals("") ? dataTable.getColumnForColumnName(dataColumnName) : dataTable.getColumnFamily(dataFamilyName).getPColumnForColumnName(dataColumnName);
                if (SchemaUtil.isPKColumn(dataColumn)) 
                    continue;
            } catch (ColumnNotFoundException e) {
             // This column must be an expression
            } catch (Exception e) {
                throw new IllegalArgumentException(e);
            }
            indexedExpressionCount++;
        }

        int dataPosOffset = (isDataTableSalted ? 1 : 0) + (this.isMultiTenant ? 1 : 0);

        // For indexes on views, we need to remember which data columns are "constants"
        // These are the values in a VIEW where clause. For these, we don't put them in the
        // index, as they're the same for every row in the index. The data table can be
        // either a VIEW or PROJECTED
        List<PColumn>dataPKColumns = dataTable.getPKColumns();
        this.indexDataColumnCount = dataPKColumns.size();
        PTable parentTable = dataTable;
        // We need to get the PK column for the table on which the index is created
        if (!dataTable.getName().equals(cdcTable != null
                ? cdcTable.getParentName() : index.getParentName())) {
            try {
                String tenantId = (index.getTenantId() != null) ? 
                        index.getTenantId().getString() : null;
                parentTable = connection.getTable(tenantId, index.getParentName().getString());
                this.indexDataColumnCount = parentTable.getPKColumns().size();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        this.parentTableType = parentTable.getType();
        
        int indexPkColumnCount = this.indexDataColumnCount + 
                indexedExpressionCount  - (this.isDataTableSalted ? 1 : 0) - (this.isMultiTenant ? 1 : 0);
        this.rowKeyMetaData = newRowKeyMetaData(indexPkColumnCount);
        BitSet bitSet = this.rowKeyMetaData.getViewConstantColumnBitSet();
        
        int nDataPKColumns = this.indexDataColumnCount - dataPosOffset;
        for (int i = dataPosOffset; i < dataPKColumns.size(); i++) {
            PColumn dataPKColumn = dataPKColumns.get(i);
            if (dataPKColumn.getViewConstant() != null) {
                bitSet.set(i);
                nDataPKColumns--;
            }
        }
        this.indexTableName = indexTableName;
        this.indexedColumnTypes = Lists.<PDataType>newArrayListWithExpectedSize(nIndexPKColumns-nDataPKColumns);
        this.indexedExpressions = Lists.newArrayListWithExpectedSize(nIndexPKColumns-nDataPKColumns);
        this.coveredColumnsMap = Maps.newHashMapWithExpectedSize(nIndexColumns - nIndexPKColumns);
        this.nIndexSaltBuckets  = nIndexSaltBuckets == null ? PTable.NO_SALTING : nIndexSaltBuckets;
        this.dataEmptyKeyValueCF = SchemaUtil.getEmptyColumnFamily(dataTable);
        this.emptyKeyValueCFPtr = SchemaUtil.getEmptyColumnFamilyPtr(index);
        this.nDataCFs = dataTable.getColumnFamilies().size();
        this.indexWALDisabled = indexWALDisabled;
        // TODO: check whether index is immutable or not. Currently it's always false so checking
        // data table is with immutable rows or not.
        this.immutableRows = dataTable.isImmutableRows();
        int indexColByteSize = 0;
        ColumnResolver resolver = null;
        List<ParseNode> parseNodes = new ArrayList<ParseNode>(1);
        UDFParseNodeVisitor visitor = new UDFParseNodeVisitor();
        for (int i = indexPosOffset; i < index.getPKColumns().size(); i++) {
            PColumn indexColumn = index.getPKColumns().get(i);
            String expressionStr = IndexUtil.getIndexColumnExpressionStr(indexColumn);
            try {
                ParseNode parseNode  = SQLParser.parseCondition(expressionStr);
                parseNode.accept(visitor);
                parseNodes.add(parseNode);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        try {
            resolver = FromCompiler.getResolver(connection, new TableRef(dataTable), visitor.getUdfParseNodes());
        } catch (SQLException e) {
            throw new RuntimeException(e); // Impossible
        }
        StatementContext context = new StatementContext(new PhoenixStatement(connection), resolver);
        this.indexedColumnsInfo = Sets.newHashSetWithExpectedSize(nIndexColumns - nIndexPKColumns);
        
        IndexExpressionCompiler expressionIndexCompiler = new IndexExpressionCompiler(context);
        for (int i = indexPosOffset; i < index.getPKColumns().size(); i++) {
            PColumn indexColumn = index.getPKColumns().get(i);
            int indexPos = i - indexPosOffset;
            Expression expression = null;
            try {
                expressionIndexCompiler.reset();
                expression = parseNodes.get(indexPos).accept(expressionIndexCompiler);
            } catch (SQLException e) {
                throw new RuntimeException(e); // Impossible
            }
            if ( expressionIndexCompiler.getColumnRef()!=null ) {
            	// get the column of the data column that corresponds to this index column
	            PColumn column = IndexUtil.getDataColumn(dataTable, indexColumn.getName().getString());
	            boolean isPKColumn = SchemaUtil.isPKColumn(column);
	            if (isPKColumn) {
	                int dataPkPos = dataTable.getPKColumns().indexOf(column) - (dataTable.getBucketNum() == null ? 0 : 1) - (this.isMultiTenant ? 1 : 0);
	                this.rowKeyMetaData.setIndexPkPosition(dataPkPos, indexPos);
	                indexedColumnsInfo.add(new Pair<>((String)null, column.getName().getString()));
	            } else {
	                indexColByteSize += column.getDataType().isFixedWidth() ? SchemaUtil.getFixedByteSize(column) : ValueSchema.ESTIMATED_VARIABLE_LENGTH_SIZE;
	                try {
	                    // Surround constant with cast so that we can still know the original type. Otherwise, if we lose the type,
	                    // (for example when VARCHAR becomes CHAR), it can lead to problems in the type translation we do between data tables and indexes.
	                    if (column.isNullable() && ExpressionUtil.isConstant(expression)) {
	                        expression = CoerceExpression.create(expression, indexColumn.getDataType());
	                    }
                        this.indexedExpressions.add(expression);
                        indexedColumnsInfo.add(new Pair<>(column.getFamilyName().getString(), column.getName().getString()));
                    } catch (SQLException e) {
                        throw new RuntimeException(e); // Impossible
                    }
	            }
            }
            else {
            	indexColByteSize += expression.getDataType().isFixedWidth() ? SchemaUtil.getFixedByteSize(expression) : ValueSchema.ESTIMATED_VARIABLE_LENGTH_SIZE;
                this.indexedExpressions.add(expression);
                KeyValueExpressionVisitor kvVisitor = new KeyValueExpressionVisitor() {
                    @Override
                    public Void visit(KeyValueColumnExpression colExpression) {
                        return addDataColInfo(dataTable, colExpression);
                    }

                    @Override
                    public Void visit(SingleCellColumnExpression expression) {
                        return addDataColInfo(dataTable, expression);
                    }

                    private Void addDataColInfo(final PTable dataTable, Expression expression) {
                        Preconditions.checkArgument(expression instanceof SingleCellColumnExpression
                                || expression instanceof KeyValueColumnExpression);

                        KeyValueColumnExpression colExpression = null;
                        if (expression instanceof SingleCellColumnExpression) {
                            colExpression =
                                    ((SingleCellColumnExpression) expression).getKeyValueExpression();
                        } else {
                            colExpression = ((KeyValueColumnExpression) expression);
                        }
                        byte[] cf = colExpression.getColumnFamily();
                        byte[] cq = colExpression.getColumnQualifier();
                        try {
                            PColumn dataColumn =
                                    cf == null ? dataTable.getColumnForColumnQualifier(null, cq)
                                            : dataTable.getColumnFamily(cf)
                                                    .getPColumnForColumnQualifier(cq);
                            if (dataColumn == null) {
                                if (Bytes.compareTo(cf, dataEmptyKeyValueCF) == 0
                                        && Bytes.compareTo(cq, EncodedColumnsUtil.getEmptyKeyValueInfo(dataEncodingScheme).getFirst()) == 0) {
                                    return null;
                                } else {
                                    throw new ColumnNotFoundException(dataTable.getSchemaName().getString(),
                                            dataTable.getTableName().getString(), Bytes.toString(cf), Bytes.toString(cq));
                                }
                            } else {
                                indexedColumnsInfo.add(new Pair<>(dataColumn.getFamilyName()
                                        .getString(), dataColumn.getName().getString()));
                            }
                        } catch (ColumnNotFoundException | ColumnFamilyNotFoundException
                                | AmbiguousColumnException e) {
                            if (dataTable.hasOnlyPkColumns()) {
                                return null;
                            }
                            throw new RuntimeException(e);
                        }
                        return null;
                    }

                };
                expression.accept(kvVisitor);
            }
            // set the sort order of the expression correctly
            if (indexColumn.getSortOrder() == SortOrder.DESC) {
                this.rowKeyMetaData.getDescIndexColumnBitSet().set(indexPos);
            }
        }
        this.estimatedExpressionSize = expressionIndexCompiler.getTotalNodeCount() * ESTIMATED_EXPRESSION_SIZE;
        for (int i = 0; i < index.getColumnFamilies().size(); i++) {
            PColumnFamily family = index.getColumnFamilies().get(i);
            for (PColumn indexColumn : family.getColumns()) {
                PColumn dataColumn = IndexUtil.getDataColumnOrNull(dataTable, indexColumn.getName().getString());
                // This can happen during deletion where we don't need covered columns
                if (dataColumn != null) {
                    byte[] dataColumnCq = dataColumn.getColumnQualifierBytes();
                    byte[] indexColumnCq = indexColumn.getColumnQualifierBytes();
                    this.coveredColumnsMap.put(new ColumnReference(dataColumn.getFamilyName().getBytes(), dataColumnCq), 
                            new ColumnReference(indexColumn.getFamilyName().getBytes(), indexColumnCq));
                }
            }
        }
        this.estimatedIndexRowKeyBytes = estimateIndexRowKeyByteSize(indexColByteSize);
        this.logicalIndexName = index.getName().getString();
        if (index.getIndexWhere() != null) {
            this.indexWhere = index.getIndexWhereExpression(connection);
            this.indexWhereColumns = index.getIndexWhereColumns(connection);
        }

        initCachedState();
    }