Search in sources :

Example 21 with Index

use of org.hsqldb_voltpatches.index.Index in project voltdb by VoltDB.

the class StatementDML method checkCascadeDelete.

// fredt@users 20020225 - patch 1.7.0 - CASCADING DELETES
/**
     *  Method is called recursively on a tree of tables from the current one
     *  until no referring foreign-key table is left. In the process, if a
     *  non-cascading foreign-key referring table contains data, an exception
     *  is thrown. Parameter delete indicates whether to delete refering rows.
     *  The method is called first to check if the row can be deleted, then to
     *  delete the row and all the refering rows.<p>
     *
     *  Support added for SET NULL and SET DEFAULT by kloska@users involves
     *  switching to checkCascadeUpdate(,,,,) when these rules are encountered
     *  in the constraint.(fredt@users)
     *
     * @param session current session
     * @param  table table to delete from
     * @param  tableUpdateList list of update lists
     * @param  row row to delete
     * @param  delete action
     * @param  path constraint path
     * @throws  HsqlException
     */
static void checkCascadeDelete(Session session, Table table, HashMappedList tableUpdateList, Row row, boolean delete, HashSet path) {
    for (int i = 0, size = table.fkMainConstraints.length; i < size; i++) {
        Constraint c = table.fkMainConstraints[i];
        RowIterator refiterator = c.findFkRef(session, row.getData(), delete);
        if (!refiterator.hasNext()) {
            continue;
        }
        try {
            if (c.core.deleteAction == Constraint.NO_ACTION || c.core.deleteAction == Constraint.RESTRICT) {
                if (c.core.mainTable == c.core.refTable) {
                    Row refrow = refiterator.getNextRow();
                    // with self-referencing FK's deletes
                    if (row.equals(refrow)) {
                        continue;
                    }
                }
                int errorCode = c.core.deleteAction == Constraint.NO_ACTION ? ErrorCode.X_23501 : ErrorCode.X_23001;
                String[] info = new String[] { c.core.refName.name, c.core.refTable.getName().name };
                throw Error.error(errorCode, ErrorCode.CONSTRAINT, info);
            }
            Table reftable = c.getRef();
            // shortcut when deltable has no imported constraint
            boolean hasref = reftable.fkMainConstraints.length > 0;
            // if (reftable == this) we don't need to go further and can return ??
            if (!delete && !hasref) {
                continue;
            }
            Index refindex = c.getRefIndex();
            int[] m_columns = c.getMainColumns();
            int[] r_columns = c.getRefColumns();
            Object[] mdata = row.getData();
            boolean isUpdate = c.getDeleteAction() == Constraint.SET_NULL || c.getDeleteAction() == Constraint.SET_DEFAULT;
            // -- list for records to be inserted if this is
            // -- a 'ON DELETE SET [NULL|DEFAULT]' constraint
            HashMappedList rowSet = null;
            if (isUpdate) {
                rowSet = (HashMappedList) tableUpdateList.get(reftable);
                if (rowSet == null) {
                    rowSet = new HashMappedList();
                    tableUpdateList.add(reftable, rowSet);
                }
            }
            // walk the index for all the nodes that reference delnode
            for (; ; ) {
                Row refrow = refiterator.getNextRow();
                if (refrow == null || refrow.isDeleted(session) || refindex.compareRowNonUnique(mdata, m_columns, refrow.getData()) != 0) {
                    break;
                }
                // -- switch over to the 'checkCascadeUpdate' method below this level
                if (isUpdate) {
                    Object[] rnd = reftable.getEmptyRowData();
                    System.arraycopy(refrow.getData(), 0, rnd, 0, rnd.length);
                    if (c.getDeleteAction() == Constraint.SET_NULL) {
                        for (int j = 0; j < r_columns.length; j++) {
                            rnd[r_columns[j]] = null;
                        }
                    } else {
                        for (int j = 0; j < r_columns.length; j++) {
                            ColumnSchema col = reftable.getColumn(r_columns[j]);
                            rnd[r_columns[j]] = col.getDefaultValue(session);
                        }
                    }
                    if (hasref && path.add(c)) {
                        // fredt - avoid infinite recursion on circular references
                        // these can be rings of two or more mutually dependent tables
                        // so only one visit per constraint is allowed
                        checkCascadeUpdate(session, reftable, null, refrow, rnd, r_columns, null, path);
                        path.remove(c);
                    }
                    if (delete) {
                        //  foreign key referencing own table - do not update the row to be deleted
                        if (reftable != table || !refrow.equals(row)) {
                            mergeUpdate(rowSet, refrow, rnd, r_columns);
                        }
                    }
                } else if (hasref) {
                    if (reftable != table) {
                        if (path.add(c)) {
                            checkCascadeDelete(session, reftable, tableUpdateList, refrow, delete, path);
                            path.remove(c);
                        }
                    } else {
                        // but chained rows can result in very deep recursion and StackOverflowError
                        if (refrow != row) {
                            checkCascadeDelete(session, reftable, tableUpdateList, refrow, delete, path);
                        }
                    }
                }
                if (delete && !isUpdate && !refrow.isDeleted(session)) {
                    reftable.deleteRowAsTriggeredAction(session, refrow);
                }
            }
        } finally {
            refiterator.release();
        }
    }
}
Also used : HashMappedList(org.hsqldb_voltpatches.lib.HashMappedList) Index(org.hsqldb_voltpatches.index.Index) RowIterator(org.hsqldb_voltpatches.navigator.RowIterator)

