Search in sources :

Example 1 with TrivialCostModel

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

the class PlannerTool method planSql.

public synchronized AdHocPlannedStatement planSql(String sqlIn, StatementPartitioning partitioning, boolean isExplainMode, final Object[] userParams, boolean isSwapTables) {
    CacheUse cacheUse = CacheUse.FAIL;
    if (m_plannerStats != null) {
        m_plannerStats.startStatsCollection();
    }
    boolean hasUserQuestionMark = false;
    boolean wrongNumberParameters = false;
    try {
        if ((sqlIn == null) || (sqlIn.length() == 0)) {
            throw new RuntimeException("Can't plan empty or null SQL.");
        }
        // remove any spaces or newlines
        String sql = sqlIn.trim();
        // if the cases tended to have mostly overlapping queries.
        if (partitioning.isInferred()) {
            // Check the literal cache for a match.
            AdHocPlannedStatement cachedPlan = m_cache.getWithSQL(sqlIn);
            if (cachedPlan != null) {
                cacheUse = CacheUse.HIT1;
                return cachedPlan;
            } else {
                cacheUse = CacheUse.MISS;
            }
        }
        // Reset plan node id counter
        AbstractPlanNode.resetPlanNodeIds();
        //////////////////////
        // PLAN THE STMT
        //////////////////////
        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;
        String[] extractedLiterals = null;
        String parsedToken = null;
        try {
            if (isSwapTables) {
                planner.planSwapTables();
            } else {
                planner.parse();
            }
            parsedToken = planner.parameterize();
            // check the parameters count
            // check user input question marks with input parameters
            int inputParamsLengh = userParams == null ? 0 : userParams.length;
            if (planner.getAdhocUserParamsCount() != inputParamsLengh) {
                wrongNumberParameters = true;
                if (!isExplainMode) {
                    throw new PlanningErrorException(String.format("Incorrect number of parameters passed: expected %d, passed %d", planner.getAdhocUserParamsCount(), inputParamsLengh));
                }
            }
            hasUserQuestionMark = planner.getAdhocUserParamsCount() > 0;
            // do not put wrong parameter explain query into cache
            if (!wrongNumberParameters && partitioning.isInferred()) {
                // QueryPlanner.
                assert (parsedToken != null);
                extractedLiterals = planner.extractedParamLiteralValues();
                List<BoundPlan> boundVariants = m_cache.getWithParsedToken(parsedToken);
                if (boundVariants != null) {
                    assert (!boundVariants.isEmpty());
                    BoundPlan matched = null;
                    for (BoundPlan boundPlan : boundVariants) {
                        if (boundPlan.allowsParams(extractedLiterals)) {
                            matched = boundPlan;
                            break;
                        }
                    }
                    if (matched != null) {
                        CorePlan core = matched.m_core;
                        ParameterSet params = null;
                        if (planner.compiledAsParameterizedPlan()) {
                            params = planner.extractedParamValues(core.parameterTypes);
                        } else if (hasUserQuestionMark) {
                            params = ParameterSet.fromArrayNoCopy(userParams);
                        } else {
                            // No constants AdHoc queries
                            params = ParameterSet.emptyParameterSet();
                        }
                        AdHocPlannedStatement ahps = new AdHocPlannedStatement(sql.getBytes(Constants.UTF8ENCODING), core, params, null);
                        ahps.setBoundConstants(matched.m_constants);
                        // parameterized plan from the cache does not have exception
                        m_cache.put(sql, parsedToken, ahps, extractedLiterals, hasUserQuestionMark, false);
                        cacheUse = CacheUse.HIT2;
                        return ahps;
                    }
                }
            }
            // If not caching or there was no cache hit, do the expensive full planning.
            plan = planner.plan();
            assert (plan != null);
            if (plan != null && plan.getStatementPartitioning() != null) {
                partitioning = plan.getStatementPartitioning();
            }
        } 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");
        }
        //////////////////////
        // OUTPUT THE RESULT
        //////////////////////
        CorePlan core = new CorePlan(plan, m_catalogHash);
        AdHocPlannedStatement ahps = new AdHocPlannedStatement(plan, core);
        // do not put wrong parameter explain query into cache
        if (!wrongNumberParameters && partitioning.isInferred()) {
            // Note either the parameter index (per force to a user-provided parameter) or
            // the actual constant value of the partitioning key inferred from the plan.
            // Either or both of these two values may simply default
            // to -1 and to null, respectively.
            core.setPartitioningParamIndex(partitioning.getInferredParameterIndex());
            core.setPartitioningParamValue(partitioning.getInferredPartitioningValue());
            assert (parsedToken != null);
            // Again, plans with inferred partitioning are the only ones supported in the cache.
            m_cache.put(sqlIn, parsedToken, ahps, extractedLiterals, hasUserQuestionMark, planner.wasBadPameterized());
        }
        return ahps;
    } finally {
        if (m_plannerStats != null) {
            m_plannerStats.endStatsCollection(m_cache.getLiteralCacheSize(), m_cache.getCoreCacheSize(), cacheUse, -1);
        }
    }
}
Also used : CompiledPlan(org.voltdb.planner.CompiledPlan) ParameterSet(org.voltdb.ParameterSet) PlanningErrorException(org.voltdb.planner.PlanningErrorException) CacheUse(org.voltdb.PlannerStatsCollector.CacheUse) CorePlan(org.voltdb.planner.CorePlan) QueryPlanner(org.voltdb.planner.QueryPlanner) PlanningErrorException(org.voltdb.planner.PlanningErrorException) HSQLParseException(org.hsqldb_voltpatches.HSQLInterface.HSQLParseException) HSQLParseException(org.hsqldb_voltpatches.HSQLInterface.HSQLParseException) TrivialCostModel(org.voltdb.planner.TrivialCostModel) BoundPlan(org.voltdb.planner.BoundPlan)

Example 2 with TrivialCostModel

use of org.voltdb.planner.TrivialCostModel 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 3 with TrivialCostModel

use of org.voltdb.planner.TrivialCostModel 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

CompiledPlan (org.voltdb.planner.CompiledPlan)3 PlanningErrorException (org.voltdb.planner.PlanningErrorException)3 QueryPlanner (org.voltdb.planner.QueryPlanner)3 TrivialCostModel (org.voltdb.planner.TrivialCostModel)3 HSQLParseException (org.hsqldb_voltpatches.HSQLInterface.HSQLParseException)2 MessageDigest (java.security.MessageDigest)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 ParameterSet (org.voltdb.ParameterSet)1 CacheUse (org.voltdb.PlannerStatsCollector.CacheUse)1 PlanFragment (org.voltdb.catalog.PlanFragment)1 Statement (org.voltdb.catalog.Statement)1 StmtParameter (org.voltdb.catalog.StmtParameter)1 VoltCompilerException (org.voltdb.compiler.VoltCompiler.VoltCompilerException)1 BoundPlan (org.voltdb.planner.BoundPlan)1 CorePlan (org.voltdb.planner.CorePlan)1 QueryType (org.voltdb.types.QueryType)1