Search in sources :

Example 21 with VoltCompilerException

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

the class DropStream method processStatement.

@Override
protected boolean processStatement(DDLStatement ddlStatement, Database db, DdlProceduresToLoad whichProcs) throws VoltCompilerException {
    // matches if it is DROP STREAM
    // group 1 is stream name
    // guard against drop regular table
    Matcher statementMatcher = SQLParser.matchDropStream(ddlStatement.statement);
    if (statementMatcher.matches()) {
        String streamName = checkIdentifierStart(statementMatcher.group(1), ddlStatement.statement);
        if (isRegularTable(m_schema, streamName)) {
            throw m_compiler.new VoltCompilerException(String.format("Invalid DROP STREAM statement: table %s is not a stream.", streamName));
        }
        m_returnAfterThis = true;
    }
    return false;
}
Also used : Matcher(java.util.regex.Matcher) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException)

Example 22 with VoltCompilerException

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

the class PartitionStatement method processPartitionTable.

private boolean processPartitionTable(String statement) throws VoltCompilerException {
    // matches if it is PARTITION TABLE <table> ON COLUMN <column>
    Matcher statementMatcher = SQLParser.matchPartitionTable(statement);
    if (!statementMatcher.matches()) {
        throw m_compiler.new VoltCompilerException(String.format("Invalid PARTITION statement: \"%s\", " + "expected syntax: PARTITION TABLE <table> ON COLUMN <column>", // remove trailing semicolon
        statement.substring(0, statement.length() - 1)));
    }
    // group(1) -> table, group(2) -> column
    String tableName = checkIdentifierStart(statementMatcher.group(1), statement);
    String columnName = checkIdentifierStart(statementMatcher.group(2), statement);
    VoltXMLElement tableXML = m_schema.findChild("table", tableName.toUpperCase());
    if (tableXML != null) {
        tableXML.attributes.put("partitioncolumn", columnName.toUpperCase());
        // Column validity check done by VoltCompiler in post-processing
        // mark the table as dirty for the purposes of caching sql statements
        m_compiler.markTableAsDirty(tableName);
    } else {
        throw m_compiler.new VoltCompilerException(String.format("Invalid PARTITION statement: table %s does not exist", tableName));
    }
    return true;
}
Also used : Matcher(java.util.regex.Matcher) VoltXMLElement(org.hsqldb_voltpatches.VoltXMLElement) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException)

Example 23 with VoltCompilerException

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

the class MaterializedViewProcessor method startProcessing.

/**
     * Add materialized view info to the catalog for the tables that are
     * materialized views.
     * @throws VoltCompilerException
     */
