/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.ais.model;
import com.foundationdb.ais.model.validation.AISInvariants;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class TableIndex extends Index
{
public static TableIndex create(AkibanInformationSchema ais,
Table table,
String indexName,
Integer indexId,
Boolean isUnique,
Boolean isPrimary) {
return create(ais, table, indexName, indexId, isUnique, isPrimary, null);
}
public static TableIndex create(AkibanInformationSchema ais,
Table table,
String indexName,
Integer indexId,
Boolean isUnique,
Boolean isPrimary,
TableName constraintName)
{
table.checkMutability();
ais.checkMutability();
AISInvariants.checkDuplicateConstraintsInSchema(ais, constraintName);
AISInvariants.checkDuplicateIndexesInTable(table, indexName);
TableIndex index = new TableIndex(table, indexName, indexId, isUnique, isPrimary, constraintName);
table.addIndex(index);
if(constraintName != null) {
ais.addConstraint(index);
}
return index;
}
/**
* Create an independent copy of an existing TableIndex.
* @param table Destination Table.
* @param index TableIndex to to copy.
* @return The new copy of the TableIndex.
*/
public static TableIndex create(Table table, TableIndex index)
{
TableIndex copy = create(table.getAIS(), table, index.getIndexName().getName(), index.getIndexId(),
index.isUnique(),
index.isPrimaryKey(), index.getConstraintName());
if (index.isSpatial()) {
copy.markSpatial(index.firstSpatialArgument(), index.spatialColumns(), index.getIndexMethod());
}
return copy;
}
public TableIndex(Table table, String indexName, Integer indexId, Boolean isUnique, Boolean isPrimary, TableName constraintName)
{
// Index check indexName for null state.
super(table.getName(), indexName, indexId, isUnique, isPrimary, constraintName, null);
this.table = table;
}
@Override
public boolean isTableIndex()
{
return true;
}
@Override
public void computeFieldAssociations(Map<Table, Integer> ordinalMap)
{
freezeColumns();
AssociationBuilder toIndexRowBuilder = new AssociationBuilder();
AssociationBuilder toHKeyBuilder = new AssociationBuilder();
List<Column> indexColumns = new ArrayList<>();
// Add index key fields
for (IndexColumn iColumn : getKeyColumns()) {
Column column = iColumn.getColumn();
indexColumns.add(column);
toIndexRowBuilder.rowCompEntry(column.getPosition(), -1);
}
// Add leafward-biased hkey fields not already included
int indexColumnPosition = indexColumns.size();
List<IndexColumn> hKeyColumns = new ArrayList<>();
HKey hKey = hKey();
for (HKeySegment hKeySegment : hKey.segments()) {
// TODO: ordinalMap is null if this function is called while marking an index as spatial.
// TODO: This is temporary, working on spatial indexes before DDL support. Once the parser
// TODO: supports spatial indexes, they'll be born as spatial, and we won't have to recompute
// TODO: field associations after the fact.
// By the way, it might actually safe to remove the reliance on ordinalMap and always get
// the ordinal from the rowdef.
Integer ordinal =
ordinalMap == null
? hKeySegment.table().getOrdinal()
: ordinalMap.get(hKeySegment.table());
assert ordinal != null : hKeySegment.table();
toHKeyBuilder.toHKeyEntry(ordinal, -1);
for (HKeyColumn hKeyColumn : hKeySegment.columns()) {
Column column = hKeyColumn.column();
if (!indexColumns.contains(column)) {
if (table.getColumnsIncludingInternal().contains(column)) {
toIndexRowBuilder.rowCompEntry(column.getPosition(), -1);
} else {
toIndexRowBuilder.rowCompEntry(-1, hKeyColumn.positionInHKey());
}
indexColumns.add(column);
hKeyColumns.add(new IndexColumn(this, column, indexColumnPosition, true, 0));
indexColumnPosition++;
}
toHKeyBuilder.toHKeyEntry(-1, indexColumns.indexOf(column));
}
}
allColumns = new ArrayList<>();
allColumns.addAll(keyColumns);
allColumns.addAll(hKeyColumns);
indexRowComposition = toIndexRowBuilder.createIndexRowComposition();
indexToHKey = toHKeyBuilder.createIndexToHKey();
}
@Override
public Table leafMostTable() {
return table;
}
@Override
public Table rootMostTable() {
return table;
}
@Override
public void checkMutability() {
table.checkMutability();
}
@Override
public Collection<Integer> getAllTableIDs() {
return Collections.singleton(table.getTableId());
}
public Table getTable()
{
return table;
}
public IndexToHKey indexToHKey()
{
return indexToHKey;
}
// For a user table index: the user table hkey
// For a group table index: the hkey of the leafmost user table, but with user table columns replaced by
// group table columns.
@Override
public HKey hKey()
{
if (hKey == null) {
hKey = table.hKey();
}
return hKey;
}
//
// Constraint
//
@Override
public Table getConstraintTable() {
return table;
}
private final Table table;
private HKey hKey;
private IndexToHKey indexToHKey;
}