Search in sources :

Example 21 with ParameterValueExpression

use of org.voltdb.expressions.ParameterValueExpression in project voltdb by VoltDB.

the class PlannerTestAideDeCamp method compile.

/**
     * Compile and cache the statement and plan and return the final plan graph.
     */
private List<AbstractPlanNode> compile(String sql, int paramCount, String joinOrder, boolean inferPartitioning, boolean forceSingle, DeterminismMode detMode) {
    String stmtLabel = "stmt-" + String.valueOf(compileCounter++);
    Statement catalogStmt = proc.getStatements().add(stmtLabel);
    catalogStmt.setSqltext(sql);
    catalogStmt.setSinglepartition(forceSingle);
    // determine the type of the query
    QueryType qtype = QueryType.SELECT;
    catalogStmt.setReadonly(true);
    if (sql.toLowerCase().startsWith("insert")) {
        qtype = QueryType.INSERT;
        catalogStmt.setReadonly(false);
    }
    if (sql.toLowerCase().startsWith("update")) {
        qtype = QueryType.UPDATE;
        catalogStmt.setReadonly(false);
    }
    if (sql.toLowerCase().startsWith("delete")) {
        qtype = QueryType.DELETE;
        catalogStmt.setReadonly(false);
    }
    catalogStmt.setQuerytype(qtype.getValue());
    // name will look like "basename-stmt-#"
    String name = catalogStmt.getParent().getTypeName() + "-" + catalogStmt.getTypeName();
    DatabaseEstimates estimates = new DatabaseEstimates();
    TrivialCostModel costModel = new TrivialCostModel();
    StatementPartitioning partitioning;
    if (inferPartitioning) {
        partitioning = StatementPartitioning.inferPartitioning();
    } else if (forceSingle) {
        partitioning = StatementPartitioning.forceSP();
    } else {
        partitioning = StatementPartitioning.forceMP();
    }
    String procName = catalogStmt.getParent().getTypeName();
    QueryPlanner planner = new QueryPlanner(sql, stmtLabel, procName, db, partitioning, hsql, estimates, false, StatementCompiler.DEFAULT_MAX_JOIN_TABLES, costModel, null, joinOrder, detMode);
    CompiledPlan plan = null;
    planner.parse();
    plan = planner.plan();
    assert (plan != null);
    // Partitioning optionally inferred from the planning process.
    if (partitioning.isInferred()) {
        catalogStmt.setSinglepartition(partitioning.isInferredSingle());
    }
    // 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));
        ParameterValueExpression pve = plan.parameters[i];
        catalogParam.setJavatype(pve.getValueType().getValue());
        catalogParam.setIsarray(pve.getParamIsVector());
        catalogParam.setIndex(i);
    }
    List<PlanNodeList> nodeLists = new ArrayList<>();
    nodeLists.add(new PlanNodeList(plan.rootPlanGraph));
    if (plan.subPlanGraph != null) {
        nodeLists.add(new PlanNodeList(plan.subPlanGraph));
    }
    // Now update our catalog information
    // HACK: We're using the node_tree's hashCode() as it's name. It would be really
    //     nice if the Catalog code give us an guid without needing a name first...
    String json = null;
    try {
        JSONObject jobj = new JSONObject(nodeLists.get(0).toJSONString());
        json = jobj.toString(4);
    } catch (JSONException e2) {
        // TODO Auto-generated catch block
        e2.printStackTrace();
        System.exit(-1);
        return null;
    }
    //
    try {
        BuildDirectoryUtils.writeFile("statement-plans", name + "_json.txt", json, true);
        BuildDirectoryUtils.writeFile("statement-plans", name + ".dot", nodeLists.get(0).toDOTString("name"), true);
    } catch (Exception e) {
        e.printStackTrace();
    }
    List<AbstractPlanNode> plannodes = new ArrayList<>();
    for (PlanNodeList nodeList : nodeLists) {
        plannodes.add(nodeList.getRootPlanNode());
    }
    m_currentPlan = plan;
    return plannodes;
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) Statement(org.voltdb.catalog.Statement) ArrayList(java.util.ArrayList) JSONException(org.json_voltpatches.JSONException) PlanNodeList(org.voltdb.plannodes.PlanNodeList) JSONException(org.json_voltpatches.JSONException) StmtParameter(org.voltdb.catalog.StmtParameter) JSONObject(org.json_voltpatches.JSONObject) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression) QueryType(org.voltdb.types.QueryType) DatabaseEstimates(org.voltdb.compiler.DatabaseEstimates)

