package com.meidusa.amoeba.route;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.meidusa.amoeba.net.DatabaseConnection;
import com.meidusa.amoeba.parser.Parser;
import com.meidusa.amoeba.parser.dbobject.Column;
import com.meidusa.amoeba.parser.dbobject.Schema;
import com.meidusa.amoeba.parser.dbobject.Table;
import com.meidusa.amoeba.parser.function.LastInsertId;
import com.meidusa.amoeba.parser.statement.AbstractStatement;
import com.meidusa.amoeba.parser.statement.DMLStatement;
import com.meidusa.amoeba.parser.statement.PropertyStatement;
import com.meidusa.amoeba.parser.statement.SelectStatement;
import com.meidusa.amoeba.parser.statement.ShowStatement;
import com.meidusa.amoeba.parser.statement.Statement;
import com.meidusa.amoeba.sqljep.function.Comparative;
import com.meidusa.amoeba.util.StringUtil;
import com.meidusa.amoeba.util.ThreadLocalMap;
public abstract class SqlBaseQueryRouter extends AbstractQueryRouter<DatabaseConnection,SqlQueryObject> {
private Lock mapLock = new ReentrantLock(false);
private static String DIAGONAL = new String(new char[]{(char)0x5c,(char)0x5c});
private static String DOT = new String(new char[]{(char)0x5c,(char)0x27});
private boolean replaceEscapeSymbol = true;
public boolean isReplaceEscapeSymbol() {
return replaceEscapeSymbol;
}
public void setReplaceEscapeSymbol(boolean replaceEscapeSymbol) {
this.replaceEscapeSymbol = replaceEscapeSymbol;
}
protected void beforeSelectPool(DatabaseConnection connection, SqlQueryObject queryObject){
Statement statment = parseStatement(connection,queryObject.sql);
if(statment instanceof DMLStatement){
DMLStatement dmlStatment = ((DMLStatement)statment);
queryObject.isRead = dmlStatment.isReadStatement();
}
ThreadLocalMap.put(_CURRENT_QUERY_OBJECT_, queryObject);
}
@Override
protected Map<Table, Map<Column, Comparative>> evaluateTable(DatabaseConnection connection,SqlQueryObject queryObject) {
Statement statment = parseStatement(connection,queryObject.sql);
Map<Table, Map<Column, Comparative>> tables = null;
if(statment instanceof DMLStatement){
tables = ((DMLStatement)statment).evaluate(queryObject.parameters);
return tables;
}else if (statment instanceof PropertyStatement) {
if (logger.isDebugEnabled()) {
logger.debug("ShowStatment:[" + queryObject.sql + "]");
}
setProperty(connection, (PropertyStatement) statment, queryObject);
return null;
}else if (statment instanceof ShowStatement) {
if (logger.isDebugEnabled()) {
logger.debug("ShowStatment:[" + queryObject.sql + "]");
}
AbstractStatement ast = (ShowStatement)statment;
if(ast.getTables() != null){
tables = new HashMap<Table, Map<Column, Comparative>>();
for(Table table:ast.getTables()){
tables.put(table, null);
}
}else{
tables.put(null, null);
}
return tables;
}
return null;
}
protected String amoebaRouterSql(String sql){
sql = sql.trim();
int sIndex = sql.indexOf("@amoeba");
if(sIndex >0){
String subSql = sql.substring(sIndex);
int lIndex = subSql.indexOf("*/");
if(lIndex>0 ){
subSql = subSql.substring(0,lIndex);
int pIndex = subSql.lastIndexOf("]");
lIndex = subSql.lastIndexOf(")");
if(pIndex < lIndex){
subSql = subSql.substring(0,lIndex+1);
}else{
subSql = subSql.substring(0,pIndex+1) +" " + sql ;
}
sql = subSql;
}
}
sql = sql.trim();
if(replaceEscapeSymbol){
sql = StringUtil.replace(sql,DIAGONAL,"");
sql = StringUtil.replace(sql,DOT,"");
}
return sql;
}
public Statement parseStatement(DatabaseConnection connection, String sql) {
if(sql == null) return null;
Statement statment = null;
String defaultSchema = (connection == null || StringUtil.isEmpty(connection.getSchema())) ? null : connection.getSchema();
long sqlKey = ((long) sql.length() << 32) | (long) (defaultSchema != null ? (defaultSchema.hashCode() ^ sql.hashCode()) : sql.hashCode());
mapLock.lock();
try {
statment = (Statement) map.get(sqlKey);
} finally {
mapLock.unlock();
}
if (statment == null) {
synchronized (sql) {
statment = (Statement) map.get(sqlKey);
if (statment != null) {
return statment;
}
Parser parser = newParser(amoebaRouterSql(sql));
parser.setFunctionMap(this.functionMap);
if (defaultSchema != null) {
Schema schema = new Schema();
schema.setName(defaultSchema);
parser.setDefaultSchema(schema);
}
try {
statment = parser.doParse();
if(statment instanceof SelectStatement){
SelectStatement st = (SelectStatement)statment;
if(st.getTables() == null || st.getTables().length == 0){
Boolean queryInsertId = (Boolean)ThreadLocalMap.get(LastInsertId.class.getName());
if(queryInsertId != null && queryInsertId.booleanValue()){
st.setQueryLastInsertId(true);
}
}
}
mapLock.lock();
if(statment instanceof DMLStatement){
((DMLStatement)statment).setSql(sql);
}
try {
map.put(sqlKey, statment);
} finally {
mapLock.unlock();
}
} catch (Error e) {
logger.error(sql, e);
return null;
}catch(Exception e){
logger.error(sql, e);
return null;
}
}
}
return statment;
}
protected void setProperty(DatabaseConnection connection,
Statement statment, SqlQueryObject queryObject) {
}
public int parseParameterCount(DatabaseConnection connection, String sql) {
Statement statment = parseStatement(connection, sql);
if (statment != null) {
return statment.getParameterCount();
} else {
return 0;
}
}
public abstract Parser newParser(String sql);
protected static String amoebaRouterSql1(String sql){
sql = sql.trim();
int sIndex = sql.indexOf("@amoeba");
if(sIndex >0){
String subSql = sql.substring(sIndex);
int lIndex = subSql.indexOf("*/");
if(lIndex>0 ){
subSql = subSql.substring(0,lIndex);
int pIndex = subSql.lastIndexOf("]");
lIndex = subSql.lastIndexOf(")");
if(pIndex < lIndex){
subSql = subSql.substring(0,lIndex+1);
}else{
subSql = subSql.substring(0,pIndex+1) +" " + sql ;
}
sql = subSql;
}
}
sql = sql.trim();
if(true){
sql = StringUtil.replace(sql,DIAGONAL,"");
sql = StringUtil.replace(sql,DOT,"");
}
return sql;
}
public static void main(String[] args){
String sql="select /* @amoeba('select * from order where year=2012') */ * from order wherer uid=?";
System.out.println(amoebaRouterSql1(sql));
}
}