package edu.brown.optimizer;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Statement;
import org.voltdb.catalog.Table;
import org.voltdb.planner.PlannerContext;
import org.voltdb.plannodes.AbstractPlanNode;
import edu.brown.benchmark.AbstractProjectBuilder;
import edu.brown.plannodes.PlanNodeTreeWalker;
import edu.brown.plannodes.PlanNodeUtil;
import edu.brown.utils.CollectionUtil;
/**
* @author sw47
*/
public class TestPlanOptimizerUtil extends BasePlanOptimizerTestCase {
AbstractProjectBuilder pb = new PlanOptimizerTestProjectBuilder("planopt1") {
{
this.addStmtProcedure("SingleProjection", "SELECT TABLEA.A_VALUE0 FROM TABLEA WHERE TABLEA.A_ID = ?");
// this.addStmtProcedure("JoinProjection",
// "SELECT TABLEA.A_VALUE0 FROM TABLEA, TABLEB WHERE TABLEA.A_ID = ? AND TABLEA.A_ID = TABLEB.B_A_ID");
}
};
PlanOptimizerState state;
@Override
protected void setUp() throws Exception {
super.setUp(pb);
this.state = new PlanOptimizerState(catalog_db, PlannerContext.singleton());
}
/**
* Check the columns A_ID and A_VALUE0 are there in in that particular order
* + they both belong to Table A.
*
* @param tableCols
*/
private void checkTableColumns(Map<Table, SortedSet<Column>> tableCols) {
assert (tableCols.size() == 1) : " ERROR: more than 1 entry in tableCols";
Table t = CollectionUtil.first(tableCols.keySet());
assert (t != null);
assert (t.getName().equals("TABLEA")) : "table " + t.getName() + " does not match TABLEA";
Set<Column> cols = CollectionUtil.first(tableCols.values());
assert (cols.size() == 2) : "Size: " + cols.size() + " doesn't match 2";
assert (((Column) cols.toArray()[0]).getName().equals("A_ID")) : " first column: " + ((Column) cols.toArray()[0]).getName() + " doesn't match: " + " A_ID";
assert (((Column) cols.toArray()[1]).getName().equals("A_VALUE0")) : "second column: " + ((Column) cols.toArray()[1]).getName() + " doesn't match: " + " A_VALUE0";
}
private void checkPlanNodeColumns(Map<AbstractPlanNode, Set<Column>> planNodeCols) {
System.out.println("planNodeCols: " + planNodeCols);
}
/**
* Checks a column gets properly added to tableColumns in the correct order
*/
public void testAddTableColumn() throws Exception {
Procedure catalog_proc = this.getProcedure("SingleProjection");
Statement catalog_stmt = this.getStatement(catalog_proc, "sql");
// Grab the root node of the multi-partition query plan tree for this Statement
AbstractPlanNode rootNode = PlanNodeUtil.getRootPlanNodeForStatement(catalog_stmt, false);
PlanOptimizerUtil.populateTableNodeInfo(state, rootNode);
// check two hashmaps contain what we expect
checkPlanNodeColumns(state.planNodeColumns);
checkTableColumns(state.tableColumns);
// add column A_VALUE5
state.addTableColumn(catalog_db.getTables().get("TABLEA").getColumns().get("A_VALUE5"));
assert (state.tableColumns.size() == 1) : " ERROR: more than 1 entry in tableCols";
Table t = CollectionUtil.first(state.tableColumns.keySet());
assert (t != null);
assert (t.getName().equals("TABLEA")) : "table " + t.getName() + " does not match TABLEA";
Set<Column> cols = CollectionUtil.first(state.tableColumns.values());
assert (cols.size() == 3) : "Size: " + cols.size() + " doesn't match 3";
assert (((Column) cols.toArray()[0]).getName().equals("A_ID")) : " first column: " + ((Column) cols.toArray()[0]).getName() + " doesn't match: " + " A_ID";
assert (((Column) cols.toArray()[1]).getName().equals("A_VALUE0")) : "second column: " + ((Column) cols.toArray()[1]).getName() + " doesn't match: " + " A_VALUE0";
assert (((Column) cols.toArray()[2]).getName().equals("A_VALUE5")) : "third column: " + ((Column) cols.toArray()[2]).getName() + " doesn't match: " + " A_VALUE5";
// add column A_VALUE3
state.addTableColumn(catalog_db.getTables().get("TABLEA").getColumns().get("A_VALUE3"));
// expect the order to be A_ID, A_VALUE0, A_VALUE3, A_VALUE5
Table t2 = CollectionUtil.first(state.tableColumns.keySet());
assert (t2 != null);
assert (t2.getName().equals("TABLEA")) : "table " + t2.getName() + " does not match TABLEA";
Set<Column> cols2 = CollectionUtil.first(state.tableColumns.values());
assert (cols2.size() == 4) : "Size: " + cols2.size() + " doesn't match 4";
assert (((Column) cols2.toArray()[0]).getName().equals("A_ID")) : " first column: " + ((Column) cols2.toArray()[0]).getName() + " doesn't match: " + " A_ID";
assert (((Column) cols2.toArray()[1]).getName().equals("A_VALUE0")) : "second column: " + ((Column) cols2.toArray()[1]).getName() + " doesn't match: " + " A_VALUE0";
assert (((Column) cols2.toArray()[2]).getName().equals("A_VALUE3")) : "third column: " + ((Column) cols2.toArray()[2]).getName() + " doesn't match: " + " A_VALUE3";
assert (((Column) cols2.toArray()[3]).getName().equals("A_VALUE5")) : "third column: " + ((Column) cols2.toArray()[3]).getName() + " doesn't match: " + " A_VALUE5";
}
/**
* testPopulateTableNodeInfo
*/
public void testPopulateTableNodeInfo() throws Exception {
Procedure catalog_proc = this.getProcedure("SingleProjection");
Statement catalog_stmt = this.getStatement(catalog_proc, "sql");
// Grab the root node of the multi-partition query plan tree for this Statement
AbstractPlanNode rootNode = PlanNodeUtil.getRootPlanNodeForStatement(catalog_stmt, false);
PlanOptimizerUtil.populateTableNodeInfo(state, rootNode);
// check two hashmaps contain what we expect
checkPlanNodeColumns(state.planNodeColumns);
checkTableColumns(state.tableColumns);
}
/**
* Checks a column gets properly added to tableColumns in the correct order
*/
public void testExtractColumnInfo() throws Exception {
Procedure catalog_proc = this.getProcedure("SingleProjection");
Statement catalog_stmt = this.getStatement(catalog_proc, "sql");
// Grab the root node of the multi-partition query plan tree for this Statement
AbstractPlanNode rootNode = PlanNodeUtil.getRootPlanNodeForStatement(catalog_stmt, false);
PlanOptimizerUtil.populateTableNodeInfo(state, rootNode);
// check two hashmaps contain what we expect
checkPlanNodeColumns(state.planNodeColumns);
checkTableColumns(state.tableColumns);
System.out.println("Root Node: " + rootNode + " output columns: " + rootNode.getOutputColumnGUIDs() + " child type: " + rootNode.getChild(0).getPlanNodeType());
// walk the tree and call extractColumnInfo on a rootNode
new PlanNodeTreeWalker(true) {
@Override
protected void callback(AbstractPlanNode element) {
// if (trace) LOG.trace(PlanNodeUtil.debugNode(element));
// call function to build the data structure that maps all nodes
// to the columns they affect
try {
if (this.getDepth() != 0) {
PlanOptimizerUtil.extractColumnInfo(state, element, false);
this.stop();
}
} catch (Exception ex) {
throw new RuntimeException("Failed to extract column information for " + element, ex);
}
}
}.traverse(rootNode);
// plan_opt.propagateProjections(rootNode);
// check planNodeColumns + tableColumns
System.out.println("planNodeColumns: " + state.planNodeColumns);
System.out.println("tableColumns: " + state.tableColumns);
System.out.println("column_guid_xref: " + state.column_guid_xref);
System.out.println("guid_column_xref: " + state.guid_column_xref);
System.out.println("orig_node_output: " + state.orig_node_output);
}
/**
* testExtractColumnInfo
*/
// @Test
// public void testExtractColumnInfo() throws Exception {
// Procedure catalog_proc = this.getProcedure("DistinctCount");
// Statement catalog_stmt = this.getStatement(catalog_proc, "sql");
//
// AbstractPlanNode root = PlanNodeUtil.getRootPlanNodeForStatement(catalog_stmt, true);
// assertNotNull(root);
// PlanOptimizerState state = new PlanOptimizerState(catalog_db, PlannerContext.singleton());
//
// Collection<SeqScanPlanNode> scan_nodes = PlanNodeUtil.getPlanNodes(root, SeqScanPlanNode.class);
// SeqScanPlanNode scan_node = CollectionUtil.first(scan_nodes);
// assertNotNull(scan_node);
//
// // Use the PlanOptimizerUtil to compute the referenced columns for this node
// PlanOptimizerUtil.populateTableNodeInfo(state, root);
//
// // Then make sure it has the right references
// Table catalog_tbl = this.getTable(scan_node.getTargetTableName());
// Set<Column> expected = new HashSet<Column>();
// for (Integer guid : scan_node.getOutputColumnGUIDs()) {
// PlanColumn pc = state.plannerContext.get(guid);
// assertNotNull(pc);
//
// Column catalog_col = catalog_tbl.getColumns().getIgnoreCase(pc.getDisplayName());
// assertNotNull(pc.toString(), catalog_col);
// expected.add(catalog_col);
// } // FOR
//
// Collection<Column> actual = state.getPlanNodeColumns(scan_node);
// assertNotNull(actual);
// assertEquals(expected.size(), actual.size());
// assertTrue(expected.containsAll(actual));
// }
}