001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (http://h2database.com/html/license.html).
004: * Initial Developer: H2 Group
005: */
006: package org.h2.command;
007:
008: import java.sql.SQLException;
009:
010: import org.h2.constant.ErrorCode;
011: import org.h2.engine.Constants;
012: import org.h2.engine.Database;
013: import org.h2.engine.Session;
014: import org.h2.message.Message;
015: import org.h2.message.Trace;
016: import org.h2.message.TraceObject;
017: import org.h2.result.LocalResult;
018: import org.h2.result.ResultInterface;
019: import org.h2.util.ObjectArray;
020:
021: /**
022: * Represents a SQL statement. This object is only used on the server side.
023: */
024: public abstract class Command implements CommandInterface {
025:
026: /**
027: * The session.
028: */
029: protected final Session session;
030:
031: /**
032: * The trace module.
033: */
034: protected final Trace trace;
035:
036: /**
037: * The last start time.
038: */
039: protected long startTime;
040:
041: /**
042: * If this query was cancelled.
043: */
044: private volatile boolean cancel;
045:
046: private final String sql;
047:
048: /**
049: * Check if this command is transactional.
050: * If it is not, then it forces the current transaction to commit.
051: *
052: * @return true if it is
053: */
054: public abstract boolean isTransactional();
055:
056: /**
057: * Check if this command is a query.
058: *
059: * @return true if it is
060: */
061: public abstract boolean isQuery();
062:
063: /**
064: * Get the list of parameters.
065: *
066: * @return the list of parameters
067: */
068: public abstract ObjectArray getParameters();
069:
070: /**
071: * Check if this command is read only.
072: *
073: * @return true if it is
074: */
075: public abstract boolean isReadOnly();
076:
077: /**
078: * Get an empty result set containing the meta data.
079: *
080: * @return an empty result set
081: */
082: public abstract LocalResult queryMeta() throws SQLException;
083:
084: public Command(Parser parser, String sql) {
085: this .session = parser.getSession();
086: this .sql = sql;
087: trace = session.getDatabase().getTrace(Trace.COMMAND);
088: }
089:
090: /**
091: * Execute an updating statement, if this is possible.
092: *
093: * @return the update count
094: * @throws SQLException if the command is not an updating statement
095: */
096: public int update() throws SQLException {
097: throw Message
098: .getSQLException(ErrorCode.METHOD_NOT_ALLOWED_FOR_QUERY);
099: }
100:
101: /**
102: * Execute a query statement, if this is possible.
103: *
104: * @param maxrows the maximum number of rows returned
105: * @return the local result set
106: * @throws SQLException if the command is not a query
107: */
108: public LocalResult query(int maxrows) throws SQLException {
109: throw Message
110: .getSQLException(ErrorCode.METHOD_ONLY_ALLOWED_FOR_QUERY);
111: }
112:
113: public final LocalResult getMetaDataLocal() throws SQLException {
114: return queryMeta();
115: }
116:
117: public final ResultInterface getMetaData() throws SQLException {
118: return queryMeta();
119: }
120:
121: public ResultInterface executeQuery(int maxrows, boolean scrollable)
122: throws SQLException {
123: return executeQueryLocal(maxrows);
124: }
125:
126: /**
127: * Execute a query and return a local result set.
128: * This method prepares everything and calls {@link #query(int)} finally.
129: *
130: * @param maxrows the maximum number of rows to return
131: * @return the local result set
132: */
133: public LocalResult executeQueryLocal(int maxrows)
134: throws SQLException {
135: startTime = System.currentTimeMillis();
136: Database database = session.getDatabase();
137: Object sync = database.getMultiThreaded() ? (Object) session
138: : (Object) database;
139: session.waitIfExclusiveModeEnabled();
140: synchronized (sync) {
141: try {
142: database.checkPowerOff();
143: session.setCurrentCommand(this , startTime);
144: return query(maxrows);
145: } catch (Throwable e) {
146: SQLException s = Message.convert(e);
147: database.exceptionThrown(s, sql);
148: throw s;
149: } finally {
150: stop();
151: }
152: }
153: }
154:
155: protected void start() {
156: startTime = System.currentTimeMillis();
157: }
158:
159: /**
160: * Check if this command has been cancelled, and throw an exception if yes.
161: *
162: * @throws SQLException if the statement has been cancelled
163: */
164: public void checkCancelled() throws SQLException {
165: if (cancel) {
166: cancel = false;
167: throw Message
168: .getSQLException(ErrorCode.STATEMENT_WAS_CANCELLED);
169: }
170: }
171:
172: private void stop() throws SQLException {
173: session.closeTemporaryResults();
174: session.setCurrentCommand(null, 0);
175: if (!isTransactional()) {
176: session.commit(true);
177: } else if (session.getAutoCommit()) {
178: session.commit(false);
179: } else if (session.getDatabase().getMultiThreaded()) {
180: Database db = session.getDatabase();
181: if (db != null
182: && db.getLockMode() == Constants.LOCK_MODE_READ_COMMITTED) {
183: session.unlockReadLocks();
184: }
185: }
186: if (trace.info()) {
187: long time = System.currentTimeMillis() - startTime;
188: if (time > Constants.LONG_QUERY_LIMIT_MS) {
189: trace.info("long query: " + time);
190: }
191: }
192: }
193:
194: public int executeUpdate() throws SQLException {
195: startTime = System.currentTimeMillis();
196: Database database = session.getDatabase();
197: Object sync = database.getMultiThreaded() ? (Object) session
198: : (Object) database;
199: session.waitIfExclusiveModeEnabled();
200: synchronized (sync) {
201: int rollback = session.getLogId();
202: session.setCurrentCommand(this , startTime);
203: try {
204: database.checkPowerOff();
205: return update();
206: } catch (SQLException e) {
207: database.exceptionThrown(e, sql);
208: database.checkPowerOff();
209: session.rollbackTo(rollback);
210: throw e;
211: } finally {
212: stop();
213: }
214: }
215: }
216:
217: public void close() {
218: // nothing to do
219: }
220:
221: public void cancel() {
222: this .cancel = true;
223: }
224:
225: public String toString() {
226: return TraceObject.toString(sql, getParameters());
227: }
228: }
|