package edu.brown.mappings; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONStringer; import org.voltdb.catalog.Column; import org.voltdb.catalog.Database; import org.voltdb.catalog.ProcParameter; import org.voltdb.catalog.Procedure; import org.voltdb.catalog.Statement; import org.voltdb.catalog.StmtParameter; import edu.brown.utils.CollectionUtil; import edu.brown.utils.JSONSerializable; import edu.brown.utils.JSONUtil; import edu.brown.utils.StringUtil; /** * Container class for all of the ParameterMappings for a single project. * We maintain internal index structures to make it easier to find the proper ParameterMapping * objects for various search arguments. * @author pavlo */ public class ParameterMappingsSet extends HashSet<ParameterMapping> implements JSONSerializable { private static final long serialVersionUID = 1L; /** * Dear son, * This right here is nasty old boy! Don't do what Daddy did... **/ private final transient HashMap<Statement, StatementMappings> stmtIndex = new HashMap<Statement, StatementMappings>(); private final transient HashMap<Procedure, ProcedureMappings> procIndex = new HashMap<Procedure, ProcedureMappings>(); private final transient HashMap<ProcParameter, ProcParameterMappings> procParamIndex = new HashMap<ProcParameter, ProcParameterMappings>(); @SuppressWarnings("serial") protected static class StatementMappings extends TreeMap<Integer, SortedMap<StmtParameter, SortedSet<ParameterMapping>>> { } @SuppressWarnings("serial") protected static class ProcedureMappings extends TreeMap<ProcParameter, SortedSet<ParameterMapping>> { } @SuppressWarnings("serial") protected static class ProcParameterMappings extends HashMap<Column, SortedSet<ParameterMapping>> { } /** * Constructor * @param catalogContext */ public ParameterMappingsSet() { super(); // Nothing for now... } /** * Removes all of the elements from this set and the internal index. */ @Override public void clear() { this.stmtIndex.clear(); this.procIndex.clear(); this.procParamIndex.clear(); super.clear(); } /** * Add a new ParameterMapping object for the given StmtParameter * @param c */ @Override public boolean add(ParameterMapping c) { assert(c != null); Statement catalog_stmt = c.getStatement(); assert(catalog_stmt != null); StmtParameter catalog_stmt_param = c.getStmtParameter(); assert(catalog_stmt_param != null); Procedure catalog_proc = catalog_stmt.getParent(); assert(catalog_proc != null); ProcParameter catalog_proc_param = c.getProcParameter(); Column catalog_col = c.getColumn(); // Procedure Index if (!this.procIndex.containsKey(catalog_proc)) { this.procIndex.put(catalog_proc, new ProcedureMappings()); } if (!this.procIndex.get(catalog_proc).containsKey(catalog_proc_param)) { this.procIndex.get(catalog_proc).put(catalog_proc_param, new TreeSet<ParameterMapping>()); } this.procIndex.get(catalog_proc).get(catalog_proc_param).add(c); // ProcParameter->Column Index if (catalog_col != null) { ProcParameterMappings m = this.procParamIndex.get(catalog_proc_param); if (m == null) { m = new ProcParameterMappings(); this.procParamIndex.put(catalog_proc_param, m); } if (m.containsKey(catalog_col) == false) { m.put(catalog_col, new TreeSet<ParameterMapping>()); } m.get(catalog_col).add(c); } // Statement Index if (!this.stmtIndex.containsKey(catalog_stmt)) { this.stmtIndex.put(catalog_stmt, new StatementMappings()); } if (!this.stmtIndex.get(catalog_stmt).containsKey(c.getStatementIndex())) { this.stmtIndex.get(catalog_stmt).put(c.getStatementIndex(), new TreeMap<StmtParameter, SortedSet<ParameterMapping>>()); } if (!this.stmtIndex.get(catalog_stmt).get(c.getStatementIndex()).containsKey(catalog_stmt_param)) { this.stmtIndex.get(catalog_stmt).get(c.getStatementIndex()).put(catalog_stmt_param, new TreeSet<ParameterMapping>()); } this.stmtIndex.get(catalog_stmt).get(c.getStatementIndex()).get(catalog_stmt_param).add(c); // Now add it to our internal set return (super.add(c)); } /** * Return the ParameterMappings for the StmtParameter in the Statement * executed at the provided offset * @param catalog_stmt * @param catalog_stmt_index The # of times that this Statement has already been executed * @param catalog_stmt_param * @return */ public Collection<ParameterMapping> get(Statement catalog_stmt, int catalog_stmt_index, StmtParameter catalog_stmt_param) { assert(catalog_stmt != null); assert(catalog_stmt_index >= 0); assert(catalog_stmt_param != null); Collection<ParameterMapping> ret = null; StatementMappings mappings = this.stmtIndex.get(catalog_stmt); if (mappings != null && mappings.containsKey(catalog_stmt_index)) { ret = mappings.get(catalog_stmt_index).get(catalog_stmt_param); } return (ret); } /** * Return the ParameterMappings for the StmtParameter offset in the Statement * @param catalog_stmt * @param catalog_stmt_index The # of times that this Statement has already been executed * @param catalog_stmt_param_index * @return */ public Collection<ParameterMapping> get(Statement catalog_stmt, int catalog_stmt_index, int catalog_stmt_param_index) { assert(catalog_stmt != null); assert(catalog_stmt_index >= 0); assert(catalog_stmt_param_index < catalog_stmt.getParameters().size()); return (this.get(catalog_stmt, catalog_stmt_index, catalog_stmt.getParameters().values()[catalog_stmt_param_index])); } /** * Return a mapping from StmtParameters to ParameterMapping * @param catalog_stmt The Statement to retrieve the mappings for * @param catalog_stmt_index The # of times that this Statement has already been executed * @return */ public Map<StmtParameter, SortedSet<ParameterMapping>> get(Statement catalog_stmt, Integer catalog_stmt_index) { StatementMappings mappings = this.stmtIndex.get(catalog_stmt); if (mappings != null) { return (mappings.get(catalog_stmt_index)); } return (null); } /** * Get all of the ParameterMapping for this StmtParameter, regardless of the catalog_stmt_index * @param catalog_stmt * @param catalog_stmt_param * @return */ protected Collection<ParameterMapping> get(Statement catalog_stmt, StmtParameter catalog_stmt_param) { assert(catalog_stmt != null); assert(catalog_stmt_param != null); Collection<ParameterMapping> set = new TreeSet<ParameterMapping>(); StatementMappings mappings = this.stmtIndex.get(catalog_stmt); if (mappings != null) { for (SortedMap<StmtParameter, SortedSet<ParameterMapping>> m : mappings.values()) { if (m.containsKey(catalog_stmt_param)) { set.addAll(m.get(catalog_stmt_param)); } } // FOR } return (set); } /** * Return a sorted list of the ParameterMapping for this ProcParameter regardless of ProcParameter index * @param catalog_proc_param * @return */ public Collection<ParameterMapping> get(ProcParameter catalog_proc_param) { assert(catalog_proc_param != null); Procedure catalog_proc = catalog_proc_param.getParent(); assert(catalog_proc != null); Collection<ParameterMapping> ret = null; ProcedureMappings mappings = this.procIndex.get(catalog_proc); if (mappings != null && mappings.containsKey(catalog_proc_param)) { ret = this.procIndex.get(catalog_proc).get(catalog_proc_param); } return (ret); } /** * Return all of the ParameterMappings for the given ProcParameter that are mapped to * a particular Column via the StmtParameter. * <B>NOTE:</B> If you have to ask, then you probably don't need this method... * @param catalog_proc_param * @param catalog_col * @return */ public Collection<ParameterMapping> get(ProcParameter catalog_proc_param, Column catalog_col) { assert(catalog_proc_param != null); assert(catalog_col != null); Collection<ParameterMapping> ret = null; ProcParameterMappings mappings = this.procParamIndex.get(catalog_proc_param); if (mappings != null) { ret = mappings.get(catalog_col); } return (ret); } /** * Convenience method to return all of the ParameterMappings for a Procedure * @param catalog_proc * @return */ public Collection<ParameterMapping> get(Procedure catalog_proc) { Collection<ParameterMapping> ret = new ArrayList<ParameterMapping>(); for (ProcParameter catalog_param : catalog_proc.getParameters()) { ret.addAll(this.get(catalog_param)); } // FOR return (ret); } /** * Convenience method to return all of the ParameterMappings for a Statement * @param catalog_stmt * @return */ protected StatementMappings get(Statement catalog_stmt) { return (this.stmtIndex.get(catalog_stmt)); } public String debug() { return (this.debug(this.stmtIndex.keySet())); } public String debug(Statement...catalog_stmts) { return (this.debug(CollectionUtil.addAll(new ArrayList<Statement>(), catalog_stmts))); } public String debug(Collection<Statement> catalog_stmts) { StringBuilder sb = new StringBuilder(); for (Statement catalog_stmt : catalog_stmts) { if (this.stmtIndex.containsKey(catalog_stmt)) { int num_instances = this.stmtIndex.get(catalog_stmt).size(); sb.append(catalog_stmt.getName() + " [# of Instances=" + num_instances + "]\n"); for (Integer catalog_stmt_index : this.stmtIndex.get(catalog_stmt).keySet()) { if (num_instances > 1) sb.append(String.format(" Instance #%02d:\n", catalog_stmt_index)); if (this.stmtIndex.get(catalog_stmt).containsKey(catalog_stmt_index)) { SortedMap<StmtParameter, SortedSet<ParameterMapping>> params = this.stmtIndex.get(catalog_stmt).get(catalog_stmt_index); for (StmtParameter catalog_stmt_param : params.keySet()) { for (ParameterMapping c : params.get(catalog_stmt_param)) { sb.append(" " + c + "\n"); } // FOR (correlation) } // FOR (catalog_stmt_param) } else { sb.append(" <NONE>\n"); } } // FOR (catalog_stmt_index) sb.append(StringUtil.SINGLE_LINE); } } // FOR (catalot_stmt) return (sb.toString()); } // ---------------------------------------------------------------------------- // SERIALIZATION METHODS // ---------------------------------------------------------------------------- @Override public void load(File input_path, Database catalog_db) throws IOException { JSONUtil.load(this, catalog_db, input_path); } @Override public void save(File output_path) throws IOException { JSONUtil.save(this, output_path); } @Override public String toJSONString() { return (JSONUtil.toJSONString(this)); } public void toJSON(JSONStringer stringer) throws JSONException { stringer.key("MAPPINGS").array(); for (ParameterMapping c : this) { assert(c != null); stringer.value(c); } // FOR stringer.endArray(); } public void fromJSON(JSONObject object, Database catalog_db) throws JSONException { JSONArray json_array = object.getJSONArray("MAPPINGS"); for (int i = 0, cnt = json_array.length(); i < cnt; i++) { JSONObject json_object = json_array.getJSONObject(i); ParameterMapping c = new ParameterMapping(); c.fromJSON(json_object, catalog_db); this.add(c); } // FOR assert(json_array.length() == this.size()); } }