All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cubrid.jdbc.driver.CUBRIDClob Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2008 Search Solution Corporation. All rights reserved by Search Solution. 
 *
 * 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  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 THE COPYRIGHT OWNER 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 cubrid.jdbc.driver;

import java.io.Flushable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.sql.Clob;
import java.sql.SQLException;
import java.util.ArrayList;

import cubrid.jdbc.jci.UUType;

public class CUBRIDClob implements Clob {

	/*
	 * ======================================================================= |
	 * CONSTANT VALUES
	 * =======================================================================
	 */
	private final static int CLOB_MAX_IO_LENGTH = 128 * 1024; // 128kB at once
	private final static int CLOB_MAX_IO_CHARS = CLOB_MAX_IO_LENGTH / 2;

	/*
	 * ======================================================================= |
	 * PRIVATE
	 * =======================================================================
	 */
	private CUBRIDConnection conn;
	private boolean isWritable;
	private CUBRIDLobHandle lobHandle;
	private String charsetName;

	private StringBuffer clobCharBuffer = new StringBuffer("");
	private long clobCharPos;
	private long clobCharLength;

	private byte[] clobByteBuffer = new byte[CLOB_MAX_IO_LENGTH];
	private long clobBytePos;
	private long clobNextReadBytePos;
	// no 'clobByteLength' member: USE 'lobHandle.getLobSize()'

	private ArrayList streamList = new ArrayList();

	/*
	 * ======================================================================= |
	 * CONSTRUCTOR
	 * =======================================================================
	 */
	// make a new clob
	public CUBRIDClob(CUBRIDConnection conn, String charsetName)
			throws SQLException {
		if (conn == null) {
			throw new CUBRIDException(CUBRIDJDBCErrorCode.invalid_value);
		}

		byte[] packedLobHandle = conn.lobNew(UUType.U_TYPE_CLOB);

		this.conn = conn;
		isWritable = true;
		lobHandle = new CUBRIDLobHandle(UUType.U_TYPE_CLOB, packedLobHandle);
		this.charsetName = charsetName;

		clobCharPos = 0;
		clobCharLength = 0;
		clobBytePos = 0;
		clobNextReadBytePos = 0;
	}

	// get clob from existing result set
	public CUBRIDClob(CUBRIDConnection conn, byte[] packedLobHandle,
			String charsetName) throws SQLException {
		if (conn == null || packedLobHandle == null) {
			throw new CUBRIDException(CUBRIDJDBCErrorCode.invalid_value);
		}

		this.conn = conn;
		isWritable = false;
		lobHandle = new CUBRIDLobHandle(UUType.U_TYPE_CLOB, packedLobHandle);
		this.charsetName = charsetName;

		clobCharPos = 0;
		clobCharLength = -1;
		clobBytePos = 0;
		clobNextReadBytePos = 0;
	}

	/*
	 * ======================================================================= |
	 * java.sql.Clob interface
	 * =======================================================================
	 */
	public synchronized long length() throws SQLException {
		if (lobHandle == null) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (clobCharLength < 0) {
			readClobPartially(Long.MAX_VALUE, 1);
		}

		return clobCharLength;
	}

	public synchronized String getSubString(long pos, int length)
			throws SQLException {
		if (lobHandle == null) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (pos < 1 || length < 0) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (length == 0) {
			return "";
		}

		int read_len = readClobPartially(pos, length);
		if (read_len <= 0) {
			return "";
		}

		return (clobCharBuffer.substring(0, read_len));
	}

	public Reader getCharacterStream() throws SQLException {
		return getCharacterStream(1, Long.MAX_VALUE);
	}

	/* JDK 1.6 */
	public Reader getCharacterStream(long pos, long length) throws SQLException {
		if (lobHandle == null) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (pos < 1 || length < 0) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}

