package edu.brown.catalog;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.voltdb.catalog.CatalogType;
import org.voltdb.catalog.Cluster;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.Constraint;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.Host;
import org.voltdb.catalog.Index;
import org.voltdb.catalog.ProcParameter;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Statement;
import org.voltdb.catalog.StmtParameter;
import org.voltdb.catalog.Table;
import edu.brown.catalog.special.MultiAttributeCatalogType;
import edu.brown.catalog.special.MultiColumn;
import edu.brown.catalog.special.MultiProcParameter;
import edu.brown.catalog.special.ReplicatedColumn;
import edu.brown.utils.ClassUtil;
public abstract class CatalogKeyOldVersion {
public static final Logger LOG = Logger.getLogger(CatalogKeyOldVersion.class);
private static final String PARENT_DELIMITER = ".";
private static final String MULTIATTRIBUTE_DELIMITER = "#";
private static final Map<CatalogType, String> CACHE_CREATEKEY = new HashMap<CatalogType, String>();
private static final Map<Database, Map<String, CatalogType>> CACHE_GETFROMKEY = new HashMap<Database, Map<String, CatalogType>>();
/**
* Returns a String key representation of the column as "Parent.Child"
*
* @param catalog_col
* @return
*/
@SuppressWarnings("unchecked")
public static <T extends CatalogType> String createKey(T catalog_item) {
// There is a 7x speed-up when we use the cache versus always
// constructing a new key
String ret = CACHE_CREATEKEY.get(catalog_item);
if (ret != null)
return (ret);
if (catalog_item == null)
return (null);
assert (catalog_item.getParent() != null) : catalog_item + " has null parent";
CatalogType parent = catalog_item.getParent();
ret = parent.getName() + PARENT_DELIMITER;
// Special Case: MultiAttributeCatalogType
if (catalog_item instanceof MultiAttributeCatalogType) {
MultiAttributeCatalogType multicatalog = (MultiAttributeCatalogType) catalog_item;
ret += multicatalog.getPrefix();
for (Object sub_item : multicatalog) {
ret += MULTIATTRIBUTE_DELIMITER + ((CatalogType) sub_item).getName();
} // FOR
} else {
ret += catalog_item.getName();
// Special Case: StmtParameter
// Since there may be Statement's with the same name but in
// different Procedures,
// we also want to include the Procedure name
if (catalog_item instanceof StmtParameter) {
assert (parent.getParent() != null);
ret = parent.getParent().getName() + PARENT_DELIMITER + ret;
}
}
CACHE_CREATEKEY.put(catalog_item, ret);
return (ret);
}
/**
* Returns a String key representation of the column as "Parent.Child"
*
* @param parent
* @param child
* @return
*/
public static String createKey(String parent, String child) {
return (new StringBuilder().append(parent).append(PARENT_DELIMITER).append(child).toString());
}
public static Collection<String> createKeys(Iterable<? extends CatalogType> map) {
Collection<String> keys = new ArrayList<String>();
for (CatalogType catalog_item : map) {
keys.add(createKey(catalog_item));
} // FOR
return (keys);
}
/**
* Return the name of the catalog object from the key
*
* @param catalog_key
* @return
*/
public static String getNameFromKey(String catalog_key) {
assert (catalog_key != null);
return (catalog_key.substring(catalog_key.lastIndexOf(PARENT_DELIMITER) + 1));
}
/**
* Given a String key generated by createKey(), return the corresponding
* catalog object for the given Database catalog. If the parent object does
* not exist, this function will return null. If the parent exists but the
* child does not exist, then it trips an assert
*
* @param catalog_db
* @param key
* @return
*/
@SuppressWarnings("unchecked")
public static <T extends CatalogType> T getFromKey(Database catalog_db, String key, Class<T> catalog_class) {
final boolean debug = LOG.isDebugEnabled();
if (debug)
LOG.debug("Grabbing " + catalog_class + " object for '" + key + "'");
assert (catalog_db != null);
assert (catalog_class != null);
// Caching...
Map<String, CatalogType> cache = CatalogKeyOldVersion.CACHE_GETFROMKEY.get(catalog_db);
if (cache != null) {
if (cache.containsKey(key))
return (T) cache.get(key);
} else {
cache = new HashMap<String, CatalogType>();
CatalogKeyOldVersion.CACHE_GETFROMKEY.put(catalog_db, cache);
}
T catalog_child = null;
CatalogType catalog_parent = null;
int idx = key.indexOf(PARENT_DELIMITER);
assert (idx != -1) : "Invalid CatalogKeyOldVersion format '" + key + "'";
String parent_key = key.substring(0, idx);
String child_key = key.substring(idx + 1);
List<Class<?>> superclasses = ClassUtil.getSuperClasses(catalog_class);
// Get the parent based on the type of the object they want back
if (catalog_class.equals(Index.class) || catalog_class.equals(Constraint.class) || superclasses.contains(Column.class)) {
catalog_parent = catalog_db.getTables().get(parent_key);
} else if (catalog_class.equals(Statement.class) || superclasses.contains(ProcParameter.class)) {
catalog_parent = catalog_db.getProcedures().get(parent_key);
} else if (catalog_class.equals(Table.class) || catalog_class.equals(Procedure.class)) {
catalog_parent = catalog_db;
} else if (catalog_class.equals(Host.class)) {
catalog_parent = (Cluster) catalog_db.getParent();
// Special Case: StmtParameter
} else if (catalog_class.equals(StmtParameter.class)) {
Procedure catalog_proc = catalog_db.getProcedures().get(parent_key);
assert (catalog_proc != null);
idx = child_key.indexOf('.');
parent_key = child_key.substring(0, idx);
child_key = child_key.substring(idx + 1);
catalog_parent = catalog_proc.getStatements().get(parent_key);
}
// Don't throw this error because it may be a dynamic catalog type that
// we use for the Markov stuff
// } else {
// assert(false) : "Unexpected Catalog key type '" + catalog_class +
// "'";
// }
// It's ok for the parent to be missing, but it's *not* ok if the child
// is missing
if (catalog_parent != null) {
if (debug)
LOG.debug("Catalog Parent: " + CatalogUtil.getDisplayName(catalog_parent));
// COLUMN
if (superclasses.contains(Column.class)) {
// Special Case: Replicated Column
if (child_key.equals(ReplicatedColumn.COLUMN_NAME)) {
catalog_child = (T) ReplicatedColumn.get((Table) catalog_parent);
// Special Case: MultiColumn
} else if (child_key.startsWith(MultiColumn.PREFIX)) {
int prefix_offset = MultiColumn.PREFIX.length() + MULTIATTRIBUTE_DELIMITER.length();
String names[] = child_key.substring(prefix_offset).split(MULTIATTRIBUTE_DELIMITER);
assert (names.length > 1) : "Invalid MultiColumn Key: " + child_key;
Column params[] = new Column[names.length];
for (int i = 0; i < names.length; i++) {
params[i] = getFromKey(catalog_db, createKey(parent_key, names[i]), Column.class);
} // FOR
catalog_child = (T) MultiColumn.get(params);
// Regular Columns
} else {
catalog_child = (T) ((Table) catalog_parent).getColumns().get(child_key);
}
// INDEX
} else if (superclasses.contains(Index.class)) {
catalog_child = (T) ((Table) catalog_parent).getIndexes().get(child_key);
// CONSTRAINT
} else if (superclasses.contains(Constraint.class)) {
catalog_child = (T) ((Table) catalog_parent).getConstraints().get(child_key);
// PROCPARAMETER
} else if (superclasses.contains(ProcParameter.class)) {
// Special Case: MultiProcParameter
if (child_key.startsWith(MultiProcParameter.PREFIX)) {
int prefix_offset = MultiProcParameter.PREFIX.length() + MULTIATTRIBUTE_DELIMITER.length();
String names[] = child_key.substring(prefix_offset).split(MULTIATTRIBUTE_DELIMITER);
assert (names.length > 1) : "Invalid MultiProcParameter Key: " + child_key.substring(prefix_offset);
ProcParameter params[] = new ProcParameter[names.length];
for (int i = 0; i < names.length; i++) {
params[i] = getFromKey(catalog_db, createKey(parent_key, names[i]), ProcParameter.class);
} // FOR
catalog_child = (T) MultiProcParameter.get(params);
// Regular ProcParameter
} else {
catalog_child = (T) ((Procedure) catalog_parent).getParameters().get(child_key);
}
// STATEMENT
} else if (superclasses.contains(Statement.class)) {
catalog_child = (T) ((Procedure) catalog_parent).getStatements().get(child_key);
// STMTPARAMETER
} else if (superclasses.contains(StmtParameter.class)) {
catalog_child = (T) ((Statement) catalog_parent).getParameters().get(child_key);
// TABLE
} else if (superclasses.contains(Table.class)) {
catalog_child = (T) ((Database) catalog_parent).getTables().get(child_key);
if (catalog_child == null) {
LOG.debug("TABLES: " + CatalogUtil.debug(((Database) catalog_parent).getTables()));
}
// PROCEDURE
} else if (superclasses.contains(Procedure.class)) {
catalog_child = (T) ((Database) catalog_parent).getProcedures().get(child_key);
// HOST
} else if (superclasses.contains(Host.class)) {
catalog_child = (T) ((Cluster) catalog_parent).getHosts().get(child_key);
// UNKNOWN!
} else {
LOG.fatal("Invalid child class '" + catalog_class + "' for catalog key " + key);
assert (false);
}
if (catalog_child != null)
cache.put(key, catalog_child);
return (catalog_child);
}
return (null);
}
public static <T extends CatalogType> Collection<T> getFromKeys(Database catalog_db, Collection<String> keys, Class<T> catalog_class, Collection<T> items) {
for (String key : keys) {
items.add(CatalogKeyOldVersion.getFromKey(catalog_db, key, catalog_class));
} // FOR
return (items);
}
public static <T extends CatalogType> Collection<T> getFromKeys(Database catalog_db, Collection<String> keys, Class<T> catalog_class) {
return (getFromKeys(catalog_db, keys, catalog_class, new ArrayList<T>()));
}
}