Search in sources :

Example 6 with PlanningErrorException

use of org.voltdb.planner.PlanningErrorException in project voltdb by VoltDB.

the class StmtSubqueryScan method canRunInOneFragment.

/**
     * Some subquery results can only be joined with a partitioned table after
     * it finishes some work on the coordinator. With the 2 fragment plan limit,
     * those queries can not be supported.
     * Other than that case, the planner will typically have added a
     * send/receive pair to the subquery plan that is actually only suitable to
     * a stand-alone plan. This function distinguishes subqueries that should NOT
     * have a send/receive pair.
     * @param root
     * @return true if there is no aspect to the plan that requires execution on the coordinator.
     */
public boolean canRunInOneFragment() {
    assert (m_subqueriesPartitioning != null);
    assert (m_subqueryStmt != null);
    if (m_subqueriesPartitioning.getCountOfPartitionedTables() == 0) {
        return true;
    }
    // of their results.
    if (failsSingleFragmentTest()) {
        return false;
    }
    // Tentative assignment in case of early return.
    // This gets immediately reset if it passes all the tests.
    m_failedSingleFragmentTest = true;
    if (m_subqueryStmt instanceof ParsedUnionStmt) {
        // Union are just returned
        return false;
    }
    if (!(m_subqueryStmt instanceof ParsedSelectStmt)) {
        throw new PlanningErrorException("Unsupported subquery found in FROM clause:" + m_subqueryStmt);
    }
    ParsedSelectStmt selectStmt = (ParsedSelectStmt) m_subqueryStmt;
    // we should get rid of the receive node. I (--paul) don't know what this means.
    if (selectStmt.hasLimitOrOffset() || selectStmt.hasDistinctWithGroupBy()) {
        return false;
    }
    // because it contains a partitioned view that does not have a partition column.
    if (selectStmt.m_mvFixInfo.needed()) {
        return false;
    }
    // Table aggregate cases should not get rid of the receive node
    if (selectStmt.hasAggregateOrGroupby()) {
        if (!selectStmt.isGrouped()) {
            m_tableAggregateSubquery = true;
            return false;
        }
        // Detect case (1) to mark receive node.
        if (!selectStmt.hasPartitionColumnInGroupby()) {
            return false;
        }
    }
    if (!selectStmt.hasPartitionColumnInWindowFunctionExpression()) {
        return false;
    }
    // Now. If this sub-query joins with a partitioned table in the parent statement,
    // push the join down by removing the send/receive plan node pair.
    m_failedSingleFragmentTest = false;
    return true;
}
Also used : PlanningErrorException(org.voltdb.planner.PlanningErrorException) ParsedUnionStmt(org.voltdb.planner.ParsedUnionStmt) ParsedSelectStmt(org.voltdb.planner.ParsedSelectStmt)

Example 7 with PlanningErrorException

use of org.voltdb.planner.PlanningErrorException in project voltdb by VoltDB.

the class TestVoltCompiler method checkDDLAgainstGivenSchema.

private Database checkDDLAgainstGivenSchema(String errorRegex, String givenSchema, String... ddl) throws Exception {
    String schemaDDL = givenSchema + StringUtils.join(ddl, " ");
    VoltCompiler compiler = new VoltCompiler(false);
    boolean success;
    String error;
    try {
        success = compileDDL(schemaDDL, compiler);
        error = (success || compiler.m_errors.size() == 0 ? "" : compiler.m_errors.get(compiler.m_errors.size() - 1).message);
    } catch (HsqlException hex) {
        success = false;
        error = hex.getMessage();
    } catch (PlanningErrorException plex) {
        success = false;
        error = plex.getMessage();
    }
    if (errorRegex == null) {
        assertTrue(String.format("Expected success\nDDL: %s\n%s", StringUtils.join(ddl, " "), error), success);
        Catalog cat = compiler.getCatalog();
        return cat.getClusters().get("cluster").getDatabases().get("database");
    } else {
        assertFalse(String.format("Expected error (\"%s\")\nDDL: %s", errorRegex, StringUtils.join(ddl, " ")), success);
        assertFalse("Expected at least one error message.", error.isEmpty());
        Matcher m = Pattern.compile(errorRegex).matcher(error);
        assertTrue(String.format("%s\nEXPECTED: %s", error, errorRegex), m.matches());
        return null;
    }
}
Also used : PlanningErrorException(org.voltdb.planner.PlanningErrorException) Matcher(java.util.regex.Matcher) HsqlException(org.hsqldb_voltpatches.HsqlException) Catalog(org.voltdb.catalog.Catalog)

