Search in sources :

Example 11 with StmtTargetTableScan

use of org.voltdb.planner.parseinfo.StmtTargetTableScan 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 12 with StmtTargetTableScan

use of org.voltdb.planner.parseinfo.StmtTargetTableScan in project voltdb by VoltDB.

the class AbstractParsedStmt method addSimplifiedSubqueryToStmtCache.

/**
     * Replace an existing subquery scan with its underlying table scan. The subquery
     * has already passed all the checks from the canSimplifySubquery method.
     * Subquery ORDER BY clause is ignored if such exists.
     *
     * @param subqueryScan subquery scan to simplify
     * @param tableAlias
     * @return StmtTargetTableScan
     */
private StmtTargetTableScan addSimplifiedSubqueryToStmtCache(StmtSubqueryScan subqueryScan, StmtTargetTableScan tableScan) {
    String tableAlias = subqueryScan.getTableAlias();
    assert (tableAlias != null);
    // It is guaranteed by the canSimplifySubquery that there is
    // one and only one TABLE in the subquery's FROM clause.
    Table promotedTable = tableScan.getTargetTable();
    StmtTargetTableScan promotedScan = new StmtTargetTableScan(promotedTable, tableAlias, m_stmtId);
    // Keep the original subquery scan to be able to tie the parent
    // statement column/table names and aliases to the table's.
    promotedScan.setOriginalSubqueryScan(subqueryScan);
    // Replace the subquery scan with the table scan
    StmtTableScan prior = m_tableAliasMap.put(tableAlias, promotedScan);
    assert (prior == subqueryScan);
    m_tableList.add(promotedTable);
    return promotedScan;
}
Also used : Table(org.voltdb.catalog.Table) StmtTargetTableScan(org.voltdb.planner.parseinfo.StmtTargetTableScan) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan)

Example 13 with StmtTargetTableScan

use of org.voltdb.planner.parseinfo.StmtTargetTableScan in project voltdb by VoltDB.

the class AbstractParsedStmt method simplifierForSubquery.

/**
     * Verify if a subquery can be replaced with a direct select from table(s)
     * @param subquery
     * @return TRUE/FALSE
     */
private StmtTargetTableScan simplifierForSubquery(AbstractParsedStmt subquery) {
    // Must be a SELECT statement (not a SET operation)
    if (!(subquery instanceof ParsedSelectStmt)) {
        return null;
    }
    ParsedSelectStmt selectSubquery = (ParsedSelectStmt) subquery;
    // No aggregation and/or GROUP BY is allowed
    if (selectSubquery.hasAggregateOrGroupby()) {
        return null;
    }
    // No DISTINCT
    if (selectSubquery.hasAggregateDistinct()) {
        return null;
    }
    // No windowed aggregate functions like RANK.
    if (selectSubquery.hasWindowFunctionExpression()) {
        return null;
    }
    // No LIMIT/OFFSET
    if (selectSubquery.hasLimitOrOffset() || selectSubquery.hasLimitOrOffsetParameters()) {
        return null;
    }
    // Only SELECT from a single TARGET TABLE is allowed
    int tableCount = 0;
    StmtTargetTableScan simpler = null;
    for (Map.Entry<String, StmtTableScan> entry : selectSubquery.m_tableAliasMap.entrySet()) {
        if (entry.getKey().startsWith(AbstractParsedStmt.TEMP_TABLE_NAME)) {
            // This is an artificial table for a subquery expression
            continue;
        }
        if (++tableCount > 1) {
            return null;
        }
        // Only allow one TARGET TABLE, not a nested subquery.
        StmtTableScan scan = entry.getValue();
        if (scan instanceof StmtTargetTableScan) {
            simpler = (StmtTargetTableScan) scan;
        } else {
            return null;
        }
    }
    return simpler;
}
Also used : StmtTargetTableScan(org.voltdb.planner.parseinfo.StmtTargetTableScan) HashMap(java.util.HashMap) Map(java.util.Map) TreeMap(java.util.TreeMap) CatalogMap(org.voltdb.catalog.CatalogMap) Constraint(org.voltdb.catalog.Constraint) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan)

Example 14 with StmtTargetTableScan

use of org.voltdb.planner.parseinfo.StmtTargetTableScan in project voltdb by VoltDB.

the class AggregatePlanNode method isTableCountNonDistinctNullableColumn.

public boolean isTableCountNonDistinctNullableColumn() {
    if (!isTableNonDistinctCount()) {
        return false;
    }
    // Is the expression a column?
    AbstractExpression aggArgument = m_aggregateExpressions.get(0);
    if (!aggArgument.getExpressionType().equals(ExpressionType.VALUE_TUPLE)) {
        return false;
    }
    // If the query is a join query then the child will be something like nested loop.
    assert (m_children.size() == 1);
    if (!(m_children.get(0) instanceof AbstractScanPlanNode)) {
        return false;
    }
    AbstractScanPlanNode asp = (AbstractScanPlanNode) m_children.get(0);
    if (!(asp.getTableScan() instanceof StmtTargetTableScan)) {
        return false;
    }
    StmtTargetTableScan sttscan = (StmtTargetTableScan) asp.getTableScan();
    Table tbl = sttscan.getTargetTable();
    TupleValueExpression tve = (TupleValueExpression) aggArgument;
    String columnName = tve.getColumnName();
    Column col = tbl.getColumns().get(columnName);
    // Is the column nullable?
    if (col.getNullable()) {
        return false;
    }
    return true;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) Table(org.voltdb.catalog.Table) AbstractExpression(org.voltdb.expressions.AbstractExpression) Column(org.voltdb.catalog.Column) StmtTargetTableScan(org.voltdb.planner.parseinfo.StmtTargetTableScan)

Aggregations

StmtTargetTableScan (org.voltdb.planner.parseinfo.StmtTargetTableScan)14 Table (org.voltdb.catalog.Table)9 AbstractExpression (org.voltdb.expressions.AbstractExpression)8 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)7 Column (org.voltdb.catalog.Column)6 ArrayList (java.util.ArrayList)5 JSONException (org.json_voltpatches.JSONException)5 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)5 HashMap (java.util.HashMap)4 HashSet (java.util.HashSet)4 ColumnRef (org.voltdb.catalog.ColumnRef)4 Constraint (org.voltdb.catalog.Constraint)4 Index (org.voltdb.catalog.Index)4 TreeMap (java.util.TreeMap)3 StmtSubqueryScan (org.voltdb.planner.parseinfo.StmtSubqueryScan)3 SchemaColumn (org.voltdb.plannodes.SchemaColumn)3 List (java.util.List)2 SimpleDateFormat (java.text.SimpleDateFormat)1 Date (java.util.Date)1 Map (java.util.Map)1