/** * 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 com.foundationdb.server.types.common.types.StringFactory; import java.util.*; /** Common base class for tables and views, which both have columns. */ public abstract class Columnar { public abstract boolean isView(); public boolean isTable() { return !isView(); } @Override public String toString() { return tableName.toString(); } protected Columnar(AkibanInformationSchema ais, String schemaName, String tableName) { ais.checkMutability(); AISInvariants.checkNullName(schemaName, "Table", "schema name"); AISInvariants.checkNullName(tableName, "Table", "table name"); AISInvariants.checkDuplicateTables(ais, schemaName, tableName); this.ais = ais; this.tableName = new TableName(schemaName, tableName); } public AkibanInformationSchema getAIS() { return ais; } public TableName getName() { return tableName; } public Column getColumn(String columnName) { return columnMap.get(columnName); } public Column getColumn(Integer position) { return getColumns().get(position); } public List<Column> getColumns() { ensureColumnsUpToDate(); return columnsWithoutInternal; } public List<Column> getColumnsIncludingInternal() { ensureColumnsUpToDate(); return columns; } public int getCharsetId() { return charsetId; } public String getCharsetName() { return StringFactory.charsetIdToName(charsetId); } public int getDefaultedCharsetId() { return charsetId == StringFactory.NULL_CHARSET_ID ? ais.getCharsetId() // schema.getDefaultedCharsetId() : charsetId; } public String getDefaultedCharsetName() { return StringFactory.charsetIdToName(getDefaultedCharsetId()); } public int getCollationId() { return collationId; } public String getCollationName() { return StringFactory.collationIdToName(collationId); } public int getDefaultedCollationId() { return collationId == StringFactory.NULL_COLLATION_ID ? ais.getCollationId() // schema.getDefaultedCollationId() : collationId; } public String getDefaultedCollationName() { return StringFactory.collationIdToName(getDefaultedCollationId()); } public void setCharsetAndCollation(String charsetName, String collationName) { charsetId = StringFactory.charsetNameToId(charsetName); collationId = StringFactory.collationNameToId(collationName); } public boolean isAISTable() { return tableName.getSchemaName().equals(TableName.INFORMATION_SCHEMA); } public boolean isProtectedTable() { return tableName.inSystemSchema(); } /** A BitSet where the field positions of all {@code NOT NULL} columns are set. */ public BitSet notNull() { ensureColumnsUpToDate(); return notNull; } public Column dropColumn(String columnName) { columnsStale = true; return columnMap.remove(columnName); } protected void addColumn(Column column) { columnMap.put(column.getName(), column); columnsStale = true; } public void dropColumns() { columnMap.clear(); columnsStale = true; } void markColumnsStale() { columnsStale = true; } // For use by this package void setTableName(TableName tableName) { this.tableName = tableName; } /** * check if this table belongs to a frozen AIS, * throw exception if ais is frozen */ void checkMutability() { ais.checkMutability(); } private void ensureColumnsUpToDate() { if (columnsStale) { synchronized (columnsStaleLock) { if (columnsStale) { columns.clear(); columns.addAll(columnMap.values()); Collections.sort(columns, new Comparator<Column>() { @Override public int compare(Column x, Column y) { return x.getPosition() - y.getPosition(); } }); columnsWithoutInternal.clear(); notNull = new BitSet(columns.size()); for (Column column : columns) { if (!column.isInternalColumn()) { columnsWithoutInternal.add(column); } assert (column.getNullable() != null) : column; notNull.set(column.getPosition(), !column.getNullable()); } columnsStale = false; } } } } // State protected final AkibanInformationSchema ais; protected final Object columnsStaleLock = new Object(); protected final List<Column> columns = new ArrayList<>(); protected final List<Column> columnsWithoutInternal = new ArrayList<>(); protected final Map<String, Column> columnMap = new TreeMap<>(); private BitSet notNull; protected TableName tableName; protected volatile boolean columnsStale = true; protected int charsetId = StringFactory.NULL_CHARSET_ID; protected int collationId = StringFactory.NULL_COLLATION_ID; }