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();
}
}
}
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);
}
}
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);
}
}
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);
}
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;
}
Aggregations