001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (http://h2database.com/html/license.html).
004: * Initial Developer: H2 Group
005: */
006: package org.h2.index;
007:
008: import java.sql.SQLException;
009:
010: import org.h2.engine.Session;
011: import org.h2.message.Message;
012: import org.h2.result.Row;
013: import org.h2.result.SearchRow;
014: import org.h2.table.Column;
015: import org.h2.table.IndexColumn;
016: import org.h2.table.TableData;
017: import org.h2.util.IntIntHashMap;
018: import org.h2.util.ObjectUtils;
019: import org.h2.util.ValueHashMap;
020: import org.h2.value.Value;
021: import org.h2.value.ValueArray;
022:
023: /**
024: * An index based on an in-memory hash map.
025: */
026: public class HashIndex extends BaseIndex {
027:
028: private ValueHashMap rows;
029: private IntIntHashMap intMap;
030: private TableData tableData;
031:
032: public HashIndex(TableData table, int id, String indexName,
033: IndexColumn[] columns, IndexType indexType) {
034: super (table, id, indexName, columns, indexType);
035: this .tableData = table;
036: reset();
037: }
038:
039: private void reset() {
040: if (columns.length == 1 && columns[0].getType() == Value.INT) {
041: intMap = new IntIntHashMap();
042: } else {
043: rows = new ValueHashMap(table.getDatabase());
044: }
045: }
046:
047: public void close(Session session) {
048: // nothing to do
049: }
050:
051: public void truncate(Session session) throws SQLException {
052: reset();
053: }
054:
055: public void remove(Session session) throws SQLException {
056: // nothing to do
057: }
058:
059: public void add(Session session, Row row) throws SQLException {
060: if (intMap != null) {
061: int key = row.getValue(columns[0].getColumnId()).getInt();
062: intMap.put(key, row.getPos());
063: } else {
064: Value key = getKey(row);
065: Object old = rows.get(key);
066: if (old != null) {
067: // TODO index duplicate key for hash indexes: is this allowed?
068: throw getDuplicateKeyException();
069: }
070: Integer pos = ObjectUtils.getInteger(row.getPos());
071: rows.put(getKey(row), pos);
072: }
073: rowCount++;
074: }
075:
076: public void remove(Session session, Row row) throws SQLException {
077: if (intMap != null) {
078: int key = row.getValue(columns[0].getColumnId()).getInt();
079: intMap.remove(key);
080: } else {
081: rows.remove(getKey(row));
082: }
083: rowCount--;
084: }
085:
086: private Value getKey(SearchRow row) {
087: if (columns.length == 1) {
088: Column column = columns[0];
089: int index = column.getColumnId();
090: Value v = row.getValue(index);
091: return v;
092: }
093: Value[] list = new Value[columns.length];
094: for (int i = 0; i < columns.length; i++) {
095: Column column = columns[i];
096: int index = column.getColumnId();
097: list[i] = row.getValue(index);
098: }
099: return ValueArray.get(list);
100: }
101:
102: public Cursor find(Session session, SearchRow first, SearchRow last)
103: throws SQLException {
104: if (first == null || last == null) {
105: // TODO hash index: should additionally check if values are the same
106: throw Message.getInternalError();
107: }
108: Row result;
109: if (intMap != null) {
110: int key = first.getValue(columns[0].getColumnId()).getInt();
111: int pos = intMap.get(key);
112: if (pos != IntIntHashMap.NOT_FOUND) {
113: result = tableData.getRow(session, pos);
114: } else {
115: result = null;
116: }
117: } else {
118: Integer pos = (Integer) rows.get(getKey(first));
119: if (pos == null) {
120: result = null;
121: } else {
122: result = tableData.getRow(session, pos.intValue());
123: }
124: }
125: return new HashCursor(result);
126: }
127:
128: public double getCost(Session session, int[] masks) {
129: for (int i = 0; i < columns.length; i++) {
130: Column column = columns[i];
131: int index = column.getColumnId();
132: int mask = masks[index];
133: if ((mask & IndexCondition.EQUALITY) != IndexCondition.EQUALITY) {
134: return Long.MAX_VALUE;
135: }
136: }
137: return 2;
138: }
139:
140: public void checkRename() throws SQLException {
141: // ok
142: }
143:
144: public boolean needRebuild() {
145: return true;
146: }
147:
148: public boolean canGetFirstOrLast() {
149: return false;
150: }
151:
152: public SearchRow findFirstOrLast(Session session, boolean first)
153: throws SQLException {
154: throw Message.getUnsupportedException();
155: }
156:
157: }
|