Example 22 with Index

use of org.hsqldb_voltpatches.index.Index in project voltdb by VoltDB.

the class RangeVariableResolver method assignToRangeVariable.

/**
     * Assigns a set of conditions to a range variable.
     */
void assignToRangeVariable(RangeVariable rangeVar, int rangeVarIndex, HsqlArrayList exprList, boolean isJoin) {
    if (exprList.isEmpty()) {
        return;
    }
    colIndexSetEqual.clear();
    colIndexSetOther.clear();
    for (int j = 0, size = exprList.size(); j < size; j++) {
        Expression e = (Expression) exprList.get(j);
        if (rangeVar.hasIndexCondition()) {
            rangeVar.addCondition(e, isJoin);
            exprList.set(j, null);
            continue;
        }
        if (e.getIndexableExpression(rangeVar) == null) {
            rangeVar.addCondition(e, isJoin);
            exprList.set(j, null);
            continue;
        }
        // can use index
        int type = e.getType();
        switch(type) {
            default:
                {
                    int colIndex = e.getLeftNode().getColumnIndex();
                    colIndexSetOther.add(colIndex);
                    break;
                }
            case OpTypes.EQUAL:
                if (e.exprSubType == OpTypes.ANY_QUANTIFIED) {
                    Index index = rangeVar.rangeTable.getIndexForColumn(e.getLeftNode().nodes[0].getColumnIndex());
                    //                        index = null;
                    if (index != null && inExpressions[rangeVarIndex] == null) {
                        inExpressions[rangeVarIndex] = e;
                        inExpressionCount++;
                    } else {
                        rangeVar.addCondition(e, isJoin);
                    }
                    exprList.set(j, null);
                    continue;
                }
            // $FALL-THROUGH$
            case OpTypes.IS_NULL:
                {
                    int colIndex = e.getLeftNode().getColumnIndex();
                    colIndexSetEqual.add(colIndex);
                    break;
                }
            case OpTypes.NOT:
                {
                    int colIndex = e.getLeftNode().getLeftNode().getColumnIndex();
                    colIndexSetOther.add(colIndex);
                    break;
                }
        }
    }
    boolean isEqual = true;
    Index idx = rangeVar.rangeTable.getIndexForColumns(colIndexSetEqual);
    if (idx == null) {
        isEqual = false;
        idx = rangeVar.rangeTable.getIndexForColumns(colIndexSetOther);
    }
    // different procedure for subquery tables
    if (idx == null && rangeVar.rangeTable.isSessionBased) {
        if (!colIndexSetEqual.isEmpty()) {
            int[] cols = colIndexSetEqual.toArray();
            idx = rangeVar.rangeTable.getIndexForColumns(cols);
        }
        if (idx == null && !colIndexSetOther.isEmpty()) {
            int[] cols = colIndexSetOther.toArray();
            idx = rangeVar.rangeTable.getIndexForColumns(cols);
        }
    }
    // no index found
    if (idx == null) {
        for (int j = 0, size = exprList.size(); j < size; j++) {
            Expression e = (Expression) exprList.get(j);
            if (e != null) {
                rangeVar.addCondition(e, isJoin);
            }
        }
        return;
    }
    // index found
    int[] cols = idx.getColumns();
    int colCount = cols.length;
    if (isEqual && colCount > 1) {
        Expression[] firstRowExpressions = new Expression[cols.length];
        for (int j = 0; j < exprList.size(); j++) {
            Expression e = (Expression) exprList.get(j);
            if (e == null) {
                continue;
            }
            int type = e.getType();
            if (type == OpTypes.EQUAL) {
                int offset = ArrayUtil.find(cols, e.getLeftNode().getColumnIndex());
                if (offset != -1 && firstRowExpressions[offset] == null) {
                    firstRowExpressions[offset] = e;
                    exprList.set(j, null);
                    continue;
                }
            }
            // not used in index lookup
            rangeVar.addCondition(e, isJoin);
            exprList.set(j, null);
        }
        boolean hasNull = false;
        for (int i = 0; i < firstRowExpressions.length; i++) {
            Expression e = firstRowExpressions[i];
            if (e == null) {
                if (colCount == cols.length) {
                    colCount = i;
                }
                hasNull = true;
                continue;
            }
            if (hasNull) {
                rangeVar.addCondition(e, isJoin);
                firstRowExpressions[i] = null;
            }
        }
        rangeVar.addIndexCondition(firstRowExpressions, idx, colCount, isJoin);
        return;
    }
    for (int j = 0; j < exprList.size(); j++) {
        Expression e = (Expression) exprList.get(j);
        if (e == null) {
            continue;
        }
        if (rangeVar.hasIndexCondition()) {
            rangeVar.addCondition(e, isJoin);
            exprList.set(j, null);
            continue;
        }
        boolean isIndexed = false;
        if (e.getType() == OpTypes.NOT && cols[0] == e.getLeftNode().getLeftNode().getColumnIndex()) {
            isIndexed = true;
        }
        if (cols[0] == e.getLeftNode().getColumnIndex()) {
            if (e.getRightNode() != null && !e.getRightNode().isCorrelated()) {
                isIndexed = true;
            }
            if (e.getType() == OpTypes.IS_NULL) {
                isIndexed = true;
            }
        }
        if (isIndexed) {
            rangeVar.addIndexCondition(e, idx, isJoin);
        } else {
            rangeVar.addCondition(e, isJoin);
        }
        exprList.set(j, null);
    }
}
Also used : Index(org.hsqldb_voltpatches.index.Index)

