/** * 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.qp.rowtype; import com.foundationdb.ais.model.*; import com.foundationdb.server.types.TInstance; import com.foundationdb.server.types.texpressions.TPreparedExpression; import java.util.*; /** Table RowTypes are indexed by the Table's ID. Derived RowTypes get higher values. */ public class Schema { public static Set<RowType> descendentTypes(RowType ancestorType, Set<? extends RowType> allTypes) { Set<RowType> descendentTypes = new HashSet<>(); for (RowType type : allTypes) { if (type != ancestorType && ancestorType.ancestorOf(type)) { descendentTypes.add(type); } } return descendentTypes; } public AggregatedRowType newAggregateType(RowType parent, int inputsIndex, List<? extends TInstance> pAggrTypes) { return new AggregatedRowType(this, nextTypeId(), parent, inputsIndex, pAggrTypes); } public FlattenedRowType newFlattenType(RowType parent, RowType child) { return new FlattenedRowType(this, nextTypeId(), parent, child); } public ProjectedRowType newProjectType(List<? extends TPreparedExpression> tExprs) { return new ProjectedRowType(this, nextTypeId(), tExprs); } public ProductRowType newProductType(RowType leftType, TableRowType branchType, RowType rightType) { return new ProductRowType(this, nextTypeId(), leftType, branchType, rightType); } public ValuesRowType newValuesType(TInstance... fields) { return new ValuesRowType(this, nextTypeId(), fields); } public HKeyRowType newHKeyRowType(HKey hKey) { return hKeyRowTypes.get(hKey.table().getTableId()); } public BufferRowType bufferRowType(RowType rightType) { ValuesRowType leftType = newValuesType(InternalIndexTypes.LONG.instance(false)); return new BufferRowType(this, nextTypeId(), leftType, rightType); } public TableRowType tableRowType(Table table) { return tableRowType(table.getTableId()); } public TableRowType tableRowType(int tableID) { return (TableRowType) rowTypes.get(tableID); } public IndexRowType indexRowType(Index index) { return index.isTableIndex() ? tableRowType(index.leafMostTable()).indexRowType(index) : groupIndexRowType((GroupIndex) index); } public Set<TableRowType> userTableTypes() { Set<TableRowType> userTableTypes = new HashSet<>(); for (AisRowType rowType : rowTypes.values()) { if (rowType instanceof TableRowType) { if (!rowType.table().isAISTable()) { userTableTypes.add((TableRowType) rowType); } } } return userTableTypes; } public Set<RowType> allTableTypes() { Set<RowType> allTableTypes = new HashSet<>(); for (RowType rowType : rowTypes.values()) { if (rowType instanceof TableRowType) { allTableTypes.add(rowType); } } return allTableTypes; } public List<IndexRowType> groupIndexRowTypes() { return groupIndexRowTypes; } public Schema(AkibanInformationSchema ais) { this.ais = ais; // Create RowTypes for AIS Tables for (Table table : ais.getTables().values()) { TableRowType tableRowType = new TableRowType(this, table); int tableTypeId = tableRowType.typeId(); rowTypes.put(tableTypeId, tableRowType); typeIdToLeast(tableRowType.typeId()); HKeyRowType hKeyRowType = new HKeyRowType (this, nextTypeId(), table.hKey()); hKeyRowTypes.put(tableTypeId, hKeyRowType); } // Create RowTypes for AIS TableIndexes for (Table table : ais.getTables().values()) { TableRowType tableRowType = tableRowType(table); for (TableIndex index : table.getIndexesIncludingInternal()) { IndexRowType indexRowType = IndexRowType.createIndexRowType(this, nextTypeId(), tableRowType, index); tableRowType.addIndexRowType(indexRowType); rowTypes.put(indexRowType.typeId(), indexRowType); } } // Create RowTypes for AIS GroupIndexes for (Group group : ais.getGroups().values()) { for (GroupIndex groupIndex : group.getIndexes()) { IndexRowType indexRowType = IndexRowType.createIndexRowType(this, nextTypeId(), tableRowType(groupIndex.leafMostTable()), groupIndex); rowTypes.put(indexRowType.typeId(), indexRowType); groupIndexRowTypes.add(indexRowType); } } } public AkibanInformationSchema ais() { return ais; } // For use by this package // For use by this class private IndexRowType groupIndexRowType(GroupIndex groupIndex) { for (IndexRowType groupIndexRowType : groupIndexRowTypes) { if (groupIndexRowType.index() == groupIndex) { return groupIndexRowType; } } return null; } private synchronized int nextTypeId() { return ++typeIdCounter; } private synchronized void typeIdToLeast(int minValue) { typeIdCounter = Math.max(typeIdCounter, minValue); } // Object state private int typeIdCounter = -1; private final AkibanInformationSchema ais; private final Map<Integer, AisRowType> rowTypes = new HashMap<>(); private final Map<Integer, HKeyRowType> hKeyRowTypes = new HashMap<>(); private final List<IndexRowType> groupIndexRowTypes = new ArrayList<>(); }