Search in sources :

Example 31 with VoltCompilerException

use of org.voltdb.compiler.VoltCompiler.VoltCompilerException in project voltdb by VoltDB.

the class ProcedureCompiler method getValidSQLStmts.

public static Map<String, SQLStmt> getValidSQLStmts(VoltCompiler compiler, String procName, Class<?> procClass, Object procInstance, boolean withPrivate) throws VoltCompilerException {
    Map<String, SQLStmt> retval = new HashMap<>();
    Field[] fields = procClass.getDeclaredFields();
    for (Field f : fields) {
        // skip non SQL fields
        if (f.getType() != SQLStmt.class)
            continue;
        int modifiers = f.getModifiers();
        // skip private fields if asked (usually a superclass)
        if (Modifier.isPrivate(modifiers) && (!withPrivate))
            continue;
        // don't allow non-final SQLStmts
        if (Modifier.isFinal(modifiers) == false) {
            String msg = "Procedure " + procName + " contains a non-final SQLStmt field.";
            if (procClass.getSimpleName().equals(procName) == false) {
                msg = "Superclass " + procClass.getSimpleName() + " of procedure " + procName + " contains a non-final SQLStmt field.";
            }
            if (compiler != null)
                throw compiler.new VoltCompilerException(msg);
            else
                new VoltLogger("HOST").warn(msg);
        }
        f.setAccessible(true);
        SQLStmt stmt = null;
        try {
            stmt = (SQLStmt) f.get(procInstance);
        }// it's weird, but seems rather hard to hit
         catch (Exception e) {
            e.printStackTrace();
            continue;
        }
        retval.put(f.getName(), stmt);
    }
    Class<?> superClass = procClass.getSuperclass();
    if (superClass != null) {
        Map<String, SQLStmt> superStmts = getValidSQLStmts(compiler, procName, superClass, procInstance, false);
        for (Entry<String, SQLStmt> e : superStmts.entrySet()) {
            if (retval.containsKey(e.getKey()) == false)
                retval.put(e.getKey(), e.getValue());
        }
    }
    return retval;
}
Also used : Field(java.lang.reflect.Field) SQLStmt(org.voltdb.SQLStmt) HashMap(java.util.HashMap) VoltLogger(org.voltcore.logging.VoltLogger) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) VoltTypeException(org.voltdb.VoltTypeException)

Example 32 with VoltCompilerException

use of org.voltdb.compiler.VoltCompiler.VoltCompilerException in project voltdb by VoltDB.

the class ProcedureCompiler method compileNTProcedure.