		return new CUBRIDBufferedReader(
				new CUBRIDClobReader(this, pos, length), CLOB_MAX_IO_CHARS);
	}

	public InputStream getAsciiStream() throws SQLException {
		if (lobHandle == null) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}

		return new CUBRIDBufferedInputStream(new CUBRIDClobInputStream(this),
				CLOB_MAX_IO_LENGTH);
	}

	public long position(String searchstr, long start) throws SQLException {
		throw new java.lang.UnsupportedOperationException();
	}

	public long position(Clob searchClob, long start) throws SQLException {
		throw new java.lang.UnsupportedOperationException();
	}

	public synchronized int setString(long pos, String str) throws SQLException {
		if (lobHandle == null) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (pos < 1) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (!isWritable) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.lob_is_not_writable, null);
		}
		if (str == null || str.length() <= 0) {
			return 0;
		}

		if (readClobPartially(pos, 1) != 0) {
			// only append is allowed.
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.lob_pos_invalid, null);
		}

		byte[] bytes = string2bytes(str);
		int bytes_len = bytes.length;
		int bytes_offset = 0;

		while (bytes_len > 0) {
			int bytesWritten = conn.lobWrite(lobHandle.getPackedLobHandle(),
					clobBytePos + bytes_offset, bytes, bytes_offset, Math.min(
							bytes_len, CLOB_MAX_IO_LENGTH));

			bytes_len -= bytesWritten;
			bytes_offset += bytesWritten;
		}

		lobHandle.setLobSize(clobBytePos + bytes_offset);
		clobCharLength = length() + str.length();

		return str.length();
	}

	public int setString(long pos, String str, int offset, int len)
			throws SQLException {
		if (lobHandle == null) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (pos < 1 || offset < 0 || len < 0) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (offset + len > str.length()) {
			throw new IndexOutOfBoundsException();
		}
		if (!isWritable) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.lob_is_not_writable, null);
		}
		if (str == null || len == 0) {
			return 0;
		}

		return (setString(pos, str.substring(offset, offset + len)));
	}

	public synchronized OutputStream setAsciiStream(long pos)
			throws SQLException {
		if (lobHandle == null) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (pos < 1) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (!isWritable) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.lob_is_not_writable, null);
		}

		if (readClobPartially(pos, 1) != 0) {
			// only append is allowed.
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.lob_pos_invalid, null);
		}

		OutputStream out = new CUBRIDBufferedOutputStream(
				new CUBRIDClobOutputStream(this, clobBytePos + 1),
				CLOB_MAX_IO_LENGTH);
		addFlushableStream(out);
		return out;
	}

	public Writer setCharacterStream(long pos) throws SQLException {
		if (lobHandle == null) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (pos < 1) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (!isWritable) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.lob_is_not_writable, null);
		}

		if (readClobPartially(pos, 1) != 0) {
			// only append is allowed.
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.lob_pos_invalid, null);
		}

		Writer out = new CUBRIDBufferedWriter(new CUBRIDClobWriter(this, pos),
				CLOB_MAX_IO_CHARS);
		addFlushableStream(out);
		return out;
	}

	public void truncate(long len) throws SQLException {
		throw new java.lang.UnsupportedOperationException();
	}

	/* JDK 1.6 */
	public void free() throws SQLException {
		conn = null;
		lobHandle = null;
		streamList = null;
		clobCharBuffer = null;
		clobByteBuffer = null;
		isWritable = false;
	}

	private int readClobPartially(long pos, int length) throws SQLException {
		if (clobCharLength != -1 && pos > clobCharLength) {
			clobBytePos = clobNextReadBytePos = lobHandle.getLobSize();
			clobCharPos = clobCharLength;
			clobCharBuffer.setLength(0);
			if (pos == clobCharLength + 1)
				return 0;
			else
				return -1;
		}

		pos--; // pos is now offset from 0

		if (pos < clobCharPos) {
			clobBytePos = clobNextReadBytePos = 0;
			clobCharPos = 0;
			clobCharBuffer.setLength(0);
			readClob();
		}

		while (pos >= clobCharPos + clobCharBuffer.length()) {
			clobBytePos = clobNextReadBytePos;
			clobCharPos += clobCharBuffer.length();
			clobCharBuffer.setLength(0);
			if (clobNextReadBytePos >= lobHandle.getLobSize()) {
				return 0;
			}
			readClob();
		}

		int delete_len = (int) (pos - clobCharPos);
		if (delete_len > 0) {
			clobCharPos = pos;
			clobBytePos += string2bytes(clobCharBuffer.substring(0, delete_len)).length;
			clobCharBuffer.delete(0, delete_len);
		}

		while (length > clobCharBuffer.length()) {
			if (clobNextReadBytePos >= lobHandle.getLobSize()) {
				return clobCharBuffer.length();
			}
			readClob();
		}

		return length;
	}

	private void readClob() throws SQLException {
		if (conn == null || lobHandle == null) {
			throw new NullPointerException();
		}

		int read_len = conn.lobRead(lobHandle.getPackedLobHandle(),
				clobNextReadBytePos, clobByteBuffer, 0, CLOB_MAX_IO_LENGTH);

		StringBuffer sb = new StringBuffer(bytes2string(clobByteBuffer, 0,
				read_len));

		if (clobNextReadBytePos + read_len >= lobHandle.getLobSize())      // End of CLOB
		{
			clobNextReadBytePos += read_len;
			clobCharLength = clobCharPos + clobCharBuffer.length()
					+ sb.length();
		} else {
			clobNextReadBytePos += string2bytes (sb.substring (0, sb.length () - 1)).length;
			sb.setLength(sb.length() - 1);
		}

		clobCharBuffer.append(sb);
	}

	private byte[] string2bytes(String s) throws SQLException {
		try {
			return (s.getBytes(charsetName));
		} catch (UnsupportedEncodingException e) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.unknown, e.getMessage(), e);
		}
	}

	private String bytes2string(byte[] b, int start, int len)
			throws SQLException {
		try {
			return (new String(b, start, len, charsetName));
		} catch (UnsupportedEncodingException e) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.unknown, e.getMessage(), e);
		}
	}

	public CUBRIDLobHandle getLobHandle() {
		return lobHandle;
	}

	private void addFlushableStream(Flushable out) {
		streamList.add(out);
	}

	public void removeFlushableStream(Flushable out) {
		streamList.remove(out);
	}

	public void flushFlushableStreams() {
		if (!streamList.isEmpty()) {
			for (Flushable out : streamList) {
				try {
					out.flush();
				} catch (IOException e) {
				}
			}
		}
	}

	public String toString() {
		return lobHandle.toString();
	}

	public boolean equals(Object obj) {
		if (obj instanceof CUBRIDClob) {
			CUBRIDClob that = (CUBRIDClob) obj;
			return lobHandle.equals(that.lobHandle);
		}
		return false;
	}

	public byte[] getBytes(long pos, int length) throws SQLException {
		if (conn == null || lobHandle == null) {
			throw new NullPointerException();
		}
		if (pos < 1 || length < 0) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (length == 0) {
			return new byte[0];
		}

		pos--; // pos is now offset from 0
		int real_read_len, read_len, total_read_len = 0;

		if (pos + length > lobHandle.getLobSize()) {
			length = (int) (lobHandle.getLobSize() - pos);
		}

		byte[] buf = new byte[length];

		while (length > 0) {
			read_len = Math.min(length, CLOB_MAX_IO_LENGTH);
			real_read_len = conn.lobRead(lobHandle.getPackedLobHandle(), pos,
					buf, total_read_len, read_len);

			pos += real_read_len;
			length -= real_read_len;
			total_read_len += real_read_len;

			if (real_read_len == 0) {
				break;
			}
		}

		if (total_read_len < buf.length) {
			// In common case, this code cannot be executed
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.unknown, null);
			// byte[]new_buf = new byte[total_read_len];
			// System.arraycopy (buf, 0, new_buf, 0, total_read_len);
			// return new_buf;
		} else {
			return buf;
		}
	}

	public int setBytes(long pos, byte[] bytes, int offset, int len)
			throws SQLException {
		if (conn == null || lobHandle == null) {
			throw new NullPointerException();
		}
		if (pos < 1 || offset < 0 || len < 0) {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.invalid_value, null);
		}
		if (offset + len > bytes.length) {
			throw new IndexOutOfBoundsException();
		}

		if (isWritable) {
			if (lobHandle.getLobSize() + 1 != pos) {
				throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.lob_pos_invalid, null);
			}

			pos--; // pos is now offset from 0
			int real_write_len, write_len, total_write_len = 0;

			while (len > 0) {
				write_len = Math.min(len, CLOB_MAX_IO_LENGTH);
				real_write_len = conn.lobWrite(lobHandle.getPackedLobHandle(),
						pos, bytes, offset, write_len);

				pos += real_write_len;
				len -= real_write_len;
				offset += real_write_len;
				total_write_len += real_write_len;
			}

			if (pos > lobHandle.getLobSize()) {
				lobHandle.setLobSize(pos);
				clobCharLength = -1;
			}

			return total_write_len;
		} else {
			throw conn.createCUBRIDException(CUBRIDJDBCErrorCode.lob_is_not_writable, null);
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy