jetbrick.dao.orm.utils.NamedParameterStatement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jetbrick-orm Show documentation
Show all versions of jetbrick-orm Show documentation
Object-relational mapping framework for jetbrick
/**
* Copyright 2013-2014 Guoqiang Chen, Shanghai, China. All rights reserved.
*
* Email: [email protected]
* URL: http://subchen.github.io/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jetbrick.dao.orm.utils;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.*;
import java.sql.Date;
import java.util.*;
/**
* This class wraps around a {@link PreparedStatement} 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 extends PreparedStatementWrapper {
private static final HashMap>> nameIndexCache = new HashMap>>();
private static final HashMap parsedSqlCache = new HashMap();
private final String parsedSql;
private final Map> nameIndexMap;
/**
* Creates a NamedParameterStatement. Wraps a call to
* c.{@link Connection#prepareStatement(java.lang.String) prepareStatement}.
* @param conn the database connection
* @param sql the parameterized sql
* @throws SQLException if the statement could not be created
*/
public NamedParameterStatement(Connection conn, String sql) throws SQLException {
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);
}
/**
* Returns the indexes for a parameter.
* @param name parameter name
* @return parameter indexes
* @throws IllegalArgumentException if the parameter does not exist
*/
private List getIndexes(String name) {
List indexes = nameIndexMap.get(name);
if (indexes == null) {
throw new IllegalArgumentException("Parameter not found: " + name);
}
return indexes;
}
/**
* Parses a sql with named parameters. The parameter-index mappings
* are put into the map, and the parsed sql is returned.
* @param sql sql with named parameters
* @return the 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 = new StringBuffer(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);
}
return parsedSql.toString();
}
public void setArray(String name, Array value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setArray(index, value);
}
}
public void setAsciiStream(String name, InputStream value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setAsciiStream(index, value);
}
}
public void setAsciiStream(String name, InputStream value, int length) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setAsciiStream(index, value, length);
}
}
public void setBigDecimal(String name, BigDecimal value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setBigDecimal(index, value);
}
}
public void setBinaryStream(String name, InputStream value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setBinaryStream(index, value);
}
}
public void setBinaryStream(String name, InputStream value, int length) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setBinaryStream(index, value, length);
}
}
public void setBinaryStream(String name, InputStream value, long length) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setBinaryStream(index, value, length);
}
}
public void setBlob(String name, Blob value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setBlob(index, value);
}
}
public void setBlob(String name, InputStream value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setBlob(index, value);
}
}
public void setBlob(String name, InputStream value, long length) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setBlob(index, value, length);
}
}
public void setBoolean(String name, boolean value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setBoolean(index, value);
}
}
public void setByte(String name, byte value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setByte(index, value);
}
}
public void setBytes(String name, byte[] value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setBytes(index, value);
}
}
public void setCharacterStream(String name, Reader value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setCharacterStream(index, value);
}
}
public void setCharacterStream(String name, Reader value, int length) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setCharacterStream(index, value, length);
}
}
public void setCharacterStream(String name, Reader value, long length) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setCharacterStream(index, value, length);
}
}
public void setClob(String name, Clob value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setClob(index, value);
}
}
public void setClob(String name, Reader value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setClob(index, value);
}
}
public void setClob(String name, Reader value, long length) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setClob(index, value, length);
}
}
public void setDate(String name, Date value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setDate(index, value);
}
}
public void setDate(String name, Date value, Calendar cal) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setDate(index, value, cal);
}
}
public void setDouble(String name, double value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setDouble(index, value);
}
}
public void setFloat(String name, float value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setFloat(index, value);
}
}
public void setInt(String name, int value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setInt(index, value);
}
}
public void setLong(String name, long value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setLong(index, value);
}
}
public void setNCharacterStream(String name, Reader value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setNCharacterStream(index, value);
}
}
public void setNCharacterStream(String name, Reader value, long length) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setNCharacterStream(index, value, length);
}
}
public void setNClob(String name, NClob value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setNClob(index, value);
}
}
public void setNClob(String name, Reader value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setNClob(index, value);
}
}
public void setNClob(String name, Reader value, long length) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setNClob(index, value, length);
}
}
public void setNString(String name, String value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setNString(index, value);
}
}
public void setNull(String name, int sqlType) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setNull(index, sqlType);
}
}
public void setObject(String name, Object value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setObject(index, value);
}
}
public void setObject(String name, Object value, int targetSqlType) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setObject(index, value, targetSqlType);
}
}
public void setObject(String name, Object value, int targetSqlType, int scaleOrLength) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setObject(index, value, targetSqlType, scaleOrLength);
}
}
public void setRef(String name, Ref value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setRef(index, value);
}
}
public void setRowId(String name, RowId value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setRowId(index, value);
}
}
public void setShort(String name, short value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setShort(index, value);
}
}
public void setSQLXML(String name, SQLXML value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setSQLXML(index, value);
}
}
public void setString(String name, String value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setString(index, value);
}
}
public void setTime(String name, Time value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setTime(index, value);
}
}
public void setTime(String name, Time value, Calendar cal) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setTime(index, value, cal);
}
}
public void setTimestamp(String name, Timestamp value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setTimestamp(index, value);
}
}
public void setTimestamp(String name, Timestamp value, Calendar cal) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setTimestamp(index, value, cal);
}
}
@SuppressWarnings("deprecation")
public void setUnicodeStream(String name, InputStream value, int length) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setUnicodeStream(index, value, length);
}
}
public void setURL(String name, URL value) throws SQLException {
for (Integer index : getIndexes(name)) {
ps.setURL(index, value);
}
}
}