Example 23 with Index

use of org.hsqldb_voltpatches.index.Index in project voltdb by VoltDB.

the class Constraint method checkReferencedRows.

/**
     * Check used before creating a new foreign key cosntraint, this method
     * checks all rows of a table to ensure they all have a corresponding
     * row in the main table.
     */
void checkReferencedRows(Session session, Table table, int[] rowColArray) {
    Index mainIndex = getMainIndex();
    PersistentStore store = session.sessionData.getRowStore(table);
    RowIterator it = table.rowIterator(session);
    while (true) {
        Row row = it.getNextRow();
        if (row == null) {
            break;
        }
        Object[] rowData = row.getData();
        if (ArrayUtil.hasNull(rowData, rowColArray)) {
            if (core.matchType == OpTypes.MATCH_SIMPLE) {
                continue;
            }
        } else if (mainIndex.exists(session, store, rowData, rowColArray)) {
            continue;
        }
        if (ArrayUtil.hasAllNull(rowData, rowColArray)) {
            continue;
        }
        String colValues = "";
        for (int i = 0; i < rowColArray.length; i++) {
            Object o = rowData[rowColArray[i]];
            colValues += table.getColumnTypes()[i].convertToString(o);
            colValues += ",";
        }
        String[] info = new String[] { getName().name, getMain().getName().name };
        throw Error.error(ErrorCode.X_23502, ErrorCode.CONSTRAINT, info);
    }
}
Also used : RowIterator(org.hsqldb_voltpatches.navigator.RowIterator) PersistentStore(org.hsqldb_voltpatches.persist.PersistentStore) Index(org.hsqldb_voltpatches.index.Index)

