Search in sources :

Example 16 with Index

use of org.voltdb.catalog.Index 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 17 with Index

use of org.voltdb.catalog.Index in project voltdb by VoltDB.

the class SwapTablesPlanNode method initializeSwapTablesPlanNode.

/**
     * Fill out all of the serializable attributes of the node, validating
     * its arguments' compatibility along the way to ensure successful
     * execution.
     * @param theTable the catalog definition of the 1st table swap argument
     * @param otherTable the catalog definition of the 2nd table swap argument
     * @throws PlannerErrorException if one or more compatibility validations fail
     */
public void initializeSwapTablesPlanNode(Table theTable, Table otherTable) {
    String theName = theTable.getTypeName();
    setTargetTableName(theName);
    String otherName = otherTable.getTypeName();
    m_otherTargetTableName = otherName;
    FailureMessage failureMessage = new FailureMessage(theName, otherName);
    validateTableCompatibility(theName, otherName, theTable, otherTable, failureMessage);
    validateColumnCompatibility(theName, otherName, theTable, otherTable, failureMessage);
    // Maintain sets of indexes and index-supported (UNIQUE) constraints
    // and the primary key index found on otherTable.
    // Removing them as they are matched by indexes/constraints on theTable
    // and added to the list of swappable indexes should leave the sets empty.
    HashSet<Index> otherIndexSet = new HashSet<>();
    // The constraint set is actually a HashMap to retain the
    // defining constraint name for help with error messages.
    // Track the primary key separately since it should match one-to-one.
    HashMap<Index, String> otherConstraintIndexMap = new HashMap<>();
    Index otherPrimaryKeyIndex = null;
    // Collect the system-defined (internal) indexes supporting constraints
    // and the primary key index if any.
    CatalogMap<Constraint> candidateConstraints = otherTable.getConstraints();
    for (Constraint otherConstraint : candidateConstraints) {
        Index otherIndex = otherConstraint.getIndex();
        if (otherIndex == null) {
            // effect on the swap table plan.
            continue;
        }
        // Set aside the one primary key index for special handling.
        if (otherConstraint.getType() == ConstraintType.PRIMARY_KEY.getValue()) {
            otherPrimaryKeyIndex = otherIndex;
            continue;
        }
        otherConstraintIndexMap.put(otherIndex, otherConstraint.getTypeName());
    }
    // Collect the user-defined (external) indexes on otherTable.  The indexes
    // in this set are removed as corresponding matches are found.
    // System-generated indexes that support constraints are checked separately,
    // so don't add them to this set.
    CatalogMap<Index> candidateIndexes = otherTable.getIndexes();
    for (Index otherIndex : candidateIndexes) {
        if (otherIndex != otherPrimaryKeyIndex && !otherConstraintIndexMap.containsKey(otherIndex)) {
            otherIndexSet.add(otherIndex);
        }
    }
    // Collect the indexes that support constraints on theTable
    HashSet<Index> theConstraintIndexSet = new HashSet<>();
    Index thePrimaryKeyIndex = null;
    for (Constraint constraint : theTable.getConstraints()) {
        Index theIndex = constraint.getIndex();
        if (theIndex == null) {
            continue;
        }
        if (constraint.getType() == ConstraintType.PRIMARY_KEY.getValue()) {
            thePrimaryKeyIndex = theIndex;
            continue;
        }
        theConstraintIndexSet.add(constraint.getIndex());
    }
    // make sure the indexes are swappable.
    if (thePrimaryKeyIndex != null && otherPrimaryKeyIndex != null) {
        if (indexesCanBeSwapped(thePrimaryKeyIndex, otherPrimaryKeyIndex)) {
            m_theIndexes.add(thePrimaryKeyIndex.getTypeName());
            m_otherIndexes.add(otherPrimaryKeyIndex.getTypeName());
        } else {
            failureMessage.addReason("PRIMARY KEY constraints do not match on both tables");
        }
    } else if ((thePrimaryKeyIndex != null && otherPrimaryKeyIndex == null) || (thePrimaryKeyIndex == null && otherPrimaryKeyIndex != null)) {
        failureMessage.addReason("one table has a PRIMARY KEY constraint and the other does not");
    }
    // Try to cross-reference each user-defined index on the two tables.
    for (Index theIndex : theTable.getIndexes()) {
        if (theConstraintIndexSet.contains(theIndex) || theIndex == thePrimaryKeyIndex) {
            // Constraints are checked below.
            continue;
        }
        boolean matched = false;
        for (Index otherIndex : otherIndexSet) {
            if (indexesCanBeSwapped(theIndex, otherIndex)) {
                m_theIndexes.add(theIndex.getTypeName());
                m_otherIndexes.add(otherIndex.getTypeName());
                otherIndexSet.remove(otherIndex);
                matched = true;
                break;
            }
        }
        if (matched) {
            continue;
        }
        // No match: look for a likely near-match based on naming
        // convention for the most helpful error message.
        // Otherwise, give a more generic error message.
        String theIndexName = theIndex.getTypeName();
        String message = "the index " + theIndexName + " on table " + theName + " has no corresponding index in the other table";
        String otherIndexName = theIndexName.replace(theName, otherName);
        Index otherIndex = candidateIndexes.getIgnoreCase(otherIndexName);
        if (otherIndex != null) {
            message += "; the closest candidate (" + otherIndexName + ") has mismatches in the following attributes: " + String.join(", ", diagnoseIndexMismatch(theIndex, otherIndex));
        }
        failureMessage.addReason(message);
    }
    // matched along the way.
    if (!otherIndexSet.isEmpty()) {
        List<String> indexNames = otherIndexSet.stream().map(idx -> idx.getTypeName()).collect(Collectors.toList());
        failureMessage.addReason("the table " + otherName + " contains these index(es) " + "which have no corresponding indexes on " + theName + ": " + "(" + String.join(", ", indexNames) + ")");
    }
    // constraints on the two tables.
    for (Constraint theConstraint : theTable.getConstraints()) {
        Index theIndex = theConstraint.getIndex();
        if (theIndex == null) {
            // effect on the swap table plan.
            continue;
        }
        if (theConstraint.getType() == ConstraintType.PRIMARY_KEY.getValue()) {
            // Primary key compatibility checked above.
            continue;
        }
        boolean matched = false;
        for (Entry<Index, String> otherEntry : otherConstraintIndexMap.entrySet()) {
            Index otherIndex = otherEntry.getKey();
            if (indexesCanBeSwapped(theIndex, otherIndex)) {
                m_theIndexes.add(theIndex.getTypeName());
                m_otherIndexes.add(otherIndex.getTypeName());
                otherConstraintIndexMap.remove(otherIndex);
                matched = true;
                break;
            }
        }
        if (matched) {
            continue;
        }
        String theConstraintName = theConstraint.getTypeName();
        failureMessage.addReason("the constraint " + theConstraintName + " on table " + theName + " " + "has no corresponding constraint on the other table");
    }
    // matched along the way.
    if (!otherConstraintIndexMap.isEmpty()) {
        StringBuilder sb = new StringBuilder();
        sb.append("these constraints (or system internal index names) on table " + otherName + " " + "have no corresponding constraints on the other table: (");
        String separator = "";
        for (Entry<Index, String> remainder : otherConstraintIndexMap.entrySet()) {
            String constraintName = remainder.getValue();
            String description = (constraintName != null && !constraintName.equals("")) ? constraintName : ("<anonymous with system internal index name: " + remainder.getKey().getTypeName() + ">");
            sb.append(separator).append(description);
            separator = ", ";
        }
        sb.append(")");
        failureMessage.addReason(sb.toString());
    }
    if (failureMessage.numFailures() > 0) {
        throw new PlanningErrorException(failureMessage.getMessage());
    }
}
Also used : Iterator(java.util.Iterator) ConstraintType(org.voltdb.types.ConstraintType) ColumnRef(org.voltdb.catalog.ColumnRef) MaterializedViewHandlerInfo(org.voltdb.catalog.MaterializedViewHandlerInfo) Table(org.voltdb.catalog.Table) HashMap(java.util.HashMap) Column(org.voltdb.catalog.Column) PlanningErrorException(org.voltdb.planner.PlanningErrorException) Collectors(java.util.stream.Collectors) Constraint(org.voltdb.catalog.Constraint) JSONException(org.json_voltpatches.JSONException) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) JSONStringer(org.json_voltpatches.JSONStringer) Index(org.voltdb.catalog.Index) List(java.util.List) Entry(java.util.Map.Entry) JSONObject(org.json_voltpatches.JSONObject) Database(org.voltdb.catalog.Database) CatalogMap(org.voltdb.catalog.CatalogMap) PlanNodeType(org.voltdb.types.PlanNodeType) MaterializedViewInfo(org.voltdb.catalog.MaterializedViewInfo) PlanningErrorException(org.voltdb.planner.PlanningErrorException) HashMap(java.util.HashMap) Constraint(org.voltdb.catalog.Constraint) Index(org.voltdb.catalog.Index) HashSet(java.util.HashSet)