public void startProcessing(Database db, HashMap<Table, String> matViewMap, TreeSet<String> exportTableNames) throws VoltCompilerException {
    HashSet<String> viewTableNames = new HashSet<>();
    for (Entry<Table, String> entry : matViewMap.entrySet()) {
        viewTableNames.add(entry.getKey().getTypeName());
    }
    for (Entry<Table, String> entry : matViewMap.entrySet()) {
        Table destTable = entry.getKey();
        String query = entry.getValue();
        // get the xml for the query
        VoltXMLElement xmlquery = null;
        try {
            xmlquery = m_hsql.getXMLCompiledStatement(query);
        } catch (HSQLParseException e) {
            e.printStackTrace();
        }
        assert (xmlquery != null);
        // parse the xml like any other sql statement
        ParsedSelectStmt stmt = null;
        try {
            stmt = (ParsedSelectStmt) AbstractParsedStmt.parse(query, xmlquery, null, db, null);
        } catch (Exception e) {
            throw m_compiler.new VoltCompilerException(e.getMessage());
        }
        assert (stmt != null);
        String viewName = destTable.getTypeName();
        // throw an error if the view isn't within voltdb's limited world view
        checkViewMeetsSpec(viewName, stmt);
        // The primary key index is yet to be defined (below).
        for (Index destIndex : destTable.getIndexes()) {
            if (destIndex.getUnique() || destIndex.getAssumeunique()) {
                String msg = "A UNIQUE or ASSUMEUNIQUE index is not allowed on a materialized view. " + "Remove the qualifier from the index " + destIndex.getTypeName() + "defined on the materialized view \"" + viewName + "\".";
                throw m_compiler.new VoltCompilerException(msg);
            }
        }
        // A Materialized view cannot depend on another view.
        for (Table srcTable : stmt.m_tableList) {
            if (viewTableNames.contains(srcTable.getTypeName())) {
                String msg = String.format("A materialized view (%s) can not be defined on another view (%s).", viewName, srcTable.getTypeName());
                throw m_compiler.new VoltCompilerException(msg);
            }
        }
        // The existing code base still need this materializer field to tell if a table
        // is a materialized view table. Leaving this for future refactoring.
        destTable.setMaterializer(stmt.m_tableList.get(0));
        List<Column> destColumnArray = CatalogUtil.getSortedCatalogItems(destTable.getColumns(), "index");
        List<AbstractExpression> groupbyExprs = null;
        if (stmt.hasComplexGroupby()) {
            groupbyExprs = new ArrayList<>();
            for (ParsedColInfo col : stmt.groupByColumns()) {
                groupbyExprs.add(col.expression);
            }
        }
        // Generate query XMLs for min/max recalculation (ENG-8641)
        boolean isMultiTableView = stmt.m_tableList.size() > 1;
        MatViewFallbackQueryXMLGenerator xmlGen = new MatViewFallbackQueryXMLGenerator(xmlquery, stmt.groupByColumns(), stmt.m_displayColumns, isMultiTableView);
        List<VoltXMLElement> fallbackQueryXMLs = xmlGen.getFallbackQueryXMLs();
        // index or constraint in order to avoid error and crash.
        if (stmt.groupByColumns().size() != 0) {
            Index pkIndex = destTable.getIndexes().add(HSQLInterface.AUTO_GEN_MATVIEW_IDX);
            pkIndex.setType(IndexType.BALANCED_TREE.getValue());
            pkIndex.setUnique(true);
            // assume index 1 throuh #grpByCols + 1 are the cols
            for (int i = 0; i < stmt.groupByColumns().size(); i++) {
                ColumnRef c = pkIndex.getColumns().add(String.valueOf(i));
                c.setColumn(destColumnArray.get(i));
                c.setIndex(i);
            }
            Constraint pkConstraint = destTable.getConstraints().add(HSQLInterface.AUTO_GEN_MATVIEW_CONST);
            pkConstraint.setType(ConstraintType.PRIMARY_KEY.getValue());
            pkConstraint.setIndex(pkIndex);
        }
        // If we have an unsafe MV message, then
        // remember it here.  We don't really know how
        // to transfer the message through the catalog, but
        // we can transmit the existence of the message.
        boolean isSafeForDDL = (stmt.getUnsafeMVMessage() == null);
        // Here the code path diverges for different kinds of views (single table view and joined table view)
        if (isMultiTableView) {
            // Materialized view on joined tables
            // Add mvHandlerInfo to the destTable:
            MaterializedViewHandlerInfo mvHandlerInfo = destTable.getMvhandlerinfo().add("mvHandlerInfo");
            mvHandlerInfo.setDesttable(destTable);
            for (Table srcTable : stmt.m_tableList) {
                // Now we do not support having a view on persistent tables joining streamed tables.
                if (exportTableNames.contains(srcTable.getTypeName())) {
                    String msg = String.format("A materialized view (%s) on joined tables cannot have streamed table (%s) as its source.", viewName, srcTable.getTypeName());
                    throw m_compiler.new VoltCompilerException(msg);
                }
                // The view table will need to keep a list of its source tables.
                // The list is used to install / uninstall the view reference on the source tables when the
                // view handler is constructed / destroyed.
                TableRef tableRef = mvHandlerInfo.getSourcetables().add(srcTable.getTypeName());
                tableRef.setTable(srcTable);
                // There could be more than one partition column candidate, but we will only use the first one we found.
                if (destTable.getPartitioncolumn() == null && srcTable.getPartitioncolumn() != null) {
                    Column partitionColumn = srcTable.getPartitioncolumn();
                    String partitionColName = partitionColumn.getTypeName();
                    String srcTableName = srcTable.getTypeName();
                    destTable.setIsreplicated(false);
                    if (stmt.hasComplexGroupby()) {
                        for (int i = 0; i < groupbyExprs.size(); i++) {
                            AbstractExpression groupbyExpr = groupbyExprs.get(i);
                            if (groupbyExpr instanceof TupleValueExpression) {
                                TupleValueExpression tve = (TupleValueExpression) groupbyExpr;
                                if (tve.getTableName().equals(srcTableName) && tve.getColumnName().equals(partitionColName)) {
                                    // The partition column is set to destColumnArray.get(i), because we have the restriction
                                    // that the non-aggregate columns must come at the very begining, and must exactly match
                                    // the group-by columns.
                                    // If we are going to remove this restriction in the future, then we need to do more work
                                    // in order to find a proper partition column.
                                    destTable.setPartitioncolumn(destColumnArray.get(i));
                                    break;
                                }
                            }
                        }
                    } else {
                        for (int i = 0; i < stmt.groupByColumns().size(); i++) {
                            ParsedColInfo gbcol = stmt.groupByColumns().get(i);
                            if (gbcol.tableName.equals(srcTableName) && gbcol.columnName.equals(partitionColName)) {
                                destTable.setPartitioncolumn(destColumnArray.get(i));
                                break;
                            }
                        }
                    }
                }
            // end find partition column
            }
            // end for each source table
            compileFallbackQueriesAndUpdateCatalog(db, query, fallbackQueryXMLs, mvHandlerInfo);
            compileCreateQueryAndUpdateCatalog(db, query, xmlquery, mvHandlerInfo);
            mvHandlerInfo.setGroupbycolumncount(stmt.groupByColumns().size());
            for (int i = 0; i < stmt.m_displayColumns.size(); i++) {
                ParsedColInfo col = stmt.m_displayColumns.get(i);
                Column destColumn = destColumnArray.get(i);
                setTypeAttributesForColumn(destColumn, col.expression);
                // Set the expression type here to determine the behavior of the merge function.
                destColumn.setAggregatetype(col.expression.getExpressionType().getValue());
            }
            mvHandlerInfo.setIssafewithnonemptysources(isSafeForDDL);
        } else {
            // =======================================================================================
            // Materialized view on single table
            // create the materializedviewinfo catalog node for the source table
            Table srcTable = stmt.m_tableList.get(0);
            MaterializedViewInfo matviewinfo = srcTable.getViews().add(viewName);
            matviewinfo.setDest(destTable);
            AbstractExpression where = stmt.getSingleTableFilterExpression();
            if (where != null) {
                String hex = Encoder.hexEncode(where.toJSONString());
                matviewinfo.setPredicate(hex);
            } else {
                matviewinfo.setPredicate("");
            }
            List<Column> srcColumnArray = CatalogUtil.getSortedCatalogItems(srcTable.getColumns(), "index");
            if (stmt.hasComplexGroupby()) {
                // Parse group by expressions to json string
                String groupbyExprsJson = null;
                try {
                    groupbyExprsJson = DDLCompiler.convertToJSONArray(groupbyExprs);
                } catch (JSONException e) {
                    throw m_compiler.new VoltCompilerException("Unexpected error serializing non-column " + "expressions for group by expressions: " + e.toString());
                }
                matviewinfo.setGroupbyexpressionsjson(groupbyExprsJson);
            } else {
                // add the group by columns from the src table
                for (int i = 0; i < stmt.groupByColumns().size(); i++) {
                    ParsedColInfo gbcol = stmt.groupByColumns().get(i);
                    Column srcCol = srcColumnArray.get(gbcol.index);
                    ColumnRef cref = matviewinfo.getGroupbycols().add(srcCol.getTypeName());
                    // groupByColumns is iterating in order of groups. Store that grouping order
                    // in the column ref index. When the catalog is serialized, it will, naturally,
                    // scramble this order like a two year playing dominos, presenting the data
                    // in a meaningless sequence.
                    // the column offset in the view's grouping order
                    cref.setIndex(i);
                    // the source column from the base (non-view) table
                    cref.setColumn(srcCol);
                    // parse out the group by columns into the dest table
                    ParsedColInfo col = stmt.m_displayColumns.get(i);
                    Column destColumn = destColumnArray.get(i);
                    processMaterializedViewColumn(srcTable, destColumn, ExpressionType.VALUE_TUPLE, (TupleValueExpression) col.expression);
                }
            }
            // Set up COUNT(*) column
            ParsedColInfo countCol = stmt.m_displayColumns.get(stmt.groupByColumns().size());
            assert (countCol.expression.getExpressionType() == ExpressionType.AGGREGATE_COUNT_STAR);
            assert (countCol.expression.getLeft() == null);
            processMaterializedViewColumn(srcTable, destColumnArray.get(stmt.groupByColumns().size()), ExpressionType.AGGREGATE_COUNT_STAR, null);
            // prepare info for aggregation columns.
            List<AbstractExpression> aggregationExprs = new ArrayList<>();
            boolean hasAggregationExprs = false;
            ArrayList<AbstractExpression> minMaxAggs = new ArrayList<>();
            for (int i = stmt.groupByColumns().size() + 1; i < stmt.m_displayColumns.size(); i++) {
                ParsedColInfo col = stmt.m_displayColumns.get(i);
                AbstractExpression aggExpr = col.expression.getLeft();
                if (aggExpr.getExpressionType() != ExpressionType.VALUE_TUPLE) {
                    hasAggregationExprs = true;
                }
                aggregationExprs.add(aggExpr);
                if (col.expression.getExpressionType() == ExpressionType.AGGREGATE_MIN || col.expression.getExpressionType() == ExpressionType.AGGREGATE_MAX) {
                    minMaxAggs.add(aggExpr);
                }
            }
            compileFallbackQueriesAndUpdateCatalog(db, query, fallbackQueryXMLs, matviewinfo);
            // set Aggregation Expressions.
            if (hasAggregationExprs) {
                String aggregationExprsJson = null;
                try {
                    aggregationExprsJson = DDLCompiler.convertToJSONArray(aggregationExprs);
                } catch (JSONException e) {
                    throw m_compiler.new VoltCompilerException("Unexpected error serializing non-column " + "expressions for aggregation expressions: " + e.toString());
                }
                matviewinfo.setAggregationexpressionsjson(aggregationExprsJson);
            }
            // Find index for each min/max aggCol/aggExpr (ENG-6511 and ENG-8512)
            for (Integer i = 0; i < minMaxAggs.size(); ++i) {
                Index found = findBestMatchIndexForMatviewMinOrMax(matviewinfo, srcTable, groupbyExprs, minMaxAggs.get(i));
                IndexRef refFound = matviewinfo.getIndexforminmax().add(i.toString());
                if (found != null) {
                    refFound.setName(found.getTypeName());
                } else {
                    refFound.setName("");
                }
            }
            // The COUNT(*) should return a BIGINT column, whereas we found here the COUNT(*) was assigned a INTEGER column.
            for (int i = 0; i <= stmt.groupByColumns().size(); i++) {
                ParsedColInfo col = stmt.m_displayColumns.get(i);
                Column destColumn = destColumnArray.get(i);
                setTypeAttributesForColumn(destColumn, col.expression);
            }
            // parse out the aggregation columns into the dest table
            for (int i = stmt.groupByColumns().size() + 1; i < stmt.m_displayColumns.size(); i++) {
                ParsedColInfo col = stmt.m_displayColumns.get(i);
                Column destColumn = destColumnArray.get(i);
                AbstractExpression colExpr = col.expression.getLeft();
                TupleValueExpression tve = null;
                if (colExpr.getExpressionType() == ExpressionType.VALUE_TUPLE) {
                    tve = (TupleValueExpression) colExpr;
                }
                processMaterializedViewColumn(srcTable, destColumn, col.expression.getExpressionType(), tve);
                setTypeAttributesForColumn(destColumn, col.expression);
            }
            if (srcTable.getPartitioncolumn() != null) {
                // Set the partitioning of destination tables of associated views.
                // If a view's source table is replicated, then a full scan of the
                // associated view is single-sited. If the source is partitioned,
                // a full scan of the view must be distributed, unless it is filtered
                // by the original table's partitioning key, which, to be filtered,
                // must also be a GROUP BY key.
                destTable.setIsreplicated(false);
                setGroupedTablePartitionColumn(matviewinfo, srcTable.getPartitioncolumn());
            }
            matviewinfo.setIssafewithnonemptysources(isSafeForDDL);
        }
    // end if single table view materialized view.
    }
}
Also used : Constraint(org.voltdb.catalog.Constraint) ArrayList(java.util.ArrayList) Index(org.voltdb.catalog.Index) VoltXMLElement(org.hsqldb_voltpatches.VoltXMLElement) HSQLParseException(org.hsqldb_voltpatches.HSQLInterface.HSQLParseException) IndexRef(org.voltdb.catalog.IndexRef) ParsedColInfo(org.voltdb.planner.ParsedColInfo) Column(org.voltdb.catalog.Column) ParsedSelectStmt(org.voltdb.planner.ParsedSelectStmt) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) HashSet(java.util.HashSet) MaterializedViewInfo(org.voltdb.catalog.MaterializedViewInfo) TupleValueExpression(org.voltdb.expressions.TupleValueExpression) Table(org.voltdb.catalog.Table) JSONException(org.json_voltpatches.JSONException) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) JSONException(org.json_voltpatches.JSONException) HSQLParseException(org.hsqldb_voltpatches.HSQLInterface.HSQLParseException) Constraint(org.voltdb.catalog.Constraint) AbstractExpression(org.voltdb.expressions.AbstractExpression) ColumnRef(org.voltdb.catalog.ColumnRef) MaterializedViewHandlerInfo(org.voltdb.catalog.MaterializedViewHandlerInfo) TableRef(org.voltdb.catalog.TableRef)