Example 24 with Index

use of org.hsqldb_voltpatches.index.Index in project voltdb by VoltDB.

the class TableWorks method addColumn.

void addColumn(ColumnSchema column, int colIndex, HsqlArrayList constraints) {
    Index index = null;
    Table originalTable = table;
    Constraint mainConstraint = null;
    boolean addFK = false;
    boolean addUnique = false;
    boolean addCheck = false;
    checkAddColumn(column);
    Constraint c = (Constraint) constraints.get(0);
    if (c.getConstraintType() == Constraint.PRIMARY_KEY) {
        c.core.mainCols = new int[] { colIndex };
        database.schemaManager.checkSchemaObjectNotExists(c.getName());
        if (table.hasPrimaryKey()) {
            throw Error.error(ErrorCode.X_42530);
        }
        addUnique = true;
    } else {
        c = null;
    }
    table = table.moveDefinition(session, table.tableType, column, c, null, colIndex, 1, emptySet, emptySet);
    for (int i = 1; i < constraints.size(); i++) {
        c = (Constraint) constraints.get(i);
        switch(c.constType) {
            case Constraint.UNIQUE:
                {
                    if (addUnique) {
                        throw Error.error(ErrorCode.X_42522);
                    }
                    addUnique = true;
                    c.core.mainCols = new int[] { colIndex };
                    database.schemaManager.checkSchemaObjectNotExists(c.getName());
                    HsqlName indexName = database.nameManager.newAutoName("IDX", c.getName().name, table.getSchemaName(), table.getName(), SchemaObject.INDEX);
                    // create an autonamed index
                    index = table.createAndAddIndexStructure(indexName, c.getMainColumns(), null, null, true, true, false);
                    // A VoltDB extension to support the assume unique attribute
                    index = index.setAssumeUnique(c.assumeUnique);
                    // End of VoltDB extension
                    c.core.mainTable = table;
                    c.core.mainIndex = index;
                    table.addConstraint(c);
                    break;
                }
            case Constraint.FOREIGN_KEY:
                {
                    if (addFK) {
                        throw Error.error(ErrorCode.X_42528);
                    }
                    addFK = true;
                    c.core.refCols = new int[] { colIndex };
                    boolean isSelf = originalTable == c.core.mainTable;
                    if (isSelf) {
                        c.core.mainTable = table;
                    }
                    c.setColumnsIndexes(table);
                    checkCreateForeignKey(c);
                    Constraint uniqueConstraint = c.core.mainTable.getUniqueConstraintForColumns(c.core.mainCols, c.core.refCols);
                    boolean isForward = c.core.mainTable.getSchemaName() != table.getSchemaName();
                    int offset = database.schemaManager.getTableIndex(originalTable);
                    if (!isSelf && offset < database.schemaManager.getTableIndex(c.core.mainTable)) {
                        isForward = true;
                    }
                    HsqlName indexName = database.nameManager.newAutoName("IDX", c.getName().name, table.getSchemaName(), table.getName(), SchemaObject.INDEX);
                    index = table.createAndAddIndexStructure(indexName, c.getRefColumns(), null, null, false, true, isForward);
                    c.core.uniqueName = uniqueConstraint.getName();
                    c.core.mainName = database.nameManager.newAutoName("REF", c.core.refName.name, table.getSchemaName(), table.getName(), SchemaObject.INDEX);
                    c.core.mainIndex = uniqueConstraint.getMainIndex();
                    c.core.refIndex = index;
                    c.isForward = isForward;
                    table.addConstraint(c);
                    mainConstraint = new Constraint(c.core.mainName, c);
                    break;
                }
            case Constraint.CHECK:
                if (addCheck) {
                    throw Error.error(ErrorCode.X_42528);
                }
                addCheck = true;
                c.prepareCheckConstraint(session, table, false);
                table.addConstraint(c);
                if (c.isNotNull()) {
                    column.setNullable(false);
                    table.setColumnTypeVars(colIndex);
                }
                break;
        }
    }
    table.moveData(session, originalTable, colIndex, 1);
    if (mainConstraint != null) {
        mainConstraint.getMain().addConstraint(mainConstraint);
    }
    registerConstraintNames(constraints);
    setNewTableInSchema(table);
    updateConstraints(table, emptySet);
    database.persistentStoreCollection.releaseStore(originalTable);
    database.schemaManager.recompileDependentObjects(table);
}
Also used : Index(org.hsqldb_voltpatches.index.Index) HsqlName(org.hsqldb_voltpatches.HsqlNameManager.HsqlName)