Example 22 with ParameterValueExpression

use of org.voltdb.expressions.ParameterValueExpression in project voltdb by VoltDB.

the class ParsedSelectStmt method parseOrderColumn.

private void parseOrderColumn(VoltXMLElement orderByNode, final boolean isDistributed) {
    // Aggregation list needs to be cleared before parsing the order by expression
    m_aggregationList.clear();
    ParsedColInfo.ExpressionAdjuster adjuster = new ParsedColInfo.ExpressionAdjuster() {

        @Override
        public AbstractExpression adjust(AbstractExpression expr) {
            if (isDistributed) {
                expr = expr.replaceAVG();
                updateAvgExpressions();
            }
            ExpressionUtil.finalizeValueTypes(expr);
            return expr;
        }
    };
    ParsedColInfo order_col = ParsedColInfo.fromOrderByXml(this, orderByNode, adjuster);
    AbstractExpression order_exp = order_col.expression;
    assert (order_exp != null);
    // guards against subquery inside of order by clause
    if (order_exp.hasSubquerySubexpression()) {
        throw new PlanningErrorException("ORDER BY clauses with subquery expressions are not allowed.");
    }
    // (for determinism).
    for (ParsedColInfo col : m_displayColumns) {
        if (col.alias.equals(order_col.alias) || col.expression.equals(order_exp)) {
            col.orderBy = true;
            col.ascending = order_col.ascending;
            order_col.alias = col.alias;
            order_col.columnName = col.columnName;
            order_col.tableName = col.tableName;
            break;
        }
    }
    assert (!(order_exp instanceof ConstantValueExpression));
    assert (!(order_exp instanceof ParameterValueExpression));
    insertAggExpressionsToAggResultColumns(m_aggregationList, order_col);
    if (m_aggregationList.size() >= 1) {
        m_hasAggregateExpression = true;
    }
    // Add TVEs in ORDER BY statement if we have,
    // stop recursive finding when we have it in AggResultColumns
    List<TupleValueExpression> tveList = new ArrayList<>();
    findAllTVEs(order_col.expression, tveList);
    insertTVEsToAggResultColumns(tveList);
    m_orderColumns.add(order_col);
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) ConstantValueExpression(org.voltdb.expressions.ConstantValueExpression) ArrayList(java.util.ArrayList) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression)

Example 23 with ParameterValueExpression

use of org.voltdb.expressions.ParameterValueExpression in project voltdb by VoltDB.

the class PlanAssembler method canPushDownDistinctAggregation.

private boolean canPushDownDistinctAggregation(AggregateExpression aggExpr) {
    assert (m_parsedSelect != null);
    assert (aggExpr != null);
    assert (aggExpr.isDistinct());
    if (aggExpr.getExpressionType() == ExpressionType.AGGREGATE_COUNT_STAR) {
        return true;
    }
    AbstractExpression aggArg = aggExpr.getLeft();
    // constant
    if (aggArg instanceof ConstantValueExpression || aggArg instanceof ParameterValueExpression) {
        return true;
    }
    if (!(aggArg instanceof TupleValueExpression)) {
        return false;
    }
    TupleValueExpression tve = (TupleValueExpression) aggArg;
    String tableAlias = tve.getTableAlias();
    StmtTableScan scanTable = m_parsedSelect.getStmtTableScanByAlias(tableAlias);
    // table alias may be from AbstractParsedStmt.TEMP_TABLE_NAME.
    if (scanTable == null || scanTable.getPartitioningColumns() == null) {
        return false;
    }
    for (SchemaColumn pcol : scanTable.getPartitioningColumns()) {
        if (pcol != null && pcol.getColumnName().equals(tve.getColumnName())) {
            return true;
        }
    }
    return false;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) ConstantValueExpression(org.voltdb.expressions.ConstantValueExpression) SchemaColumn(org.voltdb.plannodes.SchemaColumn) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan)

