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

COVERAGE SUMMARY FOR SOURCE FILE [Command.java]

nameclass, %method, %block, %line, %
Command.java100% (1/1)88%  (15/17)90%  (476/531)85%  (120.5/141)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Command100% (1/1)88%  (15/17)90%  (476/531)85%  (120.5/141)
query (int): ResultInterface 0%   (0/1)0%   (0/3)0%   (0/1)
update (): int 0%   (0/1)0%   (0/3)0%   (0/1)
executeUpdate (): int 100% (1/1)81%  (124/153)80%  (32.8/41)
executeQuery (int, boolean): ResultInterface 100% (1/1)85%  (105/124)75%  (27.8/37)
filterConcurrentUpdate (DbException, long): long 100% (1/1)99%  (76/77)94%  (16/17)
Command (Parser, String): void 100% (1/1)100% (17/17)100% (5/5)
canReuse (): boolean 100% (1/1)100% (3/3)100% (1/1)
cancel (): void 100% (1/1)100% (4/4)100% (2/2)
checkCanceled (): void 100% (1/1)100% (10/10)100% (4/4)
close (): void 100% (1/1)100% (4/4)100% (2/2)
getMetaData (): ResultInterface 100% (1/1)100% (3/3)100% (1/1)
isCacheable (): boolean 100% (1/1)100% (2/2)100% (1/1)
reuse (): void 100% (1/1)100% (26/26)100% (6/6)
setProgress (int): void 100% (1/1)100% (10/10)100% (2/2)
start (): void 100% (1/1)100% (8/8)100% (3/3)
stop (): void 100% (1/1)100% (72/72)100% (16/16)
toString (): String 100% (1/1)100% (12/12)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.command;
7 
8import java.sql.SQLException;
9import java.util.ArrayList;
10 
11import org.h2.api.ErrorCode;
12import org.h2.engine.Constants;
13import org.h2.engine.Database;
14import org.h2.engine.Session;
15import org.h2.expression.ParameterInterface;
16import org.h2.message.DbException;
17import org.h2.message.Trace;
18import org.h2.result.ResultInterface;
19import org.h2.util.MathUtils;
20 
21/**
22 * Represents a SQL statement. This object is only used on the server side.
23 */
24public abstract class Command implements CommandInterface {
25 
26    /**
27     * The session.
28     */
29    protected final Session session;
30 
31    /**
32     * The last start time.
33     */
34    protected long startTime;
35 
36    /**
37     * The trace module.
38     */
39    private final Trace trace;
40 
41    /**
42     * If this query was canceled.
43     */
44    private volatile boolean cancel;
45 
46    private final String sql;
47 
48    private boolean canReuse;
49 
50    Command(Parser parser, String sql) {
51        this.session = parser.getSession();
52        this.sql = sql;
53        trace = session.getDatabase().getTrace(Trace.COMMAND);
54    }
55 
56    /**
57     * Check if this command is transactional.
58     * If it is not, then it forces the current transaction to commit.
59     *
60     * @return true if it is
61     */
62    public abstract boolean isTransactional();
63 
64    /**
65     * Check if this command is a query.
66     *
67     * @return true if it is
68     */
69    @Override
70    public abstract boolean isQuery();
71 
72    /**
73     * Get the list of parameters.
74     *
75     * @return the list of parameters
76     */
77    @Override
78    public abstract ArrayList<? extends ParameterInterface> getParameters();
79 
80    /**
81     * Check if this command is read only.
82     *
83     * @return true if it is
84     */
85    public abstract boolean isReadOnly();
86 
87    /**
88     * Get an empty result set containing the meta data.
89     *
90     * @return an empty result set
91     */
92    public abstract ResultInterface queryMeta();
93 
94    /**
95     * Execute an updating statement (for example insert, delete, or update), if
96     * this is possible.
97     *
98     * @return the update count
99     * @throws DbException if the command is not an updating statement
100     */
101    public int update() {
102        throw DbException.get(ErrorCode.METHOD_NOT_ALLOWED_FOR_QUERY);
103    }
104 
105    /**
106     * Execute a query statement, if this is possible.
107     *
108     * @param maxrows the maximum number of rows returned
109     * @return the local result set
110     * @throws DbException if the command is not a query
111     */
112    public ResultInterface query(int maxrows) {
113        throw DbException.get(ErrorCode.METHOD_ONLY_ALLOWED_FOR_QUERY);
114    }
115 
116    @Override
117    public final ResultInterface getMetaData() {
118        return queryMeta();
119    }
120 
121    /**
122     * Start the stopwatch.
123     */
124    void start() {
125        if (trace.isInfoEnabled()) {
126            startTime = System.currentTimeMillis();
127        }
128    }
129 
130    void setProgress(int state) {
131        session.getDatabase().setProgress(state, sql, 0, 0);
132    }
133 
134    /**
135     * Check if this command has been canceled, and throw an exception if yes.
136     *
137     * @throws DbException if the statement has been canceled
138     */
139    protected void checkCanceled() {
140        if (cancel) {
141            cancel = false;
142            throw DbException.get(ErrorCode.STATEMENT_WAS_CANCELED);
143        }
144    }
145 
146    private void stop() {
147        session.endStatement();
148        session.setCurrentCommand(null);
149        if (!isTransactional()) {
150            session.commit(true);
151        } else if (session.getAutoCommit()) {
152            session.commit(false);
153        } else if (session.getDatabase().isMultiThreaded()) {
154            Database db = session.getDatabase();
155            if (db != null) {
156                if (db.getLockMode() == Constants.LOCK_MODE_READ_COMMITTED) {
157                    session.unlockReadLocks();
158                }
159            }
160        }
161        if (trace.isInfoEnabled() && startTime > 0) {
162            long time = System.currentTimeMillis() - startTime;
163            if (time > Constants.SLOW_QUERY_LIMIT_MS) {
164                trace.info("slow query: {0} ms", time);
165            }
166        }
167    }
168 
169    /**
170     * Execute a query and return the result.
171     * This method prepares everything and calls {@link #query(int)} finally.
172     *
173     * @param maxrows the maximum number of rows to return
174     * @param scrollable if the result set must be scrollable (ignored)
175     * @return the result set
176     */
177    @Override
178    public ResultInterface executeQuery(int maxrows, boolean scrollable) {
179        startTime = 0;
180        long start = 0;
181        Database database = session.getDatabase();
182        Object sync = database.isMultiThreaded() ? (Object) session : (Object) database;
183        session.waitIfExclusiveModeEnabled();
184        boolean callStop = true;
185        boolean writing = !isReadOnly();
186        if (writing) {
187            while (!database.beforeWriting()) {
188                // wait
189            }
190        }
191        synchronized (sync) {
192            session.setCurrentCommand(this);
193            try {
194                while (true) {
195                    database.checkPowerOff();
196                    try {
197                        return query(maxrows);
198                    } catch (DbException e) {
199                        start = filterConcurrentUpdate(e, start);
200                    } catch (OutOfMemoryError e) {
201                        callStop = false;
202                        // there is a serious problem:
203                        // the transaction may be applied partially
204                        // in this case we need to panic:
205                        // close the database
206                        database.shutdownImmediately();
207                        throw DbException.convert(e);
208                    } catch (Throwable e) {
209                        throw DbException.convert(e);
210                    }
211                }
212            } catch (DbException e) {
213                e = e.addSQL(sql);
214                SQLException s = e.getSQLException();
215                database.exceptionThrown(s, sql);
216                if (s.getErrorCode() == ErrorCode.OUT_OF_MEMORY) {
217                    callStop = false;
218                    database.shutdownImmediately();
219                    throw e;
220                }
221                database.checkPowerOff();
222                throw e;
223            } finally {
224                if (callStop) {
225                    stop();
226                }
227                if (writing) {
228                    database.afterWriting();
229                }
230            }
231        }
232    }
233 
234    @Override
235    public int executeUpdate() {
236        long start = 0;
237        Database database = session.getDatabase();
238        Object sync = database.isMultiThreaded() ? (Object) session : (Object) database;
239        session.waitIfExclusiveModeEnabled();
240        boolean callStop = true;
241        boolean writing = !isReadOnly();
242        if (writing) {
243            while (!database.beforeWriting()) {
244                // wait
245            }
246        }
247        synchronized (sync) {
248            Session.Savepoint rollback = session.setSavepoint();
249            session.setCurrentCommand(this);
250            try {
251                while (true) {
252                    database.checkPowerOff();
253                    try {
254                        return update();
255                    } catch (DbException e) {
256                        start = filterConcurrentUpdate(e, start);
257                    } catch (OutOfMemoryError e) {
258                        callStop = false;
259                        database.shutdownImmediately();
260                        throw DbException.convert(e);
261                    } catch (Throwable e) {
262                        throw DbException.convert(e);
263                    }
264                }
265            } catch (DbException e) {
266                e = e.addSQL(sql);
267                SQLException s = e.getSQLException();
268                database.exceptionThrown(s, sql);
269                if (s.getErrorCode() == ErrorCode.OUT_OF_MEMORY) {
270                    callStop = false;
271                    database.shutdownImmediately();
272                    throw e;
273                }
274                database.checkPowerOff();
275                if (s.getErrorCode() == ErrorCode.DEADLOCK_1) {
276                    session.rollback();
277                } else {
278                    session.rollbackTo(rollback, false);
279                }
280                throw e;
281            } finally {
282                try {
283                    if (callStop) {
284                        stop();
285                    }
286                } finally {
287                    if (writing) {
288                        database.afterWriting();
289                    }
290                }
291            }
292        }
293    }
294 
295    private long filterConcurrentUpdate(DbException e, long start) {
296        if (e.getErrorCode() != ErrorCode.CONCURRENT_UPDATE_1) {
297            throw e;
298        }
299        long now = System.nanoTime() / 1000000;
300        if (start != 0 && now - start > session.getLockTimeout()) {
301            throw DbException.get(ErrorCode.LOCK_TIMEOUT_1, e.getCause(), "");
302        }
303        Database database = session.getDatabase();
304        int sleep = 1 + MathUtils.randomInt(10);
305        while (true) {
306            try {
307                if (database.isMultiThreaded()) {
308                    Thread.sleep(sleep);
309                } else {
310                    database.wait(sleep);
311                }
312            } catch (InterruptedException e1) {
313                // ignore
314            }
315            long slept = System.nanoTime() / 1000000 - now;
316            if (slept >= sleep) {
317                break;
318            }
319        }
320        return start == 0 ? now : start;
321    }
322 
323    @Override
324    public void close() {
325        canReuse = true;
326    }
327 
328    @Override
329    public void cancel() {
330        this.cancel = true;
331    }
332 
333    @Override
334    public String toString() {
335        return sql + Trace.formatParams(getParameters());
336    }
337 
338    public boolean isCacheable() {
339        return false;
340    }
341 
342    /**
343     * Whether the command is already closed (in which case it can be re-used).
344     *
345     * @return true if it can be re-used
346     */
347    public boolean canReuse() {
348        return canReuse;
349    }
350 
351    /**
352     * The command is now re-used, therefore reset the canReuse flag, and the
353     * parameter values.
354     */
355    public void reuse() {
356        canReuse = false;
357        ArrayList<? extends ParameterInterface> parameters = getParameters();
358        for (int i = 0, size = parameters.size(); i < size; i++) {
359            ParameterInterface param = parameters.get(i);
360            param.setValue(null, true);
361        }
362    }
363 
364}

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