private static void compileNTProcedure(VoltCompiler compiler, Class<?> procClass, Procedure procedure, InMemoryJarfile jarOutput) throws VoltCompilerException {
    // get the short name of the class (no package)
    String shortName = deriveShortProcedureName(procClass.getName());
    try {
        procClass.newInstance();
    } catch (InstantiationException e) {
        throw new RuntimeException("Error instantiating procedure \"" + procClass.getName() + "\"", e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException("Error instantiating procedure \"" + procClass.getName() + "\"", e);
    }
    // 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() != CompletableFuture.class) && (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, VoltTable[] or CompleteableFuture.";
        throw compiler.new VoltCompilerException(msg);
    }
    // set procedure parameter types
    CatalogMap<ProcParameter> params = procedure.getParameters();
    Class<?>[] paramTypes = procMethod.getParameterTypes();
    setCatalogProcedureParameterTypes(compiler, shortName, params, paramTypes);
    // actually make sure the catalog records this is a different kind of procedure
    procedure.setTransactional(false);
    // 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 : Method(java.lang.reflect.Method) CompletableFuture(java.util.concurrent.CompletableFuture) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) ProcParameter(org.voltdb.catalog.ProcParameter)

Example 33 with VoltCompilerException

use of org.voltdb.compiler.VoltCompiler.VoltCompilerException in project voltdb by VoltDB.

the class ProcedureCompiler method parsePartitionInfo.

/**
     * Determine which parameter is the partition indicator
     */
static void parsePartitionInfo(VoltCompiler compiler, Database db, Procedure procedure, String info) throws VoltCompilerException {
    assert (procedure.getSinglepartition() == true);
    // check this isn't empty
    if (info.length() == 0) {
        String msg = "Missing or Truncated PartitionInfo in attribute for procedure: " + procedure.getClassname();
        throw compiler.new VoltCompilerException(msg);
    }
    // split on the colon
    String[] parts = info.split(":");
    // if the colon doesn't split well, we have a problem
    if (parts.length != 2) {
        String msg = "Possibly invalid PartitionInfo in attribute for procedure: " + procedure.getClassname();
        throw compiler.new VoltCompilerException(msg);
    }
    // relabel the parts for code readability
    String columnInfo = parts[0].trim();
    int paramIndex = Integer.parseInt(parts[1].trim());
    int paramCount = procedure.getParameters().size();
    if ((paramIndex < 0) || (paramIndex >= paramCount)) {
        String msg = "PartitionInfo specifies invalid parameter index for procedure: " + procedure.getClassname();
        throw compiler.new VoltCompilerException(msg);
    }
    // locate the parameter
    procedure.setPartitionparameter(paramIndex);
    // split the columninfo
    parts = columnInfo.split("\\.");
    if (parts.length != 2) {
        String msg = "Possibly invalid PartitionInfo in attribute for procedure: " + procedure.getClassname();
        throw compiler.new VoltCompilerException(msg);
    }
    // relabel the parts for code readability
    String tableName = parts[0].trim();
    String columnName = parts[1].trim();
    // locate the partition column
    CatalogMap<Table> tables = db.getTables();
    for (Table table : tables) {
        if (table.getTypeName().equalsIgnoreCase(tableName)) {
            CatalogMap<Column> columns = table.getColumns();
            Column partitionColumn = table.getPartitioncolumn();
            if (partitionColumn == null) {
                String msg = String.format("PartitionInfo for procedure %s references table %s which has no partition column (may be replicated).", procedure.getClassname(), table.getTypeName());
                throw compiler.new VoltCompilerException(msg);
            }
            for (Column column : columns) {
                if (column.getTypeName().equalsIgnoreCase(columnName)) {
                    if (partitionColumn.getTypeName().equals(column.getTypeName())) {
                        procedure.setPartitioncolumn(column);
                        procedure.setPartitiontable(table);
                        return;
                    } else {
                        String msg = "PartitionInfo for procedure " + procedure.getClassname() + " refers to a column in schema which is not a partition key.";
                        throw compiler.new VoltCompilerException(msg);
                    }
                }
            }
        }
    }
    String msg = "PartitionInfo for procedure " + procedure.getClassname() + " refers to a column in schema which can't be found.";
    throw compiler.new VoltCompilerException(msg);
}
Also used : Table(org.voltdb.catalog.Table) VoltTable(org.voltdb.VoltTable) Column(org.voltdb.catalog.Column) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException)

Example 34 with VoltCompilerException

use of org.voltdb.compiler.VoltCompiler.VoltCompilerException 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 35 with VoltCompilerException

use of org.voltdb.compiler.VoltCompiler.VoltCompilerException in project voltdb by VoltDB.

the class ProcedureCompiler method setCatalogProcedureParameterTypes.

private static void setCatalogProcedureParameterTypes(VoltCompiler compiler, String shortName, CatalogMap<ProcParameter> params, Class<?>[] paramTypes) throws VoltCompilerException {
    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());
    }
}
Also used : VoltTypeException(org.voltdb.VoltTypeException) VoltType(org.voltdb.VoltType) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) ProcParameter(org.voltdb.catalog.ProcParameter)

Aggregations

VoltCompilerException (org.voltdb.compiler.VoltCompiler.VoltCompilerException)38 Matcher (java.util.regex.Matcher)15 Constraint (org.voltdb.catalog.Constraint)11 VoltXMLElement (org.hsqldb_voltpatches.VoltXMLElement)10 Column (org.voltdb.catalog.Column)7 AbstractExpression (org.voltdb.expressions.AbstractExpression)7 VoltType (org.voltdb.VoltType)6 Index (org.voltdb.catalog.Index)5 IOException (java.io.IOException)4 HSQLParseException (org.hsqldb_voltpatches.HSQLInterface.HSQLParseException)4 JSONException (org.json_voltpatches.JSONException)4 VoltTypeException (org.voltdb.VoltTypeException)4 Group (org.voltdb.catalog.Group)4 ProcParameter (org.voltdb.catalog.ProcParameter)4 Statement (org.voltdb.catalog.Statement)4 Table (org.voltdb.catalog.Table)4 Method (java.lang.reflect.Method)3 ArrayList (java.util.ArrayList)3 ColumnRef (org.voltdb.catalog.ColumnRef)3 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)3