Example 24 with ParameterValueExpression

use of org.voltdb.expressions.ParameterValueExpression in project voltdb by VoltDB.

the class ProcedureCompiler method compileJavaProcedure.

static void compileJavaProcedure(VoltCompiler compiler, HSQLInterface hsql, DatabaseEstimates estimates, Database db, ProcedureDescriptor procedureDescriptor, InMemoryJarfile jarOutput) throws VoltCompiler.VoltCompilerException {
    final String className = procedureDescriptor.m_className;
    // Load the class given the class name
    Class<?> procClass = procedureDescriptor.m_class;
    // get the short name of the class (no package)
    String shortName = deriveShortProcedureName(className);
    // add an entry to the catalog
    final Procedure procedure = db.getProcedures().add(shortName);
    for (String groupName : procedureDescriptor.m_authGroups) {
        final Group group = db.getGroups().get(groupName);
        if (group == null) {
            throw compiler.new VoltCompilerException("Procedure " + className + " allows access by a role " + groupName + " that does not exist");
        }
        final GroupRef groupRef = procedure.getAuthgroups().add(groupName);
        groupRef.setGroup(group);
    }
    procedure.setClassname(className);
    // sysprocs don't use the procedure compiler
    procedure.setSystemproc(false);
    procedure.setDefaultproc(procedureDescriptor.m_builtInStmt);
    procedure.setHasjava(true);
    ProcedureAnnotation pa = (ProcedureAnnotation) procedure.getAnnotation();
    if (pa == null) {
        pa = new ProcedureAnnotation();
        procedure.setAnnotation(pa);
    }
    // get the annotation
    // first try to get one that has been passed from the compiler
    ProcInfoData info = compiler.getProcInfoOverride(shortName);
    // check if partition info was set in ddl
    ProcInfoData ddlInfo = null;
    if (procedureDescriptor.m_partitionString != null && !procedureDescriptor.m_partitionString.trim().isEmpty()) {
        ddlInfo = new ProcInfoData();
        ddlInfo.partitionInfo = procedureDescriptor.m_partitionString;
        ddlInfo.singlePartition = true;
    }
    // and create a ProcInfo.Data instance for it
    if (info == null) {
        info = new ProcInfoData();
        ProcInfo annotationInfo = procClass.getAnnotation(ProcInfo.class);
        // error out if partition info is present in both ddl and annotation
        if (annotationInfo != null) {
            if (ddlInfo != null) {
                String msg = "Procedure: " + shortName + " has partition properties defined both in ";
                msg += "class \"" + className + "\" and in the schema definition file(s)";
                throw compiler.new VoltCompilerException(msg);
            }
            // Prevent AutoGenerated DDL from including PARTITION PROCEDURE for this procedure.
            pa.classAnnotated = true;
            info.partitionInfo = annotationInfo.partitionInfo();
            info.singlePartition = annotationInfo.singlePartition();
        } else if (ddlInfo != null) {
            info = ddlInfo;
        }
    } else {
        pa.classAnnotated = true;
    }
    assert (info != null);
    // make sure multi-partition implies no partitioning info
    if (info.singlePartition == false) {
        if ((info.partitionInfo != null) && (info.partitionInfo.length() > 0)) {
            String msg = "Procedure: " + shortName + " is annotated as multi-partition";
            msg += " but partitionInfo has non-empty value: \"" + info.partitionInfo + "\"";
            throw compiler.new VoltCompilerException(msg);
        }
    }
    // if the procedure is non-transactional, then take this special path here
    if (VoltNonTransactionalProcedure.class.isAssignableFrom(procClass)) {
        compileNTProcedure(compiler, procClass, procedure, jarOutput);
        return;
    }
    // if still here, that means the procedure is transactional
    procedure.setTransactional(true);
    // track if there are any writer statements and/or sequential scans and/or an overlooked common partitioning parameter
    boolean procHasWriteStmts = false;
    boolean procHasSeqScans = false;
    // procWantsCommonPartitioning == true but commonPartitionExpression == null signifies a proc
    // for which the planner was requested to attempt to find an SP plan, but that was not possible
    // -- it had a replicated write or it had one or more partitioned reads that were not all
    // filtered by the same partition key value -- so it was planned as an MP proc.
    boolean procWantsCommonPartitioning = true;
    AbstractExpression commonPartitionExpression = null;
    String exampleSPstatement = null;
    Object exampleSPvalue = null;
    // iterate through the fields and get valid sql statements
    VoltProcedure procInstance;
    try {
        procInstance = (VoltProcedure) procClass.newInstance();
    } catch (InstantiationException e) {
        throw new RuntimeException("Error instantiating procedure \"%s\"" + procClass.getName(), e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException("Error instantiating procedure \"%s\"" + procClass.getName(), e);
    }
    Map<String, SQLStmt> stmtMap = getValidSQLStmts(compiler, procClass.getSimpleName(), procClass, procInstance, true);
    ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
    builder.putAll(stmtMap);
    // find the run() method and get the params
    Method procMethod = null;
    Method[] methods = procClass.getDeclaredMethods();
    for (final Method m : methods) {
        String name = m.getName();
        if (name.equals("run")) {
            assert (m.getDeclaringClass() == procClass);
            // if not null, then we've got more than one run method
            if (procMethod != null) {
                String msg = "Procedure: " + shortName + " has multiple public run(...) methods. ";
                msg += "Only a single run(...) method is supported.";
                throw compiler.new VoltCompilerException(msg);
            }
            if (Modifier.isPublic(m.getModifiers())) {
                // found it!
                procMethod = m;
            } else {
                compiler.addWarn("Procedure: " + shortName + " has non-public run(...) method.");
            }
        }
    }
    if (procMethod == null) {
        String msg = "Procedure: " + shortName + " has no run(...) method.";
        throw compiler.new VoltCompilerException(msg);
    }
    // check the return type of the run method
    if ((procMethod.getReturnType() != VoltTable[].class) && (procMethod.getReturnType() != VoltTable.class) && (procMethod.getReturnType() != long.class) && (procMethod.getReturnType() != Long.class)) {
        String msg = "Procedure: " + shortName + " has run(...) method that doesn't return long, Long, VoltTable or VoltTable[].";
        throw compiler.new VoltCompilerException(msg);
    }
    builder.put("@run", procMethod);
    Map<String, Object> fields = builder.build();
    // determine if proc is read or read-write by checking if the proc contains any write sql stmts
    boolean readWrite = false;
    for (Object field : fields.values()) {
        if (!(field instanceof SQLStmt))
            continue;
        SQLStmt stmt = (SQLStmt) field;
        QueryType qtype = QueryType.getFromSQL(stmt.getText());
        if (!qtype.isReadOnly()) {
            readWrite = true;
            break;
        }
    }
    // default to FASTER determinism mode, which may favor non-deterministic plans
    // but if it's a read-write proc, use a SAFER planning mode wrt determinism.
    final DeterminismMode detMode = readWrite ? DeterminismMode.SAFER : DeterminismMode.FASTER;
    for (Entry<String, Object> entry : fields.entrySet()) {
        if (!(entry.getValue() instanceof SQLStmt))
            continue;
        String stmtName = entry.getKey();
        SQLStmt stmt = (SQLStmt) entry.getValue();
        // add the statement to the catalog
        Statement catalogStmt = procedure.getStatements().add(stmtName);
        // compile the statement
        StatementPartitioning partitioning = info.singlePartition ? StatementPartitioning.forceSP() : StatementPartitioning.forceMP();
        boolean cacheHit = StatementCompiler.compileFromSqlTextAndUpdateCatalog(compiler, hsql, db, estimates, catalogStmt, stmt.getText(), stmt.getJoinOrder(), detMode, partitioning);
        // if this was a cache hit or specified single, don't worry about figuring out more partitioning
        if (partitioning.wasSpecifiedAsSingle() || cacheHit) {
            // Don't try to infer what's already been asserted.
            procWantsCommonPartitioning = false;
        // The planner does not currently attempt to second-guess a plan declared as single-partition, maybe some day.
        // In theory, the PartitioningForStatement would confirm the use of (only) a parameter as a partition key --
        // or if the partition key was determined to be some other constant (expression?) it might display an informational
        // message that the passed parameter is assumed to be equal to the hard-coded partition key constant (expression).
        // Validate any inferred statement partitioning given the statement's possible usage, until a contradiction is found.
        } else if (procWantsCommonPartitioning) {
            // conflict with the partitioning of prior statements.
            if (partitioning.getCountOfIndependentlyPartitionedTables() == 1) {
                AbstractExpression statementPartitionExpression = partitioning.singlePartitioningExpressionForReport();
                if (statementPartitionExpression != null) {
                    if (commonPartitionExpression == null) {
                        commonPartitionExpression = statementPartitionExpression;
                        exampleSPstatement = stmt.getText();
                        exampleSPvalue = partitioning.getInferredPartitioningValue();
                    } else if (commonPartitionExpression.equals(statementPartitionExpression) || (statementPartitionExpression instanceof ParameterValueExpression && commonPartitionExpression instanceof ParameterValueExpression)) {
                    // Any constant used for partitioning would have to be the same for all statements, but
                    // any statement parameter used for partitioning MIGHT come from the same proc parameter as
                    // any other statement's parameter used for partitioning.
                    } else {
                        // appears to be different partitioning for different statements
                        procWantsCommonPartitioning = false;
                    }
                } else {
                    // There is a statement with a partitioned table whose partitioning column is
                    // not equality filtered with a constant or param. Abandon all hope.
                    procWantsCommonPartitioning = false;
                }
            // Usually, replicated-only statements in a mix with others have no effect on the MP/SP decision
            } else if (partitioning.getCountOfPartitionedTables() == 0) {
                // but SP is strictly forbidden for DML, to maintain the consistency of the replicated data.
                if (partitioning.getIsReplicatedTableDML()) {
                    procWantsCommonPartitioning = false;
                }
            } else {
                // There is a statement with a partitioned table whose partitioning column is
                // not equality filtered with a constant or param. Abandon all hope.
                procWantsCommonPartitioning = false;
            }
        }
        // if a single stmt is not read only, then the proc is not read only
        if (catalogStmt.getReadonly() == false) {
            procHasWriteStmts = true;
        }
        if (catalogStmt.getSeqscancount() > 0) {
            procHasSeqScans = true;
        }
    }
    // MIGHT the planner have uncovered an overlooked opportunity to run all statements SP?
    if (procWantsCommonPartitioning && (commonPartitionExpression != null)) {
        String msg = null;
        if (commonPartitionExpression instanceof ParameterValueExpression) {
            msg = "This procedure might benefit from an @ProcInfo annotation designating parameter " + ((ParameterValueExpression) commonPartitionExpression).getParameterIndex() + " of statement '" + exampleSPstatement + "'";
        } else {
            String valueDescription = null;
            if (exampleSPvalue == null) {
                // Statements partitioned on a runtime constant. This is likely to be cryptic, but hopefully gets the idea across.
                valueDescription = "of " + commonPartitionExpression.explain("");
            } else {
                // A simple constant value COULD have been a parameter.
                valueDescription = exampleSPvalue.toString();
            }
            msg = "This procedure might benefit from an @ProcInfo annotation referencing an added parameter passed the value " + valueDescription;
        }
        compiler.addInfo(msg);
    }
    // set the read onlyness of a proc
    procedure.setReadonly(procHasWriteStmts == false);
    procedure.setHasseqscans(procHasSeqScans);
    checkForDeterminismWarnings(compiler, shortName, procedure, procHasWriteStmts);
    // set procedure parameter types
    CatalogMap<ProcParameter> params = procedure.getParameters();
    Class<?>[] paramTypes = procMethod.getParameterTypes();
    for (int i = 0; i < paramTypes.length; i++) {
        Class<?> cls = paramTypes[i];
        ProcParameter param = params.add(String.valueOf(i));
        param.setIndex(i);
        // handle the case where the param is an array
        if (cls.isArray()) {
            param.setIsarray(true);
            cls = cls.getComponentType();
        } else
            param.setIsarray(false);
        // boxed types are not supported parameters at this time
        if ((cls == Long.class) || (cls == Integer.class) || (cls == Short.class) || (cls == Byte.class) || (cls == Double.class) || (cls == Character.class) || (cls == Boolean.class)) {
            String msg = "Procedure: " + shortName + " has a parameter with a boxed type: ";
            msg += cls.getSimpleName();
            msg += ". Replace this parameter with the corresponding primitive type and the procedure may compile.";
            throw compiler.new VoltCompilerException(msg);
        } else if ((cls == Float.class) || (cls == float.class)) {
            String msg = "Procedure: " + shortName + " has a parameter with type: ";
            msg += cls.getSimpleName();
            msg += ". Replace this parameter type with double and the procedure may compile.";
            throw compiler.new VoltCompilerException(msg);
        }
        VoltType type;
        try {
            type = VoltType.typeFromClass(cls);
        } catch (VoltTypeException e) {
            // handle the case where the type is invalid
            String msg = "Procedure: " + shortName + " has a parameter with invalid type: ";
            msg += cls.getSimpleName();
            throw compiler.new VoltCompilerException(msg);
        } catch (RuntimeException e) {
            String msg = "Procedure: " + shortName + " unexpectedly failed a check on a parameter of type: ";
            msg += cls.getSimpleName();
            msg += " with error: ";
            msg += e.toString();
            throw compiler.new VoltCompilerException(msg);
        }
        param.setType(type.getValue());
    }
    // parse the procinfo
    procedure.setSinglepartition(info.singlePartition);
    if (info.singlePartition) {
        parsePartitionInfo(compiler, db, procedure, info.partitionInfo);
        if (procedure.getPartitionparameter() >= paramTypes.length) {
            String msg = "PartitionInfo parameter not a valid parameter for procedure: " + procedure.getClassname();
            throw compiler.new VoltCompilerException(msg);
        }
        // check the type of partition parameter meets our high standards
        Class<?> partitionType = paramTypes[procedure.getPartitionparameter()];
        Class<?>[] validPartitionClzzes = { Long.class, Integer.class, Short.class, Byte.class, long.class, int.class, short.class, byte.class, String.class, byte[].class };
        boolean found = false;
        for (Class<?> candidate : validPartitionClzzes) {
            if (partitionType == candidate)
                found = true;
        }
        if (!found) {
            String msg = "PartitionInfo parameter must be a String or Number for procedure: " + procedure.getClassname();
            throw compiler.new VoltCompilerException(msg);
        }
        VoltType columnType = VoltType.get((byte) procedure.getPartitioncolumn().getType());
        VoltType paramType = VoltType.typeFromClass(partitionType);
        if (!columnType.canExactlyRepresentAnyValueOf(paramType)) {
            String msg = "Type mismatch between partition column and partition parameter for procedure " + procedure.getClassname() + " may cause overflow or loss of precision.\nPartition column is type " + columnType + " and partition parameter is type " + paramType;
            throw compiler.new VoltCompilerException(msg);
        } else if (!paramType.canExactlyRepresentAnyValueOf(columnType)) {
            String msg = "Type mismatch between partition column and partition parameter for procedure " + procedure.getClassname() + " does not allow the full range of partition key values.\nPartition column is type " + columnType + " and partition parameter is type " + paramType;
            compiler.addWarn(msg);
        }
    }
    // put the compiled code for this procedure into the jarfile
    // need to find the outermost ancestor class for the procedure in the event
    // that it's actually an inner (or inner inner...) class.
    // addClassToJar recursively adds all the children, which should include this
    // class
    Class<?> ancestor = procClass;
    while (ancestor.getEnclosingClass() != null) {
        ancestor = ancestor.getEnclosingClass();
    }
    compiler.addClassToJar(jarOutput, ancestor);
}
Also used : Group(org.voltdb.catalog.Group) VoltProcedure(org.voltdb.VoltProcedure) VoltTypeException(org.voltdb.VoltTypeException) ProcedureAnnotation(org.voltdb.compilereport.ProcedureAnnotation) ProcInfoData(org.voltdb.ProcInfoData) StatementPartitioning(org.voltdb.planner.StatementPartitioning) VoltProcedure(org.voltdb.VoltProcedure) VoltNonTransactionalProcedure(org.voltdb.VoltNonTransactionalProcedure) Procedure(org.voltdb.catalog.Procedure) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression) ProcParameter(org.voltdb.catalog.ProcParameter) ProcInfo(org.voltdb.ProcInfo) SQLStmt(org.voltdb.SQLStmt) Statement(org.voltdb.catalog.Statement) Method(java.lang.reflect.Method) VoltTable(org.voltdb.VoltTable) ImmutableMap(com.google_voltpatches.common.collect.ImmutableMap) AbstractExpression(org.voltdb.expressions.AbstractExpression) VoltType(org.voltdb.VoltType) GroupRef(org.voltdb.catalog.GroupRef) QueryType(org.voltdb.types.QueryType)

