Java tutorial
/* * This file is part of AceQL. * AceQL: Remote JDBC access over HTTP. * Copyright (C) 2015, KawanSoft SAS * (http://www.kawansoft.com). All rights reserved. * * AceQL is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * AceQL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * * Any modifications to this file must keep this entire header * intact. */ package org.kawanfw.sql.jdbc; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.StringReader; import java.io.Writer; import java.math.BigDecimal; import java.net.URL; import java.sql.Array; import java.sql.BatchUpdateException; import java.sql.Blob; import java.sql.Clob; import java.sql.Date; import java.sql.NClob; import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.Ref; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLXML; import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; import java.util.Calendar; import java.util.Collections; import java.util.List; import java.util.Vector; import java.util.logging.Level; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.kawanfw.commons.util.ClientLogger; import org.kawanfw.commons.util.FrameworkDebug; import org.kawanfw.commons.util.FrameworkFileUtil; import org.kawanfw.commons.util.HtmlConverter; import org.kawanfw.commons.util.KeepTempFilePolicyParms; import org.kawanfw.commons.util.Tag; import org.kawanfw.file.api.util.client.FilesTransferWithProgress; import org.kawanfw.sql.jdbc.http.JdbcHttpBatchTransfer; import org.kawanfw.sql.jdbc.http.JdbcHttpExecuteRawTransfer; import org.kawanfw.sql.jdbc.http.JdbcHttpStatementTransfer; import org.kawanfw.sql.jdbc.http.JdbcHttpTransferUtil; import org.kawanfw.sql.jdbc.util.ParametersUtil; import org.kawanfw.sql.jdbc.util.TransportAsciiStream; import org.kawanfw.sql.jdbc.util.TransportInputStream; import org.kawanfw.sql.jdbc.util.TransportReader; import org.kawanfw.sql.json.IntArrayTransport; import org.kawanfw.sql.json.StatementHolder; import org.kawanfw.sql.transport.TransportConverter; import org.kawanfw.sql.util.FileNameFromBlobBuilder; /** * Creates and handle a Prepared Statement Http. */ public class PreparedStatementHttp extends StatementHttp implements PreparedStatement { /** Debug flag */ private static boolean DEBUG = FrameworkDebug.isSet(PreparedStatementHttp.class); /** * The holder that contains the sql order and the list if (parameter type, * parameter value ) for prepared statements **/ private StatementHolder statementHolder = null; /** The statement to execute */ private String sql = null; /** * The update count returned by PreparedStatementHttp.getUpdateCount() after * an execute() */ private int updateCount = 0; /** * The list of local files to uplaod and delete (in fire and forget mode) at * end of prepared statement. */ protected List<File> localFilesStatement = null; /** * The list of remote uploaded files delete (in fire and forget mode) at end * of prepared statement. */ protected List<String> remoteFilesStatement = null; // /** // * The list of input streams to delete (in fire and forget mode) at end of // * prepared statement // */ // protected List<InputStream> localInputStreams = null; // // // /** The length of each InputStream */ // protected List<Long> localInputStreamLengths = null; /** * Constructor * * @param connectionHttp * The Http Connection * @param sql * the sql statement to use * @param resultSetType * The result set type * @param resultSetConcurrency * The result set concurrency * @param resultSetHoldability * The result set holdability * @throws SQLException */ public PreparedStatementHttp(ConnectionHttp connectionHttp, String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { super(connectionHttp, resultSetType, resultSetConcurrency, resultSetHoldability); if (sql == null) { throw new SQLException("sql order is null!"); } this.sql = sql.trim(); statementHolder = new StatementHolder(sql, resultSetType, resultSetConcurrency, resultSetHoldability); statementHolder.setPreparedStatement(true); statementHolder.setHtmlEncodingOn(connectionHttp.isHtmlEncodingOn()); localFilesStatement = new Vector<File>(); remoteFilesStatement = new Vector<String>(); // localInputStreams = new Vector<InputStream>(); // localInputStreamLengths = new Vector<Long>(); } /** * Constructor for auto-generated keys * * @param connectionHttp * The Http Connection * @param sql * the sql statement to use * @param autoGeneratedKeys * a flag indicating whether auto-generated keys should be * returned; one of <code>Statement.RETURN_GENERATED_KEYS</code> * or <code>Statement.NO_GENERATED_KEYS</code> * * @throws SQLException */ public PreparedStatementHttp(ConnectionHttp connectionHttp, String sql, int autoGeneratedKeys) throws SQLException { super(connectionHttp, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT); if (sql == null) { throw new SQLException("sql order is null!"); } this.sql = sql.trim(); statementHolder = new StatementHolder(sql, autoGeneratedKeys); statementHolder.setPreparedStatement(true); statementHolder.setHtmlEncodingOn(connectionHttp.isHtmlEncodingOn()); localFilesStatement = new Vector<File>(); remoteFilesStatement = new Vector<String>(); // localInputStreams = new Vector<InputStream>(); // localInputStreamLengths = new Vector<Long>(); } /** * Constructor for auto-generated keys * * @param connectionHttp * The Http Connection * @param sql * the sql statement to use * @param columnIndexes * an array of column indexes indicating the columns that should * be returned from the inserted row or rows * * @throws SQLException */ public PreparedStatementHttp(ConnectionHttp connectionHttp, String sql, int[] columnIndexes) throws SQLException { super(connectionHttp, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT); if (sql == null) { throw new SQLException("sql order is null!"); } this.sql = sql.trim(); statementHolder = new StatementHolder(sql, columnIndexes); statementHolder.setPreparedStatement(true); statementHolder.setHtmlEncodingOn(connectionHttp.isHtmlEncodingOn()); localFilesStatement = new Vector<File>(); remoteFilesStatement = new Vector<String>(); } /** * Constructor for auto-generated keys * * @param connectionHttp * The Http Connection * @param sql * the sql statement to use * @param columnNames * an array of column names indicating the columns that should be * returned from the inserted row or rows * * @throws SQLException */ public PreparedStatementHttp(ConnectionHttp connectionHttp, String sql, String[] columnNames) throws SQLException { super(connectionHttp, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT); if (sql == null) { throw new SQLException("sql order is null!"); } this.sql = sql.trim(); statementHolder = new StatementHolder(sql, columnNames); statementHolder.setPreparedStatement(true); statementHolder.setHtmlEncodingOn(connectionHttp.isHtmlEncodingOn()); localFilesStatement = new Vector<File>(); remoteFilesStatement = new Vector<String>(); } /** * @throws SQLException * @see java.sql.Statement#close() */ @Override public void close() throws SQLException { super.close(); statementHolder = null; deleteLocalContainers(); } /** * Executes the SQL query in this <code>PreparedStatement</code> object and * returns the <code>ResultSet</code> object generated by the query. * * @return a <code>ResultSet</code> object that contains the data produced * by the query; never <code>null</code> * @exception SQLException * if a database access error occurs or the SQL statement * does not return a <code>ResultSet</code> object */ @Override public ResultSet executeQuery() throws SQLException { testIfClosed(); if (connectionHttp.isStatelessMode()) { if (!connectionHttp.getAutoCommit()) { throw new IllegalStateException( Tag.PRODUCT + "executeQuery() can\'t be executed when auto commit is off."); } } // Check that all parameters values are set ParametersUtil.checkParameters(statementHolder); statementHolder.setPreparedStatement(true); statementHolder.setExecuteUpdate(false); statementHolder.setJoinResultSetMetaData(connectionHttp.isJoinResultSetMetaData()); statementHolder.setZipResultSet(connectionHttp.isZipResultSet()); statementHolder.setFetchSize(fetchSize); statementHolder.setMaxRows(maxRows); statementHolder.setQueryTimeout(queryTimeout); statementHolder.setEscapeProcessing(escapeProcessingInt); // Send unique order to Server to SQL Executor JdbcHttpStatementTransfer jdbcHttpStatementTransfer = new JdbcHttpStatementTransfer(connectionHttp, connectionHttp.getAuthenticationToken()); File receiveFile = jdbcHttpStatementTransfer.getFileFromExecuteQueryOnServer(statementHolder); debug("getFileFromexecuteOnServer() : " + receiveFile); ResultSet rs = new ResultSetHttp(connectionHttp, statementHolder, this, receiveFile); return rs; } /** * Get the total length of the files to upload * * @return the total length of the files to upload */ private long getLocalTotalLength() { long totalLength = 0; for (File localFileStatement : localFilesStatement) { totalLength += localFileStatement.length(); } // for (Long localLength : localInputStreamLengths) { // totalLength += localLength; // } return totalLength; } /** * Upload all the blob parameters */ private void uploadBlobParameters() throws SQLException { try { // reinit progress connectionHttp.getProgress().set(0); long totalLength = getLocalTotalLength(); // Upload local objects FilesTransferWithProgress filesTransferWithProgress = new FilesTransferWithProgress( connectionHttp.getRemoteSession(), connectionHttp.getProgress(), connectionHttp.getCancelled()); // 1) Upoad files if (!localFilesStatement.isEmpty()) { List<File> filesUnmodifiableList = Collections.unmodifiableList(localFilesStatement); for (int i = filesUnmodifiableList.size() - 1; i > -1; i--) { // Do the upload debug("uploading file: " + filesUnmodifiableList.get(i)); filesTransferWithProgress.upload(localFilesStatement.get(i), remoteFilesStatement.get(i), totalLength); FileUtils.deleteQuietly(filesUnmodifiableList.get(i)); localFilesStatement.remove(i); } } // // 2) upload InputStreams // if (!localInputStreams.isEmpty()) { // // //debug("connectionHttp.getProgress(): " + // connectionHttp.getProgress()); // //debug("localInputStreams.size() : " + // localInputStreams.size()); // //debug("localInputStreamLengths : " + // localInputStreamLengths); // // filesTransferWithProgress.upload(localInputStreams, // localInputStreamLengths, remoteFilesStatement, // totalLength); // } } catch (Exception e) { JdbcHttpTransferUtil.wrapExceptionAsSQLException(e); } finally { // NO! We want to repeat the uploads, so stay at 99 // connectionHttp.getProgress().set(100); // deleteLocalContainers(); } } /** * Delete local files */ private void deleteLocalContainers() { if (!KeepTempFilePolicyParms.KEEP_TEMP_FILE && !DEBUG) { if (localFilesStatement != null) { for (File localFileStatement : localFilesStatement) { localFileStatement.delete(); } } } } /** * Executes the SQL statement in this <code>PreparedStatement</code> object, * which must be an SQL <code>INSERT</code>, <code>UPDATE</code> or * <code>DELETE</code> statement; or an SQL statement that returns nothing, * such as a DDL statement. * * @return either (1) the row count for <code>INSERT</code>, * <code>UPDATE</code>, or <code>DELETE</code> statements or (2) 0 * for SQL statements that return nothing * @exception SQLException * if a database access error occurs or the SQL statement * returns a <code>ResultSet</code> object */ @Override public synchronized int executeUpdate() throws SQLException { testIfClosed(); lastExecuteIsRaw = false; // Check that all parameters values are set ParametersUtil.checkParameters(statementHolder); statementHolder.setPreparedStatement(true); statementHolder.setExecuteUpdate(true); int rc = 0; // Safety reset of list if we are in statefull mode // For method to be idempotent if (!connectionHttp.isStatelessMode()) { connectionHttp.resetStatementHolderList(); } // Add the statement to the statement list connectionHttp.addStatementHolder(statementHolder); // Execute for statefull mode if (!connectionHttp.isStatelessMode()) { uploadBlobParameters(); } // 25/04/14 15:20 - HACK NDP - There were no parenthesis if ((connectionHttp.isStatelessMode() && connectionHttp.getAutoCommit()) || !connectionHttp.isStatelessMode()) { try { debug("before getStringFromExecuteUpdateListOnServer()"); // Send order to Server to SQL Executor connectionHttp.receiveFromExecuteUpdate = connectionHttp.getStringFromExecuteUpdateListOnServer(); debug("after getStringFromExecuteUpdateListOnServer()"); connectionHttp.testIfUploadInterrupted(); BufferedReader bufferedReader = new BufferedReader( new StringReader(connectionHttp.receiveFromExecuteUpdate)); String line1 = null; try { line1 = bufferedReader.readLine(); } catch (IOException e1) { throw new SQLException(e1); } connectionHttp.testIfUploadInterrupted(); try { rc = Integer.parseInt(line1); } catch (NumberFormatException e) { throw new SQLException(Tag.PRODUCT_PRODUCT_FAIL + e.getMessage(), new IOException(e.getMessage(), e)); } } finally { connectionHttp.resetStatementHolderList(); // Safety reset of // list } } return rc; } /** * Executes the given SQL statement, which may return multiple results. In * some (uncommon) situations, a single SQL statement may return multiple * result sets and/or update counts. Normally you can ignore this unless you * are (1) executing a stored procedure that you know may return multiple * results or (2) you are dynamically executing an unknown SQL string. * <P> * The <code>execute</code> method executes an SQL statement and indicates * the form of the first result. You must then use the methods * <code>getResultSet</code> or <code>getUpdateCount</code> to retrieve the * result, and <code>getMoreResults</code> to move to any subsequent * result(s). * * @param sql * any SQL statement * @return <code>true</code> if the first result is a <code>ResultSet</code> * object; <code>false</code> if it is an update count or there are * no results * @exception SQLException * if a database access error occurs * @see #getResultSet * @see #getUpdateCount * @see #getMoreResults */ @Override public boolean execute() throws SQLException { testIfClosed(); if (connectionHttp.isStatelessMode()) { if (!connectionHttp.getAutoCommit()) { throw new IllegalStateException( Tag.PRODUCT + "execute can\'t be executed when auto commit is off."); } } debug("PreparedStatementHttp.execute : " + sql); lastExecuteIsRaw = true; // Check that all parameters values are set ParametersUtil.checkParameters(statementHolder); statementHolder.setPreparedStatement(true); statementHolder.setExecuteUpdate(false); statementHolder.setJoinResultSetMetaData(connectionHttp.isJoinResultSetMetaData()); statementHolder.setZipResultSet(connectionHttp.isZipResultSet()); statementHolder.setFetchSize(fetchSize); statementHolder.setMaxRows(maxRows); statementHolder.setQueryTimeout(queryTimeout); statementHolder.setEscapeProcessing(escapeProcessingInt); // Reset the fields values rsFromExecute = null; updateCount = -1; // Send order to Server to SQL Executor JdbcHttpExecuteRawTransfer jdbcHttpExecuteRawTransfer = new JdbcHttpExecuteRawTransfer(connectionHttp, connectionHttp.getAuthenticationToken()); receiveFileFromExecute = jdbcHttpExecuteRawTransfer.getFileFromExecuteRaw(statementHolder); localFilesExecuteResult.add(receiveFileFromExecute); debug("getFileFromexecuteOnServer() : " + receiveFileFromExecute); boolean fileResultSet = super.isFileResultSet(receiveFileFromExecute); try { if (DEBUG) { String fileContent = FileUtils.readFileToString(receiveFileFromExecute); System.out.println(fileContent); } } catch (IOException e2) { throw new SQLException(e2); } if (fileResultSet) { // Transform the Result Set in String back to an Result Set // (emulated) rsFromExecute = new ResultSetHttp(connectionHttp, statementHolder, this, receiveFileFromExecute); return true; } else { BufferedReader bufferedReader = null; String line1 = null; try { bufferedReader = new BufferedReader(new FileReader(receiveFileFromExecute)); line1 = bufferedReader.readLine(); } catch (IOException e1) { throw new SQLException(e1); } finally { IOUtils.closeQuietly(bufferedReader); } String updateCountStr = StringUtils.substringAfter(line1, "getUpdateCount="); try { updateCount = Integer.parseInt(updateCountStr); } catch (NumberFormatException e) { throw new SQLException(Tag.PRODUCT_PRODUCT_FAIL + e.getMessage(), new IOException(e.getMessage(), e)); } return false; } } /* * (non-Javadoc) * * @see org.kawanfw.sql.jdbc.StatementHttp#getUpdateCount() */ @Override public int getUpdateCount() throws SQLException { return updateCount; } /** * Moves to this <code>Statement</code> object's next result, returns * <code>true</code> if it is a <code>ResultSet</code> object, and * implicitly closes any current <code>ResultSet</code> object(s) obtained * with the method <code>getResultSet</code>. * * <P> * There are no more results when the following is true: * * <PRE> * <code>(!getMoreResults() && (getUpdateCount() == -1)</code> * </PRE> * * @return <code>true</code> if the next result is a <code>ResultSet</code> * object; <code>false</code> if it is an update count or there are * no more results * @exception SQLException * if a database access error occurs * @see #execute */ public boolean getMoreResults() throws SQLException { // always return false for now: return false; } /** * Sets the designated parameter to SQL <code>NULL</code>. * * <P> * <B>Note:</B> You must specify the parameter's SQL type. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param sqlType * the SQL type code defined in <code>java.sql.Types</code> * @exception SQLException * if a database access error occurs */ public void setNull(int parameterIndex, int sqlType) throws SQLException { testIfClosed(); statementHolder.setNullParameter(parameterIndex, sqlType); } /** * Sets the designated parameter to the given Java <code>boolean</code> * value. The driver converts this to an SQL <code>BIT</code> value when it * sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setBoolean(int parameterIndex, boolean x) throws SQLException { testIfClosed(); statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given Java <code>short</code> value. * The driver converts this to an SQL <code>SMALLINT</code> value when it * sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setShort(int parameterIndex, short x) throws SQLException { testIfClosed(); statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given Java <code>int</code> value. * The driver converts this to an SQL <code>INTEGER</code> value when it * sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setInt(int parameterIndex, int x) throws SQLException { testIfClosed(); statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given Java <code>long</code> value. * The driver converts this to an SQL <code>BIGINT</code> value when it * sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setLong(int parameterIndex, long x) throws SQLException { testIfClosed(); statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given Java <code>float</code> value. * The driver converts this to an SQL <code>FLOAT</code> value when it sends * it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setFloat(int parameterIndex, float x) throws SQLException { testIfClosed(); statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given Java <code>double</code> * value. The driver converts this to an SQL <code>DOUBLE</code> value when * it sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setDouble(int parameterIndex, double x) throws SQLException { testIfClosed(); statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given * <code>java.math.BigDecimal</code> value. The driver converts this to an * SQL <code>NUMERIC</code> value when it sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if parameterIndex does not correspond to a parameter * marker in the SQL statement; if a database access error * occurs or this method is called on a closed * <code>PreparedStatement</code> */ @Override public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { testIfClosed(); statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given Java <code>String</code> * value. The driver converts this to an SQL <code>VARCHAR</code> or * <code>LONGVARCHAR</code> value (depending on the argument's size relative * to the driver's limits on <code>VARCHAR</code> values) when it sends it * to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setString(int parameterIndex, String x) throws SQLException { testIfClosed(); // x = TransportConverter.toTransportFormat(x); if (x != null && x.length() > connectionHttp.getMaxLengthForString()) { throw new SQLException("String is too big for upload: " + x.length() + " bytes. Maximum length authorized is: " + connectionHttp.getMaxLengthForString()); } statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given <code>String</code> object. * The driver converts this to a SQL <code>NCHAR</code> or * <code>NVARCHAR</code> or <code>LONGNVARCHAR</code> value (depending on * the argument's size relative to the driver's limits on * <code>NVARCHAR</code> values) when it sends it to the database. * * @param parameterIndex * of the first parameter is 1, the second is 2, ... * @param value * the parameter value * @throws SQLException * if parameterIndex does not correspond to a parameter marker * in the SQL statement; if the driver does not support national * character sets; if the driver can detect that a data * conversion error could occur; if a database access error * occurs; or this method is called on a closed * <code>PreparedStatement</code> * @throws SQLFeatureNotSupportedException * if the JDBC driver does not support this method * @since 1.6 */ @Override public void setNString(int parameterIndex, String value) throws SQLException { testIfClosed(); // x = TransportConverter.toTransportFormat(x); if (value != null && value.length() > connectionHttp.getMaxLengthForString()) { throw new SQLException("String is too big for upload: " + value.length() + " bytes. Maximum length authorized is: " + connectionHttp.getMaxLengthForString()); } statementHolder.setParameter(parameterIndex, value, StatementHolder.SET_N_STRING); } /** * Sets the designated parameter to the given Java <code>byte</code> value. * The driver converts this to an SQL <code>TINYINT</code> value when it * sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setByte(int parameterIndex, byte x) throws SQLException { testIfClosed(); byte[] theByte = new byte[1]; theByte[0] = x; String encodedString = TransportConverter.toTransportFormat(theByte); // parameterValues.put(parameterIndex, hexString); statementHolder.setParameter(parameterIndex, encodedString); } /** * Sets the designated parameter to the given Java array of bytes. The * driver converts this to an SQL <code>VARBINARY</code> or * <code>LONGVARBINARY</code> (depending on the argument's size relative to * the driver's limits on <code>VARBINARY</code> values) when it sends it to * the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setBytes(int parameterIndex, byte[] x) throws SQLException { testIfClosed(); String encodedString = TransportConverter.toTransportFormat(x); // parameterValues.put(parameterIndex, hexString); statementHolder.setParameter(parameterIndex, encodedString); } /** * Sets the designated parameter to the given <code>java.sql.Date</code> * value. The driver converts this to an SQL <code>DATE</code> value when it * sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setDate(int parameterIndex, java.sql.Date x) throws SQLException { testIfClosed(); statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given <code>java.sql.Time</code> * value. The driver converts this to an SQL <code>TIME</code> value when it * sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ public void setTime(int parameterIndex, java.sql.Time x) throws SQLException { testIfClosed(); statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given * <code>java.sql.Timestamp</code> value. The driver converts this to an SQL * <code>TIMESTAMP</code> value when it sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @exception SQLException * if a database access error occurs */ @Override public void setTimestamp(int parameterIndex, java.sql.Timestamp x) throws SQLException { testIfClosed(); statementHolder.setParameter(parameterIndex, x); } /** * <p> * Sets the value of the designated parameter using the given object. The * second parameter must be of type <code>Object</code>; therefore, the * <code>java.lang</code> equivalent objects should be used for built-in * types. * * <p> * The JDBC specification specifies a standard mapping from Java * <code>Object</code> types to SQL types. The given argument will be * converted to the corresponding SQL type before being sent to the * database. * * <p> * Note that this method may be used to pass datatabase- specific abstract * data types, by using a driver-specific Java type. * * If the object is of a class implementing the interface * <code>SQLData</code>, the JDBC driver should call the method * <code>SQLData.writeSQL</code> to write it to the SQL data stream. If, on * the other hand, the object is of a class implementing <code>Ref</code>, * <code>Blob</code>, <code>Clob</code>, <code>Struct</code>, or * <code>Array</code>, the driver should pass it to the database as a value * of the corresponding SQL type. * <P> * This method throws an exception if there is an ambiguity, for example, if * the object is of a class implementing more than one of the interfaces * named above. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the object containing the input parameter value * @exception SQLException * if a database access error occurs or the type of the given * object is ambiguous */ @Override public void setObject(int parameterIndex, Object x) throws SQLException { testIfClosed(); if (x != null && x.toString().length() > connectionHttp.getMaxLengthForString()) { throw new SQLException("Object is too big for upload: " + x.toString().length() + " bytes. Maximum length authorized is: " + connectionHttp.getMaxLengthForString()); } statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given input stream. When a very * large binary value is input to a <code>LONGVARBINARY</code> parameter, it * may be more practical to send it via a <code>java.io.InputStream</code> * object. The data will be read from the stream as needed until end-of-file * is reached. * * <P> * <B>Note:</B> This stream object can either be a standard Java stream * object or your own subclass that implements the standard interface. * <P> * <B>Note:</B> Consult your JDBC driver documentation to determine if it * might be more efficient to use a version of <code>setBinaryStream</code> * which takes a length parameter. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the java input stream which contains the binary parameter * value * @exception SQLException * if parameterIndex does not correspond to a parameter * marker in the SQL statement; if a database access error * occurs or this method is called on a closed * <code>PreparedStatement</code> * @throws SQLFeatureNotSupportedException * if the JDBC driver does not support this method * @since 1.6 */ @Override public void setBinaryStream(int parameterIndex, java.io.InputStream x) throws SQLException { testIfClosed(); this.setBinaryStream(parameterIndex, x, (long) -1); } /** * Add the files to the stack * * @param file * the local file, blob or clob * @param rawRemoteFileName * the remote filename */ protected void addFiles(File file, String rawRemoteFileName) { // HACK NDP if (!rawRemoteFileName.startsWith("/")) { rawRemoteFileName = "/" + rawRemoteFileName; } if (connectionHttp.isStatelessMode()) { connectionHttp.localFiles.add(file); connectionHttp.remoteFiles.add(rawRemoteFileName); } else { this.localFilesStatement.add(file); this.remoteFilesStatement.add(rawRemoteFileName); } } // /** // * Add InputStream to the stack // * @param in the input stream // * @param length the input stream length // * @param rawRemoteFileName the remote file naes // */ // protected void addInputStreams(InputStream in, long length, String // rawRemoteFileName) { // if (connectionHttp.isStatelessMode()) { // connectionHttp.localInputStreams.add(in); // connectionHttp.localInputStreamLengths.add(length); // connectionHttp.remoteFiles.add(rawRemoteFileName); // } else { // this.localInputStreams.add(in); // this.localInputStreamLengths.add(length); // this.remoteFilesStatement.add(rawRemoteFileName); // } // } /** * Sets the designated parameter to the given input stream, which will have * the specified number of bytes. When a very large binary value is input to * a <code>LONGVARBINARY</code> parameter, it may be more practical to send * it via a <code>java.io.InputStream</code> object. The data will be read * from the stream as needed until end-of-file is reached. * * <P> * <B>Note:</B> This stream object can either be a standard Java stream * object or your own subclass that implements the standard interface. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the java input stream which contains the binary parameter * value * @param length * the number of bytes in the stream * @exception SQLException * if parameterIndex does not correspond to a parameter * marker in the SQL statement; if a database access error * occurs or this method is called on a closed * <code>PreparedStatement</code> */ @Override public void setBinaryStream(int parameterIndex, java.io.InputStream x, int length) throws SQLException { testIfClosed(); this.setBinaryStream(parameterIndex, x, (long) length); } /** * Sets the designated parameter to the given input stream, which will have * the specified number of bytes. When a very large binary value is input to * a <code>LONGVARBINARY</code> parameter, it may be more practical to send * it via a <code>java.io.InputStream</code> object. The data will be read * from the stream as needed until end-of-file is reached. * * <P> * <B>Note:</B> This stream object can either be a standard Java stream * object or your own subclass that implements the standard interface. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the java input stream which contains the binary parameter * value * @param length * the number of bytes in the stream * @exception SQLException * if parameterIndex does not correspond to a parameter * marker in the SQL statement; if a database access error * occurs or this method is called on a closed * <code>PreparedStatement</code> * @since 1.6 */ @Override public void setBinaryStream(int parameterIndex, java.io.InputStream x, long length) throws SQLException { testIfClosed(); // Create the file from the input Stream, naming it on the table name FileNameFromBlobBuilder fileNameFromBlobBuilder = new FileNameFromBlobBuilder(sql, parameterIndex, false); String rawRemoteFileName = fileNameFromBlobBuilder.getFileName(); String dir = FrameworkFileUtil.getKawansoftTempDir(); File blobFile = new File(dir + File.separator + rawRemoteFileName); debug("rawRemoteFileName: " + rawRemoteFileName); debug("blobFile : " + blobFile); OutputStream out = null; try { out = new BufferedOutputStream(new FileOutputStream(blobFile)); IOUtils.copy(x, out); } catch (IOException e) { throw new SQLException(e.getMessage()); } finally { IOUtils.closeQuietly(x); IOUtils.closeQuietly(out); } addFiles(blobFile, rawRemoteFileName); // Create the file from the input Stream, naming it on the table name // FileNameFromBlobBuilder fileNameFromBlobBuilder = new // FileNameFromBlobBuilder( // sql, parameterIndex, false); // String rawRemoteFileName = fileNameFromBlobBuilder.getFileName(); // // addInputStreams(x, length, rawRemoteFileName); // Ok. File is successfully uploaded! // Set the parameter using the file name InputStream inputStream = new TransportInputStream(rawRemoteFileName); // parameterValues.put(parameterIndex, inputStream); statementHolder.setParameter(parameterIndex, inputStream); } @Override public void setBlob(int parameterIndex, Blob x) throws SQLException { testIfClosed(); if (x instanceof BlobHttp) { BlobHttp blobHttp = (BlobHttp) x; // Close the underlying output stream, cleaner: blobHttp.close(); String rawRemoteFileName = blobHttp.getFile().getName(); debug("blobHttp.getFile(): " + blobHttp.getFile()); debug("rawRemoteFileName : " + rawRemoteFileName); addFiles(blobHttp.getFile(), rawRemoteFileName); // Ok. File is successfully uploaded! // Set the parameter using the file name InputStream inputStream = new TransportInputStream(rawRemoteFileName); // parameterValues.put(parameterIndex, inputStream); statementHolder.setParameter(parameterIndex, inputStream); } else { InputStream in = x.getBinaryStream(); setBinaryStream(parameterIndex, in, x.length()); } } @Override public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { testIfClosed(); setBinaryStream(parameterIndex, inputStream); } @Override public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { testIfClosed(); setBinaryStream(parameterIndex, inputStream, length); } @Override public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { setAsciiStream(parameterIndex, x); } @Override public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { setAsciiStream(parameterIndex, x); } @Override public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { testIfClosed(); // Create the file from the input Stream, naming it on the table name FileNameFromBlobBuilder fileNameFromBlobBuilder = new FileNameFromBlobBuilder(sql, parameterIndex, true); String rawRemoteFileName = fileNameFromBlobBuilder.getFileName(); String dir = FrameworkFileUtil.getKawansoftTempDir(); File clobFile = new File(dir + File.separator + rawRemoteFileName); debug("rawRemoteFileName: " + rawRemoteFileName); debug("blobFile : " + clobFile); Writer writer = null; try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(x)); writer = new BufferedWriter(new FileWriter(clobFile)); String line = null; while ((line = bufferedReader.readLine()) != null) { if (connectionHttp.isHtmlEncodingOn()) { line = HtmlConverter.toHtml(line); } writer.write(line + CR_LF); } } catch (IOException e) { throw new SQLException(e.getMessage()); } finally { IOUtils.closeQuietly(x); IOUtils.closeQuietly(writer); } addFiles(clobFile, rawRemoteFileName); // Ok. File is successfully uploaded! // Set the parameter using the file name TransportAsciiStream transportAsciiStream = new TransportAsciiStream(rawRemoteFileName); // parameterValues.put(parameterIndex, inputStream); statementHolder.setParameter(parameterIndex, transportAsciiStream); } /** * Sets the designated parameter to the given <code>Reader</code> object. * When a very large UNICODE value is input to a <code>LONGVARCHAR</code> * parameter, it may be more practical to send it via a * <code>java.io.Reader</code> object. The data will be read from the stream * as needed until end-of-file is reached. The JDBC driver will do any * necessary conversion from UNICODE to the database char format. * * <P> * <B>Note:</B> This stream object can either be a standard Java stream * object or your own subclass that implements the standard interface. * <P> * <B>Note:</B> Consult your JDBC driver documentation to determine if it * might be more efficient to use a version of * <code>setCharacterStream</code> which takes a length parameter. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param reader * the <code>java.io.Reader</code> object that contains the * Unicode data * @exception SQLException * if parameterIndex does not correspond to a parameter * marker in the SQL statement; if a database access error * occurs or this method is called on a closed * <code>PreparedStatement</code> * @throws SQLFeatureNotSupportedException * if the JDBC driver does not support this method * @since 1.6 */ @Override public void setCharacterStream(int parameterIndex, java.io.Reader reader) throws SQLException { testIfClosed(); // Create the file from the input Stream, naming it on the table name FileNameFromBlobBuilder fileNameFromBlobBuilder = new FileNameFromBlobBuilder(sql, parameterIndex, true); String rawRemoteFileName = fileNameFromBlobBuilder.getFileName(); String dir = FrameworkFileUtil.getKawansoftTempDir(); File clobFile = new File(dir + File.separator + rawRemoteFileName); debug("rawFileName: " + rawRemoteFileName); debug("clobFile : " + clobFile); BufferedReader bufferedReader = null; Writer writer = null; try { bufferedReader = new BufferedReader(reader); writer = new BufferedWriter(new FileWriter(clobFile)); String line = null; while ((line = bufferedReader.readLine()) != null) { if (connectionHttp.isHtmlEncodingOn()) { line = HtmlConverter.toHtml(line); } writer.write(line + CR_LF); } } catch (IOException e) { throw new SQLException(e.getMessage()); } finally { IOUtils.closeQuietly(reader); IOUtils.closeQuietly(writer); } addFiles(clobFile, rawRemoteFileName); // Ok. File is successfully uploaded! // Set the parameter using the file name Reader transportReader = new TransportReader(rawRemoteFileName); statementHolder.setParameter(parameterIndex, transportReader); } /** * Sets the designated parameter to the given <code>Reader</code> object, * which is the given number of characters long. When a very large UNICODE * value is input to a <code>LONGVARCHAR</code> parameter, it may be more * practical to send it via a <code>java.io.Reader</code> object. The data * will be read from the stream as needed until end-of-file is reached. The * JDBC driver will do any necessary conversion from UNICODE to the database * char format. * * <P> * <B>Note:</B> This stream object can either be a standard Java stream * object or your own subclass that implements the standard interface. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param reader * the <code>java.io.Reader</code> object that contains the * Unicode data * @param length * the number of characters in the stream * @exception SQLException * if parameterIndex does not correspond to a parameter * marker in the SQL statement; if a database access error * occurs or this method is called on a closed * <code>PreparedStatement</code> * @since 1.2 */ @Override public void setCharacterStream(int parameterIndex, java.io.Reader reader, int length) throws SQLException { testIfClosed(); this.setCharacterStream(parameterIndex, reader); } /** * Sets the designated parameter to the given <code>Reader</code> object, * which is the given number of characters long. When a very large UNICODE * value is input to a <code>LONGVARCHAR</code> parameter, it may be more * practical to send it via a <code>java.io.Reader</code> object. The data * will be read from the stream as needed until end-of-file is reached. The * JDBC driver will do any necessary conversion from UNICODE to the database * char format. * * <P> * <B>Note:</B> This stream object can either be a standard Java stream * object or your own subclass that implements the standard interface. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param reader * the <code>java.io.Reader</code> object that contains the * Unicode data * @param length * the number of characters in the stream * @exception SQLException * if parameterIndex does not correspond to a parameter * marker in the SQL statement; if a database access error * occurs or this method is called on a closed * <code>PreparedStatement</code> * @since 1.6 */ @Override public void setCharacterStream(int parameterIndex, java.io.Reader reader, long length) throws SQLException { testIfClosed(); this.setCharacterStream(parameterIndex, reader); } @Override public void setClob(int parameterIndex, Clob x) throws SQLException { testIfClosed(); // Clob creation is not optimized (other file creation) , because if // htmlEncoding is on we must rewrite the file Reader reader = x.getCharacterStream(); setCharacterStream(parameterIndex, reader); } @Override public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { testIfClosed(); setCharacterStream(parameterIndex, reader, length); } @Override public void setClob(int parameterIndex, Reader reader) throws SQLException { testIfClosed(); setCharacterStream(parameterIndex, reader); } /** * Clears the current parameter values immediately. * <P> * In general, parameter values remain in force for repeated use of a * statement. Setting a parameter value automatically clears its previous * value. However, in some cases it is useful to immediately release the * resources used by the current parameter values; this can be done by * calling the method <code>clearParameters</code>. * * @exception SQLException * if a database access error occurs */ @Override public void clearParameters() throws SQLException { statementHolder.clearParameters(); } // --------------------------JDBC 2.0----------------------------- /** * Adds a set of parameters to this <code>PreparedStatement</code> object's * batch of commands. * * @exception SQLException * if a database access error occurs * @see Statement#addBatch * @since 1.2 */ @Override public void addBatch() throws SQLException { // Check that all parameters values are set ParametersUtil.checkParameters(statementHolder); // Create a StatementHolder that contains only the parameter // and add it to the batchHolderList field: StatementHolder batchHolder = new StatementHolder(statementHolder.getParameterTypes(), statementHolder.getParameterStringValues(), statementHolder.isHtmlEncodingOn()); batchHolder.setPreparedStatement(true); batchHolder.setExecuteUpdate(true); batchHolderFileList.add(batchHolder); debug("batchHolder: " + batchHolder); } /** * Submits a batch of commands to the database for execution and if all * commands execute successfully, returns an array of update counts. The * <code>int</code> elements of the array that is returned are ordered to * correspond to the commands in the batch, which are ordered according to * the order in which they were added to the batch. The elements in the * array returned by the method <code>executeBatch</code> may be one of the * following: * <OL> * <LI>A number greater than or equal to zero -- indicates that the command * was processed successfully and is an update count giving the number of * rows in the database that were affected by the command's execution * <LI>A value of <code>SUCCESS_NO_INFO</code> -- indicates that the command * was processed successfully but that the number of rows affected is * unknown * <P> * If one of the commands in a batch update fails to execute properly, this * method throws a <code>BatchUpdateException</code>, and a JDBC driver may * or may not continue to process the remaining commands in the batch. * However, the driver's behavior must be consistent with a particular DBMS, * either always continuing to process commands or never continuing to * process commands. If the driver continues processing after a failure, the * array returned by the method * <code>BatchUpdateException.getUpdateCounts</code> will contain as many * elements as there are commands in the batch, and at least one of the * elements will be the following: * <P> * <LI>A value of <code>EXECUTE_FAILED</code> -- indicates that the command * failed to execute successfully and occurs only if a driver continues to * process commands after a command fails * </OL> * <P> * A driver is not required to implement this method. The possible * implementations and return values have been modified in the Java 2 SDK, * Standard Edition, version 1.3 to accommodate the option of continuing to * proccess commands in a batch update after a * <code>BatchUpdateException</code> obejct has been thrown. * * @return an array of update counts containing one element for each command * in the batch. The elements of the array are ordered according to * the order in which commands were added to the batch. * @exception SQLException * if a database access error occurs or the driver does not * support batch statements. Throws * {@link BatchUpdateException} (a subclass of * <code>SQLException</code>) if one of the commands sent to * the database fails to execute properly or attempts to * return a result set. * @since 1.3 */ @Override public int[] executeBatch() throws SQLException { int updateCounts[] = new int[batchHolderFileList.size()]; if (batchHolderFileList.size() == 0) { return updateCounts; } JdbcHttpBatchTransfer jdbcHttpBatchTransfer = new JdbcHttpBatchTransfer(connectionHttp, connectionHttp.getAuthenticationToken()); String updateCountsStr = jdbcHttpBatchTransfer .getStringFromExecutePrepStatementBatchOnServer(statementHolder, batchHolderFileList); updateCounts = IntArrayTransport.fromJson(updateCountsStr); clearBatch(); return updateCounts; } /** * Sets the designated parameter to the given <code>java.net.URL</code> * value. The driver converts this to an SQL <code>DATALINK</code> value * when it sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the <code>java.net.URL</code> object to be set * @exception SQLException * if parameterIndex does not correspond to a parameter * marker in the SQL statement; if a database access error * occurs or this method is called on a closed * <code>PreparedStatement</code> * @throws SQLFeatureNotSupportedException * if the JDBC driver does not support this method * @since 1.4 */ @Override public void setURL(int parameterIndex, URL x) throws SQLException { if (x == null) { throw new IllegalArgumentException("URL can not be null!"); } statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given <code>java.sql.Array</code> * object. The driver converts this to an SQL <code>ARRAY</code> value when * it sends it to the database. * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * an <code>Array</code> object that maps an SQL * <code>ARRAY</code> value * @exception SQLException * if parameterIndex does not correspond to a parameter * marker in the SQL statement; if a database access error * occurs or this method is called on a closed * <code>PreparedStatement</code> * @throws SQLFeatureNotSupportedException * if the JDBC driver does not support this method * @since 1.2 */ public void setArray(int parameterIndex, Array x) throws SQLException { if (connectionHttp.isStatelessMode()) { throw new SQLException(ConnectionHttp.FEATURE_NOT_SUPPORTED_IN_STATELESS_MODE); } if (x == null) { throw new IllegalArgumentException("Array can not be null!"); } statementHolder.setParameter(parameterIndex, x); } /** * Sets the designated parameter to the given <code>java.sql.RowId</code> * object. The driver converts this to a SQL <code>ROWID</code> value when * it sends it to the database * * @param parameterIndex * the first parameter is 1, the second is 2, ... * @param x * the parameter value * @throws SQLException * if parameterIndex does not correspond to a parameter marker * in the SQL statement; if a database access error occurs or * this method is called on a closed * <code>PreparedStatement</code> * @throws SQLFeatureNotSupportedException * if the JDBC driver does not support this method * * @since 1.6 */ @Override public void setRowId(int parameterIndex, RowId x) throws SQLException { if (connectionHttp.isStatelessMode()) { throw new SQLException(ConnectionHttp.FEATURE_NOT_SUPPORTED_IN_STATELESS_MODE); } if (x == null) { throw new IllegalArgumentException("RowId can not be null!"); } statementHolder.setParameter(parameterIndex, x); } // // Not (yet) implemented methods // @Override public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setRef(int parameterIndex, Ref x) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public ResultSetMetaData getMetaData() throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public ParameterMetaData getParameterMetaData() throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setNClob(int parameterIndex, NClob value) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } @Override public void setNClob(int parameterIndex, Reader reader) throws SQLException { throw new SQLFeatureNotSupportedException(ConnectionHttp.KAWANFW_NOT_SUPPORTED_METHOD); } private static void debug(String s) { if (DEBUG) ClientLogger.getLogger().log(Level.WARNING, s); } }