/*
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
*
* 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 org.jivesoftware.database;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Allows PreparedStatement information to be cached. A prepared statement consists of
* a SQL statement containing bind variables as well as variable values. For example,
* the SQL statement <tt>"SELECT * FROM person WHERE age > ?"</tt> would have the integer
* variable <tt>18</tt> (which replaces the "?" chracter) to find all adults. This class
* encapsulates both the SQL string and bind variable values so that actual
* PreparedStatement can be created from that information later.
*
* @author Matt Tucker
*/
public class CachedPreparedStatement {
private static final Logger Log = LoggerFactory.getLogger(CachedPreparedStatement.class);
private String sql;
private List<Object> params;
private List<Integer> types;
/**
* Constructs a new CachedPreparedStatement.
*/
public CachedPreparedStatement() {
params = new ArrayList<>();
types = new ArrayList<>();
}
/**
* Constructs a new CachedPreparedStatement.
*
* @param sql the SQL.
*/
public CachedPreparedStatement(String sql) {
this();
setSQL(sql);
}
/**
* Returns the SQL.
*
* @return the SQL.
*/
public String getSQL() {
return sql;
}
/**
* Sets the SQL.
*
* @param sql the SQL.
*/
public void setSQL(String sql) {
this.sql = sql;
}
/**
* Adds a boolean parameter to the prepared statement.
*
* @param value the boolean value.
*/
public void addBoolean(boolean value) {
params.add(value);
types.add(Types.BOOLEAN);
}
/**
* Adds an integer parameter to the prepared statement.
*
* @param value the int value.
*/
public void addInt(int value) {
params.add(value);
types.add(Types.INTEGER);
}
/**
* Adds a long parameter to the prepared statement.
*
* @param value the long value.
*/
public void addLong(long value) {
params.add(value);
types.add(Types.BIGINT);
}
/**
* Adds a String parameter to the prepared statement.
*
* @param value the String value.
*/
public void addString(String value) {
params.add(value);
types.add(Types.VARCHAR);
}
/**
* Sets all parameters on the given PreparedStatement. The standard code block
* for turning a CachedPreparedStatement into a PreparedStatement is as follows:
*
* <pre>
* PreparedStatement pstmt = con.prepareStatement(cachedPstmt.getSQL());
* cachedPstmt.setParams(pstmt);
* </pre>
*
* @param pstmt the prepared statement.
* @throws java.sql.SQLException if an SQL Exception occurs.
*/
public void setParams(PreparedStatement pstmt) throws SQLException {
for (int i=0; i<params.size(); i++) {
Object param = params.get(i);
int type = types.get(i);
// Set param, noting fact that params start at 1 and not 0.
switch(type) {
case Types.INTEGER:
pstmt.setInt(i+1, (Integer)param);
break;
case Types.BIGINT:
pstmt.setLong(i+1, (Long)param);
break;
case Types.VARCHAR:
pstmt.setString(i+1, (String)param);
break;
case Types.BOOLEAN:
pstmt.setBoolean(i+1, (Boolean)param);
}
}
}
@Override
public boolean equals(Object object) {
if (object == null) {
return false;
}
if (!(object instanceof CachedPreparedStatement)) {
return false;
}
if (this == object) {
return true;
}
CachedPreparedStatement otherStmt = (CachedPreparedStatement)object;
return (sql == null && otherStmt.sql == null) || sql != null && sql.equals(otherStmt.sql)
&& types.equals(otherStmt.types) && params.equals(otherStmt.params);
}
@Override
public int hashCode() {
int hashCode = 1;
if (sql != null) {
hashCode += sql.hashCode();
}
hashCode = hashCode * 31 + types.hashCode();
hashCode = hashCode * 31 + params.hashCode();
return hashCode;
}
@Override
public String toString() {
String toStringSql = sql;
try {
int index = toStringSql.indexOf('?');
int count = 0;
while (index > -1) {
Object param = params.get(count);
int type = types.get(count);
String val = null;
// Get param
switch(type) {
case Types.INTEGER:
val = "" + param;
break;
case Types.BIGINT:
val = "" + param;
break;
case Types.VARCHAR:
val = '\'' + (String) param + '\'';
break;
case Types.BOOLEAN:
val = "" + param;
}
toStringSql = toStringSql.substring(0, index) + val +
((index == toStringSql.length() -1) ? "" : toStringSql.substring(index + 1));
index = toStringSql.indexOf('?', index + val.length());
count++;
}
}
catch (Exception e) {
Log.error(e.getMessage(), e);
}
return "CachedPreparedStatement{ sql=" + toStringSql + '}';
}
}