Example 25 with ParameterValueExpression

use of org.voltdb.expressions.ParameterValueExpression in project voltdb by VoltDB.

the class StatementCompiler method compileDefaultProcedure.

/**
     * This procedure compiles a shim org.voltdb.catalog.Procedure representing a default proc.
     * The shim has no plan and few details that are expensive to compute.
     * The returned proc instance has a full plan and can be used to create a ProcedureRunner.
     * Note that while there are two procedure objects here, none are rooted in a real catalog;
     * they are entirely parallel to regular, catalog procs.
     *
     * This code could probably go a few different places. It duplicates a bit too much of the
     * StatmentCompiler code for my taste, so I put it here. Next pass could reduce some of the
     * duplication?
     */
public static Procedure compileDefaultProcedure(PlannerTool plannerTool, Procedure catProc, String sqlText) {
    // fake db makes it easy to create procedures that aren't part of the main catalog
    Database fakeDb = new Catalog().getClusters().add("cluster").getDatabases().add("database");
    Table table = catProc.getPartitiontable();
    // determine the type of the query
    QueryType qtype = QueryType.getFromSQL(sqlText);
    StatementPartitioning partitioning = catProc.getSinglepartition() ? StatementPartitioning.forceSP() : StatementPartitioning.forceMP();
    CompiledPlan plan = plannerTool.planSqlCore(sqlText, partitioning);
    Procedure newCatProc = fakeDb.getProcedures().add(catProc.getTypeName());
    newCatProc.setClassname(catProc.getClassname());
    newCatProc.setDefaultproc(true);
    newCatProc.setEverysite(false);
    newCatProc.setHasjava(false);
    newCatProc.setPartitioncolumn(catProc.getPartitioncolumn());
    newCatProc.setPartitionparameter(catProc.getPartitionparameter());
    newCatProc.setPartitiontable(catProc.getPartitiontable());
    newCatProc.setReadonly(catProc.getReadonly());
    newCatProc.setSinglepartition(catProc.getSinglepartition());
    newCatProc.setSystemproc(false);
    if (catProc.getPartitionparameter() >= 0) {
        newCatProc.setAttachment(new ProcedurePartitionInfo(VoltType.get((byte) catProc.getPartitioncolumn().getType()), catProc.getPartitionparameter()));
    }
    CatalogMap<Statement> statements = newCatProc.getStatements();
    assert (statements != null);
    Statement stmt = statements.add(VoltDB.ANON_STMT_NAME);
    stmt.setSqltext(sqlText);
    stmt.setReadonly(catProc.getReadonly());
    stmt.setQuerytype(qtype.getValue());
    stmt.setSinglepartition(catProc.getSinglepartition());
    stmt.setIscontentdeterministic(true);
    stmt.setIsorderdeterministic(true);
    stmt.setNondeterminismdetail("NO CONTENT FOR DEFAULT PROCS");
    stmt.setSeqscancount(plan.countSeqScans());
    stmt.setReplicatedtabledml(!catProc.getReadonly() && table.getIsreplicated());
    // We will need to update the system catalogs with this new information
    for (int i = 0; i < plan.parameters.length; ++i) {
        StmtParameter catalogParam = stmt.getParameters().add(String.valueOf(i));
        catalogParam.setIndex(i);
        ParameterValueExpression pve = plan.parameters[i];
        catalogParam.setJavatype(pve.getValueType().getValue());
        catalogParam.setIsarray(pve.getParamIsVector());
    }
    PlanFragment frag = stmt.getFragments().add("0");
    // 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);
    }
    byte[] planBytes = writePlanBytes(frag, 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);
    frag.setPlanhash(Encoder.hexEncode(md.digest()));
    if (plan.subPlanGraph != null) {
        frag.setHasdependencies(true);
        frag.setNontransactional(true);
        frag.setMultipartition(true);
        frag = stmt.getFragments().add("1");
        frag.setHasdependencies(false);
        frag.setNontransactional(false);
        frag.setMultipartition(true);
        byte[] subBytes = writePlanBytes(frag, plan.subPlanGraph);
        // compute the 40 bytes of hex from the 20 byte sha1 hash of the plans
        md.reset();
        md.update(subBytes);
        frag.setPlanhash(Encoder.hexEncode(md.digest()));
    } else {
        frag.setHasdependencies(false);
        frag.setNontransactional(false);
        frag.setMultipartition(false);
    }
    // set the procedure parameter types from the statement parameter types
    int paramCount = 0;
    for (StmtParameter stmtParam : CatalogUtil.getSortedCatalogItems(stmt.getParameters(), "index")) {
        // name each parameter "param1", "param2", etc...
        ProcParameter procParam = newCatProc.getParameters().add("param" + String.valueOf(paramCount));
        procParam.setIndex(stmtParam.getIndex());
        procParam.setIsarray(stmtParam.getIsarray());
        procParam.setType(stmtParam.getJavatype());
        paramCount++;
    }
    return newCatProc;
}
Also used : CompiledPlan(org.voltdb.planner.CompiledPlan) ProcedurePartitionInfo(org.voltdb.CatalogContext.ProcedurePartitionInfo) Table(org.voltdb.catalog.Table) Statement(org.voltdb.catalog.Statement) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) Catalog(org.voltdb.catalog.Catalog) PlanFragment(org.voltdb.catalog.PlanFragment) StmtParameter(org.voltdb.catalog.StmtParameter) Database(org.voltdb.catalog.Database) StatementPartitioning(org.voltdb.planner.StatementPartitioning) Procedure(org.voltdb.catalog.Procedure) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression) MessageDigest(java.security.MessageDigest) QueryType(org.voltdb.types.QueryType) ProcParameter(org.voltdb.catalog.ProcParameter)

Aggregations

ParameterValueExpression (org.voltdb.expressions.ParameterValueExpression)25 AbstractExpression (org.voltdb.expressions.AbstractExpression)16 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)9 ConstantValueExpression (org.voltdb.expressions.ConstantValueExpression)8 Constraint (org.voltdb.catalog.Constraint)6 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)5 ArrayList (java.util.ArrayList)4 Statement (org.voltdb.catalog.Statement)4 Table (org.voltdb.catalog.Table)4 SchemaColumn (org.voltdb.plannodes.SchemaColumn)4 VoltType (org.voltdb.VoltType)3 ProcParameter (org.voltdb.catalog.ProcParameter)3 Procedure (org.voltdb.catalog.Procedure)3 StmtParameter (org.voltdb.catalog.StmtParameter)3 StatementPartitioning (org.voltdb.planner.StatementPartitioning)3 QueryType (org.voltdb.types.QueryType)3 HashSet (java.util.HashSet)2 Set (java.util.Set)2 VoltXMLElement (org.hsqldb_voltpatches.VoltXMLElement)2 JSONException (org.json_voltpatches.JSONException)2