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}