Search in sources :

Example 46 with TupleValueExpression

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;
}
Also used : StmtSubqueryScan(org.voltdb.planner.parseinfo.StmtSubqueryScan) TupleValueExpression(org.voltdb.expressions.TupleValueExpression) Table(org.voltdb.catalog.Table) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) JSONException(org.json_voltpatches.JSONException) Index(org.voltdb.catalog.Index) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan) AbstractExpression(org.voltdb.expressions.AbstractExpression) Column(org.voltdb.catalog.Column) SchemaColumn(org.voltdb.plannodes.SchemaColumn) StmtTargetTableScan(org.voltdb.planner.parseinfo.StmtTargetTableScan) ArrayList(java.util.ArrayList) List(java.util.List) ColumnRef(org.voltdb.catalog.ColumnRef) HashSet(java.util.HashSet)

Example 47 with TupleValueExpression

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;
                }
            }
        }
    }
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) HashSet(java.util.HashSet) Set(java.util.Set) Table(org.voltdb.catalog.Table) Constraint(org.voltdb.catalog.Constraint) Index(org.voltdb.catalog.Index) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan) AbstractExpression(org.voltdb.expressions.AbstractExpression) Column(org.voltdb.catalog.Column) SchemaColumn(org.voltdb.plannodes.SchemaColumn) ConstantValueExpression(org.voltdb.expressions.ConstantValueExpression) ColumnRef(org.voltdb.catalog.ColumnRef) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression) HashSet(java.util.HashSet)

Example 48 with TupleValueExpression

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;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) Table(org.voltdb.catalog.Table) HashSet(java.util.HashSet) Set(java.util.Set) Index(org.voltdb.catalog.Index) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan) AbstractExpression(org.voltdb.expressions.AbstractExpression) Column(org.voltdb.catalog.Column) SchemaColumn(org.voltdb.plannodes.SchemaColumn) ConstantValueExpression(org.voltdb.expressions.ConstantValueExpression) ColumnRef(org.voltdb.catalog.ColumnRef) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression) HashSet(java.util.HashSet)

Example 49 with TupleValueExpression

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;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) VoltXMLElement(org.hsqldb_voltpatches.VoltXMLElement)

Example 50 with TupleValueExpression

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);
    }
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression)

Aggregations

TupleValueExpression (org.voltdb.expressions.TupleValueExpression)83 AbstractExpression (org.voltdb.expressions.AbstractExpression)59 SchemaColumn (org.voltdb.plannodes.SchemaColumn)19 Column (org.voltdb.catalog.Column)17 ArrayList (java.util.ArrayList)16 HashSet (java.util.HashSet)14 Constraint (org.voltdb.catalog.Constraint)13 Table (org.voltdb.catalog.Table)10 ColumnRef (org.voltdb.catalog.ColumnRef)9 ParameterValueExpression (org.voltdb.expressions.ParameterValueExpression)9 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)9 JSONException (org.json_voltpatches.JSONException)8 AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)8 NodeSchema (org.voltdb.plannodes.NodeSchema)8 ConstantValueExpression (org.voltdb.expressions.ConstantValueExpression)7 VoltXMLElement (org.hsqldb_voltpatches.VoltXMLElement)6 Set (java.util.Set)5 Index (org.voltdb.catalog.Index)5 StmtTargetTableScan (org.voltdb.planner.parseinfo.StmtTargetTableScan)5 ProjectionPlanNode (org.voltdb.plannodes.ProjectionPlanNode)5