File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\index\ScanIndex.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.index;
8
9 import java.util.ArrayList;
10 import java.util.Collections;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.Iterator;
14 import java.util.List;
15 import org.h2.constant.ErrorCode;
16 import org.h2.engine.Constants;
17 import org.h2.engine.Session;
18 import org.h2.engine.UndoLogRecord;
19 import org.h2.message.DbException;
20 import org.h2.result.Row;
21 import org.h2.result.SearchRow;
22 import org.h2.table.Column;
23 import org.h2.table.IndexColumn;
24 import org.h2.table.RegularTable;
25 import org.h2.util.New;
26
27 /**
28 * The scan index is not really an 'index' in the strict sense, because it can
29 * not be used for direct lookup. It can only be used to iterate over all rows
30 * of a table. Each regular table has one such object, even if no primary key or
31 * indexes are defined.
32 */
33 public class ScanIndex extends BaseIndex {
34 private long firstFree = -1;
35 private ArrayList<Row> rows = New.arrayList();
36 private final RegularTable tableData;
37 private int rowCountDiff;
38 private final HashMap<Integer, Integer> sessionRowCount;
39 private HashSet<Row> delta;
40 private long rowCount;
41
42 public ScanIndex(RegularTable table, int id, IndexColumn[] columns, IndexType indexType) {
43 initBaseIndex(table, id, table.getName() + "_DATA", columns, indexType);
44 if (database.isMultiVersion()) {
45 sessionRowCount = New.hashMap();
46 } else {
47 sessionRowCount = null;
48 }
49 tableData = table;
50 }
51
52 public void remove(Session session) {
53 truncate(session);
54 }
55
56 public void truncate(Session session) {
57 rows = New.arrayList();
58 firstFree = -1;
59 if (tableData.getContainsLargeObject() && tableData.isPersistData()) {
60 database.getLobStorage().removeAllForTable(table.getId());
61 }
62 tableData.setRowCount(0);
63 rowCount = 0;
64 rowCountDiff = 0;
65 if (database.isMultiVersion()) {
66 sessionRowCount.clear();
67 }
68 }
69
70 public String getCreateSQL() {
71 return null;
72 }
73
74 public void close(Session session) {
75 // nothing to do
76 }
77
78 public Row getRow(Session session, long key) {
79 return rows.get((int) key);
80 }
81
82 public void add(Session session, Row row) {
83 // in-memory
84 if (firstFree == -1) {
85 int key = rows.size();
86 row.setKey(key);
87 rows.add(row);
88 } else {
89 long key = firstFree;
90 Row free = rows.get((int) key);
91 firstFree = free.getKey();
92 row.setKey(key);
93 rows.set((int) key, row);
94 }
95 row.setDeleted(false);
96 if (database.isMultiVersion()) {
97 if (delta == null) {
98 delta = New.hashSet();
99 }
100 boolean wasDeleted = delta.remove(row);
101 if (!wasDeleted) {
102 delta.add(row);
103 }
104 incrementRowCount(session.getId(), 1);
105 }
106 rowCount++;
107 }
108
109 public void commit(int operation, Row row) {
110 if (database.isMultiVersion()) {
111 if (delta != null) {
112 delta.remove(row);
113 }
114 incrementRowCount(row.getSessionId(), operation == UndoLogRecord.DELETE ? 1 : -1);
115 }
116 }
117
118 private void incrementRowCount(int sessionId, int count) {
119 if (database.isMultiVersion()) {
120 Integer id = sessionId;
121 Integer c = sessionRowCount.get(id);
122 int current = c == null ? 0 : c.intValue();
123 sessionRowCount.put(id, current + count);
124 rowCountDiff += count;
125 }
126 }
127
128 public void remove(Session session, Row row) {
129 // in-memory
130 if (!database.isMultiVersion() && rowCount == 1) {
131 rows = New.arrayList();
132 firstFree = -1;
133 } else {
134 Row free = new Row(null, 1);
135 free.setKey(firstFree);
136 long key = row.getKey();
137 if (rows.size() <= key) {
138 throw DbException.get(ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, rows.size() + ": " + key);
139 }
140 rows.set((int) key, free);
141 firstFree = key;
142 }
143 if (database.isMultiVersion()) {
144 // if storage is null, the delete flag is not yet set
145 row.setDeleted(true);
146 if (delta == null) {
147 delta = New.hashSet();
148 }
149 boolean wasAdded = delta.remove(row);
150 if (!wasAdded) {
151 delta.add(row);
152 }
153 incrementRowCount(session.getId(), -1);
154 }
155 rowCount--;
156 }
157
158 public Cursor find(Session session, SearchRow first, SearchRow last) {
159 return new ScanCursor(session, this, database.isMultiVersion());
160 }
161
162 public double getCost(Session session, int[] masks) {
163 return tableData.getRowCountApproximation() + Constants.COST_ROW_OFFSET;
164 }
165
166 public long getRowCount(Session session) {
167 if (database.isMultiVersion()) {
168 Integer i = sessionRowCount.get(session.getId());
169 long count = i == null ? 0 : i.intValue();
170 count += rowCount;
171 count -= rowCountDiff;
172 return count;
173 }
174 return rowCount;
175 }
176
177 /**
178 * Get the next row that is stored after this row.
179 *
180 * @param row the current row or null to start the scan
181 * @return the next row or null if there are no more rows
182 */
183 Row getNextRow(Row row) {
184 long key;
185 if (row == null) {
186 key = -1;
187 } else {
188 key = row.getKey();
189 }
190 while (true) {
191 key++;
192 if (key >= rows.size()) {
193 return null;
194 }
195 row = rows.get((int) key);
196 if (!row.isEmpty()) {
197 return row;
198 }
199 }
200 }
201
202 public int getColumnIndex(Column col) {
203 // the scan index cannot use any columns
204 return -1;
205 }
206
207 public void checkRename() {
208 throw DbException.getUnsupportedException("SCAN");
209 }
210
211 public boolean needRebuild() {
212 return false;
213 }
214
215 public boolean canGetFirstOrLast() {
216 return false;
217 }
218
219 public Cursor findFirstOrLast(Session session, boolean first) {
220 throw DbException.getUnsupportedException("SCAN");
221 }
222
223 Iterator<Row> getDelta() {
224 if (delta == null) {
225 List<Row> e = Collections.emptyList();
226 return e.iterator();
227 }
228 return delta.iterator();
229 }
230
231 public long getRowCountApproximation() {
232 return rowCount;
233 }
234
235 public String getPlanSQL() {
236 return table.getSQL() + ".tableScan";
237 }
238
239 }
240