use of org.voltdb.catalog.ColumnRef in project voltdb by VoltDB.
the class AbstractParsedStmt method addHonoraryOrderByExpressions.
/**
* Given a set of order-by expressions and a select list, which is a list of
* columns, each with an expression and an alias, expand the order-by list
* with new expressions which could be on the order-by list without changing
* the sort order and which are otherwise helpful.
*/
protected void addHonoraryOrderByExpressions(HashSet<AbstractExpression> orderByExprs, List<ParsedColInfo> candidateColumns) {
// of joins is the content of ticket ENG-8677.
if (m_tableAliasMap.size() != 1) {
return;
}
HashMap<AbstractExpression, Set<AbstractExpression>> valueEquivalence = analyzeValueEquivalence();
for (ParsedColInfo colInfo : candidateColumns) {
AbstractExpression colExpr = colInfo.expression;
if (colExpr instanceof TupleValueExpression) {
Set<AbstractExpression> tveEquivs = valueEquivalence.get(colExpr);
if (tveEquivs != null) {
for (AbstractExpression expr : tveEquivs) {
if (expr instanceof ParameterValueExpression || expr instanceof ConstantValueExpression) {
orderByExprs.add(colExpr);
}
}
}
}
}
// We know there's exactly one.
StmtTableScan scan = m_tableAliasMap.values().iterator().next();
// Get the table. There's only one.
Table table = getTableFromDB(scan.getTableName());
// there's no use to continue.
if (table == null) {
return;
}
// Now, look to see if there is a constraint which can help us.
// If there is a unique constraint on a set of columns, and all
// the constrained columns are in the order by list, then all
// the columns in the table can be added to the order by list.
//
// The indices we care about have columns, but the order by list has expressions.
// Extract the columns from the order by list.
Set<Column> orderByColumns = new HashSet<>();
for (AbstractExpression expr : orderByExprs) {
if (expr instanceof TupleValueExpression) {
TupleValueExpression tve = (TupleValueExpression) expr;
Column col = table.getColumns().get(tve.getColumnName());
orderByColumns.add(col);
}
}
CatalogMap<Constraint> constraints = table.getConstraints();
// If we have no constraints, there's nothing more to do here.
if (constraints == null) {
return;
}
Set<Index> indices = new HashSet<>();
for (Constraint constraint : constraints) {
Index index = constraint.getIndex();
// Only use column indices for now.
if (index != null && index.getUnique() && index.getExpressionsjson().isEmpty()) {
indices.add(index);
}
}
for (ParsedColInfo colInfo : candidateColumns) {
AbstractExpression expr = colInfo.expression;
if (expr instanceof TupleValueExpression) {
TupleValueExpression tve = (TupleValueExpression) expr;
// So, we remember this and early-out.
for (Index index : indices) {
CatalogMap<ColumnRef> columns = index.getColumns();
// If all the columns in this index are in the current
// honorary order by list, then we can add all the
// columns in this table to the honorary order by list.
boolean addAllColumns = true;
for (ColumnRef cr : columns) {
Column col = cr.getColumn();
if (orderByColumns.contains(col) == false) {
addAllColumns = false;
break;
}
}
if (addAllColumns) {
for (Column addCol : table.getColumns()) {
// We have to convert this to a TVE to add
// it to the orderByExprs. We will use -1
// for the column index. We don't have a column
// alias.
TupleValueExpression ntve = new TupleValueExpression(tve.getTableName(), tve.getTableAlias(), addCol.getName(), null, -1);
orderByExprs.add(ntve);
}
// Don't forget to remember to forget the other indices. (E. Presley, 1955)
break;
}
}
}
}
}
use of org.voltdb.catalog.ColumnRef in project voltdb by VoltDB.
the class AbstractParsedStmt method producesOneRowOutput.
// Function evaluates whether the statement results in at most
// one output row. This is implemented for single table by checking
// value equivalence of predicates in where clause and checking
// if all defined unique indexes are in value equivalence set.
// Returns true if the statement results is at most one output
// row else false
protected boolean producesOneRowOutput() {
if (m_tableAliasMap.size() != 1) {
return false;
}
// Get the table. There's only one.
StmtTableScan scan = m_tableAliasMap.values().iterator().next();
Table table = getTableFromDB(scan.getTableName());
// May be sub-query? If can't find the table there's no use to continue.
if (table == null) {
return false;
}
// Get all the indexes defined on the table
CatalogMap<Index> indexes = table.getIndexes();
if (indexes == null || indexes.size() == 0) {
// no indexes defined on the table
return false;
}
// Collect value equivalence expression for the SQL statement
HashMap<AbstractExpression, Set<AbstractExpression>> valueEquivalence = analyzeValueEquivalence();
// If no value equivalence filter defined in SQL statement, there's no use to continue
if (valueEquivalence.isEmpty()) {
return false;
}
// Collect all tve expressions from value equivalence set which have equivalence
// defined to parameterized or constant value expression.
// Eg: T.A = ? or T.A = 1
Set<AbstractExpression> parameterizedConstantKeys = new HashSet<>();
// get all the keys
Set<AbstractExpression> valueEquivalenceKeys = valueEquivalence.keySet();
for (AbstractExpression key : valueEquivalenceKeys) {
if (key instanceof TupleValueExpression) {
Set<AbstractExpression> values = valueEquivalence.get(key);
for (AbstractExpression value : values) {
if ((value instanceof ParameterValueExpression) || (value instanceof ConstantValueExpression)) {
TupleValueExpression tve = (TupleValueExpression) key;
parameterizedConstantKeys.add(tve);
}
}
}
}
// index defined on table appears in tve equivalence expression gathered above.
for (Index index : indexes) {
// Perform lookup only on pure column indices which are unique
if (!index.getUnique() || !index.getExpressionsjson().isEmpty()) {
continue;
}
Set<AbstractExpression> indexExpressions = new HashSet<>();
CatalogMap<ColumnRef> indexColRefs = index.getColumns();
for (ColumnRef indexColRef : indexColRefs) {
Column col = indexColRef.getColumn();
TupleValueExpression tve = new TupleValueExpression(scan.getTableName(), scan.getTableAlias(), col.getName(), col.getName(), col.getIndex());
indexExpressions.add(tve);
}
if (parameterizedConstantKeys.containsAll(indexExpressions)) {
return true;
}
}
return false;
}
use of org.voltdb.catalog.ColumnRef in project voltdb by VoltDB.
the class SwapTablesPlanNode method indexesCanBeSwapped.
/**
* @param theIndex candidate match for otherIndex on the target table
* @param otherIndex candidate match for theIndex on the other target table
* @param candidateIndexSet set of otherTable indexes as yet unmatched
*/
private static boolean indexesCanBeSwapped(Index theIndex, Index otherIndex) {
// Pairs of matching indexes must agree on type (int hash, etc.).
if (theIndex.getType() != otherIndex.getType()) {
return false;
}
// Pairs of matching indexes must agree whether they are (assume)unique.
if (theIndex.getUnique() != otherIndex.getUnique() || theIndex.getAssumeunique() != otherIndex.getAssumeunique()) {
return false;
}
// Pairs of matching indexes must agree whether they are partial
// and if so, agree on the predicate.
String thePredicateJSON = theIndex.getPredicatejson();
String otherPredicateJSON = otherIndex.getPredicatejson();
if (thePredicateJSON == null) {
if (otherPredicateJSON != null) {
return false;
}
} else if (!thePredicateJSON.equals(otherPredicateJSON)) {
return false;
}
// Pairs of matching indexes must agree that they do or do not index
// expressions and, if so, agree on the expressions.
String theExprsJSON = theIndex.getExpressionsjson();
String otherExprsJSON = otherIndex.getExpressionsjson();
if (theExprsJSON == null) {
if (otherExprsJSON != null) {
return false;
}
} else if (!theExprsJSON.equals(otherExprsJSON)) {
return false;
}
// Indexes must agree on the columns they are based on,
// identifiable by the columns' order in the table.
CatalogMap<ColumnRef> theColumns = theIndex.getColumns();
int theColumnCount = theColumns.size();
CatalogMap<ColumnRef> otherColumns = otherIndex.getColumns();
if (theColumnCount != otherColumns.size()) {
return false;
}
Iterator<ColumnRef> theColumnIterator = theColumns.iterator();
Iterator<ColumnRef> otherColumnIterator = otherColumns.iterator();
for (int ii = 0; ii < theColumnCount; ++ii) {
int theColIndex = theColumnIterator.next().getColumn().getIndex();
int otherColIndex = otherColumnIterator.next().getColumn().getIndex();
if (theColIndex != otherColIndex) {
return false;
}
}
return true;
}
use of org.voltdb.catalog.ColumnRef in project voltdb by VoltDB.
the class SwapTablesPlanNode method diagnoseIndexMismatch.
/**
* Give two strings, return a list of attributes that do not match
* @param theIndex
* @param otherIndex
* @return list of attributes that do not match
*/
private List<String> diagnoseIndexMismatch(Index theIndex, Index otherIndex) {
List<String> mismatchedAttrs = new ArrayList<>();
// Pairs of matching indexes must agree on type (int hash, etc.).
if (theIndex.getType() != otherIndex.getType()) {
mismatchedAttrs.add("index type (hash vs tree)");
}
// Pairs of matching indexes must agree whether they are (assume)unique.
if (theIndex.getUnique() != otherIndex.getUnique() || theIndex.getAssumeunique() != otherIndex.getAssumeunique()) {
mismatchedAttrs.add("UNIQUE attribute");
}
// Pairs of matching indexes must agree whether they are partial
// and if so, agree on the predicate.
String thePredicateJSON = theIndex.getPredicatejson();
String otherPredicateJSON = otherIndex.getPredicatejson();
if (thePredicateJSON == null) {
if (otherPredicateJSON != null) {
mismatchedAttrs.add("WHERE predicate");
}
} else if (!thePredicateJSON.equals(otherPredicateJSON)) {
mismatchedAttrs.add("WHERE predicate");
}
// Pairs of matching indexes must agree that they do or do not index
// expressions and, if so, agree on the expressions.
String theExprsJSON = theIndex.getExpressionsjson();
String otherExprsJSON = otherIndex.getExpressionsjson();
if (theExprsJSON == null) {
if (otherExprsJSON != null) {
mismatchedAttrs.add("indexed expression");
}
} else if (!theExprsJSON.equals(otherExprsJSON)) {
mismatchedAttrs.add("indexed expression");
}
// Indexes must agree on the columns they are based on,
// identifiable by the columns' order in the table.
CatalogMap<ColumnRef> theColumns = theIndex.getColumns();
int theColumnCount = theColumns.size();
CatalogMap<ColumnRef> otherColumns = otherIndex.getColumns();
if (theColumnCount != otherColumns.size()) {
mismatchedAttrs.add("indexed expression");
}
Iterator<ColumnRef> theColumnIterator = theColumns.iterator();
Iterator<ColumnRef> otherColumnIterator = otherColumns.iterator();
for (int ii = 0; ii < theColumnCount; ++ii) {
int theColIndex = theColumnIterator.next().getColumn().getIndex();
int otherColIndex = otherColumnIterator.next().getColumn().getIndex();
if (theColIndex != otherColIndex) {
mismatchedAttrs.add("indexed expression");
}
}
return mismatchedAttrs;
}
use of org.voltdb.catalog.ColumnRef in project voltdb by VoltDB.
the class IndexCountPlanNode method explainPlanForNode.
@Override
protected String explainPlanForNode(String indent) {
assert (m_catalogIndex != null);
int indexSize = CatalogUtil.getCatalogIndexSize(m_catalogIndex);
int searchkeySize = m_searchkeyExpressions.size();
int endkeySize = m_endkeyExpressions.size();
int keySize = Math.max(searchkeySize, endkeySize);
String scanType = "tree-counter";
String cover = "covering";
if (indexSize > keySize)
cover = String.format("%d/%d cols", keySize, indexSize);
String usageInfo = String.format("(%s %s)", scanType, cover);
String[] asIndexed = new String[indexSize];
// they beat an NPE.
for (int ii = 0; ii < keySize; ++ii) {
asIndexed[ii] = "(index key " + ii + ")";
}
String jsonExpr = m_catalogIndex.getExpressionsjson();
// if this is a pure-column index...
if (jsonExpr.isEmpty()) {
// grab the short names of the indexed columns in use.
for (ColumnRef cref : m_catalogIndex.getColumns()) {
Column col = cref.getColumn();
asIndexed[cref.getIndex()] = col.getName();
}
} else {
try {
List<AbstractExpression> indexExpressions = AbstractExpression.fromJSONArrayString(jsonExpr, m_tableScan);
int ii = 0;
for (AbstractExpression ae : indexExpressions) {
asIndexed[ii++] = ae.explain(m_targetTableName);
}
} catch (JSONException e) {
// If something unexpected went wrong,
// just fall back on the positional key labels.
}
}
// "(event_type = 1 AND event_start > x.start_time)"
if (searchkeySize > 0) {
String start = explainKeys(asIndexed, m_searchkeyExpressions, m_targetTableName, m_lookupType, m_compareNotDistinct);
usageInfo += "\n" + indent + " count matches from " + start;
}
if (endkeySize > 0) {
String end = explainKeys(asIndexed, m_endkeyExpressions, m_targetTableName, m_endType, m_compareNotDistinct);
usageInfo += "\n" + indent + " count matches to " + end;
}
if (m_skip_null_predicate != null) {
String predicate = m_skip_null_predicate.explain(m_targetTableName);
usageInfo += "\n" + indent + " discounting rows where " + predicate;
}
// Describe the table name and either a user-provided name of the index or
// its user-specified role ("primary key").
String retval = "INDEX COUNT of \"" + m_targetTableName + "\"";
String indexDescription = " using \"" + m_targetIndexName + "\"";
// Replace ugly system-generated index name with a description of its user-specified role.
if (m_targetIndexName.startsWith(HSQLInterface.AUTO_GEN_PRIMARY_KEY_PREFIX) || m_targetIndexName.startsWith(HSQLInterface.AUTO_GEN_NAMED_CONSTRAINT_IDX) || m_targetIndexName.equals(HSQLInterface.AUTO_GEN_MATVIEW_IDX)) {
indexDescription = " using its primary key index";
}
// Bring all the pieces together describing the index, how it is scanned,
// and whatever extra filter processing is done to the result.
retval += indexDescription;
retval += usageInfo;
return retval;
}
Aggregations