Example 8 with PlanningErrorException

use of org.voltdb.planner.PlanningErrorException in project voltdb by VoltDB.

the class StatementCompiler method compileStatementAndUpdateCatalog.

/**
     * This static method conveniently does a few things for its caller:
     * - Formats the statement by replacing newlines with spaces
     *     and appends a semicolon if needed
     * - Updates the catalog Statement with metadata about the statement
     * - Plans the statement and puts the serialized plan in the catalog Statement
     * - Updates the catalog Statment with info about the statement's parameters
     * Upon successful completion, catalog statement will have been updated with
     * plan fragments needed to execute the statement.
     *
     * @param  compiler     The VoltCompiler instance
     * @param  hsql         Pass through parameter to QueryPlanner
     * @param  catalog      Pass through parameter to QueryPlanner
     * @param  db           Pass through parameter to QueryPlanner
     * @param  estimates    Pass through parameter to QueryPlanner
     * @param  catalogStmt  Catalog statement to be updated with plan
     * @param  xml          XML for statement, if it has been previously parsed
     *                      (may be null)
     * @param  stmt         Text of statement to be compiled
     * @param  joinOrder    Pass through parameter to QueryPlanner
     * @param  detMode      Pass through parameter to QueryPlanner
     * @param  partitioning Partition info for statement
    */
