blob: d886d8a12f67883bb7c60feb37bb9c6a0fb000e1 [file] [log] [blame]
/* Copyright (c) 2001-2010, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb.result;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.StringReader;
import org.hsqldb.ColumnBase;
import org.hsqldb.Database;
import org.hsqldb.HsqlException;
import org.hsqldb.Session;
import org.hsqldb.SessionInterface;
import org.hsqldb.Statement;
import org.hsqldb.StatementTypes;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.DataOutputStream;
import org.hsqldb.navigator.RowSetNavigator;
import org.hsqldb.navigator.RowSetNavigatorClient;
import org.hsqldb.rowio.RowInputBinary;
import org.hsqldb.rowio.RowOutputInterface;
import org.hsqldb.store.ValuePool;
import org.hsqldb.types.Type;
/**
* The primary unit of communication between Connection, Server and Session
* objects.
*
* An HSQLDB Result object encapsulates all requests (such as to alter or
* query session settings, to allocate and execute statements, etc.) and all
* responses (such as exception indications, update counts, result sets and
* result set metadata). It also implements the HSQL wire protocol for
* comunicating all such requests and responses across the network.
* Uses a navigator for data.
*
* @author Campbell Boucher-Burnett (boucherb@users dot sourceforge.net)
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 1.9.0
* @since 1.9.0
*/
public class Result {
public static final ResultMetaData sessionAttributesMetaData =
ResultMetaData.newResultMetaData(SessionInterface.INFO_LIMIT);
static {
for (int i = 0; i < Session.INFO_LIMIT; i++) {
sessionAttributesMetaData.columns[i] = new ColumnBase(null, null,
null, null);
}
sessionAttributesMetaData.columns[Session.INFO_ID].setType(
Type.SQL_INTEGER);
sessionAttributesMetaData.columns[Session.INFO_INTEGER].setType(
Type.SQL_INTEGER);
sessionAttributesMetaData.columns[Session.INFO_BOOLEAN].setType(
Type.SQL_BOOLEAN);
sessionAttributesMetaData.columns[Session.INFO_VARCHAR].setType(
Type.SQL_VARCHAR);
sessionAttributesMetaData.prepareData();
}
private static final ResultMetaData emptyMeta =
ResultMetaData.newResultMetaData(0);
public static final Result emptyGeneratedResult =
Result.newDataResult(emptyMeta);
public static final Result updateZeroResult = newUpdateCountResult(0);
public static final Result updateOneResult = newUpdateCountResult(1);
// type of result
public byte mode;
// database ID
int databaseID;
// session ID
long sessionID;
// result id
private long id;
// database name for new connection
private String databaseName;
// user / password for new connection
// error strings in error results
private String mainString;
private String subString;
private String zoneString;
// vendor error code
int errorCode;
// the exception if this is an error
private HsqlException exception;
// prepared statement id
long statementID;
// statement type based on whether it returns an update count or a result set
// type of session info requested
int statementReturnType;
// max rows (out)
// update count (in)
// fetch part result count (in)
// time zone seconds (connect)
public int updateCount;
// fetch size (in)
private int fetchSize;
// secondary result
private Result chainedResult;
//
private int lobCount;
ResultLob lobResults;
/** A Result object's metadata */
public ResultMetaData metaData;
/** Additional meta data for parameters used in PREPARE_ACK results */
public ResultMetaData parameterMetaData;
/** Additional meta data for required generated columns */
public ResultMetaData generatedMetaData;
//
public int rsProperties;
//
public int queryTimeout;
//
int generateKeys;
// simple value for PSM, or parameter array
public Object valueData;
//
public Statement statement;
Result(int mode) {
this.mode = (byte) mode;
}
public Result(int mode, int count) {
this.mode = (byte) mode;
updateCount = count;
}
public static Result newResult(RowSetNavigator nav) {
Result result = new Result(ResultConstants.DATA);
result.navigator = nav;
return result;
}
public static Result newResult(int type) {
RowSetNavigator navigator = null;
Result result = null;
switch (type) {
case ResultConstants.CALL_RESPONSE :
case ResultConstants.EXECUTE :
case ResultConstants.UPDATE_RESULT :
break;
case ResultConstants.BATCHEXECUTE :
case ResultConstants.BATCHEXECDIRECT :
navigator = new RowSetNavigatorClient(4);
break;
case ResultConstants.SETSESSIONATTR :
case ResultConstants.PARAM_METADATA :
navigator = new RowSetNavigatorClient(1);
break;
case ResultConstants.BATCHEXECRESPONSE :
navigator = new RowSetNavigatorClient(4);
break;
case ResultConstants.DATA :
case ResultConstants.DATAHEAD :
case ResultConstants.DATAROWS :
break;
case ResultConstants.LARGE_OBJECT_OP :
throw Error.runtimeError(ErrorCode.U_S0500, "Result");
default :
}
result = new Result(type);
result.navigator = navigator;
return result;
}
public static Result newResult(DataInput dataInput,
RowInputBinary in)
throws IOException, HsqlException {
return newResult(null, dataInput.readByte(), dataInput, in);
}
public static Result newResult(Session session, int mode,
DataInput dataInput,
RowInputBinary in)
throws IOException, HsqlException {
try {
if (mode == ResultConstants.LARGE_OBJECT_OP) {
return ResultLob.newLob(dataInput, false);
}
Result result = newResult(session, dataInput, in, mode);
return result;
} catch (IOException e) {
throw Error.error(ErrorCode.X_08000);
}
}
public void readAdditionalResults(SessionInterface session,
DataInputStream inputStream,
RowInputBinary in)
throws IOException, HsqlException {
setSession(session);
Result currentResult = this;
boolean hasLob = false;
while (true) {
int addedResultMode = inputStream.readByte();
if (addedResultMode == ResultConstants.LARGE_OBJECT_OP) {
ResultLob resultLob = ResultLob.newLob(inputStream, false);
if (session instanceof Session) {
((Session) session).allocateResultLob(resultLob,
inputStream);
}
currentResult.addLobResult(resultLob);
hasLob = true;
continue;
}
if (hasLob) {
hasLob = false;
if (session instanceof Session) {
((Session) session).registerResultLobs(currentResult);
}
}
if (addedResultMode == ResultConstants.NONE) {
return;
}
currentResult = newResult(null, inputStream, in, addedResultMode);
addChainedResult(currentResult);
}
}
private static Result newResult(Session session, DataInput dataInput,
RowInputBinary in,
int mode)
throws IOException, HsqlException {
Result result = newResult(mode);
int length = dataInput.readInt();
in.resetRow(0, length);
byte[] byteArray = in.getBuffer();
final int offset = 4;
dataInput.readFully(byteArray, offset, length - offset);
switch (mode) {
case ResultConstants.GETSESSIONATTR :
result.statementReturnType = in.readByte();
break;
case ResultConstants.DISCONNECT :
case ResultConstants.RESETSESSION :
case ResultConstants.STARTTRAN :
break;
case ResultConstants.PREPARE :
result.setStatementType(in.readByte());
result.mainString = in.readString();
result.rsProperties = in.readByte();
result.generateKeys = in.readByte();
if (result.generateKeys == ResultConstants
.RETURN_GENERATED_KEYS_COL_NAMES || result
.generateKeys == ResultConstants
.RETURN_GENERATED_KEYS_COL_INDEXES) {
result.generatedMetaData = new ResultMetaData(in);
}
break;
case ResultConstants.CLOSE_RESULT :
result.id = in.readLong();
break;
case ResultConstants.FREESTMT :
result.statementID = in.readLong();
break;
case ResultConstants.EXECDIRECT :
result.updateCount = in.readInt();
result.fetchSize = in.readInt();
result.statementReturnType = in.readByte();
result.mainString = in.readString();
result.rsProperties = in.readByte();
result.queryTimeout = in.readShort();
result.generateKeys = in.readByte();
if (result.generateKeys == ResultConstants
.RETURN_GENERATED_KEYS_COL_NAMES || result
.generateKeys == ResultConstants
.RETURN_GENERATED_KEYS_COL_INDEXES) {
result.generatedMetaData = new ResultMetaData(in);
}
break;
case ResultConstants.CONNECT :
result.databaseName = in.readString();
result.mainString = in.readString();
result.subString = in.readString();
result.zoneString = in.readString();
result.updateCount = in.readInt();
break;
case ResultConstants.ERROR :
case ResultConstants.WARNING :
result.mainString = in.readString();
result.subString = in.readString();
result.errorCode = in.readInt();
break;
case ResultConstants.CONNECTACKNOWLEDGE :
result.databaseID = in.readInt();
result.sessionID = in.readLong();
result.mainString = in.readString();
break;
case ResultConstants.UPDATECOUNT :
result.updateCount = in.readInt();
break;
case ResultConstants.ENDTRAN : {
int type = in.readInt();
result.setActionType(type); // endtran type
switch (type) {
case ResultConstants.TX_SAVEPOINT_NAME_RELEASE :
case ResultConstants.TX_SAVEPOINT_NAME_ROLLBACK :
result.mainString = in.readString(); // savepoint name
break;
case ResultConstants.TX_COMMIT :
case ResultConstants.TX_ROLLBACK :
case ResultConstants.TX_COMMIT_AND_CHAIN :
case ResultConstants.TX_ROLLBACK_AND_CHAIN :
break;
default :
throw Error.runtimeError(ErrorCode.U_S0500, "Result");
}
break;
}
case ResultConstants.SETCONNECTATTR : {
int type = in.readInt(); // attr type
result.setConnectionAttrType(type);
switch (type) {
case ResultConstants.SQL_ATTR_SAVEPOINT_NAME :
result.mainString = in.readString(); // savepoint name
break;
// case ResultConstants.SQL_ATTR_AUTO_IPD :
// - always true
// default: throw - case never happens
default :
throw Error.runtimeError(ErrorCode.U_S0500, "Result");
}
break;
}
case ResultConstants.PREPARE_ACK :
result.statementReturnType = in.readByte();
result.statementID = in.readLong();
result.rsProperties = in.readByte();
result.metaData = new ResultMetaData(in);
result.parameterMetaData = new ResultMetaData(in);
break;
case ResultConstants.CALL_RESPONSE :
result.updateCount = in.readInt();
result.fetchSize = in.readInt();
result.statementID = in.readLong();
result.rsProperties = in.readByte();
result.metaData = new ResultMetaData(in);
result.valueData = readSimple(in, result.metaData);
break;
case ResultConstants.EXECUTE :
result.updateCount = in.readInt();
result.fetchSize = in.readInt();
result.statementID = in.readLong();
result.rsProperties = in.readByte();
result.queryTimeout = in.readShort();
Statement statement =
session.statementManager.getStatement(session,
result.statementID);
result.statement = statement;
if (statement != null) {
result.metaData = result.statement.getParametersMetaData();
}
result.valueData = readSimple(in, result.metaData);
break;
case ResultConstants.UPDATE_RESULT : {
result.id = in.readLong();
int type = in.readInt();
result.setActionType(type);
result.metaData = new ResultMetaData(in);
result.valueData = readSimple(in, result.metaData);
break;
}
case ResultConstants.BATCHEXECRESPONSE :
case ResultConstants.BATCHEXECUTE :
case ResultConstants.BATCHEXECDIRECT :
case ResultConstants.SETSESSIONATTR : {
result.updateCount = in.readInt();
result.fetchSize = in.readInt();
result.statementID = in.readLong();
result.queryTimeout = in.readShort();
result.metaData = new ResultMetaData(in);
result.navigator.readSimple(in, result.metaData);
break;
}
case ResultConstants.PARAM_METADATA : {
result.metaData = new ResultMetaData(in);
result.navigator.read(in, result.metaData);
break;
}
case ResultConstants.REQUESTDATA : {
result.id = in.readLong();
result.updateCount = in.readInt();
result.fetchSize = in.readInt();
break;
}
case ResultConstants.DATAHEAD :
case ResultConstants.DATA : {
result.id = in.readLong();
result.updateCount = in.readInt();
result.fetchSize = in.readInt();
result.rsProperties = in.readByte();
result.metaData = new ResultMetaData(in);
result.navigator = new RowSetNavigatorClient();
result.navigator.read(in, result.metaData);
break;
}
case ResultConstants.DATAROWS : {
result.metaData = new ResultMetaData(in);
result.navigator = new RowSetNavigatorClient();
result.navigator.read(in, result.metaData);
break;
}
default :
throw Error.runtimeError(ErrorCode.U_S0500, "Result");
}
return result;
}
/**
* For interval PSM return values
*/
public static Result newPSMResult(int type, String label, Object value) {
Result result = newResult(ResultConstants.VALUE);
result.errorCode = type;
result.mainString = label;
result.valueData = value;
return result;
}
/**
* For interval PSM return values
*/
public static Result newPSMResult(Object value) {
Result result = newResult(ResultConstants.VALUE);
result.valueData = value;
return result;
}
/**
* For SQLPREPARE
* For parparation of SQL parepared statements.
*/
public static Result newPrepareStatementRequest() {
return newResult(ResultConstants.PREPARE);
}
/**
* For SQLEXECUTE
* For execution of SQL prepared statements.
* The parameters are set afterwards as the Result is reused
*/
public static Result newPreparedExecuteRequest(Type[] types,
long statementId) {
Result result = newResult(ResultConstants.EXECUTE);
result.metaData = ResultMetaData.newSimpleResultMetaData(types);
result.statementID = statementId;
result.valueData = ValuePool.emptyObjectArray;
return result;
}
/**
* For CALL_RESPONSE
* For execution of SQL callable statements.
*/
public static Result newCallResponse(Type[] types, long statementId,
Object[] values) {
Result result = newResult(ResultConstants.CALL_RESPONSE);
result.metaData = ResultMetaData.newSimpleResultMetaData(types);
result.statementID = statementId;
result.valueData = values;
return result;
}
/**
* For UPDATE_RESULT
* The parameters are set afterwards as the Result is reused
*/
public static Result newUpdateResultRequest(Type[] types, long id) {
Result result = newResult(ResultConstants.UPDATE_RESULT);
result.metaData = ResultMetaData.newUpdateResultMetaData(types);
result.id = id;
result.valueData = new Object[]{};
return result;
}
/**
* For UPDATE_RESULT results
* The parameters are set by this method as the Result is reused
*/
public void setPreparedResultUpdateProperties(Object[] parameterValues) {
valueData = parameterValues;
}
/**
* For SQLEXECUTE results
* The parameters are set by this method as the Result is reused
*/
public void setPreparedExecuteProperties(Object[] parameterValues,
int maxRows, int fetchSize, int resultProps) {
mode = ResultConstants.EXECUTE;
valueData = parameterValues;
updateCount = maxRows;
this.fetchSize = fetchSize;
this.rsProperties = resultProps;
}
/**
* For BATCHEXECUTE
*/
public void setBatchedPreparedExecuteRequest() {
mode = ResultConstants.BATCHEXECUTE;
if (navigator == null) {
navigator = new RowSetNavigatorClient(4);
} else {
((RowSetNavigatorClient) navigator).clear();
}
updateCount = 0;
this.fetchSize = 0;
}
public void addBatchedPreparedExecuteRequest(Object[] parameterValues) {
((RowSetNavigatorClient) navigator).add(parameterValues);
}
/**
* For BATCHEXECDIRECT
*/
public static Result newBatchedExecuteRequest() {
Type[] types = new Type[]{ Type.SQL_VARCHAR };
Result result = newResult(ResultConstants.BATCHEXECDIRECT);
result.metaData = ResultMetaData.newSimpleResultMetaData(types);
return result;
}
/**
* For BATCHEXERESPONSE for a BATCHEXECUTE or BATCHEXECDIRECT
*/
public static Result newBatchedExecuteResponse(int[] updateCounts,
Result generatedResult, Result e) {
Result result = newResult(ResultConstants.BATCHEXECRESPONSE);
result.addChainedResult(generatedResult);
result.addChainedResult(e);
Type[] types = new Type[]{ Type.SQL_INTEGER };
result.metaData = ResultMetaData.newSimpleResultMetaData(types);
Object[][] table = new Object[updateCounts.length][];
for (int i = 0; i < updateCounts.length; i++) {
table[i] = new Object[]{ ValuePool.getInt(updateCounts[i]) };
}
((RowSetNavigatorClient) result.navigator).setData(table);
return result;
}
public static Result newResetSessionRequest() {
Result result = newResult(ResultConstants.RESETSESSION);
return result;
}
public static Result newConnectionAttemptRequest(String user,
String password, String database, String zoneString,
int timeZoneSeconds) {
Result result = newResult(ResultConstants.CONNECT);
result.mainString = user;
result.subString = password;
result.zoneString = zoneString;
result.databaseName = database;
result.updateCount = timeZoneSeconds;
return result;
}
public static Result newConnectionAcknowledgeResponse(Database database,
long sessionID, int databaseID) {
Result result = newResult(ResultConstants.CONNECTACKNOWLEDGE);
result.sessionID = sessionID;
result.databaseID = databaseID;
result.mainString =
database.getProperties().getClientPropertiesAsString();
return result;
}
public static Result newUpdateZeroResult() {
return new Result(ResultConstants.UPDATECOUNT, 0);
}
public static Result newUpdateCountResult(int count) {
return new Result(ResultConstants.UPDATECOUNT, count);
}
public static Result newUpdateCountResult(ResultMetaData meta, int count) {
Result result = newResult(ResultConstants.UPDATECOUNT);
Result dataResult = newDataResult(meta);
result.updateCount = count;
result.addChainedResult(dataResult);
return result;
}
public static Result newSingleColumnResult(ResultMetaData meta) {
Result result = newResult(ResultConstants.DATA);
result.metaData = meta;
result.navigator = new RowSetNavigatorClient();
return result;
}
public static Result newSingleColumnResult(String colName, Type type) {
Result result = newResult(ResultConstants.DATA);
result.metaData = ResultMetaData.newResultMetaData(1);
result.metaData.columns[0] = new ColumnBase(null, null, null, colName);
result.metaData.columns[0].setType(type);
result.metaData.prepareData();
//
result.navigator = new RowSetNavigatorClient(8);
return result;
}
public static Result newSingleColumnStringResult(String colName,
String contents) {
Result result = Result.newSingleColumnResult("OPERATION",
Type.SQL_VARCHAR);
LineNumberReader lnr =
new LineNumberReader(new StringReader(contents));
while (true) {
String line = null;
try {
line = lnr.readLine();
} catch (Exception e) {}
if (line == null) {
break;
}
result.getNavigator().add(new Object[]{ line });
}
return result;
}
public static Result newPrepareResponse(Statement statement) {
Result r = newResult(ResultConstants.PREPARE_ACK);
r.statement = statement;
r.statementID = statement.getID();
int csType = statement.getType();
r.statementReturnType =
(csType == StatementTypes.SELECT_CURSOR || csType == StatementTypes
.CALL) ? StatementTypes.RETURN_RESULT
: StatementTypes.RETURN_COUNT;
r.metaData = statement.getResultMetaData();
r.parameterMetaData = statement.getParametersMetaData();
return r;
}
public static Result newFreeStmtRequest(long statementID) {
Result r = newResult(ResultConstants.FREESTMT);
r.statementID = statementID;
return r;
}
/**
* For direct execution of SQL statements. The statement and other
* parameters are set afterwards as the Result is reused
*/
public static Result newExecuteDirectRequest() {
return newResult(ResultConstants.EXECDIRECT);
}
/**
* For both EXECDIRECT and PREPARE
*/
public void setPrepareOrExecuteProperties(String sql, int maxRows,
int fetchSize, int statementReturnType, int timeout,
int resultSetProperties, int keyMode, int[] generatedIndexes,
String[] generatedNames) {
mainString = sql;
updateCount = maxRows;
this.fetchSize = fetchSize;
this.statementReturnType = statementReturnType;
this.queryTimeout = timeout;
rsProperties = resultSetProperties;
generateKeys = keyMode;
generatedMetaData =
ResultMetaData.newGeneratedColumnsMetaData(generatedIndexes,
generatedNames);
}
public static Result newSetSavepointRequest(String name) {
Result result;
result = newResult(ResultConstants.SETCONNECTATTR);
result.setConnectionAttrType(ResultConstants.SQL_ATTR_SAVEPOINT_NAME);
result.setMainString(name);
return result;
}
public static Result newRequestDataResult(long id, int offset, int count) {
Result result = newResult(ResultConstants.REQUESTDATA);
result.id = id;
result.updateCount = offset;
result.fetchSize = count;
return result;
}
public static Result newDataResult(ResultMetaData md) {
Result result = newResult(ResultConstants.DATA);
result.navigator = new RowSetNavigatorClient();
result.metaData = md;
return result;
}
/**
* initially, only used for updatability
*/
public int getExecuteProperties() {
return rsProperties;
}
/**
* For DATA
*/
public void setDataResultProperties(int maxRows, int fetchSize,
int resultSetScrollability,
int resultSetConcurrency,
int resultSetHoldability) {
updateCount = maxRows;
this.fetchSize = fetchSize;
rsProperties = ResultProperties.getValueForJDBC(resultSetScrollability,
resultSetConcurrency, resultSetHoldability);
}
public static Result newDataHeadResult(SessionInterface session,
Result source, int offset,
int count) {
if (offset + count > source.navigator.getSize()) {
count = source.navigator.getSize() - offset;
}
Result result = newResult(ResultConstants.DATAHEAD);
result.metaData = source.metaData;
result.navigator = new RowSetNavigatorClient(source.navigator, offset,
count);
result.navigator.setId(source.navigator.getId());
result.setSession(session);
result.rsProperties = source.rsProperties;
result.fetchSize = source.fetchSize;
return result;
}
public static Result newDataRowsResult(Result source, int offset,
int count) {
if (offset + count > source.navigator.getSize()) {
count = source.navigator.getSize() - offset;
}
Result result = newResult(ResultConstants.DATAROWS);
result.id = source.id;
result.metaData = source.metaData;
result.navigator = new RowSetNavigatorClient(source.navigator, offset,
count);
return result;
}
public static Result newDataRowsResult(RowSetNavigator navigator) {
Result result = newResult(ResultConstants.DATAROWS);
result.navigator = navigator;
return result;
}
/**
* Result structure used for set/get session attributes
*/
public static Result newSessionAttributesResult() {
Result result = newResult(ResultConstants.DATA);
result.navigator = new RowSetNavigatorClient(1);
result.metaData = sessionAttributesMetaData;
result.navigator.add(new Object[SessionInterface.INFO_LIMIT]);
return result;
}
public static Result newWarningResult(HsqlException w) {
Result result = newResult(ResultConstants.WARNING);
result.mainString = w.getMessage();
result.subString = w.getSQLState();
result.errorCode = w.getErrorCode();
return result;
}
public static Result newErrorResult(Throwable t) {
return newErrorResult(t, null);
}
/** @todo 1.9.0 fredt - move the messages to Error.java */
public static Result newErrorResult(Throwable t, String statement) {
Result result = newResult(ResultConstants.ERROR);
if (t instanceof HsqlException) {
result.exception = (HsqlException) t;
result.mainString = result.exception.getMessage();
result.subString = result.exception.getSQLState();
if (statement != null) {
result.mainString += " in statement [" + statement + "]";
}
result.errorCode = result.exception.getErrorCode();
} else if (t instanceof OutOfMemoryError) {
// gc() at this point may clear the memory allocated so far
/** @todo 1.9.0 - review if it's better to gc higher up the stack */
System.gc();
result.exception = Error.error(ErrorCode.OUT_OF_MEMORY, t);
result.mainString = result.exception.getMessage();
result.subString = result.exception.getSQLState();
result.errorCode = result.exception.getErrorCode();
} else {
result.exception = Error.error(ErrorCode.GENERAL_ERROR, t);
result.mainString = result.exception.getMessage() + " "
+ t.getMessage();
result.subString = result.exception.getSQLState();
result.errorCode = result.exception.getErrorCode();
if (statement != null) {
result.mainString += " in statement [" + statement + "]";
}
}
return result;
}
public void write(DataOutputStream dataOut,
RowOutputInterface rowOut)
throws IOException, HsqlException {
rowOut.reset();
rowOut.writeByte(mode);
int startPos = rowOut.size();
rowOut.writeSize(0);
switch (mode) {
case ResultConstants.GETSESSIONATTR :
rowOut.writeByte(statementReturnType);
break;
case ResultConstants.DISCONNECT :
case ResultConstants.RESETSESSION :
case ResultConstants.STARTTRAN :
break;
case ResultConstants.PREPARE :
rowOut.writeByte(statementReturnType);
rowOut.writeString(mainString);
rowOut.writeByte(rsProperties);
rowOut.writeByte(generateKeys);
if (generateKeys == ResultConstants
.RETURN_GENERATED_KEYS_COL_NAMES || generateKeys == ResultConstants
.RETURN_GENERATED_KEYS_COL_INDEXES) {
generatedMetaData.write(rowOut);
}
break;
case ResultConstants.FREESTMT :
rowOut.writeLong(statementID);
break;
case ResultConstants.CLOSE_RESULT :
rowOut.writeLong(id);
break;
case ResultConstants.EXECDIRECT :
rowOut.writeInt(updateCount);
rowOut.writeInt(fetchSize);
rowOut.writeByte(statementReturnType);
rowOut.writeString(mainString);
rowOut.writeByte(rsProperties);
rowOut.writeShort(queryTimeout);
rowOut.writeByte(generateKeys);
if (generateKeys == ResultConstants
.RETURN_GENERATED_KEYS_COL_NAMES || generateKeys == ResultConstants
.RETURN_GENERATED_KEYS_COL_INDEXES) {
generatedMetaData.write(rowOut);
}
break;
case ResultConstants.CONNECT :
rowOut.writeString(databaseName);
rowOut.writeString(mainString);
rowOut.writeString(subString);
rowOut.writeString(zoneString);
rowOut.writeInt(updateCount);
break;
case ResultConstants.ERROR :
case ResultConstants.WARNING :
rowOut.writeString(mainString);
rowOut.writeString(subString);
rowOut.writeInt(errorCode);
break;
case ResultConstants.CONNECTACKNOWLEDGE :
rowOut.writeInt(databaseID);
rowOut.writeLong(sessionID);
rowOut.writeString(mainString);
break;
case ResultConstants.UPDATECOUNT :
rowOut.writeInt(updateCount);
break;
case ResultConstants.ENDTRAN : {
int type = getActionType();
rowOut.writeInt(type); // endtran type
switch (type) {
case ResultConstants.TX_SAVEPOINT_NAME_RELEASE :
case ResultConstants.TX_SAVEPOINT_NAME_ROLLBACK :
rowOut.writeString(mainString); // savepoint name
break;
case ResultConstants.TX_COMMIT :
case ResultConstants.TX_ROLLBACK :
case ResultConstants.TX_COMMIT_AND_CHAIN :
case ResultConstants.TX_ROLLBACK_AND_CHAIN :
break;
default :
throw Error.runtimeError(ErrorCode.U_S0500, "Result");
}
break;
}
case ResultConstants.PREPARE_ACK :
rowOut.writeByte(statementReturnType);
rowOut.writeLong(statementID);
rowOut.writeByte(rsProperties);
metaData.write(rowOut);
parameterMetaData.write(rowOut);
break;
case ResultConstants.CALL_RESPONSE :
rowOut.writeInt(updateCount);
rowOut.writeInt(fetchSize);
rowOut.writeLong(statementID);
rowOut.writeByte(rsProperties);
metaData.write(rowOut);
writeSimple(rowOut, metaData, (Object[]) valueData);
break;
case ResultConstants.EXECUTE :
rowOut.writeInt(updateCount);
rowOut.writeInt(fetchSize);
rowOut.writeLong(statementID);
rowOut.writeByte(rsProperties);
rowOut.writeShort(queryTimeout);
writeSimple(rowOut, metaData, (Object[]) valueData);
break;
case ResultConstants.UPDATE_RESULT :
rowOut.writeLong(id);
rowOut.writeInt(getActionType());
metaData.write(rowOut);
writeSimple(rowOut, metaData, (Object[]) valueData);
break;
case ResultConstants.BATCHEXECRESPONSE :
case ResultConstants.BATCHEXECUTE :
case ResultConstants.BATCHEXECDIRECT :
case ResultConstants.SETSESSIONATTR : {
rowOut.writeInt(updateCount);
rowOut.writeInt(fetchSize);
rowOut.writeLong(statementID);
rowOut.writeShort(queryTimeout);
metaData.write(rowOut);
navigator.writeSimple(rowOut, metaData);
break;
}
case ResultConstants.PARAM_METADATA : {
metaData.write(rowOut);
navigator.write(rowOut, metaData);
break;
}
case ResultConstants.SETCONNECTATTR : {
int type = getConnectionAttrType();
rowOut.writeInt(type); // attr type / updateCount
switch (type) {
case ResultConstants.SQL_ATTR_SAVEPOINT_NAME :
rowOut.writeString(mainString); // savepoint name
break;
// case ResultConstants.SQL_ATTR_AUTO_IPD // always true
// default: // throw, but case never happens
default :
throw Error.runtimeError(ErrorCode.U_S0500, "Result");
}
break;
}
case ResultConstants.REQUESTDATA : {
rowOut.writeLong(id);
rowOut.writeInt(updateCount);
rowOut.writeInt(fetchSize);
break;
}
case ResultConstants.DATAROWS :
metaData.write(rowOut);
navigator.write(rowOut, metaData);
break;
case ResultConstants.DATAHEAD :
case ResultConstants.DATA :
rowOut.writeLong(id);
rowOut.writeInt(updateCount);
rowOut.writeInt(fetchSize);
rowOut.writeByte(rsProperties);
metaData.write(rowOut);
navigator.write(rowOut, metaData);
break;
default :
throw Error.runtimeError(ErrorCode.U_S0500, "Result");
}
rowOut.writeIntData(rowOut.size() - startPos, startPos);
dataOut.write(rowOut.getOutputStream().getBuffer(), 0, rowOut.size());
int count = getLobCount();
Result current = this;
for (int i = 0; i < count; i++) {
ResultLob lob = current.lobResults;
lob.writeBody(dataOut);
current = current.lobResults;
}
if (chainedResult == null) {
dataOut.writeByte(ResultConstants.NONE);
} else {
chainedResult.write(dataOut, rowOut);
}
dataOut.flush();
}
public int getType() {
return mode;
}
public boolean isData() {
return mode == ResultConstants.DATA
|| mode == ResultConstants.DATAHEAD;
}
public boolean isError() {
return mode == ResultConstants.ERROR;
}
public boolean isWarning() {
return mode == ResultConstants.WARNING;
}
public boolean isUpdateCount() {
return mode == ResultConstants.UPDATECOUNT;
}
public boolean isSimpleValue() {
return mode == ResultConstants.VALUE;
}
public boolean hasGeneratedKeys() {
return mode == ResultConstants.UPDATECOUNT && chainedResult != null;
}
public HsqlException getException() {
return exception;
}
public long getStatementID() {
return statementID;
}
public void setStatementID(long statementId) {
this.statementID = statementId;
}
public String getMainString() {
return mainString;
}
public void setMainString(String sql) {
this.mainString = sql;
}
public String getSubString() {
return subString;
}
public String getZoneString() {
return zoneString;
}
public int getErrorCode() {
return errorCode;
}
public Object getValueObject() {
return valueData;
}
public void setValueObject(Object value) {
valueData = value;
}
public Statement getStatement() {
return statement;
}
public void setStatement(Statement statement) {
this.statement = statement;
}
public String getDatabaseName() {
return databaseName;
}
public void setMaxRows(int count) {
updateCount = count;
}
public int getFetchSize() {
return this.fetchSize;
}
public void setFetchSize(int count) {
fetchSize = count;
}
public int getUpdateCount() {
return updateCount;
}
public int getConnectionAttrType() {
return updateCount;
}
public void setConnectionAttrType(int type) {
updateCount = type;
}
public int getActionType() {
return updateCount;
}
public void setActionType(int type) {
updateCount = type;
}
public long getSessionId() {
return sessionID;
}
public void setSessionId(long id) {
sessionID = id;
}
public void setSession(SessionInterface session) {
if (navigator != null) {
navigator.setSession(session);
}
}
public int getDatabaseId() {
return databaseID;
}
public void setDatabaseId(int id) {
databaseID = id;
}
public long getResultId() {
return id;
}
public void setResultId(long id) {
this.id = id;
if (navigator != null) {
navigator.setId(id);
}
}
public void setUpdateCount(int count) {
updateCount = count;
}
public void setAsTransactionEndRequest(int subType, String savepoint) {
mode = ResultConstants.ENDTRAN;
updateCount = subType;
mainString = savepoint == null ? ""
: savepoint;
}
public Object[] getSingleRowData() {
Object[] data = (Object[]) initialiseNavigator().getNext();
data = (Object[]) ArrayUtil.resizeArrayIfDifferent(data,
metaData.getColumnCount());
return data;
}
public Object[] getParameterData() {
return (Object[]) valueData;
}
public Object[] getSessionAttributes() {
return (Object[]) initialiseNavigator().getNext();
}
public void setResultType(int type) {
mode = (byte) type;
}
public void setStatementType(int type) {
statementReturnType = type;
}
public int getStatementType() {
return statementReturnType;
}
public int getGeneratedResultType() {
return generateKeys;
}
public ResultMetaData getGeneratedResultMetaData() {
return generatedMetaData;
}
public Result getChainedResult() {
return chainedResult;
}
public Result getUnlinkChainedResult() {
Result result = chainedResult;
chainedResult = null;
return result;
}
public void addChainedResult(Result result) {
Result current = this;
while (current.chainedResult != null) {
current = current.chainedResult;
}
current.chainedResult = result;
}
public void addWarnings(HsqlException[] warnings) {
for (int i = 0; i < warnings.length; i++) {
Result warning = newWarningResult(warnings[i]);
addChainedResult(warning);
}
}
public int getLobCount() {
return lobCount;
}
public ResultLob getLOBResult() {
return lobResults;
}
public void addLobResult(ResultLob result) {
Result current = this;
while (current.lobResults != null) {
current = current.lobResults;
}
current.lobResults = result;
lobCount++;
}
public void clearLobResults() {
lobResults = null;
lobCount = 0;
}
private static Object[] readSimple(RowInputBinary in,
ResultMetaData meta)
throws IOException {
int size = in.readInt();
return in.readData(meta.columnTypes);
}
private static void writeSimple(RowOutputInterface out,
ResultMetaData meta,
Object[] data) throws IOException {
out.writeInt(1);
out.writeData(meta.getColumnCount(), meta.columnTypes, data, null,
null);
}
//----------- Navigation
public RowSetNavigator navigator;
public RowSetNavigator getNavigator() {
return navigator;
}
public void setNavigator(RowSetNavigator navigator) {
this.navigator = navigator;
}
public RowSetNavigator initialiseNavigator() {
switch (mode) {
case ResultConstants.BATCHEXECUTE :
case ResultConstants.BATCHEXECDIRECT :
case ResultConstants.BATCHEXECRESPONSE :
case ResultConstants.SETSESSIONATTR :
case ResultConstants.PARAM_METADATA :
navigator.beforeFirst();
return navigator;
case ResultConstants.DATA :
case ResultConstants.DATAHEAD :
navigator.reset();
return navigator;
default :
throw Error.runtimeError(ErrorCode.U_S0500, "Result");
}
}
}