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.io.IOException;
009: import java.sql.SQLException;
010:
011: import org.h2.constant.SysProperties;
012: import org.h2.engine.SessionRemote;
013: import org.h2.expression.ParameterInterface;
014: import org.h2.expression.ParameterRemote;
015: import org.h2.message.Trace;
016: import org.h2.message.TraceObject;
017: import org.h2.result.ResultInterface;
018: import org.h2.result.ResultRemote;
019: import org.h2.util.ObjectArray;
020: import org.h2.value.Transfer;
021:
022: /**
023: * Represents the client-side part of a SQL statement.
024: * This class is not used in embedded mode.
025: */
026: public class CommandRemote implements CommandInterface {
027:
028: private final ObjectArray transferList;
029: private final ObjectArray parameters;
030: private final Trace trace;
031: private final String sql;
032: private final int fetchSize;
033: private SessionRemote session;
034: private int id;
035: private boolean isQuery;
036: private boolean readonly;
037: private int paramCount;
038:
039: public CommandRemote(SessionRemote session,
040: ObjectArray transferList, String sql, int fetchSize)
041: throws SQLException {
042: this .transferList = transferList;
043: trace = session.getTrace();
044: this .sql = sql;
045: parameters = new ObjectArray();
046: prepare(session);
047: for (int i = 0; i < paramCount; i++) {
048: parameters.add(new ParameterRemote(i));
049: }
050: // set session late because prepare might fail - in this case we don't
051: // need to close the object
052: this .session = session;
053: this .fetchSize = fetchSize;
054: }
055:
056: private void prepare(SessionRemote session) throws SQLException {
057: id = session.getNextId();
058: paramCount = 0;
059: for (int i = 0; i < transferList.size(); i++) {
060: try {
061: Transfer transfer = (Transfer) transferList.get(i);
062: session.traceOperation("SESSION_PREPARE", id);
063: transfer.writeInt(SessionRemote.SESSION_PREPARE)
064: .writeInt(id).writeString(sql);
065: session.done(transfer);
066: isQuery = transfer.readBoolean();
067: readonly = transfer.readBoolean();
068: paramCount = transfer.readInt();
069: } catch (IOException e) {
070: session.removeServer(i--);
071: }
072: }
073: }
074:
075: public boolean isQuery() {
076: return isQuery;
077: }
078:
079: public ObjectArray getParameters() {
080: return parameters;
081: }
082:
083: public ResultInterface getMetaData() throws SQLException {
084: synchronized (session) {
085: session.checkClosed();
086: if (!isQuery) {
087: return null;
088: }
089: if (id <= session.getCurrentId()
090: - SysProperties.SERVER_CACHED_OBJECTS) {
091: // object is too old - we need to prepare again
092: prepare(session);
093: }
094: int objectId = session.getNextId();
095: ResultRemote result = null;
096: for (int i = 0; i < transferList.size(); i++) {
097: Transfer transfer = (Transfer) transferList.get(i);
098: try {
099: // TODO cluster: support load balance with values for each server / auto detect
100: session.traceOperation("COMMAND_GET_META_DATA", id);
101: transfer.writeInt(
102: SessionRemote.COMMAND_GET_META_DATA)
103: .writeInt(id).writeInt(objectId);
104: session.done(transfer);
105: int columnCount = transfer.readInt();
106: result = new ResultRemote(session, transfer,
107: objectId, columnCount, Integer.MAX_VALUE);
108: break;
109: } catch (IOException e) {
110: session.removeServer(i--);
111: }
112: }
113: session.autoCommitIfCluster();
114: return result;
115: }
116: }
117:
118: public ResultInterface executeQuery(int maxRows, boolean scrollable)
119: throws SQLException {
120: checkParameters();
121: synchronized (session) {
122: session.checkClosed();
123: if (id <= session.getCurrentId()
124: - SysProperties.SERVER_CACHED_OBJECTS) {
125: // object is too old - we need to prepare again
126: prepare(session);
127: }
128: int objectId = session.getNextId();
129: ResultRemote result = null;
130: for (int i = 0; i < transferList.size(); i++) {
131: Transfer transfer = (Transfer) transferList.get(i);
132: try {
133: // TODO cluster: support load balance with values for each
134: // server / auto detect
135: session.traceOperation("COMMAND_EXECUTE_QUERY", id);
136: transfer.writeInt(
137: SessionRemote.COMMAND_EXECUTE_QUERY)
138: .writeInt(id).writeInt(objectId).writeInt(
139: maxRows);
140: int fetch;
141: if (session.isClustered() || scrollable) {
142: fetch = Integer.MAX_VALUE;
143: } else {
144: fetch = fetchSize;
145: }
146: transfer.writeInt(fetch);
147: sendParameters(transfer);
148: session.done(transfer);
149: int columnCount = transfer.readInt();
150: if (result != null) {
151: result.close();
152: result = null;
153: }
154: result = new ResultRemote(session, transfer,
155: objectId, columnCount, fetch);
156: if (readonly) {
157: break;
158: }
159: } catch (IOException e) {
160: session.removeServer(i--);
161: }
162: }
163: session.autoCommitIfCluster();
164: return result;
165: }
166: }
167:
168: public int executeUpdate() throws SQLException {
169: checkParameters();
170: synchronized (session) {
171: session.checkClosed();
172: if (id <= session.getCurrentId()
173: - SysProperties.SERVER_CACHED_OBJECTS) {
174: // object is too old - we need to prepare again
175: prepare(session);
176: }
177: int updateCount = 0;
178: boolean autoCommit = false;
179: for (int i = 0; i < transferList.size(); i++) {
180: try {
181: Transfer transfer = (Transfer) transferList.get(i);
182: session
183: .traceOperation("COMMAND_EXECUTE_UPDATE",
184: id);
185: transfer.writeInt(
186: SessionRemote.COMMAND_EXECUTE_UPDATE)
187: .writeInt(id);
188: sendParameters(transfer);
189: session.done(transfer);
190: updateCount = transfer.readInt();
191: autoCommit = transfer.readBoolean();
192: } catch (IOException e) {
193: session.removeServer(i--);
194: }
195: }
196: session.setAutoCommit(autoCommit);
197: session.autoCommitIfCluster();
198: return updateCount;
199: }
200: }
201:
202: private void checkParameters() throws SQLException {
203: int len = parameters.size();
204: for (int i = 0; i < len; i++) {
205: ParameterInterface p = (ParameterInterface) parameters
206: .get(i);
207: p.checkSet();
208: }
209: }
210:
211: private void sendParameters(Transfer transfer) throws IOException,
212: SQLException {
213: int len = parameters.size();
214: transfer.writeInt(len);
215: for (int i = 0; i < len; i++) {
216: ParameterInterface p = (ParameterInterface) parameters
217: .get(i);
218: transfer.writeValue(p.getParamValue());
219: }
220: }
221:
222: public void close() {
223: if (session == null || session.isClosed()) {
224: return;
225: }
226: synchronized (session) {
227: for (int i = 0; i < transferList.size(); i++) {
228: try {
229: Transfer transfer = (Transfer) transferList.get(i);
230: session.traceOperation("COMMAND_CLOSE", id);
231: transfer.writeInt(SessionRemote.COMMAND_CLOSE)
232: .writeInt(id);
233: } catch (IOException e) {
234: // TODO cluster: do we need to to handle io exception on
235: // close?
236: trace.error("close", e);
237: }
238: }
239: session = null;
240: }
241: }
242:
243: /**
244: * Cancel this current statement.
245: * This method is not yet implemented for this class.
246: */
247: public void cancel() {
248: // TODO server: support cancel
249: }
250:
251: public String toString() {
252: return TraceObject.toString(sql, getParameters());
253: }
254:
255: }
|