/*
* Created on Oct 17, 2003
*/
package cyrille.sql.wrapper.logging;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.StringTokenizer;
import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang.time.DateFormatUtils;
/**
* @author <a href="mailto:cleclerc@pobox.com">Cyrille Le Clerc </a>
*/
public class PreparedStatementToStringBuilder {
private final static String DATE_FORMAT_PATTERN = "yyyy-MM-dd";
private static final char SQL_PARAMETER_CHAR = '?';
private static final String SQL_PARAMETER_STRING = "?";
private final static String TIME_FORMAT_PATTERN = "hh:mm:ss";
private final static String TIMESTAMP_FORMAT_PATTERN = "yyyy-MM-dd hh:mm:ss";
/**
* 1 based array to fit PreparementStatements 1 based parameters indexes
*/
private String[] parameters;
private int parametersCount;
private String[] splitSql;
private String sql;
/**
* @param sql
*/
public PreparedStatementToStringBuilder(String sql) {
super();
if (sql == null) {
throw new NullArgumentException("sql");
}
this.sql = sql;
// (+ 1) because array is 1 based
this.parametersCount = count(sql, SQL_PARAMETER_CHAR) + 1;
this.parameters = new String[this.parametersCount];
}
private void checkIndexOutOfBound(int idx) {
if (idx >= this.parametersCount) {
throw new IndexOutOfBoundsException("There is no parameter for index " + idx + " for the sql request " + this.sql);
}
}
/**
* Optimized (char instead of String) count implementation
*
* @param str
* @param chr
* @return number of occurences of the given <code>char</code> in the <code>String</code>
*
*/
private int count(String str, char chr) {
int count = 0;
int length = str.length();
for (int i = 0; i < length; i++) {
if (str.charAt(i) == chr) {
count++;
}
}
return count;
}
public void setNullParameter(int idx) {
checkIndexOutOfBound(idx);
this.parameters[idx] = null;
}
public void setParameter(int idx, boolean value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = String.valueOf(value);
}
public void setParameter(int idx, Date value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = "TO_DATE('" + DateFormatUtils.format(value, DATE_FORMAT_PATTERN) + "', 'YYYY-MM-DD')";
}
public void setParameter(int idx, double value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = String.valueOf(value);
}
public void setParameter(int idx, float value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = String.valueOf(value);
}
public void setParameter(int idx, int value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = String.valueOf(value);
}
public void setParameter(int idx, long value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = String.valueOf(value);
}
public void setParameter(int idx, Number value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = String.valueOf(value);
}
public void setParameter(int idx, Object value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = "[" + String.valueOf(value) + "]";
}
public void setParameter(int idx, String value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = "'" + value + "'";
}
public void setParameter(int idx, Time value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = "TO_DATE('" + DateFormatUtils.format(value, TIME_FORMAT_PATTERN) + "', 'HH24:MI:SS')";
}
public void setParameter(int idx, Timestamp value) {
checkIndexOutOfBound(idx);
this.parameters[idx] = "TO_DATE('" + DateFormatUtils.format(value, TIMESTAMP_FORMAT_PATTERN) + "', 'YYYY-MM-DD HH24:MI:SS')";
}
/**
* Returns a filled sql statement
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
// Lazy split
if (this.splitSql == null) {
StringTokenizer tkSql = new StringTokenizer(this.sql, SQL_PARAMETER_STRING, true);
this.splitSql = new String[tkSql.countTokens()];
int i = 0;
while (tkSql.hasMoreElements()) {
this.splitSql[i] = tkSql.nextToken();
i++;
}
}
StringBuffer sb = new StringBuffer();
int parameterIdx = 1;
for (String element : this.splitSql) {
if (SQL_PARAMETER_STRING.equals(element)) {
sb.append(this.parameters[parameterIdx]);
parameterIdx++;
} else {
sb.append(element);
}
}
return sb.toString();
}
}