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

com.redis.sidecar.jdbc.Clob Maven / Gradle / Ivy

The newest version!
package com.redis.sidecar.jdbc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Clob implements java.sql.Clob {

	private static final Logger log = Logger.getLogger(Clob.class.getName());

	@Override
	public long length() throws SQLException {
		return getData().length();
	}

	@Override
	public String getSubString(final long pos, final int length) throws SQLException {

		final String data = getData();
		final int dlen = data.length();

		if (pos == MIN_POS && length == dlen) {
			return data;
		}

		if (pos < MIN_POS || pos > dlen) {
			throw outOfRangeArgument("pos: " + pos);
		}

		final long index = pos - 1;

		if (length < 0 || length > dlen - index) {
			throw outOfRangeArgument("length: " + length);
		}

		return data.substring((int) index, (int) index + length);
	}

	private static SQLException outOfRangeArgument(String message) {
		return new SQLException("Out of range argument " + message);
	}

	@Override
	public Reader getCharacterStream() throws SQLException {
		return new StringReader(getData());
	}

	@Override
	public InputStream getAsciiStream() throws SQLException {

		try {
			return new ByteArrayInputStream(getData().getBytes("US-ASCII"));
		} catch (UnsupportedEncodingException e) {
			log.log(Level.WARNING, e.getMessage(), e);
			return null;
		}
	}

	@Override
	public long position(final String searchstr, long start) throws SQLException {

		final String data = getData();

		if (start < MIN_POS) {
			throw outOfRangeArgument("start: " + start);
		}

		if (searchstr == null || start > MAX_POS) {
			return -1;
		}

		final int position = data.indexOf(searchstr, (int) start - 1);

		return (position == -1) ? -1 : position + 1;
	}

	@Override
	public long position(final java.sql.Clob searchstr, final long start) throws SQLException {

		final String data = getData();

		if (start < MIN_POS) {
			throw outOfRangeArgument("start: " + start);
		}

		if (searchstr == null) {
			return -1;
		}

		final long dlen = data.length();
		final long sslen = searchstr.length();
		final long startIndex = start - 1;

		// This is potentially much less expensive than materializing a large
		// substring from some other vendor's CLOB. Indeed, we should probably
		// do the comparison piecewise, using an in-memory buffer (or temp-files
		// when available), if it is detected that the input CLOB is very long.
		if (startIndex > dlen - sslen) {
			return -1;
		}

		// by now, we know sslen and startIndex are both < Integer.MAX_VALUE
		String pattern;

		if (searchstr instanceof Clob) {
			pattern = ((Clob) searchstr).getData();
		} else {
			pattern = searchstr.getSubString(1L, (int) sslen);
		}

		final int index = data.indexOf(pattern, (int) startIndex);

		return (index == -1) ? -1 : index + 1;
	}

	@Override
	public int setString(long pos, String str) throws SQLException {
		return setString(pos, str, 0, str == null ? 0 : str.length());
	}

	private static SQLException nullArgument(String arg) {
		return new SQLException("Null argument: " + arg);
	}

	@Override
	public int setString(final long pos, final String str, final int offset, final int len) throws SQLException {
		checkReadonly();

		final String data = getData();

		if (str == null) {
			throw nullArgument("str");
		}

		final int strlen = str.length();
		final int dlen = data.length();
		final int ipos = (int) (pos - 1);

		if (offset == 0 && len == strlen && ipos == 0 && len >= dlen) {
			setData(str);
			return len;
		}

		if (offset < 0 || offset > strlen) {
			throw outOfRangeArgument("offset: " + offset);
		}

		if (len < 0 || len > strlen - offset) {
			throw outOfRangeArgument("len: " + len);
		}

		if (pos < MIN_POS || (pos - MIN_POS) > (Integer.MAX_VALUE - len)) {
			throw outOfRangeArgument("pos: " + pos);
		}

		final long endPos = (pos + len);
		char[] chars;

		if (pos > dlen) {
			// 1.) 'datachars' + '\32\32\32...' + substring
			chars = new char[(int) endPos - 1];
			data.getChars(0, dlen, chars, 0);
			for (int i = dlen; i < ipos; i++) {
				chars[i] = ' ';
			}
			str.getChars(offset, offset + len, chars, ipos);
		} else if (endPos > dlen) {
			// 2.) 'datach...' + substring
			chars = new char[(int) endPos - 1];
			data.getChars(0, ipos, chars, 0);
			str.getChars(offset, offset + len, chars, ipos);
		} else {
			// 3.) 'dat' + substring + 'rs'
			chars = new char[dlen];

			data.getChars(0, ipos, chars, 0);
			str.getChars(offset, offset + len, chars, ipos);
			final int dataOffset = ipos + len;
			data.getChars(dataOffset, dlen, chars, dataOffset);
		}

		setData(new String(chars));

		return len;
	}

	@Override
	public OutputStream setAsciiStream(final long pos) throws SQLException {

		checkReadonly();
		checkClosed();

		if (pos < MIN_POS || pos > MAX_POS) {
			throw outOfRangeArgument("pos: " + pos);
		}

		return new ByteArrayOutputStream() {
			boolean closed = false;

			public synchronized void close() throws IOException {
				if (closed) {
					return;
				}
				closed = true;
				final byte[] bytes = super.buf;
				final int length = super.count;
				super.buf = null;
				super.count = 0;
				try {
					final String str = new String(bytes, 0, length, "US-ASCII");
					Clob.this.setString(pos, str);
				} catch (SQLException se) {
					throw new IOException(se);
				}
			}
		};
	}

	@Override
	public Writer setCharacterStream(final long pos) throws SQLException {

		checkReadonly();
		checkClosed();

		if (pos < MIN_POS || pos > MAX_POS) {
			throw outOfRangeArgument("pos: " + pos);
		}

		return new StringWriter() {
			private boolean closed = false;

			public synchronized void close() throws IOException {
				if (closed) {
					return;
				}
				closed = true;
				final StringBuffer sb = super.getBuffer();
				try {
					Clob.this.setStringBuffer(pos, sb, 0, sb.length());
				} catch (SQLException se) {
					throw new IOException(se);
				} finally {
					sb.setLength(0);
					sb.trimToSize();
				}
			}
		};
	}

	@Override
	public void truncate(final long len) throws SQLException {
		checkReadonly();

		final String data = getData();
		final long dlen = data.length();

		if (len == dlen) {
			return;
		}

		if (len < 0 || len > dlen) {
			throw outOfRangeArgument("len: " + len);
		}

		setData(data.substring(0, (int) len));

	}

	@Override
	public synchronized void free() throws SQLException {
		m_closed = true;
		m_data = null;
	}

	@Override
	public Reader getCharacterStream(long pos, long length) throws SQLException {

		if (length > Integer.MAX_VALUE) {
			throw outOfRangeArgument("length: " + length);
		}

		final String data = getData();
		final int dlen = data.length();

		if (pos == MIN_POS && length == dlen) {
			return new StringReader(data);
		}

		if (pos < MIN_POS || pos > dlen) {
			throw outOfRangeArgument("pos: " + pos);
		}

		final long startIndex = pos - 1;

		if (length < 0 || length > dlen - startIndex) {
			throw outOfRangeArgument("length: " + length);
		}

		final int endIndex = (int) (startIndex + length); // exclusive
		final char[] chars = new char[(int) length];

		data.getChars((int) startIndex, endIndex, chars, 0);

		return new CharArrayReader(chars);
	}

	private static final long MIN_POS = 1L;
	private static final long MAX_POS = 1L + (long) Integer.MAX_VALUE;
	private boolean m_closed;
	private String m_data;
	private final boolean m_createdByConnection;

	public Clob(final String data) throws SQLException {

		if (data == null) {
			throw new SQLException("Null argument");
		}
		m_data = data;
		m_createdByConnection = false;
	}

	/**
	 * Constructs a new, empty (zero-length), read/write JDBCClob object.
	 */
	protected Clob() {
		m_data = "";
		m_createdByConnection = true;
	}

	protected void checkReadonly() throws SQLException {
		if (!m_createdByConnection) {
			throw new SQLException("Clob is read-only");
		}
	}

	protected synchronized void checkClosed() throws SQLException {

		if (m_closed) {
			throw new SQLException("Clob is closed");
		}
	}

	synchronized String getData() throws SQLException {

		checkClosed();

		return m_data;
	}

	private synchronized void setData(String data) throws SQLException {

		checkClosed();

		m_data = data;
	}

	public int setStringBuffer(final long pos, final StringBuffer sb, final int offset, final int len)
			throws SQLException {

		checkReadonly();

		String data = getData();

		if (sb == null) {
			throw nullArgument("sb");
		}

		final int strlen = sb.length();
		final int dlen = data.length();
		final int ipos = (int) (pos - 1);

		if (offset == 0 && len == strlen && ipos == 0 && len >= dlen) {
			setData(sb.toString());
			return len;
		}

		if (offset < 0 || offset > strlen) {
			throw outOfRangeArgument("offset: " + offset);
		}

		if (len > strlen - offset) {
			throw outOfRangeArgument("len: " + len);
		}

		if (pos < MIN_POS || (pos - MIN_POS) > (Integer.MAX_VALUE - len)) {
			throw outOfRangeArgument("pos: " + pos);
		}

		final long endPos = (pos + len);
		char[] chars;

		if (pos > dlen) {
			// 1.) 'datachars' + '\32\32\32...' + substring
			chars = new char[(int) endPos - 1];
			data.getChars(0, dlen, chars, 0);
			for (int i = dlen; i < ipos; i++) {
				chars[i] = ' ';
			}
			sb.getChars(offset, offset + len, chars, ipos);
		} else if (endPos > dlen) {
			// 2.) 'datach...' + substring
			chars = new char[(int) endPos - 1];
			data.getChars(0, ipos, chars, 0);
			sb.getChars(offset, offset + len, chars, ipos);
		} else {
			// 3.) 'dat' + substring + 'rs'
			chars = new char[dlen];

			data.getChars(0, ipos, chars, 0);
			sb.getChars(offset, offset + len, chars, ipos);
			final int dataOffset = ipos + len;
			data.getChars(dataOffset, dlen, chars, dataOffset);
		}

		setData(new String(chars));

		return len;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy