package org.test4j.module.dbfit.model;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.test4j.module.database.environment.normalise.TypeNormaliser;
import org.test4j.module.database.environment.normalise.TypeNormaliserFactory;
import fit.Fixture;
@SuppressWarnings({ "rawtypes" })
public class DbParameterAccessor extends DbTypeAdapter {
public static final int RETURN_VALUE = 0;
public static final int INPUT = 1;
public static final int OUTPUT = 2;
public static final int INPUT_OUTPUT = 3;
public static final int SEQUENCE = 4;
private int index; // index in effective sql statement (not necessarily the
// same as position below)
private int direction;
private String name;
private String placeholder = "?"; // default insert place holder
private int sqlType;
private int position; // zero-based index of parameter in procedure or
// column in table
public static Object normaliseValue(Object currVal) throws Exception {
if (currVal == null) {
return null;
}
TypeNormaliser tn = TypeNormaliserFactory.getNormaliser(currVal.getClass());
if (tn != null) {
currVal = tn.normalise(currVal);
}
return currVal;
}
public DbParameterAccessor(DbParameterAccessor acc) {
this.name = acc.name;
this.direction = acc.direction;
this.sqlType = acc.sqlType;
this.type = acc.type;
this.position = acc.position;
}
public DbParameterAccessor(String name, int direction, int sqlType, Class javaType, int position) {
this.name = name;
this.direction = direction;
this.sqlType = sqlType;
this.type = javaType;
this.position = position;
}
public int getSqlType() {
return sqlType;
}
/**
* One of the constants from this class declaring whether the param is
* input, output or a return value. JDBC does not have a return value
* parameter directions, so a new constant list had to be introduced public
* static final int RETURN_VALUE=0; public static final int INPUT=1; public
* static final int OUTPUT=2; public static final int INPUT_OUTPUT=3;
*/
public int getDirection() {
return direction;
}
public String getName() {
return name;
}
public void setDirection(int direction) {
this.direction = direction;
}
/**
* prepareStament语句的占位符,默认值是"?"
*
* @return
*/
public String getPlaceholder() {
return placeholder;
}
public void setPlaceholder(String placeholder) {
this.placeholder = placeholder;
}
// really ugly, but a hack to support mysql, because it will not execute
// inserts with a callable statement
private CallableStatement convertStatementToCallable() throws SQLException {
if (cs instanceof CallableStatement) {
return (CallableStatement) cs;
}
throw new SQLException("This operation requires a callable statement instead of " + cs.getClass().getName());
}
/*******************************************/
private PreparedStatement cs;
public void bindTo(Fixture f, PreparedStatement cs, int ind) throws SQLException {
this.cs = cs;
this.fixture = f;
this.index = ind;
boolean tocall = direction == DbParameterAccessor.OUTPUT || direction == DbParameterAccessor.RETURN_VALUE
|| direction == DbParameterAccessor.INPUT_OUTPUT;
if (tocall) {
convertStatementToCallable().registerOutParameter(ind, getSqlType());
}
}
public void set(Object value) throws Exception {
if (direction == OUTPUT || direction == RETURN_VALUE) {
throw new UnsupportedOperationException("Trying to set value of output parameter " + name);
}
if (value instanceof InputStream) {
InputStream is = (InputStream) value;
cs.setBinaryStream(index, is, is.available());
} else {
cs.setObject(index, value);
}
}
public Object get() throws IllegalAccessException, InvocationTargetException {
try {
if (direction == INPUT) {
String err = "Trying to get value of input parameter " + name;
throw new UnsupportedOperationException(err);
}
CallableStatement statment = convertStatementToCallable();
Object o = statment.getObject(index);
return normaliseValue(o);
} catch (Exception sqle) {
throw new InvocationTargetException(sqle);
}
}
/**
* Zero-based column or parameter position in a query, table or stored proc
*/
public int getPosition() {
return position;
}
}