Search in sources :

Example 41 with Index

use of org.h2.index.Index in project h2database by h2database.

the class Session method rollbackTo.

/**
 * Partially roll back the current transaction.
 *
 * @param savepoint the savepoint to which should be rolled back
 * @param trimToSize if the list should be trimmed
 */
public void rollbackTo(Savepoint savepoint, boolean trimToSize) {
    int index = savepoint == null ? 0 : savepoint.logIndex;
    while (undoLog.size() > index) {
        UndoLogRecord entry = undoLog.getLast();
        entry.undo(this);
        undoLog.removeLast(trimToSize);
    }
    if (transaction != null) {
        long savepointId = savepoint == null ? 0 : savepoint.transactionSavepoint;
        HashMap<String, MVTable> tableMap = database.getMvStore().getTables();
        Iterator<Change> it = transaction.getChanges(savepointId);
        while (it.hasNext()) {
            Change c = it.next();
            MVTable t = tableMap.get(c.mapName);
            if (t != null) {
                long key = ((ValueLong) c.key).getLong();
                ValueArray value = (ValueArray) c.value;
                short op;
                Row row;
                if (value == null) {
                    op = UndoLogRecord.INSERT;
                    row = t.getRow(this, key);
                } else {
                    op = UndoLogRecord.DELETE;
                    row = createRow(value.getList(), Row.MEMORY_CALCULATE);
                }
                row.setKey(key);
                UndoLogRecord log = new UndoLogRecord(t, op, row);
                log.undo(this);
            }
        }
    }
    if (savepoints != null) {
        String[] names = savepoints.keySet().toArray(new String[savepoints.size()]);
        for (String name : names) {
            Savepoint sp = savepoints.get(name);
            int savepointIndex = sp.logIndex;
            if (savepointIndex > index) {
                savepoints.remove(name);
            }
        }
    }
}
Also used : ValueLong(org.h2.value.ValueLong) MVTable(org.h2.mvstore.db.MVTable) ValueString(org.h2.value.ValueString) Change(org.h2.mvstore.db.TransactionStore.Change) Constraint(org.h2.constraint.Constraint) Row(org.h2.result.Row) ValueArray(org.h2.value.ValueArray)

Example 42 with Index

use of org.h2.index.Index in project h2database by h2database.

the class AggregateDataMedian method isNullsLast.

private static boolean isNullsLast(Index index) {
    IndexColumn ic = index.getIndexColumns()[0];
    int sortType = ic.sortType;
    return (sortType & SortOrder.NULLS_LAST) != 0 || (sortType & SortOrder.DESCENDING) != 0 && (sortType & SortOrder.NULLS_FIRST) == 0;
}
Also used : IndexColumn(org.h2.table.IndexColumn)

Example 43 with Index

use of org.h2.index.Index in project h2database by h2database.

the class AggregateDataMedian method getMedianColumnIndex.

/**
 * Get the index (if any) for the column specified in the median aggregate.
 *
 * @param on the expression (usually a column expression)
 * @return the index, or null
 */
static Index getMedianColumnIndex(Expression on) {
    if (on instanceof ExpressionColumn) {
        ExpressionColumn col = (ExpressionColumn) on;
        Column column = col.getColumn();
        TableFilter filter = col.getTableFilter();
        if (filter != null) {
            Table table = filter.getTable();
            ArrayList<Index> indexes = table.getIndexes();
            Index result = null;
            if (indexes != null) {
                boolean nullable = column.isNullable();
                for (int i = 1, size = indexes.size(); i < size; i++) {
                    Index index = indexes.get(i);
                    if (!index.canFindNext()) {
                        continue;
                    }
                    if (!index.isFirstColumn(column)) {
                        continue;
                    }
                    // Prefer index without nulls last for nullable columns
                    if (result == null || result.getColumns().length > index.getColumns().length || nullable && isNullsLast(result) && !isNullsLast(index)) {
                        result = index;
                    }
                }
            }
            return result;
        }
    }
    return null;
}
Also used : Table(org.h2.table.Table) Column(org.h2.table.Column) IndexColumn(org.h2.table.IndexColumn) TableFilter(org.h2.table.TableFilter) Index(org.h2.index.Index)

Example 44 with Index

use of org.h2.index.Index in project h2database by h2database.