static boolean compileStatementAndUpdateCatalog(VoltCompiler compiler, HSQLInterface hsql, Database db, DatabaseEstimates estimates, Statement catalogStmt, VoltXMLElement xml, String stmt, String joinOrder, DeterminismMode detMode, StatementPartitioning partitioning) throws VoltCompiler.VoltCompilerException {
    // Cleanup whitespace newlines for catalog compatibility
    // and to make statement parsing easier.
    stmt = stmt.replaceAll("\n", " ");
    stmt = stmt.trim();
    compiler.addInfo("Compiling Statement: " + stmt);
    // put the data in the catalog that we have
    if (!stmt.endsWith(";")) {
        stmt += ";";
    }
    // if this key + sql is the same, then a cached stmt can be used
    String keyPrefix = compiler.getKeyPrefix(partitioning, detMode, joinOrder);
    // if the key is cache-able, look for a previous statement
    if (keyPrefix != null) {
        Statement previousStatement = compiler.getCachedStatement(keyPrefix, stmt);
        // check if the stmt exists and if it's the same sql text
        if (previousStatement != null) {
            catalogStmt.setAnnotation(previousStatement.getAnnotation());
            catalogStmt.setAttachment(previousStatement.getAttachment());
            catalogStmt.setCachekeyprefix(previousStatement.getCachekeyprefix());
            catalogStmt.setCost(previousStatement.getCost());
            catalogStmt.setExplainplan(previousStatement.getExplainplan());
            catalogStmt.setIscontentdeterministic(previousStatement.getIscontentdeterministic());
            catalogStmt.setIsorderdeterministic(previousStatement.getIsorderdeterministic());
            catalogStmt.setNondeterminismdetail(previousStatement.getNondeterminismdetail());
            catalogStmt.setQuerytype(previousStatement.getQuerytype());
            catalogStmt.setReadonly(previousStatement.getReadonly());
            catalogStmt.setReplicatedtabledml(previousStatement.getReplicatedtabledml());
            catalogStmt.setSeqscancount(previousStatement.getSeqscancount());
            catalogStmt.setSinglepartition(previousStatement.getSinglepartition());
            catalogStmt.setSqltext(previousStatement.getSqltext());
            catalogStmt.setTablesread(previousStatement.getTablesread());
            catalogStmt.setTablesupdated(previousStatement.getTablesupdated());
            catalogStmt.setIndexesused(previousStatement.getIndexesused());
            for (StmtParameter oldSp : previousStatement.getParameters()) {
                StmtParameter newSp = catalogStmt.getParameters().add(oldSp.getTypeName());
                newSp.setAnnotation(oldSp.getAnnotation());
                newSp.setAttachment(oldSp.getAttachment());
                newSp.setIndex(oldSp.getIndex());
                newSp.setIsarray(oldSp.getIsarray());
                newSp.setJavatype(oldSp.getJavatype());
                newSp.setSqltype(oldSp.getSqltype());
            }
            for (PlanFragment oldFrag : previousStatement.getFragments()) {
                PlanFragment newFrag = catalogStmt.getFragments().add(oldFrag.getTypeName());
                newFrag.setAnnotation(oldFrag.getAnnotation());
                newFrag.setAttachment(oldFrag.getAttachment());
                newFrag.setHasdependencies(oldFrag.getHasdependencies());
                newFrag.setMultipartition(oldFrag.getMultipartition());
                newFrag.setNontransactional(oldFrag.getNontransactional());
                newFrag.setPlanhash(oldFrag.getPlanhash());
                newFrag.setPlannodetree(oldFrag.getPlannodetree());
            }
            return true;
        }
    }
    // determine the type of the query
    QueryType qtype = QueryType.getFromSQL(stmt);
    catalogStmt.setReadonly(qtype.isReadOnly());
    catalogStmt.setQuerytype(qtype.getValue());
    // might be null if not cacheable
    catalogStmt.setCachekeyprefix(keyPrefix);
    catalogStmt.setSqltext(stmt);
    catalogStmt.setSinglepartition(partitioning.wasSpecifiedAsSingle());
    String name = catalogStmt.getParent().getTypeName() + "-" + catalogStmt.getTypeName();
    String sql = catalogStmt.getSqltext();
    String stmtName = catalogStmt.getTypeName();
    String procName = catalogStmt.getParent().getTypeName();
    TrivialCostModel costModel = new TrivialCostModel();
    CompiledPlan plan = null;
    QueryPlanner planner = new QueryPlanner(sql, stmtName, procName, db, partitioning, hsql, estimates, false, DEFAULT_MAX_JOIN_TABLES, costModel, null, joinOrder, detMode);
    try {
        try {
            if (xml != null) {
                planner.parseFromXml(xml);
            } else {
                planner.parse();
            }
            plan = planner.plan();
            assert (plan != null);
        } catch (PlanningErrorException e) {
            // These are normal expectable errors -- don't normally need a stack-trace.
            String msg = "Failed to plan for statement (" + catalogStmt.getTypeName() + ") \"" + catalogStmt.getSqltext() + "\".";
            if (e.getMessage() != null) {
                msg += " Error: \"" + e.getMessage() + "\"";
            }
            throw compiler.new VoltCompilerException(msg);
        } catch (Exception e) {
            e.printStackTrace();
            throw compiler.new VoltCompilerException("Failed to plan for stmt: " + catalogStmt.getTypeName());
        }
        // There is a hard-coded limit to the number of parameters that can be passed to the EE.
        if (plan.parameters.length > CompiledPlan.MAX_PARAM_COUNT) {
            throw compiler.new VoltCompilerException("The statement's parameter count " + plan.parameters.length + " must not exceed the maximum " + CompiledPlan.MAX_PARAM_COUNT);
        }
        // Check order and content determinism before accessing the detail which
        // it caches.
        boolean orderDeterministic = plan.isOrderDeterministic();
        catalogStmt.setIsorderdeterministic(orderDeterministic);
        boolean contentDeterministic = plan.isContentDeterministic() && (orderDeterministic || !plan.hasLimitOrOffset());
        catalogStmt.setIscontentdeterministic(contentDeterministic);
        String nondeterminismDetail = plan.nondeterminismDetail();
        catalogStmt.setNondeterminismdetail(nondeterminismDetail);
        catalogStmt.setSeqscancount(plan.countSeqScans());
        // We will need to update the system catalogs with this new information
        for (int i = 0; i < plan.parameters.length; ++i) {
            StmtParameter catalogParam = catalogStmt.getParameters().add(String.valueOf(i));
            catalogParam.setJavatype(plan.parameters[i].getValueType().getValue());
            catalogParam.setIsarray(plan.parameters[i].getParamIsVector());
            catalogParam.setIndex(i);
        }
        catalogStmt.setReplicatedtabledml(plan.replicatedTableDML);
        // output the explained plan to disk (or caller) for debugging
        // Initial capacity estimate.
        StringBuilder planDescription = new StringBuilder(1000);
        planDescription.append("SQL: ").append(plan.sql);
        // Cost seems to only confuse people who don't understand how this number is used/generated.
        if (VoltCompiler.DEBUG_MODE) {
            planDescription.append("\nCOST: ").append(plan.cost);
        }
        planDescription.append("\nPLAN:\n");
        planDescription.append(plan.explainedPlan);
        String planString = planDescription.toString();
        // only write to disk if compiler is in standalone mode
        if (compiler.standaloneCompiler) {
            BuildDirectoryUtils.writeFile(null, name + ".txt", planString, false);
        }
        compiler.captureDiagnosticContext(planString);
        // build usage links for report generation and put them in the catalog
        CatalogUtil.updateUsageAnnotations(db, catalogStmt, plan.rootPlanGraph, plan.subPlanGraph);
        // set the explain plan output into the catalog (in hex) for reporting
        catalogStmt.setExplainplan(Encoder.hexEncode(plan.explainedPlan));
        // compute a hash of the plan
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA-1");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            assert (false);
            // should never happen with healthy jvm
            System.exit(-1);
        }
        // Now update our catalog information
        PlanFragment planFragment = catalogStmt.getFragments().add("0");
        planFragment.setHasdependencies(plan.subPlanGraph != null);
        // mark a fragment as non-transactional if it never touches a persistent table
        planFragment.setNontransactional(!fragmentReferencesPersistentTable(plan.rootPlanGraph));
        planFragment.setMultipartition(plan.subPlanGraph != null);
        byte[] planBytes = writePlanBytes(compiler, planFragment, plan.rootPlanGraph);
        md.update(planBytes, 0, planBytes.length);
        // compute the 40 bytes of hex from the 20 byte sha1 hash of the plans
        md.reset();
        md.update(planBytes);
        planFragment.setPlanhash(Encoder.hexEncode(md.digest()));
        if (plan.subPlanGraph != null) {
            planFragment = catalogStmt.getFragments().add("1");
            planFragment.setHasdependencies(false);
            planFragment.setNontransactional(false);
            planFragment.setMultipartition(true);
            byte[] subBytes = writePlanBytes(compiler, planFragment, plan.subPlanGraph);
            // compute the 40 bytes of hex from the 20 byte sha1 hash of the plans
            md.reset();
            md.update(subBytes);
            planFragment.setPlanhash(Encoder.hexEncode(md.digest()));
        }
        // Planner should have rejected with an exception any statement with an unrecognized type.
        int validType = catalogStmt.getQuerytype();
        assert (validType != QueryType.INVALID.getValue());
        return false;
    } catch (StackOverflowError error) {
        String msg = "Failed to plan for statement (" + catalogStmt.getTypeName() + ") \"" + catalogStmt.getSqltext() + "\". Error: \"Encountered stack overflow error. " + "Try reducing the number of predicate expressions in the query.\"";
        throw compiler.new VoltCompilerException(msg);
    }
}
Also used : CompiledPlan(org.voltdb.planner.CompiledPlan) PlanningErrorException(org.voltdb.planner.PlanningErrorException) Statement(org.voltdb.catalog.Statement) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) PlanFragment(org.voltdb.catalog.PlanFragment) QueryPlanner(org.voltdb.planner.QueryPlanner) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) PlanningErrorException(org.voltdb.planner.PlanningErrorException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) StmtParameter(org.voltdb.catalog.StmtParameter) TrivialCostModel(org.voltdb.planner.TrivialCostModel) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) MessageDigest(java.security.MessageDigest) QueryType(org.voltdb.types.QueryType)