Example 18 with Index

use of org.voltdb.catalog.Index in project voltdb by VoltDB.

the class PlanAssembler method calculateIndexGroupByInfo.

// Sets IndexGroupByInfo for an IndexScan
private void calculateIndexGroupByInfo(IndexScanPlanNode root, IndexGroupByInfo gbInfo) {
    String fromTableAlias = root.getTargetTableAlias();
    assert (fromTableAlias != null);
    Index index = root.getCatalogIndex();
    if (!IndexType.isScannable(index.getType())) {
        return;
    }
    ArrayList<AbstractExpression> bindings = new ArrayList<>();
    gbInfo.m_coveredGroupByColumns = calculateGroupbyColumnsCovered(index, fromTableAlias, bindings);
    gbInfo.m_canBeFullySerialized = (gbInfo.m_coveredGroupByColumns.size() == m_parsedSelect.groupByColumns().size());
}
Also used : AbstractExpression(org.voltdb.expressions.AbstractExpression) ArrayList(java.util.ArrayList) Index(org.voltdb.catalog.Index)

Example 19 with Index

use of org.voltdb.catalog.Index in project voltdb by VoltDB.

the class CatalogSizing method getTableSize.

private static TableSize getTableSize(Table table, boolean bActiveActiveEnabled) {
    // The cardinality is the estimated tuple count or an arbitrary number
    // if not estimated.
    long cardinality = table.getEstimatedtuplecount();
    if (cardinality <= 0) {
        cardinality = 1000;
    }
    //Do we need to adjust for DR-AA?
    boolean bAdjustForDrAA = (table.getIsdred() && bActiveActiveEnabled);
    // Add up the column widths.
    CatalogMap<Column> columnsMap = table.getColumns();
    List<Column> columns = new ArrayList<Column>(columnsMap.size());
    for (Column column : columnsMap) {
        columns.add(column);
    }
    CatalogItemSizeBase csize = getColumnsSize(columns, false, bAdjustForDrAA);
    boolean isView = table.getMaterializer() != null;
    TableSize tsize = new TableSize(table, isView, csize.widthMin, csize.widthMax, cardinality);
    // Add the table indexes.
    CatalogMap<Index> indexes = table.getIndexes();
    for (Index index : indexes) {
        CatalogItemSizeBase isize = getIndexSize(index);
        tsize.addIndex(index, isize.widthMin, isize.widthMax);
    }
    return tsize;
}
Also used : Column(org.voltdb.catalog.Column) ArrayList(java.util.ArrayList) Index(org.voltdb.catalog.Index)