the class AggregateDataMedian method getResultFromIndex.

/**
 * Get the result from the index.
 *
 * @param session the session
 * @param on the expression
 * @param dataType the data type
 * @return the result
 */
static Value getResultFromIndex(Session session, Expression on, int dataType) {
    Index index = getMedianColumnIndex(on);
    long count = index.getRowCount(session);
    if (count == 0) {
        return ValueNull.INSTANCE;
    }
    Cursor cursor = index.find(session, null, null);
    cursor.next();
    int columnId = index.getColumns()[0].getColumnId();
    ExpressionColumn expr = (ExpressionColumn) on;
    if (expr.getColumn().isNullable()) {
        boolean hasNulls = false;
        SearchRow row;
        // will be used to read values.
        while (count > 0) {
            row = cursor.getSearchRow();
            if (row == null) {
                return ValueNull.INSTANCE;
            }
            if (row.getValue(columnId) == ValueNull.INSTANCE) {
                count--;
                cursor.next();
                hasNulls = true;
            } else {
                break;
            }
        }
        if (count == 0) {
            return ValueNull.INSTANCE;
        }
        // cursor to count nulls at the end.
        if (!hasNulls && isNullsLast(index)) {
            TableFilter tableFilter = expr.getTableFilter();
            SearchRow check = tableFilter.getTable().getTemplateSimpleRow(true);
            check.setValue(columnId, ValueNull.INSTANCE);
            Cursor nullsCursor = index.find(session, check, check);
            while (nullsCursor.next()) {
                count--;
            }
            if (count <= 0) {
                return ValueNull.INSTANCE;
            }
        }
    }
    long skip = (count - 1) / 2;
    for (int i = 0; i < skip; i++) {
        cursor.next();
    }
    SearchRow row = cursor.getSearchRow();
    if (row == null) {
        return ValueNull.INSTANCE;
    }
    Value v = row.getValue(columnId);
    if (v == ValueNull.INSTANCE) {
        return v;
    }
    if ((count & 1) == 0) {
        cursor.next();
        row = cursor.getSearchRow();
        if (row == null) {
            return v;
        }
        Value v2 = row.getValue(columnId);
        if (v2 == ValueNull.INSTANCE) {
            return v;
        }
        return getMedian(v, v2, dataType, session.getDatabase().getCompareMode());
    }
    return v;
}
Also used : TableFilter(org.h2.table.TableFilter) Value(org.h2.value.Value) Index(org.h2.index.Index) Cursor(org.h2.index.Cursor) SearchRow(org.h2.result.SearchRow)

Example 45 with Index

use of org.h2.index.Index in project h2database by h2database.

the class BaseIndex method getCostRangeIndex.

/**
 * Calculate the cost for the given mask as if this index was a typical
 * b-tree range index. This is the estimated cost required to search one
 * row, and then iterate over the given number of rows.
 *
 * @param masks the IndexCondition search masks, one for each column in the
 *            table
 * @param rowCount the number of rows in the index
 * @param filters all joined table filters
 * @param filter the current table filter index
 * @param sortOrder the sort order
 * @param isScanIndex whether this is a "table scan" index
 * @param allColumnsSet the set of all columns
 * @return the estimated cost
 */
