File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\result\RowList.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.result;
8
9 import java.util.ArrayList;
10 import org.h2.engine.Constants;
11 import org.h2.engine.Database;
12 import org.h2.engine.Session;
13 import org.h2.store.Data;
14 import org.h2.store.FileStore;
15 import org.h2.util.New;
16 import org.h2.value.Value;
17
18 /**
19 * A list of rows. If the list grows too large, it is buffered to disk
20 * automatically.
21 */
22 public class RowList {
23
24 private final Session session;
25 private final ArrayList<Row> list = New.arrayList();
26 private int size;
27 private int index, listIndex;
28 private FileStore file;
29 private Data rowBuff;
30 private ArrayList<Value> lobs;
31 private final int maxMemory;
32 private int memory;
33 private boolean written;
34 private boolean readUncached;
35
36 /**
37 * Construct a new row list for this session.
38 *
39 * @param session the session
40 */
41 public RowList(Session session) {
42 this.session = session;
43 if (session.getDatabase().isPersistent()) {
44 maxMemory = session.getDatabase().getMaxOperationMemory();
45 } else {
46 maxMemory = 0;
47 }
48 }
49
50 private void writeRow(Data buff, Row r) {
51 buff.checkCapacity(1 + Data.LENGTH_INT * 8);
52 buff.writeByte((byte) 1);
53 buff.writeInt(r.getMemory());
54 int columnCount = r.getColumnCount();
55 buff.writeInt(columnCount);
56 buff.writeLong(r.getKey());
57 buff.writeInt(r.getVersion());
58 buff.writeInt(r.isDeleted() ? 1 : 0);
59 buff.writeInt(r.getSessionId());
60 for (int i = 0; i < columnCount; i++) {
61 Value v = r.getValue(i);
62 buff.checkCapacity(1);
63 if (v == null) {
64 buff.writeByte((byte) 0);
65 } else {
66 buff.writeByte((byte) 1);
67 if (v.getType() == Value.CLOB || v.getType() == Value.BLOB) {
68 // need to keep a reference to temporary lobs,
69 // otherwise the temp file is deleted
70 if (v.getSmall() == null && v.getTableId() == 0) {
71 if (lobs == null) {
72 lobs = New.arrayList();
73 }
74 // need to create a copy, otherwise,
75 // if stored multiple times, it may be renamed
76 // and then not found
77 v = v.copyToTemp();
78 lobs.add(v);
79 }
80 }
81 buff.checkCapacity(buff.getValueLen(v));
82 buff.writeValue(v);
83 }
84 }
85 }
86
87 private void writeAllRows() {
88 if (file == null) {
89 Database db = session.getDatabase();
90 String fileName = db.createTempFile();
91 file = db.openFile(fileName, "rw", false);
92 file.setCheckedWriting(false);
93 file.seek(FileStore.HEADER_LENGTH);
94 rowBuff = Data.create(db, Constants.DEFAULT_PAGE_SIZE);
95 file.seek(FileStore.HEADER_LENGTH);
96 }
97 Data buff = rowBuff;
98 initBuffer(buff);
99 for (int i = 0, size = list.size(); i < size; i++) {
100 if (i > 0 && buff.length() > Constants.IO_BUFFER_SIZE) {
101 flushBuffer(buff);
102 initBuffer(buff);
103 }
104 Row r = list.get(i);
105 writeRow(buff, r);
106 }
107 flushBuffer(buff);
108 file.autoDelete();
109 list.clear();
110 memory = 0;
111 }
112
113 private static void initBuffer(Data buff) {
114 buff.reset();
115 buff.writeInt(0);
116 }
117
118 private void flushBuffer(Data buff) {
119 buff.checkCapacity(1);
120 buff.writeByte((byte) 0);
121 buff.fillAligned();
122 buff.setInt(0, buff.length() / Constants.FILE_BLOCK_SIZE);
123 file.write(buff.getBytes(), 0, buff.length());
124 }
125
126 /**
127 * Add a row to the list.
128 *
129 * @param r the row to add
130 */
131 public void add(Row r) {
132 list.add(r);
133 memory += r.getMemory() + Constants.MEMORY_POINTER;
134 if (maxMemory > 0 && memory > maxMemory) {
135 writeAllRows();
136 }
137 size++;
138 }
139
140 /**
141 * Remove all rows from the list.
142 */
143 public void reset() {
144 index = 0;
145 if (file != null) {
146 listIndex = 0;
147 if (!written) {
148 writeAllRows();
149 written = true;
150 }
151 list.clear();
152 file.seek(FileStore.HEADER_LENGTH);
153 }
154 }
155
156 /**
157 * Check if there are more rows in this list.
158 *
159 * @return true it there are more rows
160 */
161 public boolean hasNext() {
162 return index < size;
163 }
164
165 private Row readRow(Data buff) {
166 if (buff.readByte() == 0) {
167 return null;
168 }
169 int mem = buff.readInt();
170 int columnCount = buff.readInt();
171 long key = buff.readLong();
172 int version = buff.readInt();
173 if (readUncached) {
174 key = 0;
175 }
176 boolean deleted = buff.readInt() == 1;
177 int sessionId = buff.readInt();
178 Value[] values = new Value[columnCount];
179 for (int i = 0; i < columnCount; i++) {
180 Value v;
181 if (buff.readByte() == 0) {
182 v = null;
183 } else {
184 v = buff.readValue();
185 if (v.isLinked()) {
186 // the table id is 0 if it was linked when writing
187 // a temporary entry
188 if (v.getTableId() == 0) {
189 session.unlinkAtCommit(v);
190 }
191 }
192 }
193 values[i] = v;
194 }
195 Row row = new Row(values, mem);
196 row.setKey(key);
197 row.setVersion(version);
198 row.setDeleted(deleted);
199 row.setSessionId(sessionId);
200 return row;
201 }
202
203 /**
204 * Get the next row from the list.
205 *
206 * @return the next row
207 */
208 public Row next() {
209 Row r;
210 if (file == null) {
211 r = list.get(index++);
212 } else {
213 if (listIndex >= list.size()) {
214 list.clear();
215 listIndex = 0;
216 Data buff = rowBuff;
217 buff.reset();
218 int min = Constants.FILE_BLOCK_SIZE;
219 file.readFully(buff.getBytes(), 0, min);
220 int len = buff.readInt() * Constants.FILE_BLOCK_SIZE;
221 buff.checkCapacity(len);
222 if (len - min > 0) {
223 file.readFully(buff.getBytes(), min, len - min);
224 }
225 while (true) {
226 r = readRow(buff);
227 if (r == null) {
228 break;
229 }
230 list.add(r);
231 }
232 }
233 index++;
234 r = list.get(listIndex++);
235 }
236 return r;
237 }
238
239 /**
240 * Get the number of rows in this list.
241 *
242 * @return the number of rows
243 */
244 public int size() {
245 return size;
246 }
247
248 /**
249 * Do not use the cache.
250 */
251 public void invalidateCache() {
252 readUncached = true;
253 }
254
255 /**
256 * Close the result list and delete the temporary file.
257 */
258 public void close() {
259 if (file != null) {
260 file.autoDelete();
261 file.closeAndDeleteSilently();
262 file = null;
263 rowBuff = null;
264 }
265 }
266
267 }
268