use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.
the class AbstractParsedStmt method orderByColumnsCoverUniqueKeys.
/**
* Order by Columns or expressions has to operate on the display columns or expressions.
* @return
*/
protected boolean orderByColumnsCoverUniqueKeys() {
// In theory, if EVERY table in the query has a uniqueness constraint
// (primary key or other unique index) on columns that are all listed in the ORDER BY values,
// the result is deterministic.
// This holds regardless of whether the associated index is actually used in the selected plan,
// so this check is plan-independent.
//
// baseTableAliases associates table aliases with the order by
// expressions which reference them. Presumably by using
// table aliases we will map table scans to expressions rather
// than tables to expressions, and not confuse ourselves with
// different instances of the same table in self joins.
HashMap<String, List<AbstractExpression>> baseTableAliases = new HashMap<>();
for (ParsedColInfo col : orderByColumns()) {
AbstractExpression expr = col.expression;
//
// Compute the set of tables mentioned in the expression.
// 1. Search out all the TVEs.
// 2. Throw the aliases of the tables of each of these into a HashSet.
// The table must have an alias. It might not have a name.
// 3. If the HashSet has size > 1 we can't use this expression.
//
List<TupleValueExpression> baseTVEExpressions = expr.findAllTupleValueSubexpressions();
Set<String> baseTableNames = new HashSet<>();
for (TupleValueExpression tve : baseTVEExpressions) {
String tableAlias = tve.getTableAlias();
assert (tableAlias != null);
baseTableNames.add(tableAlias);
}
if (baseTableNames.size() != 1) {
// Neither are (nonsense) constant (table-less) expressions.
continue;
}
// Everything in the baseTVEExpressions table is a column
// in the same table and has the same alias. So just grab the first one.
// All we really want is the alias.
AbstractExpression baseTVE = baseTVEExpressions.get(0);
String nextTableAlias = ((TupleValueExpression) baseTVE).getTableAlias();
// and disappear.
assert (nextTableAlias != null);
List<AbstractExpression> perTable = baseTableAliases.get(nextTableAlias);
if (perTable == null) {
perTable = new ArrayList<>();
baseTableAliases.put(nextTableAlias, perTable);
}
perTable.add(expr);
}
if (m_tableAliasMap.size() > baseTableAliases.size()) {
// like Unique Index nested loop join, etc.
return false;
}
boolean allScansAreDeterministic = true;
for (Entry<String, List<AbstractExpression>> orderedAlias : baseTableAliases.entrySet()) {
List<AbstractExpression> orderedAliasExprs = orderedAlias.getValue();
StmtTableScan tableScan = getStmtTableScanByAlias(orderedAlias.getKey());
if (tableScan == null) {
assert (false);
return false;
}
if (tableScan instanceof StmtSubqueryScan) {
// don't yet handle FROM clause subquery, here.
return false;
}
Table table = ((StmtTargetTableScan) tableScan).getTargetTable();
// This table's scans need to be proven deterministic.
allScansAreDeterministic = false;
// Search indexes for one that makes the order by deterministic
for (Index index : table.getIndexes()) {
// skip non-unique indexes
if (!index.getUnique()) {
continue;
}
// get the list of expressions for the index
List<AbstractExpression> indexExpressions = new ArrayList<>();
String jsonExpr = index.getExpressionsjson();
// if this is a pure-column index...
if (jsonExpr.isEmpty()) {
for (ColumnRef cref : index.getColumns()) {
Column col = cref.getColumn();
TupleValueExpression tve = new TupleValueExpression(table.getTypeName(), orderedAlias.getKey(), col.getName(), col.getName(), col.getIndex());
indexExpressions.add(tve);
}
} else // if this is a fancy expression-based index...
{
try {
indexExpressions = AbstractExpression.fromJSONArrayString(jsonExpr, tableScan);
} catch (JSONException e) {
e.printStackTrace();
assert (false);
continue;
}
}
// ORDER BY A.unique_id, A.b_id
if (orderedAliasExprs.containsAll(indexExpressions)) {
allScansAreDeterministic = true;
break;
}
}
// ALL tables' scans need to have proved deterministic
if (!allScansAreDeterministic) {
return false;
}
}
return true;
}
use of org.voltdb.expressions.TupleValueExpression 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.expressions.TupleValueExpression 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.expressions.TupleValueExpression in project voltdb by VoltDB.
the class ParsedColInfo method fromOrderByXml.
/** Construct a ParsedColInfo from Volt XML.
* Allow caller to specify actions to finalize the parsed expression.
*/
public static ParsedColInfo fromOrderByXml(AbstractParsedStmt parsedStmt, VoltXMLElement orderByXml, ExpressionAdjuster adjuster) {
// make sure everything is kosher
assert (orderByXml.name.equalsIgnoreCase("orderby"));
// get desc/asc
String desc = orderByXml.attributes.get("desc");
boolean descending = (desc != null) && (desc.equalsIgnoreCase("true"));
// get the columnref or other expression inside the orderby node
VoltXMLElement child = orderByXml.children.get(0);
assert (child != null);
// create the orderby column
ParsedColInfo orderCol = new ParsedColInfo();
orderCol.orderBy = true;
orderCol.ascending = !descending;
AbstractExpression orderExpr = parsedStmt.parseExpressionTree(child);
assert (orderExpr != null);
orderCol.expression = adjuster.adjust(orderExpr);
// right thing later.
if (orderExpr instanceof TupleValueExpression) {
TupleValueExpression tve = (TupleValueExpression) orderExpr;
orderCol.columnName = tve.getColumnName();
orderCol.tableName = tve.getTableName();
orderCol.tableAlias = tve.getTableAlias();
if (orderCol.tableAlias == null) {
orderCol.tableAlias = orderCol.tableName;
}
orderCol.alias = tve.getColumnAlias();
} else {
String alias = child.attributes.get("alias");
orderCol.alias = alias;
orderCol.tableName = AbstractParsedStmt.TEMP_TABLE_NAME;
orderCol.tableAlias = AbstractParsedStmt.TEMP_TABLE_NAME;
orderCol.columnName = "";
if ((child.name.equals("operation") == false) && (child.name.equals("aggregation") == false) && (child.name.equals("win_aggregation") == false) && (child.name.equals("function") == false) && (child.name.equals("rank") == false) && (child.name.equals("value") == false) && (child.name.equals("columnref") == false)) {
throw new RuntimeException("ORDER BY parsed with strange child node type: " + child.name);
}
}
return orderCol;
}
use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.
the class MockPlanNode method generateOutputSchema.
@Override
public void generateOutputSchema(Database db) {
m_outputSchema = new NodeSchema();
m_hasSignificantOutputSchema = true;
for (int i = 0; i < m_columnNames.length; ++i) {
String colName = m_columnNames[i];
TupleValueExpression tve = new TupleValueExpression(m_tableName, m_tableName, colName, colName, i);
m_outputSchema.addColumn(m_tableName, m_tableName, colName, colName, tve);
}
}
Aggregations