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