EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.result]

COVERAGE SUMMARY FOR SOURCE FILE [LocalResult.java]

nameclass, %method, %block, %line, %
LocalResult.java100% (1/1)100% (40/40)96%  (833/866)96%  (206.4/215)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class LocalResult100% (1/1)100% (40/40)96%  (833/866)96%  (206.4/215)
needToClose (): boolean 100% (1/1)71%  (5/7)71%  (0.7/1)
removeDistinct (Value []): void 100% (1/1)71%  (20/28)78%  (7/9)
read (Session, ResultSet, int): LocalResult 100% (1/1)89%  (55/62)85%  (11.9/14)
LocalResult (Session, Expression [], int): void 100% (1/1)91%  (41/45)93%  (13/14)
applyOffset (): void 100% (1/1)94%  (61/65)93%  (14/15)
createShallowCopy (Session): LocalResult 100% (1/1)96%  (87/91)92%  (23/25)
done (): void 100% (1/1)97%  (117/121)99%  (29.8/30)
LocalResult (): void 100% (1/1)100% (6/6)100% (3/3)
addRow (Value []): void 100% (1/1)100% (93/93)100% (20/20)
addRowsToDisk (): void 100% (1/1)100% (11/11)100% (3/3)
applyLimit (): void 100% (1/1)100% (37/37)100% (9/9)
cloneLobs (Value []): void 100% (1/1)100% (27/27)100% (7/7)
close (): void 100% (1/1)100% (13/13)100% (5/5)
containsDistinct (Value []): boolean 100% (1/1)100% (64/64)100% (14/14)
currentRow (): Value [] 100% (1/1)100% (3/3)100% (1/1)
getAlias (int): String 100% (1/1)100% (6/6)100% (1/1)
getColumnName (int): String 100% (1/1)100% (6/6)100% (1/1)
getColumnPrecision (int): long 100% (1/1)100% (6/6)100% (1/1)
getColumnScale (int): int 100% (1/1)100% (6/6)100% (1/1)
getColumnType (int): int 100% (1/1)100% (6/6)100% (1/1)
getDisplaySize (int): int 100% (1/1)100% (6/6)100% (1/1)
getFetchSize (): int 100% (1/1)100% (2/2)100% (1/1)
getNullable (int): int 100% (1/1)100% (6/6)100% (1/1)
getRowCount (): int 100% (1/1)100% (3/3)100% (1/1)
getRowId (): int 100% (1/1)100% (3/3)100% (1/1)
getSchemaName (int): String 100% (1/1)100% (6/6)100% (1/1)
getTableName (int): String 100% (1/1)100% (6/6)100% (1/1)
getVisibleColumnCount (): int 100% (1/1)100% (3/3)100% (1/1)
isAutoIncrement (int): boolean 100% (1/1)100% (6/6)100% (1/1)
isClosed (): boolean 100% (1/1)100% (3/3)100% (1/1)
next (): boolean 100% (1/1)100% (43/43)100% (9/9)
reset (): void 100% (1/1)100% (25/25)100% (7/7)
setDistinct (): void 100% (1/1)100% (7/7)100% (3/3)
setFetchSize (int): void 100% (1/1)100% (1/1)100% (1/1)
setLimit (int): void 100% (1/1)100% (4/4)100% (2/2)
setMaxMemoryRows (int): void 100% (1/1)100% (4/4)100% (2/2)
setOffset (int): void 100% (1/1)100% (4/4)100% (2/2)
setRandomAccess (): void 100% (1/1)100% (4/4)100% (2/2)
setSortOrder (SortOrder): void 100% (1/1)100% (4/4)100% (2/2)
toString (): String 100% (1/1)100% (23/23)100% (1/1)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.result;
7 
8import java.sql.ResultSet;
9import java.sql.SQLException;
10import java.util.ArrayList;
11import org.h2.engine.Database;
12import org.h2.engine.Session;
13import org.h2.expression.Expression;
14import org.h2.message.DbException;
15import org.h2.util.New;
16import org.h2.util.ValueHashMap;
17import org.h2.value.DataType;
18import org.h2.value.Value;
19import org.h2.value.ValueArray;
20 
21/**
22 * A local result set contains all row data of a result set.
23 * This is the object generated by engine,
24 * and it is also used directly by the ResultSet class in the embedded mode.
25 * If the result does not fit in memory, it is written to a temporary file.
26 */
27public class LocalResult implements ResultInterface, ResultTarget {
28 
29    private int maxMemoryRows;
30    private Session session;
31    private int visibleColumnCount;
32    private Expression[] expressions;
33    private int rowId, rowCount;
34    private ArrayList<Value[]> rows;
35    private SortOrder sort;
36    private ValueHashMap<Value[]> distinctRows;
37    private Value[] currentRow;
38    private int offset;
39    private int limit = -1;
40    private ResultExternal external;
41    private int diskOffset;
42    private boolean distinct;
43    private boolean randomAccess;
44    private boolean closed;
45 
46    /**
47     * Construct a local result object.
48     */
49    public LocalResult() {
50        // nothing to do
51    }
52 
53    /**
54     * Construct a local result object.
55     *
56     * @param session the session
57     * @param expressions the expression array
58     * @param visibleColumnCount the number of visible columns
59     */
60    public LocalResult(Session session, Expression[] expressions,
61            int visibleColumnCount) {
62        this.session = session;
63        if (session == null) {
64            this.maxMemoryRows = Integer.MAX_VALUE;
65        } else {
66            Database db = session.getDatabase();
67            if (db.isPersistent() && !db.isReadOnly()) {
68                this.maxMemoryRows = session.getDatabase().getMaxMemoryRows();
69            } else {
70                this.maxMemoryRows = Integer.MAX_VALUE;
71            }
72        }
73        rows = New.arrayList();
74        this.visibleColumnCount = visibleColumnCount;
75        rowId = -1;
76        this.expressions = expressions;
77    }
78 
79    public void setMaxMemoryRows(int maxValue) {
80        this.maxMemoryRows = maxValue;
81    }
82 
83    /**
84     * Construct a local result set by reading all data from a regular result
85     * set.
86     *
87     * @param session the session
88     * @param rs the result set
89     * @param maxrows the maximum number of rows to read (0 for no limit)
90     * @return the local result set
91     */
92    public static LocalResult read(Session session, ResultSet rs, int maxrows) {
93        Expression[] cols = Expression.getExpressionColumns(session, rs);
94        int columnCount = cols.length;
95        LocalResult result = new LocalResult(session, cols, columnCount);
96        try {
97            for (int i = 0; (maxrows == 0 || i < maxrows) && rs.next(); i++) {
98                Value[] list = new Value[columnCount];
99                for (int j = 0; j < columnCount; j++) {
100                    int type = result.getColumnType(j);
101                    list[j] = DataType.readValue(session, rs, j + 1, type);
102                }
103                result.addRow(list);
104            }
105        } catch (SQLException e) {
106            throw DbException.convert(e);
107        }
108        result.done();
109        return result;
110    }
111 
112    /**
113     * Create a shallow copy of the result set. The data and a temporary table
114     * (if there is any) is not copied.
115     *
116     * @param targetSession the session of the copy
117     * @return the copy
118     */
119    public LocalResult createShallowCopy(Session targetSession) {
120        if (external == null && (rows == null || rows.size() < rowCount)) {
121            return null;
122        }
123        ResultExternal e2 = null;
124        if (external != null) {
125            e2 = external.createShallowCopy();
126            if (e2 == null) {
127                return null;
128            }
129        }
130        LocalResult copy = new LocalResult();
131        copy.maxMemoryRows = this.maxMemoryRows;
132        copy.session = targetSession;
133        copy.visibleColumnCount = this.visibleColumnCount;
134        copy.expressions = this.expressions;
135        copy.rowId = -1;
136        copy.rowCount = this.rowCount;
137        copy.rows = this.rows;
138        copy.sort = this.sort;
139        copy.distinctRows = this.distinctRows;
140        copy.distinct = distinct;
141        copy.randomAccess = randomAccess;
142        copy.currentRow = null;
143        copy.offset = 0;
144        copy.limit = -1;
145        copy.external = e2;
146        copy.diskOffset = this.diskOffset;
147        return copy;
148    }
149 
150    /**
151     * Set the sort order.
152     *
153     * @param sort the sort order
154     */
155    public void setSortOrder(SortOrder sort) {
156        this.sort = sort;
157    }
158 
159    /**
160     * Remove duplicate rows.
161     */
162    public void setDistinct() {
163        distinct = true;
164        distinctRows = ValueHashMap.newInstance();
165    }
166 
167    /**
168     * Random access is required (containsDistinct).
169     */
170    public void setRandomAccess() {
171        this.randomAccess = true;
172    }
173 
174    /**
175     * Remove the row from the result set if it exists.
176     *
177     * @param values the row
178     */
179    public void removeDistinct(Value[] values) {
180        if (!distinct) {
181            DbException.throwInternalError();
182        }
183        if (distinctRows != null) {
184            ValueArray array = ValueArray.get(values);
185            distinctRows.remove(array);
186            rowCount = distinctRows.size();
187        } else {
188            rowCount = external.removeRow(values);
189        }
190    }
191 
192    /**
193     * Check if this result set contains the given row.
194     *
195     * @param values the row
196     * @return true if the row exists
197     */
198    public boolean containsDistinct(Value[] values) {
199        if (external != null) {
200            return external.contains(values);
201        }
202        if (distinctRows == null) {
203            distinctRows = ValueHashMap.newInstance();
204            for (Value[] row : rows) {
205                if (row.length > visibleColumnCount) {
206                    Value[] r2 = new Value[visibleColumnCount];
207                    System.arraycopy(row, 0, r2, 0, visibleColumnCount);
208                    row = r2;
209                }
210                ValueArray array = ValueArray.get(row);
211                distinctRows.put(array, row);
212            }
213        }
214        ValueArray array = ValueArray.get(values);
215        return distinctRows.get(array) != null;
216    }
217 
218    @Override
219    public void reset() {
220        rowId = -1;
221        if (external != null) {
222            external.reset();
223            if (diskOffset > 0) {
224                for (int i = 0; i < diskOffset; i++) {
225                    external.next();
226                }
227            }
228        }
229    }
230 
231    @Override
232    public Value[] currentRow() {
233        return currentRow;
234    }
235 
236    @Override
237    public boolean next() {
238        if (!closed && rowId < rowCount) {
239            rowId++;
240            if (rowId < rowCount) {
241                if (external != null) {
242                    currentRow = external.next();
243                } else {
244                    currentRow = rows.get(rowId);
245                }
246                return true;
247            }
248            currentRow = null;
249        }
250        return false;
251    }
252 
253    @Override
254    public int getRowId() {
255        return rowId;
256    }
257 
258    private void cloneLobs(Value[] values) {
259        for (int i = 0; i < values.length; i++) {
260            Value v = values[i];
261            Value v2 = v.copyToResult();
262            if (v2 != v) {
263                session.addTemporaryLob(v2);
264                values[i] = v2;
265            }
266        }
267    }
268 
269    /**
270     * Add a row to this object.
271     *
272     * @param values the row to add
273     */
274    @Override
275    public void addRow(Value[] values) {
276        cloneLobs(values);
277        if (distinct) {
278            if (distinctRows != null) {
279                ValueArray array = ValueArray.get(values);
280                distinctRows.put(array, values);
281                rowCount = distinctRows.size();
282                if (rowCount > maxMemoryRows) {
283                    external = new ResultTempTable(session, expressions, true, sort);
284                    rowCount = external.addRows(distinctRows.values());
285                    distinctRows = null;
286                }
287            } else {
288                rowCount = external.addRow(values);
289            }
290            return;
291        }
292        rows.add(values);
293        rowCount++;
294        if (rows.size() > maxMemoryRows) {
295            if (external == null) {
296                external = new ResultTempTable(session, expressions, false, sort);
297            }
298            addRowsToDisk();
299        }
300    }
301 
302    private void addRowsToDisk() {
303        rowCount = external.addRows(rows);
304        rows.clear();
305    }
306 
307    @Override
308    public int getVisibleColumnCount() {
309        return visibleColumnCount;
310    }
311 
312    /**
313     * This method is called after all rows have been added.
314     */
315    public void done() {
316        if (distinct) {
317            if (distinctRows != null) {
318                rows = distinctRows.values();
319            } else {
320                if (external != null && sort != null) {
321                    // external sort
322                    ResultExternal temp = external;
323                    external = null;
324                    temp.reset();
325                    rows = New.arrayList();
326                    // TODO use offset directly if possible
327                    while (true) {
328                        Value[] list = temp.next();
329                        if (list == null) {
330                            break;
331                        }
332                        if (external == null) {
333                            external = new ResultTempTable(session, expressions, true, sort);
334                        }
335                        rows.add(list);
336                        if (rows.size() > maxMemoryRows) {
337                            rowCount = external.addRows(rows);
338                            rows.clear();
339                        }
340                    }
341                    temp.close();
342                    // the remaining data in rows is written in the following
343                    // lines
344                }
345            }
346        }
347        if (external != null) {
348            addRowsToDisk();
349            external.done();
350        } else {
351            if (sort != null) {
352                if (offset > 0 || limit > 0) {
353                    sort.sort(rows, offset, limit < 0 ? rows.size() : limit);
354                } else {
355                    sort.sort(rows);
356                }
357            }
358        }
359        applyOffset();
360        applyLimit();
361        reset();
362    }
363 
364    @Override
365    public int getRowCount() {
366        return rowCount;
367    }
368 
369    /**
370     * Set the number of rows that this result will return at the maximum.
371     *
372     * @param limit the limit (-1 means no limit, 0 means no rows)
373     */
374    public void setLimit(int limit) {
375        this.limit = limit;
376    }
377 
378    private void applyLimit() {
379        if (limit < 0) {
380            return;
381        }
382        if (external == null) {
383            if (rows.size() > limit) {
384                rows = New.arrayList(rows.subList(0, limit));
385                rowCount = limit;
386            }
387        } else {
388            if (limit < rowCount) {
389                rowCount = limit;
390            }
391        }
392    }
393 
394    @Override
395    public boolean needToClose() {
396        return external != null;
397    }
398 
399    @Override
400    public void close() {
401        if (external != null) {
402            external.close();
403            external = null;
404            closed = true;
405        }
406    }
407 
408    @Override
409    public String getAlias(int i) {
410        return expressions[i].getAlias();
411    }
412 
413    @Override
414    public String getTableName(int i) {
415        return expressions[i].getTableName();
416    }
417 
418    @Override
419    public String getSchemaName(int i) {
420        return expressions[i].getSchemaName();
421    }
422 
423    @Override
424    public int getDisplaySize(int i) {
425        return expressions[i].getDisplaySize();
426    }
427 
428    @Override
429    public String getColumnName(int i) {
430        return expressions[i].getColumnName();
431    }
432 
433    @Override
434    public int getColumnType(int i) {
435        return expressions[i].getType();
436    }
437 
438    @Override
439    public long getColumnPrecision(int i) {
440        return expressions[i].getPrecision();
441    }
442 
443    @Override
444    public int getNullable(int i) {
445        return expressions[i].getNullable();
446    }
447 
448    @Override
449    public boolean isAutoIncrement(int i) {
450        return expressions[i].isAutoIncrement();
451    }
452 
453    @Override
454    public int getColumnScale(int i) {
455        return expressions[i].getScale();
456    }
457 
458    /**
459     * Set the offset of the first row to return.
460     *
461     * @param offset the offset
462     */
463    public void setOffset(int offset) {
464        this.offset = offset;
465    }
466 
467    private void applyOffset() {
468        if (offset <= 0) {
469            return;
470        }
471        if (external == null) {
472            if (offset >= rows.size()) {
473                rows.clear();
474                rowCount = 0;
475            } else {
476                // avoid copying the whole array for each row
477                int remove = Math.min(offset, rows.size());
478                rows = New.arrayList(rows.subList(remove, rows.size()));
479                rowCount -= remove;
480            }
481        } else {
482            if (offset >= rowCount) {
483                rowCount = 0;
484            } else {
485                diskOffset = offset;
486                rowCount -= offset;
487            }
488        }
489    }
490 
491    @Override
492    public String toString() {
493        return super.toString() + " columns: " + visibleColumnCount +
494                " rows: " + rowCount + " pos: " + rowId;
495    }
496 
497    /**
498     * Check if this result set is closed.
499     *
500     * @return true if it is
501     */
502    public boolean isClosed() {
503        return closed;
504    }
505 
506    @Override
507    public int getFetchSize() {
508        return 0;
509    }
510 
511    @Override
512    public void setFetchSize(int fetchSize) {
513        // ignore
514    }
515 
516}

[all classes][org.h2.result]
EMMA 2.0.5312 (C) Vladimir Roubtsov