Example 25 with Index

use of org.hsqldb_voltpatches.index.Index in project voltdb by VoltDB.

the class TableWorks method addIndex.

/**
     * Because of the way indexes and column data are held in memory and on
     * disk, it is necessary to recreate the table when an index is added to a
     * non-empty cached table.
     *
     * <p> With empty tables, Index objects are simply added
     *
     * <p> With MEOMRY and TEXT tables, a new index is built up and nodes for
     * earch row are interlinked (fredt@users)
     *
     * @param col int[]
     * @param name HsqlName
     * @param unique boolean
     * @return new index
     */
Index addIndex(int[] col, HsqlName name, boolean unique) {
    Index newindex;
    if (table.isEmpty(session) || table.isIndexingMutable()) {
        PersistentStore store = session.sessionData.getRowStore(table);
        newindex = table.createIndex(store, name, col, null, null, unique, false, false);
    } else {
        newindex = table.createIndexStructure(name, col, null, null, unique, false, false);
        Table tn = table.moveDefinition(session, table.tableType, null, null, newindex, -1, 0, emptySet, emptySet);
        // for all sessions move the data
        tn.moveData(session, table, -1, 0);
        database.persistentStoreCollection.releaseStore(table);
        table = tn;
        setNewTableInSchema(table);
        updateConstraints(table, emptySet);
    }
    database.schemaManager.addSchemaObject(newindex);
    database.schemaManager.recompileDependentObjects(table);
    return newindex;
}
Also used : PersistentStore(org.hsqldb_voltpatches.persist.PersistentStore) Index(org.hsqldb_voltpatches.index.Index)

Aggregations

Index (org.hsqldb_voltpatches.index.Index)29 HsqlName (org.hsqldb_voltpatches.HsqlNameManager.HsqlName)6 RowIterator (org.hsqldb_voltpatches.navigator.RowIterator)4 PersistentStore (org.hsqldb_voltpatches.persist.PersistentStore)3 IndexAVL (org.hsqldb_voltpatches.index.IndexAVL)2 HashMappedList (org.hsqldb_voltpatches.lib.HashMappedList)2 HashMap (java.util.HashMap)1 HSQLParseException (org.hsqldb_voltpatches.HSQLInterface.HSQLParseException)1 HsqlArrayList (org.hsqldb_voltpatches.lib.HsqlArrayList)1 OrderedHashSet (org.hsqldb_voltpatches.lib.OrderedHashSet)1 Type (org.hsqldb_voltpatches.types.Type)1