Example 9 with PlanningErrorException

use of org.voltdb.planner.PlanningErrorException in project voltdb by VoltDB.

the class PlannerTool method planSqlCore.

/**
     * Stripped down compile that is ONLY used to plan default procedures.
     */
public synchronized CompiledPlan planSqlCore(String sql, StatementPartitioning partitioning) {
    TrivialCostModel costModel = new TrivialCostModel();
    DatabaseEstimates estimates = new DatabaseEstimates();
    QueryPlanner planner = new QueryPlanner(sql, "PlannerTool", "PlannerToolProc", m_database, partitioning, m_hsql, estimates, !VoltCompiler.DEBUG_MODE, AD_HOC_JOINED_TABLE_LIMIT, costModel, null, null, DeterminismMode.FASTER);
    CompiledPlan plan = null;
    try {
        // do the expensive full planning.
        planner.parse();
        plan = planner.plan();
        assert (plan != null);
    } catch (Exception e) {
        /*
             * Don't log PlanningErrorExceptions or HSQLParseExceptions, as they
             * are at least somewhat expected.
             */
        String loggedMsg = "";
        if (!(e instanceof PlanningErrorException || e instanceof HSQLParseException)) {
            logException(e, "Error compiling query");
            loggedMsg = " (Stack trace has been written to the log.)";
        }
        throw new RuntimeException("Error compiling query: " + e.toString() + loggedMsg, e);
    }
    if (plan == null) {
        throw new RuntimeException("Null plan received in PlannerTool.planSql");
    }
    return plan;
}
Also used : CompiledPlan(org.voltdb.planner.CompiledPlan) PlanningErrorException(org.voltdb.planner.PlanningErrorException) TrivialCostModel(org.voltdb.planner.TrivialCostModel) QueryPlanner(org.voltdb.planner.QueryPlanner) PlanningErrorException(org.voltdb.planner.PlanningErrorException) HSQLParseException(org.hsqldb_voltpatches.HSQLInterface.HSQLParseException) HSQLParseException(org.hsqldb_voltpatches.HSQLInterface.HSQLParseException)

Aggregations

PlanningErrorException (org.voltdb.planner.PlanningErrorException)9 CompiledPlan (org.voltdb.planner.CompiledPlan)3 QueryPlanner (org.voltdb.planner.QueryPlanner)3 TrivialCostModel (org.voltdb.planner.TrivialCostModel)3 HSQLParseException (org.hsqldb_voltpatches.HSQLInterface.HSQLParseException)2 JSONException (org.json_voltpatches.JSONException)2 TimestampType (org.voltdb.types.TimestampType)2 MessageDigest (java.security.MessageDigest)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Iterator (java.util.Iterator)1 List (java.util.List)1 Entry (java.util.Map.Entry)1 Matcher (java.util.regex.Matcher)1 Collectors (java.util.stream.Collectors)1 HsqlException (org.hsqldb_voltpatches.HsqlException)1 JSONObject (org.json_voltpatches.JSONObject)1 JSONStringer (org.json_voltpatches.JSONStringer)1