package com.meidusa.amoeba.sqljep.function;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import com.meidusa.amoeba.context.ProxyRuntimeContext;
import com.meidusa.amoeba.net.poolable.ObjectPool;
import com.meidusa.amoeba.sqljep.ASTFunNode;
import com.meidusa.amoeba.sqljep.JepRuntime;
import com.meidusa.amoeba.sqljep.ParseException;
import com.meidusa.amoeba.util.Initialisable;
import com.meidusa.amoeba.util.InitialisationException;
import com.meidusa.amoeba.util.ThreadLocalMap;
/**
* ��ʹ��@see JdbcConnectionFactory �ṩ��pool
*
* @author struct
* @author hexianmao
*/
public class SqlQueryCommand extends PostfixCommand implements Initialisable {
private static Logger logger = Logger.getLogger(SqlQueryCommand.class);
private String sql;
private String poolName;
private boolean threadLocalCache = false;
private int parameterSize = 1;
public boolean isThreadLocalCache() {
return threadLocalCache;
}
public void setSql(String sql) {
this.sql = sql;
}
public void setPoolName(String poolName) {
this.poolName = poolName;
}
public void setThreadLocalCache(boolean threadLocalCache) {
this.threadLocalCache = threadLocalCache;
}
@Override
public Comparable<?>[] evaluate(ASTFunNode node, JepRuntime runtime) throws ParseException {
node.childrenAccept(runtime.ev, null);
Comparable<?>[] parameters = null;
parameters = new Comparable<?>[parameterSize];
for (int i = parameterSize - 1; i >= 0; i--) {
parameters[i] = runtime.stack.pop();
}
return parameters;
}
private Map<String, Object> query(Comparable<?>[] parameters) {
ObjectPool pool = ProxyRuntimeContext.getInstance().getPoolMap().get(poolName);
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
Map<String, Object> columnMap = null;
conn = (Connection) pool.borrowObject();
st = conn.prepareStatement(sql);
if (parameters != null) {
for (int i = 0; i < parameters.length; i++) {
if (parameters[i] instanceof Comparative) {
st.setObject(i + 1, ((Comparative) parameters[i]).getValue());
} else {
st.setObject(i + 1, parameters[i]);
}
}
}
rs = st.executeQuery();
if (rs.next()) {
columnMap = new HashMap<String, Object>();
ResultSetMetaData metaData = rs.getMetaData();
for (int i = 1; i <= metaData.getColumnCount(); i++) {
String columnName = null;
String label = metaData.getColumnLabel(i);
if (label != null) {
columnName = label.toLowerCase();
} else {
columnName = metaData.getColumnName(i).toLowerCase();
}
Object columnValue = rs.getObject(i);
columnMap.put(columnName, columnValue);
if (logger.isDebugEnabled()) {
logger.debug("[columnName]:" + columnName + " [columnValue]:" + columnValue + " [args]:" + Arrays.toString(parameters));
}
}
} else {
logger.error("no result!sql:[" + sql + "], args:" + Arrays.toString(parameters));
}
return columnMap;
} catch (Exception e) {
logger.error("execute sql error :" + sql, e);
return null;
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e1) {
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e1) {
}
}
if (conn != null) {
try {
pool.returnObject(conn);
} catch (Exception e) {
}
}
}
}
@Override
public int getNumberOfParameters() {
return parameterSize;
}
public void init() throws InitialisationException {
parameterSize = ProxyRuntimeContext.getInstance().getQueryRouter().parseParameterCount(null, sql) + 1;
}
@SuppressWarnings("unchecked")
public Comparable<?> getResult(Comparable<?>... comparables) throws ParseException {
String returnColumnName = null;
returnColumnName = comparables[0].toString().toLowerCase();
Map<String, Object> result = null;
Comparable<?>[] parameters = new Comparable<?>[comparables.length - 1];
if (isThreadLocalCache()) {
int threadLocalKey = this.hashCode();
if (parameterSize > 1) {
int hash = this.hashCode();
for (int i = 0; i < parameters.length; i++) {
parameters[i] = comparables[i + 1];
hash ^= parameters[i].hashCode() << (i + 1);
}
threadLocalKey = threadLocalKey ^ hash;
}
result = (Map<String, Object>) ThreadLocalMap.get(threadLocalKey);
if (result == null) {
if (!ThreadLocalMap.containsKey(threadLocalKey)) {
result = query(parameters);
ThreadLocalMap.put(threadLocalKey, result);
}
}
} else {
result = query(parameters);
}
if (result == null) {
return (null);
} else {
return ((Comparable<?>) result.get(returnColumnName));
}
}
}