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

COVERAGE SUMMARY FOR SOURCE FILE [ResultTempTable.java]

nameclass, %method, %block, %line, %
ResultTempTable.java100% (1/1)94%  (15/16)87%  (614/707)88%  (141.8/162)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ResultTempTable100% (1/1)94%  (15/16)87%  (614/707)88%  (141.8/162)
removeRow (Value []): int 0%   (0/1)0%   (0/28)0%   (0/7)
dropTable (): void 100% (1/1)71%  (79/111)84%  (21.1/25)
next (): Value [] 100% (1/1)73%  (53/73)82%  (10.7/13)
createShallowCopy (): ResultExternal 100% (1/1)74%  (17/23)67%  (4/6)
closeChild (): void 100% (1/1)86%  (12/14)67%  (2/3)
find (Row): Cursor 100% (1/1)92%  (48/52)80%  (12/15)
close (): void 100% (1/1)95%  (19/20)88%  (7/8)
ResultTempTable (ResultTempTable): void 100% (1/1)100% (40/40)100% (12/12)
ResultTempTable (Session, Expression [], boolean, SortOrder): void 100% (1/1)100% (110/110)100% (25/25)
addRow (Value []): int 100% (1/1)100% (41/41)100% (10/10)
addRows (ArrayList): int 100% (1/1)100% (25/25)100% (6/6)
contains (Value []): boolean 100% (1/1)100% (10/10)100% (1/1)
convertToRow (Value []): Row 100% (1/1)100% (32/32)100% (6/6)
createIndex (): void 100% (1/1)100% (123/123)100% (22/22)
done (): void 100% (1/1)100% (1/1)100% (1/1)
reset (): void 100% (1/1)100% (4/4)100% (2/2)

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.util.ArrayList;
9import java.util.Arrays;
10 
11import org.h2.command.ddl.CreateTableData;
12import org.h2.engine.Constants;
13import org.h2.engine.Database;
14import org.h2.engine.Session;
15import org.h2.expression.Expression;
16import org.h2.index.Cursor;
17import org.h2.index.Index;
18import org.h2.index.IndexType;
19import org.h2.schema.Schema;
20import org.h2.table.Column;
21import org.h2.table.IndexColumn;
22import org.h2.table.Table;
23import org.h2.value.Value;
24import org.h2.value.ValueNull;
25 
26/**
27 * This class implements the temp table buffer for the LocalResult class.
28 */
29public class ResultTempTable implements ResultExternal {
30 
31    private static final String COLUMN_NAME = "DATA";
32    private final boolean distinct;
33    private final SortOrder sort;
34    private Index index;
35    private Session session;
36    private Table table;
37    private Cursor resultCursor;
38    private int rowCount;
39    private int columnCount;
40 
41    private final ResultTempTable parent;
42    private boolean closed;
43    private int childCount;
44    private boolean containsLob;
45 
46    ResultTempTable(Session session, Expression[] expressions, boolean distinct, SortOrder sort) {
47        this.session = session;
48        this.distinct = distinct;
49        this.sort = sort;
50        this.columnCount = expressions.length;
51        Schema schema = session.getDatabase().getSchema(Constants.SCHEMA_MAIN);
52        CreateTableData data = new CreateTableData();
53        for (int i = 0; i < expressions.length; i++) {
54            int type = expressions[i].getType();
55            Column col = new Column(COLUMN_NAME + i,
56                    type);
57            if (type == Value.CLOB || type == Value.BLOB) {
58                containsLob = true;
59            }
60            data.columns.add(col);
61        }
62        data.id = session.getDatabase().allocateObjectId();
63        data.tableName = "TEMP_RESULT_SET_" + data.id;
64        data.temporary = true;
65        data.persistIndexes = false;
66        data.persistData = true;
67        data.create = true;
68        data.session = session;
69        table = schema.createTable(data);
70        if (sort != null || distinct) {
71            createIndex();
72        }
73        parent = null;
74    }
75 
76    private ResultTempTable(ResultTempTable parent) {
77        this.parent = parent;
78        this.columnCount = parent.columnCount;
79        this.distinct = parent.distinct;
80        this.session = parent.session;
81        this.table = parent.table;
82        this.index = parent.index;
83        this.rowCount = parent.rowCount;
84        this.sort = parent.sort;
85        this.containsLob = parent.containsLob;
86        reset();
87    }
88 
89    private void createIndex() {
90        IndexColumn[] indexCols = null;
91        if (sort != null) {
92            int[] colIndex = sort.getQueryColumnIndexes();
93            indexCols = new IndexColumn[colIndex.length];
94            for (int i = 0; i < colIndex.length; i++) {
95                IndexColumn indexColumn = new IndexColumn();
96                indexColumn.column = table.getColumn(colIndex[i]);
97                indexColumn.sortType = sort.getSortTypes()[i];
98                indexColumn.columnName = COLUMN_NAME + i;
99                indexCols[i] = indexColumn;
100            }
101        } else {
102            indexCols = new IndexColumn[columnCount];
103            for (int i = 0; i < columnCount; i++) {
104                IndexColumn indexColumn = new IndexColumn();
105                indexColumn.column = table.getColumn(i);
106                indexColumn.columnName = COLUMN_NAME + i;
107                indexCols[i] = indexColumn;
108            }
109        }
110        String indexName = table.getSchema().getUniqueIndexName(session,
111                table, Constants.PREFIX_INDEX);
112        int indexId = session.getDatabase().allocateObjectId();
113        IndexType indexType = IndexType.createNonUnique(true);
114        index = table.addIndex(session, indexName, indexId, indexCols,
115                indexType, true, null);
116    }
117 
118    @Override
119    public synchronized ResultExternal createShallowCopy() {
120        if (parent != null) {
121            return parent.createShallowCopy();
122        }
123        if (closed) {
124            return null;
125        }
126        childCount++;
127        return new ResultTempTable(this);
128    }
129 
130    @Override
131    public int removeRow(Value[] values) {
132        Row row = convertToRow(values);
133        Cursor cursor = find(row);
134        if (cursor != null) {
135            row = cursor.get();
136            table.removeRow(session, row);
137            rowCount--;
138        }
139        return rowCount;
140    }
141 
142    @Override
143    public boolean contains(Value[] values) {
144        return find(convertToRow(values)) != null;
145    }
146 
147    @Override
148    public int addRow(Value[] values) {
149        Row row = convertToRow(values);
150        if (distinct) {
151            Cursor cursor = find(row);
152            if (cursor == null) {
153                table.addRow(session, row);
154                rowCount++;
155            }
156        } else {
157            table.addRow(session, row);
158            rowCount++;
159        }
160        return rowCount;
161    }
162 
163    @Override
164    public int addRows(ArrayList<Value[]> rows) {
165        // speeds up inserting, but not really needed:
166        if (sort != null) {
167            sort.sort(rows);
168        }
169        for (Value[] values : rows) {
170            addRow(values);
171        }
172        return rowCount;
173    }
174 
175    private synchronized void closeChild() {
176        if (--childCount == 0 && closed) {
177            dropTable();
178        }
179    }
180 
181    @Override
182    public synchronized void close() {
183        if (closed) {
184            return;
185        }
186        closed = true;
187        if (parent != null) {
188            parent.closeChild();
189        } else {
190            if (childCount == 0) {
191                dropTable();
192            }
193        }
194    }
195 
196    private void dropTable() {
197        if (table == null) {
198            return;
199        }
200        if (containsLob) {
201            // contains BLOB or CLOB: can not truncate now,
202            // otherwise the BLOB and CLOB entries are removed
203            return;
204        }
205        try {
206            Database database = session.getDatabase();
207            // Need to lock because not all of the code-paths
208            // that reach here have already taken this lock,
209            // notably via the close() paths.
210            synchronized (session) {
211                synchronized (database) {
212                    table.truncate(session);
213                }
214            }
215            // This session may not lock the sys table (except if it already has
216            // locked it) because it must be committed immediately, otherwise
217            // other threads can not access the sys table. If the table is not
218            // removed now, it will be when the database is opened the next
219            // time. (the table is truncated, so this is just one record)
220            if (!database.isSysTableLocked()) {
221                Session sysSession = database.getSystemSession();
222                table.removeChildrenAndResources(sysSession);
223                if (index != null) {
224                    // need to explicitly do this,
225                    // as it's not registered in the system session
226                    session.removeLocalTempTableIndex(index);
227                }
228                // the transaction must be committed immediately
229                // TODO this synchronization cascade is very ugly
230                synchronized (session) {
231                    synchronized (sysSession) {
232                        synchronized (database) {
233                            sysSession.commit(false);
234                        }
235                    }
236                }
237            }
238        } finally {
239            table = null;
240        }
241    }
242 
243    @Override
244    public void done() {
245        // nothing to do
246    }
247 
248    @Override
249    public Value[] next() {
250        if (resultCursor == null) {
251            Index idx;
252            if (distinct || sort != null) {
253                idx = index;
254            } else {
255                idx = table.getScanIndex(session);
256            }
257            if (session.getDatabase().getMvStore() != null) {
258                // sometimes the transaction is already committed,
259                // in which case we can't use the session
260                if (idx.getRowCount(session) == 0 && rowCount > 0) {
261                    // this means querying is not transactional
262                    resultCursor = idx.find((Session) null, null, null);
263                } else {
264                    // the transaction is still open
265                    resultCursor = idx.find(session, null, null);
266                }
267            } else {
268                resultCursor = idx.find(session, null, null);
269            }
270        }
271        if (!resultCursor.next()) {
272            return null;
273        }
274        Row row = resultCursor.get();
275        return row.getValueList();
276    }
277 
278    @Override
279    public void reset() {
280        resultCursor = null;
281    }
282 
283    private Row convertToRow(Value[] values) {
284        if (values.length < columnCount) {
285            Value[] v2 = Arrays.copyOf(values, columnCount);
286            for (int i = values.length; i < columnCount; i++) {
287                v2[i] = ValueNull.INSTANCE;
288            }
289            values = v2;
290        }
291        return new Row(values, Row.MEMORY_CALCULATE);
292    }
293 
294    private Cursor find(Row row) {
295        if (index == null) {
296            // for the case "in(select ...)", the query might
297            // use an optimization and not create the index
298            // up front
299            createIndex();
300        }
301        Cursor cursor = index.find(session, row, row);
302        while (cursor.next()) {
303            SearchRow found = cursor.getSearchRow();
304            boolean ok = true;
305            Database db = session.getDatabase();
306            for (int i = 0; i < row.getColumnCount(); i++) {
307                if (!db.areEqual(row.getValue(i), found.getValue(i))) {
308                    ok = false;
309                    break;
310                }
311            }
312            if (ok) {
313                return cursor;
314            }
315        }
316        return null;
317    }
318 
319}
320 

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