package org.nutz.dao.impl.sql;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.SQLException;
import java.util.List;
import org.nutz.castor.Castors;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Entity;
import org.nutz.dao.impl.entity.field.NutMappingField;
import org.nutz.dao.jdbc.JdbcExpert;
import org.nutz.dao.jdbc.Jdbcs;
import org.nutz.dao.jdbc.ValueAdaptor;
import org.nutz.dao.sql.DaoStatement;
import org.nutz.dao.sql.SqlContext;
import org.nutz.dao.sql.SqlType;
import org.nutz.dao.util.Daos;
import org.nutz.dao.util.blob.SimpleBlob;
import org.nutz.dao.util.blob.SimpleClob;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
public abstract class NutStatement implements DaoStatement {
private static final long serialVersionUID = 1L;
private Entity<?> entity;
private SqlContext context;
private SqlType sqlType;
protected JdbcExpert expert;
public NutStatement() {
this.context = new SqlContext();
}
public boolean isSelect() {
return SqlType.SELECT == sqlType;
}
public boolean isUpdate() {
return SqlType.UPDATE == sqlType;
}
public boolean isDelete() {
return SqlType.DELETE == sqlType;
}
public boolean isInsert() {
return SqlType.INSERT == sqlType;
}
public boolean isCreate() {
return SqlType.CREATE == sqlType;
}
public boolean isDrop() {
return SqlType.DROP == sqlType;
}
public boolean isRun() {
return SqlType.RUN == sqlType;
}
public boolean isAlter() {
return SqlType.ALTER == sqlType;
}
public boolean isExec() {
return SqlType.EXEC == sqlType;
}
public boolean isCall() {
return SqlType.CALL == sqlType;
}
public boolean isOther() {
return SqlType.OTHER == sqlType;
}
public Entity<?> getEntity() {
return entity;
}
public DaoStatement setEntity(Entity<?> entity) {
this.entity = entity;
return this;
}
public SqlContext getContext() {
return context;
}
public void setContext(SqlContext context) {
this.context = context;
}
public SqlType getSqlType() {
return sqlType;
}
public DaoStatement setSqlType(SqlType sqlType) {
this.sqlType = sqlType;
return this;
}
public Object getResult() {
return context.getResult();
}
// TODO 是不是太暴力了涅~~~ --> 不是一般的暴力!!
@SuppressWarnings("unchecked")
public <T> List<T> getList(Class<T> classOfT) {
Object re = getResult();
if (re == null)
return null;
if (re.getClass().isArray()) {
return Lang.array2list(re, classOfT);
}
return (List<T>) re;// TODO 考虑先遍历转换一次
}
public <T> T getObject(Class<T> classOfT) {
return Castors.me().castTo(getResult(), classOfT);
}
public int getInt() {
return getNumber().intValue();
}
public int getInt(int defaultValue) {
Number re = getNumber();
if (re == null)
return defaultValue;
return re.intValue();
}
public long getLong() {
return getNumber().longValue();
}
public long getLong(long defaultValue) {
Number re = getNumber();
if (re == null)
return defaultValue;
return re.longValue();
}
public double getDouble() {
return getNumber().doubleValue();
}
public double getDouble(double defaultValue) {
Number re = getNumber();
if (re == null)
return defaultValue;
return re.doubleValue();
}
public float getFloat() {
return getNumber().floatValue();
}
public float getFloat(float defaultValue) {
Number re = getNumber();
if (re == null)
return defaultValue;
return re.floatValue();
}
public Number getNumber() {
return getObject(Number.class);
}
public String getString() {
return getObject(String.class);
}
public boolean getBoolean() {
return getObject(Boolean.class);
}
public int getUpdateCount() {
return context.getUpdateCount();
}
public String forPrint() {
String sql = this.toPreparedStatement();
StringBuilder sb = new StringBuilder(sql);
// 准备打印参数表
Object[][] mtrx = this.getParamMatrix();
SqlFormat format = Daos.getSqlFormat().clone();
if (null != mtrx && mtrx.length > 0 && mtrx[0].length > 0) {
if (format.isPrintParam()) {
// 计算每列最大宽度,以及获取列参数的内容
int[] maxes = new int[mtrx[0].length];
String[][] sss = new String[mtrx.length][mtrx[0].length];
for (int row = 0; row < mtrx.length; row++)
for (int col = 0; col < mtrx[0].length; col++) {
String s = param2String(mtrx[row][col]);
maxes[col] = Math.max(maxes[col], s.length());
if (format.getParamLengthLimit() > 0 && maxes[col] > format.getParamLengthLimit())
maxes[col] = format.getParamLengthLimit();
sss[row][col] = s;
}
// 输出表头
sb.append("\n |");
for (int i = 0; i < mtrx[0].length; i++) {
sb.append(' ');
sb.append(Strings.alignRight("" + (i + 1), maxes[i], ' '));
sb.append(" |");
}
// 输出分隔线
sb.append("\n |");
for (int i = 0; i < mtrx[0].length; i++) {
sb.append('-');
sb.append(Strings.dup('-', maxes[i]));
sb.append("-|");
}
// 输出内容到字符串缓冲区
int maxRow = mtrx.length > format.getParamRowLimit() ? format.getParamRowLimit() : mtrx.length;
for (int row = 0; row < maxRow; row++) {
sb.append("\n |");
for (int col = 0; col < mtrx[0].length; col++) {
sb.append(' ');
sb.append(sss[row][col].length() > maxes[col] ? Strings.brief(sss[row][col], maxes[col] - 5) : Strings.alignLeft(sss[row][col], maxes[col], ' '));
sb.append(" |");
}
}
if (maxRow != mtrx.length)
sb.append("\n -- Only display first " + maxRow + " lines , don't show the remaining record(count=" + mtrx.length + ")");
}
if (format.isPrintExample()) {
// 输出可执行的 SQL 语句, TODO 格式非常不好看!!如果要复制SQL,很麻烦!!!
sb.append("\n For example:> \"");
sb.append(toExampleStatement(mtrx, sql));
sb.append('"');
}
}
return sb.toString();
}
protected String toExampleStatement(Object[][] mtrx, String sql) {
return toStatement(mtrx, sql);
}
protected String toStatement(Object[][] mtrx, String sql) {
StringBuilder sb = new StringBuilder();
String[] ss = sql.split("[?]");
int i = 0;
if (mtrx.length > 0) {
for (; i < mtrx[0].length; i++) {
sb.append(ss[i]);
Object obj = param2obj(mtrx[0][i]);
sb.append(Sqls.formatFieldValue(obj));
}
}
for (; i < ss.length; i++)
sb.append(ss[i]);
return sb.toString();
}
protected String param2String(Object obj) {
obj = param2obj(obj);
return obj instanceof String ? (String)obj : Castors.me().castToString(obj);
}
protected Object param2obj(Object obj) {
if (obj == null)
return "NULL";
if (obj instanceof CharSequence)
return obj.toString();
else {
if (obj instanceof Blob) {
Blob blob = (Blob) obj;
if (blob instanceof SimpleBlob) {
try {
return "*Blob(len=" + blob.length() + ")";
}
catch (SQLException e) {}// 不可能
}
return "*Blob(hascode=" + blob.hashCode() + ")";
} else if (obj instanceof Clob) {
Clob clob = (Clob) obj;
if (clob instanceof SimpleClob) {
try {
return "*Clob(len=" + clob.length() + ")";
}
catch (SQLException e) {}// 不可能
}
return "*Clob(" + clob.hashCode() + ")";
} else if (obj instanceof byte[] || obj instanceof char[]) {
return "*"+(obj instanceof byte[] ? "byte" : "char" ) + "[len=" + Array.getLength(obj) + "]";
} else if (obj instanceof InputStream) {
try {
obj = "*InputStream[len=" + ((InputStream) obj).available() + "]";
}
catch (IOException e) {}
} else if (obj instanceof Reader) {
obj = "*Reader@" + obj.hashCode();
}
return obj;
}
}
public void forceExecQuery() {
this.sqlType = SqlType.SELECT;
}
public boolean isForceExecQuery() {
return isSelect();
}
public String toString() {
return toStatement(this.getParamMatrix(), this.toPreparedStatement());
}
public void setExpert(JdbcExpert expert) {
this.expert = expert;
}
protected ValueAdaptor getAdapterBy(Object value) {
if (value == null)
return Jdbcs.Adaptor.asNull;
if (expert == null)
return Jdbcs.getAdaptorBy(value);
NutMappingField mf = new NutMappingField(entity);
mf.setType(value.getClass());
Jdbcs.guessEntityFieldColumnType(mf);
return expert.getAdaptor(mf);
}
}