001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.type.sql; 020 021import java.io.ByteArrayInputStream; 022import java.io.IOException; 023import java.io.OutputStream; 024import java.io.Reader; 025import java.io.Serializable; 026import java.io.StringReader; 027import java.io.StringWriter; 028import java.io.Writer; 029import java.sql.CallableStatement; 030import java.sql.Clob; 031import java.sql.PreparedStatement; 032import java.sql.SQLException; 033 034import lucee.commons.io.IOUtil; 035import lucee.runtime.exp.ExpressionException; 036import lucee.runtime.exp.PageException; 037import lucee.runtime.op.Caster; 038 039 040 041/** 042 * The representation (mapping) in the Java <sup><small>TM </small> </sup> 043 * programming language of an SQL <code>CLOB</code> value. An SQL 044 * <code>CLOB</code> is a built-in type that stores a Character Large Object 045 * as a column value in a row of a database table. By default drivers implement 046 * <code>Clob</code> using an SQL <code>locator(CLOB)</code>, which means 047 * that a <code>Clob</code> object contains a logical pointer to the SQL 048 * <code>CLOB</code> data rather than the data itself. A <code>Clob</code> 049 * object is valid for the duration of the transaction in which is was created. 050 * <p> 051 * Methods in the interfaces {@link DriverResultSet},{@link CallableStatement}, 052 * and {@link PreparedStatement}, such as <code>getClob</code> and 053 * <code>setClob</code> allow a programmer to access an SQL <code>CLOB</code> 054 * value. The <code>Clob</code> interface provides methods for getting the 055 * length of an SQL <code>CLOB</code> (Character Large Object) value, for 056 * materializing a <code>CLOB</code> value on the client, and for determining 057 * the position of a pattern of bytes within a <code>CLOB</code> value. In 058 * addition, this interface has methods for updating a <code>CLOB</code> 059 * value. 060 */ 061public final class ClobImpl implements java.sql.Clob, Serializable { 062 063 064 065 /** 066 * cast given value to a clob 067 * @param value 068 * @return clob 069 * @throws PageException 070 */ 071 public static Clob toClob(Object value) throws PageException { 072 if(value instanceof Clob) return (Clob)value; 073 else if(value instanceof char[]) 074 return toClob(new String((char[])value)); 075 else if(value instanceof Reader) { 076 StringWriter sw=new StringWriter(); 077 try { 078 IOUtil.copy((Reader)value,sw,false,true); 079 } 080 catch (IOException e) { 081 throw ExpressionException.newInstance(e); 082 } 083 return toClob(sw.toString()); 084 } 085 return toClob(Caster.toString(value)); 086 } 087 088 public static Clob toClob(String value) { 089 return new ClobImpl(value); 090 } 091 092 093 094 095 /** The data represented as a string of this <code>CLOB</code> */ 096 private String stringData = null; 097 098 /** 099 * Creates a new <code>Clob</code> instance. 100 * 101 * @param data a <code>String</code> of character data 102 */ 103 private ClobImpl(String data) { 104 stringData = data; 105 } 106 107 /** 108 * Returns the size of the <code>CLOB</code> value designated by this 109 * <code>Clob</code> object 110 * 111 * @return length of the <code>CLOB</code> value that this <code>clob</code> 112 * represents 113 * @exception SQLException if there is an error accessing the length of the 114 * <code>CLOB</code> 115 */ 116 public long length() throws SQLException { 117 return stringData.length(); 118 } 119 120 /** 121 * Retrieves the <code>CLOB</code> value designated by this 122 * <code>Clob</code> instance as a stream. 123 * 124 * @return a stream containing the <code>CLOB</code> data 125 * @exception SQLException if there is an error accessing the 126 * <code>CLOB</code> value 127 */ 128 public java.io.InputStream getAsciiStream() throws SQLException { 129 return new ByteArrayInputStream(stringData.getBytes()); 130 } 131 132 /** 133 * Materializes the <code>CLOB</code> value designated by this <Code>object 134 * as a stream of Unicode character. 135 * 136 * @return A reader object with all the data in the <code>CLOB</code> value 137 * designated by this clob object as unicode characters. 138 * @exception SQLException if there is an error accessing the 139 * <code>CLOB</code> value 140 */ 141 public java.io.Reader getCharacterStream() throws SQLException { 142 return new StringReader(stringData); 143 } 144 145 public Reader getCharacterStream(long pos, long len) { 146 return new StringReader(stringData.substring((int)pos, (int)len)); 147 } 148 149 /** 150 * Returns a copy of the portion of the <code>CLOB</code> value represented 151 * by this <code>CLOB</code> object that starts at position <i>position </i> 152 * and has ip to <i>length </i> consecutive characters. 153 * 154 * @param pos the position where to get the substring from 155 * @param length the length of the substring 156 * @return the substring 157 * @exception SQLException if there is an error accessing the 158 * <code>CLOB</code> 159 */ 160 public String getSubString(long pos, int length) throws SQLException { 161 if (length > stringData.length()) 162 throw new SQLException("Clob contains only " + stringData.length() 163 + " characters (asking for " + length + ")."); 164 return stringData.substring((int) pos-1, length); 165 } 166 167 /** 168 * Retrieves the character position at which the specified string 169 * <code>searchstr</code> begins within the <code>CLOB</code> value that 170 * this <code>Clob</code> object represents. The search for 171 * <code>searchstr</code> begins at position <code>start</code>. 172 * 173 * @param searchstr the byte array for which to search 174 * @param start the position at which to begin searching; the first position 175 * is 1 176 * @return the position at which the pattern appears, else -1 177 * @exception SQLException if there is an error accessing the 178 * <code>CLOB</code> 179 */ 180 public long position(String searchstr, long start) throws SQLException { 181 return stringData.indexOf(searchstr, (int) start); 182 } 183 184 /** 185 * Retrieves the character position at which the specified <code>Clob</code> 186 * object <code>searchstr</code> begins within the <code>CLOB</code> value 187 * that this <code>Clob</code> object represents. The search for 188 * <code>searchstr</code> begins at position <code>start</code>. 189 * 190 * @param searchstr the byte array for which to search 191 * @param start the position at which to begin searching; the first position 192 * is 1 193 * @return the position at which the pattern appears, else -1 194 * @exception SQLException if there is an error accessing the 195 * <code>CLOB</code> 196 */ 197 public long position(java.sql.Clob searchstr, long start) throws SQLException { 198 return position(searchstr.getSubString(0, (int) searchstr.length()), 199 (int) start); 200 } 201 202 // -------------------------- JDBC 3.0 ----------------------------------- 203 204 /** 205 * Retrieves a stream to be used to write Ascii characters to the CLOB value 206 * that this Clob object represents, starting at position pos. 207 * 208 * @param pos the position where to start the stream 209 * @return the ascii outputstream to this <code>clob</code> object 210 * @throws SQLException if there is an error accessing the <code>clob</code> 211 */ 212 public OutputStream setAsciiStream(long pos) throws SQLException { 213 // TODO impl. 214 throw new SQLException("JDBC 3.0 Method setAsciiStream not implemented"); 215 } 216 217 /** 218 * Retrieves a stream to be used to write a stream of Unicode characters to 219 * the CLOB value that this Clob object represents, at position pos. 220 * 221 * @param pos the position where to start the writer 222 * @return the writer to this <code>clob</code> object 223 * @throws SQLException if there is an error accessing the <code>clob</code> 224 */ 225 public Writer setCharacterStream(long pos) throws SQLException { 226 // TODO impl. 227 throw new SQLException("JDBC 3.0 Method setCharacterStream not implemented"); 228 } 229 230 /** 231 * Writes the given Java String to the CLOB value that this Clob object 232 * designates at the position pos. 233 * 234 * @param pos the position where to set the string 235 * @param str string to insert in the <code>clob</code> 236 * @return return value 237 * @throws SQLException if there is an error accessing the <code>clob</code> 238 */ 239 public int setString(long pos, String str) throws SQLException { 240 // TODO impl. 241 throw new SQLException("JDBC 3.0 Method setString not implemented"); 242 } 243 244 /** 245 * Writes len characters of str, starting at character offset, to the CLOB 246 * value that this Clob represents. 247 * 248 * @param pos the position 249 * @param str the string 250 * @param offset the offset 251 * @param len the length 252 * @return return value 253 * @throws SQLException if there is an error accessing the <code>clob</code> 254 */ 255 public int setString(long pos, String str, int offset, int len) throws SQLException{ 256 // TODO impl. 257 throw new SQLException("JDBC 3.0 Method setString not implemented"); 258 } 259 260 /** 261 * Truncates the CLOB value that this Clob designates to have a length of len 262 * characters. 263 * 264 * @param len the length 265 * @throws SQLException if there is an error accessing the <code>clob</code> 266 */ 267 public void truncate(long len) throws SQLException 268 { 269 // TODO impl. 270 throw new SQLException("JDBC 3.0 Method truncate not implemented"); 271 } 272 273 274 @Override 275 public String toString() { 276 return stringData; 277 } 278 279 public void free() { 280 stringData=""; 281 } 282 283 284 285}