Example 24 with VoltCompilerException

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

the class MaterializedViewProcessor method checkViewMeetsSpec.

/**
     * Verify the materialized view meets our arcane rules about what can and can't
     * go in a materialized view. Throw hopefully helpful error messages when these
     * rules are inevitably borked.
     *
     * @param viewName The name of the view being checked.
     * @param stmt The output from the parser describing the select statement that creates the view.
     * @throws VoltCompilerException
     */
private void checkViewMeetsSpec(String viewName, ParsedSelectStmt stmt) throws VoltCompilerException {
    int groupColCount = stmt.groupByColumns().size();
    int displayColCount = stmt.m_displayColumns.size();
    StringBuffer msg = new StringBuffer();
    msg.append("Materialized view \"" + viewName + "\" ");
    if (stmt.getParameters().length > 0) {
        msg.append("contains placeholders (?), which are not allowed in the SELECT query for a view.");
        throw m_compiler.new VoltCompilerException(msg.toString());
    }
    List<AbstractExpression> checkExpressions = new ArrayList<>();
    int i;
    // the beginning of the display list.
    for (i = 0; i < groupColCount; i++) {
        ParsedColInfo gbcol = stmt.groupByColumns().get(i);
        ParsedColInfo outcol = stmt.m_displayColumns.get(i);
        // The columns must be equal.
        if (!outcol.expression.equals(gbcol.expression)) {
            msg.append("must exactly match the GROUP BY clause at index " + String.valueOf(i) + " of SELECT list.");
            throw m_compiler.new VoltCompilerException(msg.toString());
        }
        // check if the expression return type is not unique indexable
        StringBuffer exprMsg = new StringBuffer();
        if (!outcol.expression.isValueTypeUniqueIndexable(exprMsg)) {
            msg.append("with " + exprMsg + " in GROUP BY clause not supported.");
            throw m_compiler.new VoltCompilerException(msg.toString());
        }
        // collect all the expressions and we will check
        // for other guards on all of them together
        checkExpressions.add(outcol.expression);
    }
    // check for count star in the display list
    boolean countStarFound = false;
    if (i < displayColCount) {
        AbstractExpression coli = stmt.m_displayColumns.get(i).expression;
        if (coli.getExpressionType() == ExpressionType.AGGREGATE_COUNT_STAR) {
            countStarFound = true;
        }
    }
    if (countStarFound == false) {
        msg.append("must have count(*) after the GROUP BY columns (if any) but before the aggregate functions (if any).");
        throw m_compiler.new VoltCompilerException(msg.toString());
    }
    UnsafeOperatorsForDDL unsafeOps = new UnsafeOperatorsForDDL();
    // must be count(), min(), max() or sum().
    for (i++; i < displayColCount; i++) {
        ParsedColInfo outcol = stmt.m_displayColumns.get(i);
        // second one would fail.
        if ((outcol.expression.getExpressionType() != ExpressionType.AGGREGATE_COUNT) && (outcol.expression.getExpressionType() != ExpressionType.AGGREGATE_SUM) && (outcol.expression.getExpressionType() != ExpressionType.AGGREGATE_MIN) && (outcol.expression.getExpressionType() != ExpressionType.AGGREGATE_MAX)) {
            msg.append("must have non-group by columns aggregated by sum, count, min or max.");
            throw m_compiler.new VoltCompilerException(msg.toString());
        }
        // want to fail on legal aggregate expressions.
        if (outcol.expression.getLeft() != null) {
            checkExpressions.add(outcol.expression.getLeft());
        }
        // Check if the aggregation is safe for non-empty view source table.
        outcol.expression.findUnsafeOperatorsForDDL(unsafeOps);
        assert (outcol.expression.getRight() == null);
        assert (outcol.expression.getArgs() == null || outcol.expression.getArgs().size() == 0);
    }
    AbstractExpression where = stmt.getSingleTableFilterExpression();
    if (where != null) {
        checkExpressions.add(where);
    }
    /*
         * Gather up all the join expressions.  The ParsedSelectStatement
         * has not been analyzed yet, so it's not clear where these are.  But
         * the stmt knows.
         */
    stmt.gatherJoinExpressions(checkExpressions);
    if (stmt.getHavingPredicate() != null) {
        checkExpressions.add(stmt.getHavingPredicate());
    }
    // Check all the subexpressions we gathered up.
    if (!AbstractExpression.validateExprsForIndexesAndMVs(checkExpressions, msg)) {
        // The error message will be in the StringBuffer msg.
        throw m_compiler.new VoltCompilerException(msg.toString());
    }
    // views on nonempty tables.
    for (AbstractExpression expr : checkExpressions) {
        expr.findUnsafeOperatorsForDDL(unsafeOps);
    }
    if (unsafeOps.isUnsafe()) {
        stmt.setUnsafeDDLMessage(unsafeOps.toString());
    }
    if (stmt.hasSubquery()) {
        msg.append("with subquery sources is not supported.");
        throw m_compiler.new VoltCompilerException(msg.toString());
    }
    if (!stmt.m_joinTree.allInnerJoins()) {
        throw m_compiler.new VoltCompilerException("Materialized view only supports INNER JOIN.");
    }
    if (stmt.orderByColumns().size() != 0) {
        msg.append("with ORDER BY clause is not supported.");
        throw m_compiler.new VoltCompilerException(msg.toString());
    }
    if (stmt.hasLimitOrOffset()) {
        msg.append("with LIMIT or OFFSET clause is not supported.");
        throw m_compiler.new VoltCompilerException(msg.toString());
    }
    if (stmt.getHavingPredicate() != null) {
        msg.append("with HAVING clause is not supported.");
        throw m_compiler.new VoltCompilerException(msg.toString());
    }
    if (displayColCount <= groupColCount) {
        msg.append("has too few columns.");
        throw m_compiler.new VoltCompilerException(msg.toString());
    }
    checkViewSources(stmt.m_tableList);
}
Also used : UnsafeOperatorsForDDL(org.voltdb.expressions.AbstractExpression.UnsafeOperatorsForDDL) ParsedColInfo(org.voltdb.planner.ParsedColInfo) AbstractExpression(org.voltdb.expressions.AbstractExpression) ArrayList(java.util.ArrayList) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) Constraint(org.voltdb.catalog.Constraint)