protected final long getCostRangeIndex(int[] masks, long rowCount, TableFilter[] filters, int filter, SortOrder sortOrder, boolean isScanIndex, HashSet<Column> allColumnsSet) {
    rowCount += Constants.COST_ROW_OFFSET;
    int totalSelectivity = 0;
    long rowsCost = rowCount;
    if (masks != null) {
        for (int i = 0, len = columns.length; i < len; i++) {
            Column column = columns[i];
            int index = column.getColumnId();
            int mask = masks[index];
            if ((mask & IndexCondition.EQUALITY) == IndexCondition.EQUALITY) {
                if (i == columns.length - 1 && getIndexType().isUnique()) {
                    rowsCost = 3;
                    break;
                }
                totalSelectivity = 100 - ((100 - totalSelectivity) * (100 - column.getSelectivity()) / 100);
                long distinctRows = rowCount * totalSelectivity / 100;
                if (distinctRows <= 0) {
                    distinctRows = 1;
                }
                rowsCost = 2 + Math.max(rowCount / distinctRows, 1);
            } else if ((mask & IndexCondition.RANGE) == IndexCondition.RANGE) {
                rowsCost = 2 + rowCount / 4;
                break;
            } else if ((mask & IndexCondition.START) == IndexCondition.START) {
                rowsCost = 2 + rowCount / 3;
                break;
            } else if ((mask & IndexCondition.END) == IndexCondition.END) {
                rowsCost = rowCount / 3;
                break;
            } else {
                break;
            }
        }
    }
    // If the ORDER BY clause matches the ordering of this index,
    // it will be cheaper than another index, so adjust the cost
    // accordingly.
    long sortingCost = 0;
    if (sortOrder != null) {
        sortingCost = 100 + rowCount / 10;
    }
    if (sortOrder != null && !isScanIndex) {
        boolean sortOrderMatches = true;
        int coveringCount = 0;
        int[] sortTypes = sortOrder.getSortTypes();
        TableFilter tableFilter = filters == null ? null : filters[filter];
        for (int i = 0, len = sortTypes.length; i < len; i++) {
            if (i >= indexColumns.length) {
                // more of the order by columns.
                break;
            }
            Column col = sortOrder.getColumn(i, tableFilter);
            if (col == null) {
                sortOrderMatches = false;
                break;
            }
            IndexColumn indexCol = indexColumns[i];
            if (!col.equals(indexCol.column)) {
                sortOrderMatches = false;
                break;
            }
            int sortType = sortTypes[i];
            if (sortType != indexCol.sortType) {
                sortOrderMatches = false;
                break;
            }
            coveringCount++;
        }
        if (sortOrderMatches) {
            // "coveringCount" makes sure that when we have two
            // or more covering indexes, we choose the one
            // that covers more.
            sortingCost = 100 - coveringCount;
        }
    }
    // If we have two indexes with the same cost, and one of the indexes can
    // satisfy the query without needing to read from the primary table
    // (scan index), make that one slightly lower cost.
    boolean needsToReadFromScanIndex = true;
    if (!isScanIndex && allColumnsSet != null && !allColumnsSet.isEmpty()) {
        boolean foundAllColumnsWeNeed = true;
        for (Column c : allColumnsSet) {
            if (c.getTable() == getTable()) {
                boolean found = false;
                for (Column c2 : columns) {
                    if (c == c2) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    foundAllColumnsWeNeed = false;
                    break;
                }
            }
        }
        if (foundAllColumnsWeNeed) {
            needsToReadFromScanIndex = false;
        }
    }
    long rc;
    if (isScanIndex) {
        rc = rowsCost + sortingCost + 20;
    } else if (needsToReadFromScanIndex) {
        rc = rowsCost + rowsCost + sortingCost + 20;
    } else {
        // The (20-x) calculation makes sure that when we pick a covering
        // index, we pick the covering index that has the smallest number of
        // columns (the more columns we have in index - the higher cost).
        // This is faster because a smaller index will fit into fewer data
        // blocks.
        rc = rowsCost + sortingCost + columns.length;
    }
    return rc;
}
Also used : Column(org.h2.table.Column) IndexColumn(org.h2.table.IndexColumn) TableFilter(org.h2.table.TableFilter) IndexColumn(org.h2.table.IndexColumn)

Aggregations

ResultSet (java.sql.ResultSet)77 Index (org.h2.index.Index)75 Statement (java.sql.Statement)64 SimpleResultSet (org.h2.tools.SimpleResultSet)61 SQLException (java.sql.SQLException)60 Value (org.h2.value.Value)58 DbException (org.h2.message.DbException)57 Connection (java.sql.Connection)56 PreparedStatement (java.sql.PreparedStatement)56 Column (org.h2.table.Column)53 IndexColumn (org.h2.table.IndexColumn)45 ArrayList (java.util.ArrayList)31 ValueString (org.h2.value.ValueString)29 Constraint (org.h2.constraint.Constraint)25 Row (org.h2.result.Row)22 MultiVersionIndex (org.h2.index.MultiVersionIndex)19 JdbcConnection (org.h2.jdbc.JdbcConnection)19 IgniteCheckedException (org.apache.ignite.IgniteCheckedException)18 Table (org.h2.table.Table)18 HashSet (java.util.HashSet)17