/* Copyright (c) 2001-2019, 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.IOException;
import java.io.InputStream;
import java.io.Reader;

import org.hsqldb.SessionInterface;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.DataOutputStream;
import org.hsqldb.lib.HsqlByteArrayOutputStream;
import org.hsqldb.rowio.RowOutputInterface;

Sub-class of Result for communicating Blob and Clob operations.

Author:Fred Toussi (fredt@users dot sourceforge.net)
Version:2.0.1
Since:1.9.0
/** * Sub-class of Result for communicating Blob and Clob operations.<p> * * @author Fred Toussi (fredt@users dot sourceforge.net) * @version 2.0.1 * @since 1.9.0 */
public final class ResultLob extends Result { public interface LobResultTypes { int REQUEST_GET_BYTES = 1; int REQUEST_SET_BYTES = 2; int REQUEST_GET_CHARS = 3; int REQUEST_SET_CHARS = 4; int REQUEST_GET_BYTE_PATTERN_POSITION = 5; int REQUEST_GET_CHAR_PATTERN_POSITION = 6; int REQUEST_CREATE_BYTES = 7; int REQUEST_CREATE_CHARS = 8; int REQUEST_TRUNCATE = 9; int REQUEST_GET_LENGTH = 10; int REQUEST_GET_LOB = 11; int REQUEST_DUPLICATE_LOB = 12; // non-network int REQUEST_GET_TRUNCATE_LENGTH = 13; // int RESPONSE_GET_BYTES = 21; int RESPONSE_SET = 22; int RESPONSE_GET_CHARS = 23; int RESPONSE_GET_BYTE_PATTERN_POSITION = 25; int RESPONSE_GET_CHAR_PATTERN_POSITION = 26; int RESPONSE_CREATE_BYTES = 27; int RESPONSE_CREATE_CHARS = 28; int RESPONSE_TRUNCATE = 29; } long lobID; int subType; long blockOffset; long blockLength; byte[] byteBlock; char[] charBlock; Reader reader; InputStream stream; private ResultLob() { super(ResultConstants.LARGE_OBJECT_OP); } public static ResultLob newLobGetLengthRequest(long id) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_GET_LENGTH; result.lobID = id; return result; } public static ResultLob newLobGetBytesRequest(long id, long offset, int length) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_GET_BYTES; result.lobID = id; result.blockOffset = offset; result.blockLength = length; return result; } public static ResultLob newLobGetCharsRequest(long id, long offset, int length) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_GET_CHARS; result.lobID = id; result.blockOffset = offset; result.blockLength = length; return result; } public static ResultLob newLobSetBytesRequest(long id, long offset, byte[] block) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_SET_BYTES; result.lobID = id; result.blockOffset = offset; result.byteBlock = block; result.blockLength = block.length; return result; } public static ResultLob newLobSetCharsRequest(long id, long offset, char[] chars) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_SET_CHARS; result.lobID = id; result.blockOffset = offset; result.charBlock = chars; result.blockLength = chars.length; return result; } public static ResultLob newLobTruncateRequest(long id, long offset) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_TRUNCATE; result.lobID = id; result.blockOffset = offset; return result; } public static ResultLob newLobGetBytesResponse(long id, long offset, byte[] block) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.RESPONSE_GET_BYTES; result.lobID = id; result.blockOffset = offset; result.byteBlock = block; result.blockLength = block.length; return result; } public static ResultLob newLobGetCharsResponse(long id, long offset, char[] chars) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.RESPONSE_GET_CHARS; result.lobID = id; result.blockOffset = offset; result.charBlock = chars; result.blockLength = chars.length; return result; } public static ResultLob newLobSetResponse(long id, long length) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.RESPONSE_SET; result.lobID = id; result.blockLength = length; return result; } public static ResultLob newLobGetBytePatternPositionRequest(long id, byte[] pattern, long offset) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_GET_BYTE_PATTERN_POSITION; result.lobID = id; result.blockOffset = offset; result.byteBlock = pattern; result.blockLength = pattern.length; return result; } public static ResultLob newLobGetBytePatternPositionRequest(long id, long otherId, long offset) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_GET_BYTE_PATTERN_POSITION; result.lobID = id; result.blockOffset = offset; return result; } public static ResultLob newLobGetCharPatternPositionRequest(long id, char[] pattern, long offset) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_GET_CHAR_PATTERN_POSITION; result.lobID = id; result.blockOffset = offset; result.charBlock = pattern; result.blockLength = pattern.length; return result; } public static ResultLob newLobGetCharPatternPositionRequest(long id, long otherId, long offset) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_GET_CHAR_PATTERN_POSITION; result.lobID = id; result.blockOffset = offset; result.blockLength = otherId; return result; } public static ResultLob newLobCreateBlobRequest(long sessionID, long lobID, InputStream stream, long length) { ResultLob result = new ResultLob(); result.lobID = lobID; result.subType = LobResultTypes.REQUEST_CREATE_BYTES; result.blockLength = length; result.stream = stream; return result; } public static ResultLob newLobCreateClobRequest(long sessionID, long lobID, Reader reader, long length) { ResultLob result = new ResultLob(); result.lobID = lobID; result.subType = LobResultTypes.REQUEST_CREATE_CHARS; result.blockLength = length; result.reader = reader; return result; } public static ResultLob newLobGetTruncateLength(long id) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_GET_TRUNCATE_LENGTH; result.lobID = id; return result; } public static ResultLob newLobCreateBlobResponse(long id) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.RESPONSE_CREATE_BYTES; result.lobID = id; return result; } public static ResultLob newLobCreateClobResponse(long id) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.RESPONSE_CREATE_CHARS; result.lobID = id; return result; } public static ResultLob newLobTruncateResponse(long id, long length) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.RESPONSE_TRUNCATE; result.lobID = id; result.blockLength = length; return result; } public static ResultLob newLobGetRequest(long id, long offset, long length) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_GET_LOB; result.lobID = id; result.blockOffset = offset; result.blockLength = length; return result; } public static ResultLob newLobDuplicateRequest(long id) { ResultLob result = new ResultLob(); result.subType = LobResultTypes.REQUEST_DUPLICATE_LOB; result.lobID = id; return result; } public static ResultLob newLob(DataInput dataInput, boolean readTerminate) throws IOException { ResultLob result = new ResultLob(); result.databaseID = dataInput.readInt(); result.sessionID = dataInput.readLong(); result.lobID = dataInput.readLong(); result.subType = dataInput.readInt(); switch (result.subType) { case LobResultTypes.REQUEST_CREATE_BYTES : case LobResultTypes.REQUEST_CREATE_CHARS : result.blockOffset = dataInput.readLong(); result.blockLength = dataInput.readLong(); break; case LobResultTypes.REQUEST_GET_LOB : case LobResultTypes.REQUEST_DUPLICATE_LOB : // case LobResultTypes.REQUEST_GET_BYTES : case LobResultTypes.REQUEST_GET_CHARS : result.blockOffset = dataInput.readLong(); result.blockLength = dataInput.readLong(); break; case LobResultTypes.REQUEST_SET_BYTES : case LobResultTypes.REQUEST_GET_BYTE_PATTERN_POSITION : result.blockOffset = dataInput.readLong(); result.blockLength = dataInput.readLong(); result.byteBlock = new byte[(int) result.blockLength]; dataInput.readFully(result.byteBlock); break; case LobResultTypes.REQUEST_SET_CHARS : case LobResultTypes.REQUEST_GET_CHAR_PATTERN_POSITION : result.blockOffset = dataInput.readLong(); result.blockLength = dataInput.readLong(); result.charBlock = new char[(int) result.blockLength]; for (int i = 0; i < result.charBlock.length; i++) { result.charBlock[i] = dataInput.readChar(); } break; case LobResultTypes.REQUEST_GET_LENGTH : case LobResultTypes.REQUEST_TRUNCATE : result.blockOffset = dataInput.readLong(); break; case LobResultTypes.RESPONSE_GET_BYTES : result.blockOffset = dataInput.readLong(); result.blockLength = dataInput.readLong(); result.byteBlock = new byte[(int) result.blockLength]; dataInput.readFully(result.byteBlock); break; case LobResultTypes.RESPONSE_GET_CHARS : result.blockOffset = dataInput.readLong(); result.blockLength = dataInput.readLong(); result.charBlock = new char[(int) result.blockLength]; for (int i = 0; i < result.charBlock.length; i++) { result.charBlock[i] = dataInput.readChar(); } break; case LobResultTypes.RESPONSE_SET : case LobResultTypes.RESPONSE_CREATE_BYTES : case LobResultTypes.RESPONSE_CREATE_CHARS : case LobResultTypes.RESPONSE_TRUNCATE : result.blockLength = dataInput.readLong(); break; case LobResultTypes.RESPONSE_GET_BYTE_PATTERN_POSITION : case LobResultTypes.RESPONSE_GET_CHAR_PATTERN_POSITION : result.blockOffset = dataInput.readLong(); break; default : throw Error.runtimeError(ErrorCode.U_S0500, "ResultLob"); } if (readTerminate) { dataInput.readByte(); } return result; } public void write(SessionInterface session, DataOutputStream dataOut, RowOutputInterface rowOut) throws IOException { writeBody(session, dataOut); dataOut.writeByte(ResultConstants.NONE); dataOut.flush(); } public void writeBody(SessionInterface session, DataOutputStream dataOut) throws IOException { switch (subType) { case LobResultTypes.REQUEST_CREATE_BYTES : if (blockLength >= 0) { writeCreate(session, dataOut); return; } writeCreateByteSegments(session, dataOut); return; case LobResultTypes.REQUEST_CREATE_CHARS : { if (blockLength >= 0) { writeCreate(session, dataOut); return; } writeCreateCharSegments(session, dataOut); return; } } dataOut.writeByte(mode); dataOut.writeInt(databaseID); dataOut.writeLong(sessionID); dataOut.writeLong(lobID); dataOut.writeInt(subType); switch (subType) { case LobResultTypes.REQUEST_SET_BYTES : case LobResultTypes.REQUEST_GET_BYTE_PATTERN_POSITION : dataOut.writeLong(blockOffset); dataOut.writeLong(blockLength); dataOut.write(byteBlock); break; case LobResultTypes.REQUEST_SET_CHARS : case LobResultTypes.REQUEST_GET_CHAR_PATTERN_POSITION : dataOut.writeLong(blockOffset); dataOut.writeLong(blockLength); dataOut.writeChars(charBlock); break; case LobResultTypes.REQUEST_GET_LOB : case LobResultTypes.REQUEST_DUPLICATE_LOB : // case LobResultTypes.REQUEST_GET_BYTES : case LobResultTypes.REQUEST_GET_CHARS : dataOut.writeLong(blockOffset); dataOut.writeLong(blockLength); break; case LobResultTypes.REQUEST_GET_LENGTH : case LobResultTypes.REQUEST_TRUNCATE : dataOut.writeLong(blockOffset); break; case LobResultTypes.RESPONSE_GET_BYTES : dataOut.writeLong(blockOffset); dataOut.writeLong(blockLength); dataOut.write(byteBlock); break; case LobResultTypes.RESPONSE_GET_CHARS : dataOut.writeLong(blockOffset); dataOut.writeLong(blockLength); dataOut.writeChars(charBlock); break; case LobResultTypes.RESPONSE_SET : case LobResultTypes.RESPONSE_CREATE_BYTES : case LobResultTypes.RESPONSE_CREATE_CHARS : case LobResultTypes.RESPONSE_TRUNCATE : dataOut.writeLong(blockLength); break; case LobResultTypes.RESPONSE_GET_BYTE_PATTERN_POSITION : case LobResultTypes.RESPONSE_GET_CHAR_PATTERN_POSITION : dataOut.writeLong(blockOffset); break; default : throw Error.runtimeError(ErrorCode.U_S0500, "ResultLob"); } } private void writeCreate(SessionInterface session, DataOutputStream dataOut) throws IOException { dataOut.writeByte(mode); dataOut.writeInt(databaseID); dataOut.writeLong(sessionID); dataOut.writeLong(lobID); dataOut.writeInt(subType); dataOut.writeLong(blockOffset); dataOut.writeLong(blockLength); switch (subType) { case LobResultTypes.REQUEST_CREATE_BYTES : dataOut.write(stream, blockLength); break; case LobResultTypes.REQUEST_CREATE_CHARS : dataOut.write(reader, blockLength); break; } } private void writeCreateByteSegments(SessionInterface session, DataOutputStream dataOut) throws IOException { // int bufferLength = session.getStreamBlockSize(); long currentOffset = blockOffset; dataOut.writeByte(mode); dataOut.writeInt(databaseID); dataOut.writeLong(sessionID); dataOut.writeLong(lobID); dataOut.writeInt(subType); HsqlByteArrayOutputStream byteArrayOS = new HsqlByteArrayOutputStream(bufferLength); byteArrayOS.reset(); byteArrayOS.write(stream, bufferLength); dataOut.writeLong(currentOffset); dataOut.writeLong(byteArrayOS.size()); dataOut.write(byteArrayOS.getBuffer(), 0, byteArrayOS.size()); currentOffset += byteArrayOS.size(); if (byteArrayOS.size() < bufferLength) { return; } // while (true) { byteArrayOS.reset(); byteArrayOS.write(stream, bufferLength); if (byteArrayOS.size() == 0) { break; } // dataOut.writeByte(mode); dataOut.writeInt(databaseID); dataOut.writeLong(sessionID); dataOut.writeLong(lobID); dataOut.writeInt(LobResultTypes.REQUEST_SET_BYTES); dataOut.writeLong(currentOffset); dataOut.writeLong(byteArrayOS.size()); dataOut.write(byteArrayOS.getBuffer(), 0, byteArrayOS.size()); currentOffset += byteArrayOS.size(); if (byteArrayOS.size() < bufferLength) { break; } } } private void writeCreateCharSegments(SessionInterface session, DataOutputStream dataOut) throws IOException { // int bufferLength = session.getStreamBlockSize(); long currentOffset = blockOffset; dataOut.writeByte(mode); dataOut.writeInt(databaseID); dataOut.writeLong(sessionID); dataOut.writeLong(lobID); dataOut.writeInt(subType); HsqlByteArrayOutputStream byteArrayOS = new HsqlByteArrayOutputStream(bufferLength); byteArrayOS.reset(); byteArrayOS.write(reader, bufferLength / 2); // dataOut.writeLong(currentOffset); dataOut.writeLong(byteArrayOS.size() / 2); dataOut.write(byteArrayOS.getBuffer(), 0, byteArrayOS.size()); currentOffset += byteArrayOS.size() / 2; if (byteArrayOS.size() < bufferLength) { return; } // while (true) { byteArrayOS.reset(); byteArrayOS.write(reader, bufferLength / 2); if (byteArrayOS.size() == 0) { break; } // dataOut.writeByte(mode); dataOut.writeInt(databaseID); dataOut.writeLong(sessionID); dataOut.writeLong(lobID); dataOut.writeInt(LobResultTypes.REQUEST_SET_CHARS); dataOut.writeLong(currentOffset); dataOut.writeLong(byteArrayOS.size() / 2); dataOut.write(byteArrayOS.getBuffer(), 0, byteArrayOS.size()); currentOffset += byteArrayOS.size() / 2; if (byteArrayOS.size() < bufferLength) { break; } } } public long getLobID() { return lobID; } public int getSubType() { return subType; } public long getOffset() { return blockOffset; } public long getBlockLength() { return blockLength; } public byte[] getByteArray() { return byteBlock; } public char[] getCharArray() { return charBlock; } public InputStream getInputStream() { return stream; } public Reader getReader() { return reader; } }