Example 25 with VoltCompilerException

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

the class DDLCompiler method addConstraintToCatalog.

/**
     * Add a constraint on a given table to the catalog
     * @param table                The table on which the constraint will be enforced
     * @param node                 The XML node representing the constraint
     * @param indexReplacementMap
     * @throws VoltCompilerException
     */
private void addConstraintToCatalog(Table table, VoltXMLElement node, Map<String, String> indexReplacementMap, Map<String, Index> indexMap) throws VoltCompilerException {
    assert node.name.equals("constraint");
    String name = node.attributes.get("name");
    String typeName = node.attributes.get("constrainttype");
    ConstraintType type = ConstraintType.valueOf(typeName);
    String tableName = table.getTypeName();
    if (type == ConstraintType.LIMIT) {
        int tupleLimit = Integer.parseInt(node.attributes.get("rowslimit"));
        if (tupleLimit < 0) {
            throw m_compiler.new VoltCompilerException("Invalid constraint limit number '" + tupleLimit + "'");
        }
        if (tableLimitConstraintCounter.contains(tableName)) {
            throw m_compiler.new VoltCompilerException("Too many table limit constraints for table " + tableName);
        } else {
            tableLimitConstraintCounter.add(tableName);
        }
        table.setTuplelimit(tupleLimit);
        String deleteStmt = node.attributes.get("rowslimitdeletestmt");
        if (deleteStmt != null) {
            Statement catStmt = table.getTuplelimitdeletestmt().add("limit_delete");
            catStmt.setSqltext(deleteStmt);
            validateTupleLimitDeleteStmt(catStmt);
        }
        return;
    }
    if (type == ConstraintType.CHECK) {
        String msg = "VoltDB does not enforce check constraints. ";
        msg += "Constraint on table " + tableName + " will be ignored.";
        m_compiler.addWarn(msg);
        return;
    } else if (type == ConstraintType.FOREIGN_KEY) {
        String msg = "VoltDB does not enforce foreign key references and constraints. ";
        msg += "Constraint on table " + tableName + " will be ignored.";
        m_compiler.addWarn(msg);
        return;
    } else if (type == ConstraintType.MAIN) {
        // should never see these
        assert (false);
    } else if (type == ConstraintType.NOT_NULL) {
        // these get handled by table metadata inspection
        return;
    } else if (type != ConstraintType.PRIMARY_KEY && type != ConstraintType.UNIQUE) {
        throw m_compiler.new VoltCompilerException("Invalid constraint type '" + typeName + "'");
    }
    // else, create the unique index below
    // primary key code is in other places as well
    // The constraint is backed by an index, therefore we need to create it
    // TODO: We need to be able to use indexes for foreign keys. I am purposely
    //       leaving those out right now because HSQLDB just makes too many of them.
    Constraint catalog_const = table.getConstraints().add(name);
    String indexName = node.attributes.get("index");
    assert (indexName != null);
    // handle replacements from duplicate index pruning
    if (indexReplacementMap.containsKey(indexName)) {
        indexName = indexReplacementMap.get(indexName);
    }
    Index catalog_index = indexMap.get(indexName);
    // Attach the index to the catalog constraint (catalog_const).
    if (catalog_index != null) {
        catalog_const.setIndex(catalog_index);
        // This may be redundant.
        catalog_index.setUnique(true);
        boolean assumeUnique = Boolean.parseBoolean(node.attributes.get("assumeunique"));
        catalog_index.setAssumeunique(assumeUnique);
    }
    catalog_const.setType(type.getValue());
}
Also used : Constraint(org.voltdb.catalog.Constraint) Statement(org.voltdb.catalog.Statement) CatchAllVoltDBStatement(org.voltdb.compiler.statements.CatchAllVoltDBStatement) PartitionStatement(org.voltdb.compiler.statements.PartitionStatement) ConstraintType(org.voltdb.types.ConstraintType) Index(org.voltdb.catalog.Index) VoltCompilerException(org.voltdb.compiler.VoltCompiler.VoltCompilerException) Constraint(org.voltdb.catalog.Constraint)

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