} else if (frag_cache.isValid()) {
assert (!frag_cache.isValid()) : "Cache entry for " + CatalogUtil.getDisplayName(catalog_frag) + " is marked as valid when we were expecting to be invalid\n" + this.toString();
frag_cache.setValid();
}
AbstractPlanNode root = PlanNodeUtil.getPlanNodeTreeForPlanFragment(catalog_frag);
Collection<Table> frag_tables = CatalogUtil.getReferencedTablesForTree(catalogContext.database, root);
// Table tables_arr[] = new Table[frag_tables.size()];
// tables_arr = frag_tables.toArray(tables_arr);
// assert (tables_arr.length == frag_tables.size());
if (trace.val)
LOG.trace("Analyzing " + catalog_frag.fullName());
// Check whether the predicate expression in this PlanFragment contains an OR
// We need to know this if we get hit with Multi-Column Partitioning
// XXX: Why does this matter??
Collection<ExpressionType> exp_types = PlanNodeUtil.getScanExpressionTypes(root);
if (exp_types.contains(ExpressionType.CONJUNCTION_OR)) {
if (debug.val)
LOG.warn(String.format("%s contains %s. Cannot be used with multi-column partitioning",
catalog_frag.fullName(), ExpressionType.CONJUNCTION_OR));
stmt_cache.markContainsOR(true);
frag_cache.markContainsOR(true);
}
// If there are no tables, then we need to double check that the "non-transactional"
// flag is set for the fragment. This means that this fragment does not operate directly
// on a persistent table in the database. We'll add an entry in the cache using our
// special "no tables" flag. This means that the fragment needs to be executed locally.
if (frag_tables.isEmpty()) {
String msg = catalog_frag.fullName() + " does not reference any tables";
if (!catalog_frag.getNontransactional()) {
LOG.warn(catalog_stmt.fullName() + "\n" + PlanNodeUtil.debug(PlanNodeUtil.getRootPlanNodeForStatement(catalog_stmt, false)));
for (PlanFragment f : fragments) {
LOG.warn("singlePartiton=" + singlesited + " - " + f.fullName() + "\n" + PlanNodeUtil.debug(PlanNodeUtil.getPlanNodeTreeForPlanFragment(f)));
}
throw new Exception(msg + " but the non-transactional flag is not set");
}
if (trace.val)
LOG.trace(msg);
}
if (trace.val && frag_tables.isEmpty() == false )
LOG.trace("Fragment Tables: " + frag_tables);
// We only need to find where the partition column is referenced
// If it's not in there, then this query has to be broadcasted to all nodes
// Note that we pass all the tables that are part of the fragment, since
// we need to be able to handle joins
PredicatePairs predicates = CatalogUtil.extractFragmentPredicates(catalog_frag, false, frag_tables);
assert (predicates != null);
Map<Column, Set<Column>> column_joins = new TreeMap<Column, Set<Column>>();
if (trace.val)
LOG.trace("Extracted PredicatePairs for " + frag_tables + ":\n" + predicates.debug());
// -------------------------------
// If there are no columns, then this fragment is doing a full table scan
// -------------------------------
if (predicates.isEmpty() && frag_tables.size() > 0) {
if (trace.val)
LOG.trace("No columns accessed in " + catalog_frag + " despite reading " + frag_tables.size() + " tables");
stmt_cache.markAsBroadcast(frag_tables);
frag_cache.markAsBroadcast(frag_tables);
}
// -------------------------------
// Fragment references the columns for our tables. Pick them apart!
// -------------------------------
else {
// First go through all the entries and add any mappings from
// Columns to StmtParameters to our stmt_cache
for (CatalogPair pair : predicates) {
if (trace.val)
LOG.trace(String.format("Examining extracted %s: %s",
pair.getClass().getSimpleName(), pair));
// Column = Column
if (pair.getFirst() instanceof Column && pair.getSecond() instanceof Column) {
Column col0 = (Column) pair.getFirst();
Column col1 = (Column) pair.getSecond();
// If this table is a view, then we need to check whether
// we have to point the column down to the origin column
if (col0.getMatviewsource() != null) {
col0 = col0.getMatviewsource();
}
if (col1.getMatviewsource() != null) {
col1 = col1.getMatviewsource();
}
if (!pair.getComparisonExp().equals(ExpressionType.COMPARE_EQUAL)) {
if (debug.val)
LOG.warn(String.format("Unsupported non-equality join in %s: %s",
catalog_stmt.fullName(), pair));
} else {
if (!column_joins.containsKey(col0))
column_joins.put(col0, new TreeSet<Column>());
if (!column_joins.containsKey(col1))
column_joins.put(col1, new TreeSet<Column>());
column_joins.get(col0).add(col1);
column_joins.get(col1).add(col0);
}
continue;
}
// Look for predicates with StmtParameters or ConstantValues
for (Table catalog_tbl : frag_tables) {
Column catalog_col = null;
CatalogType catalog_param = null;
// *********************************** DEBUG ***********************************
if (trace.val) {
LOG.trace("Current Table: " + catalog_tbl.hashCode());
if (pair.getFirst() != null) {
LOG.trace("entry.getFirst().getParent(): " + (pair.getFirst().getParent() != null ?
pair.getFirst().getParent().hashCode() :
pair.getFirst() + " parent is null?"));
if (pair.getFirst().getParent() instanceof Table) {
Table parent = pair.getFirst().getParent();
if (parent.getName().equals(catalog_tbl.getName())) {
assert(parent.equals(catalog_tbl)) :
"Mismatch on " + parent.getName() + "???";
}
}
} else {
LOG.trace("entry.getFirst(): " + null);
}
if (pair.getSecond() != null) {
LOG.trace("entry.getSecond().getParent(): " + (pair.getSecond().getParent() != null ?
pair.getSecond().getParent().hashCode() :
pair.getSecond() + " parent is null?"));
} else {
LOG.trace("entry.getSecond(): " + null);
}
}
// *********************************** DEBUG ***********************************
// Column = (StmtParameter or ConstantValue)
if (pair.getFirst().getParent() != null && pair.getFirst().getParent().equals(catalog_tbl) &&
(pair.getSecond() instanceof StmtParameter || pair.getSecond() instanceof ConstantValue) ) {
catalog_col = (Column) pair.getFirst();
catalog_param = pair.getSecond();
}
// (StmtParameter or ConstantValue) = Column
else if (pair.getSecond().getParent() != null && pair.getSecond().getParent().equals(catalog_tbl) &&
(pair.getFirst() instanceof StmtParameter || pair.getFirst() instanceof ConstantValue)) {
catalog_col = (Column) pair.getSecond();
catalog_param = pair.getFirst();
}
if (catalog_col != null && catalog_param != null) {
// If this table is a view, then we need to check whether
// we have to point the column down to the origin column
if (catalog_col.getMatviewsource() != null) {
if (debug.val)
LOG.debug("Found View Column: " + catalog_col.fullName() + " -> " + catalog_col.getMatviewsource().fullName());
catalog_col = catalog_col.getMatviewsource();
}
if (trace.val)
LOG.trace(String.format("[%s] Adding cache entry for %s: %s -> %s",
CatalogUtil.getDisplayName(catalog_tbl),
CatalogUtil.getDisplayName(catalog_frag),
CatalogUtil.getDisplayName(catalog_col),
CatalogUtil.getDisplayName(catalog_param)));
stmt_cache.put(catalog_col, catalog_param, pair.getComparisonExp(), catalog_tbl);
frag_cache.put(catalog_col, catalog_param, pair.getComparisonExp(), catalog_tbl);
}
} // FOR (tables)
if (trace.val)
LOG.trace("-------------------");
} // FOR (entry)
// We now have to take a second pass through the column mappings
// This will pick-up those columns that are joined together where one of them
// is also referenced with an input parameter. So we will map the input
// parameter to the second column as well
PartitionEstimator.populateColumnJoinSets(column_joins);
for (Column catalog_col : column_joins.keySet()) {
// Otherwise, we have to examine the the ColumnSet and
// look for any reference to this column
if (trace.val)
LOG.trace("Trying to find all references to " + CatalogUtil.getDisplayName(catalog_col));
for (Column other_col : column_joins.get(catalog_col)) {
// IMPORTANT: If the other entry is a column from another table and we don't
// have a reference in stmt_cache for ourselves, then we can look to see if
// this guy was used against a StmtParameter some where else in the Statement
// If this is the case, then we can substitute that mofo in it's place
if (stmt_cache.predicates.containsKey(catalog_col)) {
for (Pair<ExpressionType, CatalogType> pair : stmt_cache.predicates.get(catalog_col)) {
if (trace.val)
LOG.trace(String.format("Linking %s to predicate %s because of %s",
other_col.fullName(), pair, catalog_col.fullName()));
ExpressionType expType = pair.getFirst();
CatalogType param = pair.getSecond();
stmt_cache.put(other_col, param, expType, (Table)other_col.getParent());
frag_cache.put(other_col, param, expType, (Table)other_col.getParent());
} // FOR (StmtParameter.Index)
}
} // FOR (Column)
} // FOR (Column)
}
if (trace.val)
LOG.trace(frag_cache.toString());
// Loop through all of our tables and make sure that there is an entry in the PlanFragment CacheEntrry
// If there isn't, then that means there was no predicate on the table and therefore the PlanFragment
// must be broadcast to all partitions (unless it is replicated)
for (Table catalog_tbl : frag_tables) {
if (!frag_cache.hasTable(catalog_tbl)) {
if (trace.val)
LOG.trace(String.format("No column predicate for %s. Marking as broadcast for %s: %s",
catalog_tbl.fullName(), catalog_frag.fullName(), frag_cache.getTables()));
frag_cache.markAsBroadcast(catalog_tbl);
stmt_cache.markAsBroadcast(catalog_tbl);
}
} // FOR
// Store the Fragment cache and update the Table xref mapping
this.cache_fragmentEntries.put(frag_key, frag_cache);
this.addTableCacheXref(frag_cache, frag_tables);
} // FOR (fragment)
// Then for updates we need to look to see whether they are updating an attribute
// that they are partitioned on. If so, then it gets dicey because we need to
// know the value...
if (stmt_type == QueryType.UPDATE) {
List<Table> tables = new ArrayList<Table>();
PredicatePairs update_cset = new PredicatePairs();
for (Table catalog_tbl : CatalogUtil.getReferencedTables(catalog_stmt)) {
update_cset.clear();
tables.clear();
tables.add(catalog_tbl);
AbstractPlanNode root_node = PlanNodeUtil.getRootPlanNodeForStatement(catalog_stmt, true);
CatalogUtil.extractUpdatePredicates(catalog_stmt, catalogContext.database, update_cset, root_node, true, tables);
boolean found = false;
for (CatalogPair pair : update_cset) {
Column catalog_col = null;