packageyay.jdbc.rdd;importjava.io.InputStream;importjava.io.Reader;importjava.math.BigDecimal;importjava.net.URL;import java.sql.*;importjava.sql.Date;import java.util.*;/*** This class wraps around a {@linkPreparedStatement} and allows the programmer to set parameters by name instead
* of by index. This eliminates any confusion as to which parameter index represents what. This also means that
* rearranging the SQL statement or adding a parameter doesn't involve renumbering your indices.
* Code such as this:
*
*
* Connection conn = getConnection();
* String sql = "select * from my_table where name=? or address=?";
* PreparedStatement p = conn.prepareStatement(sql);
* p.setString(1, "bob");
* p.setString(2, "123");
* ResultSet rs = p.executeQuery();
*
*
* Can be replaced with:
*
*
* Connection conn = getConnection();
* String sql = "select * from my_table where name=:name or address=:address";
* NamedParameterStatement p = new NamedParameterStatement(conn, sql);
* p.setString("name", "bob");
* p.setString("address", "123");
* ResultSet rs = p.executeQuery();
*
*/
public class NamedParameterStatement extendsPreparedStatementWrapper
{private static final HashMap>> nameIndexCache = new HashMap>>();private static final HashMap parsedSqlCache = new HashMap();private finalString parsedSql;private final Map>nameIndexMap;/*** Creates a NamedParameterStatement. Wraps a call to
* c.{@linkConnection#prepareStatement(java.lang.String) prepareStatement}.
*
*@paramconn the database connection
*@paramsql the parameterized sql
*@throwsSQLException if the statement could not be created*/
public NamedParameterStatement(Connection conn, String sql,int resultSetType,int resultSetConcurrency) throwsSQLException
{if(nameIndexCache.containsKey(sql))
{
nameIndexMap=nameIndexCache.get(sql);
parsedSql=parsedSqlCache.get(sql);
}else{
nameIndexMap= new HashMap>();
parsedSql=parseNamedSql(sql, nameIndexMap);
nameIndexCache.put(sql, nameIndexMap);
parsedSqlCache.put(sql, parsedSql);
}
ps=conn.prepareStatement(parsedSql,resultSetType,resultSetConcurrency);
}/*** Returns the indexes for a parameter.
*
*@paramname parameter name
*@returnparameter indexes
*@throwsIllegalArgumentException if the parameter does not exist*/
private ListgetIndexes(String name)
{
List indexes =nameIndexMap.get(name);if (indexes == null)
{throw new IllegalArgumentException("Parameter not found: " +name);
}returnindexes;
}/*** Parses a sql with named parameters. The parameter-index mappings
* are put into the map, and the parsed sql is returned.
*
*@paramsql sql with named parameters
*@returnthe parsed sql*/
private static String parseNamedSql(String sql, Map>nameIndexMap)
{//I was originally using regular expressions, but they didn't work well for ignoring//parameter-like strings inside quotes.
int length =sql.length();
StringBuffer parsedSql= newStringBuffer(length);boolean inSingleQuote = false;boolean inDoubleQuote = false;int index = 1;for (int i = 0; i < length; i++)
{char c =sql.charAt(i);if(inSingleQuote)
{if (c == '\'')
{
inSingleQuote= false;
}
}else if(inDoubleQuote)
{if (c == '"')
{
inDoubleQuote= false;
}
}else{if (c == '\'')
{
inSingleQuote= true;
}else if (c == '"')
{
inDoubleQuote= true;
}else if (c == ':' && i + 1 < length && Character.isJavaIdentifierStart(sql.charAt(i + 1)))
{int j = i + 2;while (j < length &&Character.isJavaIdentifierPart(sql.charAt(j)))
{
j++;
}
String name= sql.substring(i + 1, j);
c= '?'; //replace the parameter with a question mark
i += name.length(); //skip past the end if the parameter
List indexList =nameIndexMap.get(name);if (indexList == null)
{
indexList= new LinkedList();
nameIndexMap.put(name, indexList);
}
indexList.add(index);
index++;
}
}
parsedSql.append(c);
}returnparsedSql.toString();
}public void setArray(String name, Array value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setArray(index, value);
}
}public void setAsciiStream(String name, InputStream value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setAsciiStream(index, value);
}
}public void setAsciiStream(String name, InputStream value, int length) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setAsciiStream(index, value, length);
}
}public void setBigDecimal(String name, BigDecimal value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setBigDecimal(index, value);
}
}public void setBinaryStream(String name, InputStream value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setBinaryStream(index, value);
}
}public void setBinaryStream(String name, InputStream value, int length) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setBinaryStream(index, value, length);
}
}public void setBinaryStream(String name, InputStream value, long length) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setBinaryStream(index, value, length);
}
}public void setBlob(String name, Blob value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setBlob(index, value);
}
}public void setBlob(String name, InputStream value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setBlob(index, value);
}
}public void setBlob(String name, InputStream value, long length) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setBlob(index, value, length);
}
}public void setBoolean(String name, boolean value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setBoolean(index, value);
}
}public void setByte(String name, byte value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setByte(index, value);
}
}public void setBytes(String name, byte[] value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setBytes(index, value);
}
}public void setCharacterStream(String name, Reader value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setCharacterStream(index, value);
}
}public void setCharacterStream(String name, Reader value, int length) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setCharacterStream(index, value, length);
}
}public void setCharacterStream(String name, Reader value, long length) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setCharacterStream(index, value, length);
}
}public void setClob(String name, Clob value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setClob(index, value);
}
}public void setClob(String name, Reader value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setClob(index, value);
}
}public void setClob(String name, Reader value, long length) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setClob(index, value, length);
}
}public void setDate(String name, Date value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setDate(index, value);
}
}public void setDate(String name, Date value, Calendar cal) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setDate(index, value, cal);
}
}public void setDouble(String name, double value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setDouble(index, value);
}
}public void setFloat(String name, float value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setFloat(index, value);
}
}public void setInt(String name, int value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setInt(index, value);
}
}public void setLong(String name, long value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setLong(index, value);
}
}public void setNCharacterStream(String name, Reader value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setNCharacterStream(index, value);
}
}public void setNCharacterStream(String name, Reader value, long length) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setNCharacterStream(index, value, length);
}
}public void setNClob(String name, NClob value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setNClob(index, value);
}
}public void setNClob(String name, Reader value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setNClob(index, value);
}
}public void setNClob(String name, Reader value, long length) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setNClob(index, value, length);
}
}public void setNString(String name, String value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setNString(index, value);
}
}public void setNull(String name, int sqlType) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setNull(index, sqlType);
}
}public void setObject(String name, Object value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setObject(index, value);
}
}public void setObject(String name, Object value, int targetSqlType) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setObject(index, value, targetSqlType);
}
}public void setObject(String name, Object value, int targetSqlType, int scaleOrLength) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setObject(index, value, targetSqlType, scaleOrLength);
}
}public void setRef(String name, Ref value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setRef(index, value);
}
}public void setRowId(String name, RowId value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setRowId(index, value);
}
}public void setShort(String name, short value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setShort(index, value);
}
}public void setSQLXML(String name, SQLXML value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setSQLXML(index, value);
}
}public void setString(String name, String value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setString(index, value);
}
}public void setTime(String name, Time value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setTime(index, value);
}
}public void setTime(String name, Time value, Calendar cal) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setTime(index, value, cal);
}
}public void setTimestamp(String name, Timestamp value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setTimestamp(index, value);
}
}public void setTimestamp(String name, Timestamp value, Calendar cal) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setTimestamp(index, value, cal);
}
}
@SuppressWarnings("deprecation")public void setUnicodeStream(String name, InputStream value, int length) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setUnicodeStream(index, value, length);
}
}public void setURL(String name, URL value) throwsSQLException
{for(Integer index : getIndexes(name))
{
ps.setURL(index, value);
}
}
}