Example 20 with Index

use of org.voltdb.catalog.Index in project voltdb by VoltDB.

the class ReportMaker method generateProcedureRow.

static String generateProcedureRow(CatalogMap<Table> tables, Procedure procedure) {
    StringBuilder sb = new StringBuilder();
    sb.append("<tr class='primaryrow'>");
    // column 1: procedure name
    String anchor = procedure.getTypeName().toLowerCase();
    sb.append("<td style='white-space: nowrap'><i id='p-" + anchor + "--icon' class='icon-chevron-right'></i> <a href='#p-");
    sb.append(anchor).append("' id='p-").append(anchor).append("' class='togglex'>");
    sb.append(procedure.getTypeName());
    sb.append("</a></td>");
    // column 2: parameter types
    sb.append("<td>");
    List<ProcParameter> params = CatalogUtil.getSortedCatalogItems(procedure.getParameters(), "index");
    List<String> paramTypes = new ArrayList<String>();
    for (ProcParameter param : params) {
        String paramType = VoltType.get((byte) param.getType()).name();
        if (param.getIsarray()) {
            paramType += "[]";
        }
        paramTypes.add(paramType);
    }
    if (paramTypes.size() == 0) {
        sb.append("<i>None</i>");
    }
    sb.append(StringUtils.join(paramTypes, ", "));
    sb.append("</td>");
    // column 3: partitioning
    sb.append("<td>");
    if (procedure.getSinglepartition()) {
        tag(sb, "success", "Single");
    } else {
        tag(sb, "warning", "Multi");
    }
    sb.append("</td>");
    // column 4: read/write
    sb.append("<td>");
    if (procedure.getReadonly()) {
        tag(sb, "success", "Read");
    } else {
        tag(sb, "warning", "Write");
    }
    sb.append("</td>");
    // column 5: access
    sb.append("<td>");
    List<String> groupNames = new ArrayList<String>();
    for (GroupRef groupRef : procedure.getAuthgroups()) {
        groupNames.add(groupRef.getGroup().getTypeName());
    }
    if (groupNames.size() == 0) {
        sb.append("<i>None</i>");
    }
    sb.append(StringUtils.join(groupNames, ", "));
    sb.append("</td>");
    // column 6: attributes
    sb.append("<td>");
    if (procedure.getHasjava()) {
        tag(sb, "info", "Java");
    } else {
        tag(sb, null, "Single-Stmt");
    }
    boolean isND = false;
    int scanCount = 0;
    for (Statement stmt : procedure.getStatements()) {
        scanCount += stmt.getSeqscancount();
        if (!stmt.getIscontentdeterministic() || !stmt.getIsorderdeterministic()) {
            isND = false;
        }
    }
    if (isND) {
        tag(sb, "inverse", "Determinism");
    }
    if (scanCount > 0) {
        tag(sb, "important", "Scans");
    }
    sb.append("</td>");
    sb.append("</tr>\n");
    // BUILD THE DROPDOWN FOR THE STATEMENT/DETAIL TABLE
    sb.append("<tr class='tablesorter-childRow'><td class='invert' colspan='6' id='p-" + procedure.getTypeName().toLowerCase() + "--dropdown'>\n");
    // output partitioning parameter info
    if (procedure.getSinglepartition()) {
        String pTable = procedure.getPartitioncolumn().getParent().getTypeName();
        String pColumn = procedure.getPartitioncolumn().getTypeName();
        int pIndex = procedure.getPartitionparameter();
        sb.append(String.format("<p>Partitioned on parameter %d which maps to column %s" + " of table <a class='invert' href='#s-%s'>%s</a>.</p>", pIndex, pColumn, pTable, pTable));
    }
    // get the annotation or ensure it's there
    ProcedureAnnotation annotation = (ProcedureAnnotation) procedure.getAnnotation();
    if (annotation == null) {
        annotation = new ProcedureAnnotation();
        procedure.setAnnotation(annotation);
    }
    // this needs to be run before the ProcedureAnnotation is used below
    // because it modifies it
    String statementsTable = generateStatementsTable(tables, procedure);
    // output what schema this interacts with
    // make sure tables appear in only one category
    annotation.tablesRead.removeAll(annotation.tablesUpdated);
    if (annotation.tablesRead.size() > 0) {
        sb.append("<p>Read-only access to tables: ");
        List<String> tableList = new ArrayList<String>();
        for (Table table : annotation.tablesRead) {
            tableList.add("<a href='#s-" + table.getTypeName() + "'>" + table.getTypeName() + "</a>");
        }
        sb.append(StringUtils.join(tableList, ", "));
        sb.append("</p>");
    }
    if (annotation.tablesUpdated.size() > 0) {
        sb.append("<p>Read/Write access to tables: ");
        List<String> tableList = new ArrayList<String>();
        for (Table table : annotation.tablesUpdated) {
            tableList.add("<a href='#s-" + table.getTypeName() + "'>" + table.getTypeName() + "</a>");
        }
        sb.append(StringUtils.join(tableList, ", "));
        sb.append("</p>");
    }
    if (annotation.indexesUsed.size() > 0) {
        sb.append("<p>Uses indexes: ");
        List<String> indexes = new ArrayList<String>();
        for (Index index : annotation.indexesUsed) {
            Table table = (Table) index.getParent();
            indexes.add("<a href='#s-" + table.getTypeName() + "-" + index.getTypeName() + "'>" + index.getTypeName() + "</a>");
        }
        sb.append(StringUtils.join(indexes, ", "));
        sb.append("</p>");
    }
    sb.append(statementsTable);
    sb.append("</td></tr>\n");
    return sb.toString();
}
Also used : Table(org.voltdb.catalog.Table) Statement(org.voltdb.catalog.Statement) ArrayList(java.util.ArrayList) Index(org.voltdb.catalog.Index) Constraint(org.voltdb.catalog.Constraint) GroupRef(org.voltdb.catalog.GroupRef) ProcParameter(org.voltdb.catalog.ProcParameter)

Aggregations

Index (org.voltdb.catalog.Index)30 Table (org.voltdb.catalog.Table)17 ArrayList (java.util.ArrayList)16 Column (org.voltdb.catalog.Column)14 AbstractExpression (org.voltdb.expressions.AbstractExpression)14 Constraint (org.voltdb.catalog.Constraint)11 ColumnRef (org.voltdb.catalog.ColumnRef)10 JSONException (org.json_voltpatches.JSONException)8 HashSet (java.util.HashSet)6 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)6 VoltCompilerException (org.voltdb.compiler.VoltCompiler.VoltCompilerException)5 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)5 IndexScanPlanNode (org.voltdb.plannodes.IndexScanPlanNode)5 AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)4 ConstraintType (org.voltdb.types.ConstraintType)4 HashMap (java.util.HashMap)3 VoltXMLElement (org.hsqldb_voltpatches.VoltXMLElement)3 VoltType (org.voltdb.VoltType)3 Database (org.voltdb.catalog.Database)3 Statement (org.voltdb.catalog.Statement)3