/**
* Alipay.com Inc.
* Copyright (c) 2004-2012 All Rights Reserved.
*/
package com.alipay.zdal.client.controller;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.alipay.zdal.client.RouteCondition;
import com.alipay.zdal.client.dispatcher.DispatcherResult;
import com.alipay.zdal.client.dispatcher.EXECUTE_PLAN;
import com.alipay.zdal.client.dispatcher.Matcher;
import com.alipay.zdal.client.dispatcher.Result;
import com.alipay.zdal.client.dispatcher.SqlDispatcher;
import com.alipay.zdal.client.dispatcher.impl.DatabaseAndTablesDispatcherResultImp;
import com.alipay.zdal.client.util.condition.DBSelectorRouteCondition;
import com.alipay.zdal.client.util.condition.DummySqlParcerResult;
import com.alipay.zdal.client.util.condition.JoinCondition;
import com.alipay.zdal.client.util.condition.RuleRouteCondition;
import com.alipay.zdal.common.DBType;
import com.alipay.zdal.common.exception.checked.ZdalCheckedExcption;
import com.alipay.zdal.common.sqljep.function.Comparative;
import com.alipay.zdal.parser.SQLParser;
import com.alipay.zdal.parser.output.OutputHandlerConsist;
import com.alipay.zdal.parser.result.SqlParserResult;
import com.alipay.zdal.parser.sqlobjecttree.ComparativeMapChoicer;
import com.alipay.zdal.parser.visitor.OrderByEle;
import com.alipay.zdal.rule.LogicTableRule;
import com.alipay.zdal.rule.bean.LogicTable;
import com.alipay.zdal.rule.bean.ZdalRoot;
import com.alipay.zdal.rule.ruleengine.entities.retvalue.TargetDB;
/**
* ��Ҫ����root���õ���Ҫ����Ϣ��Ȼ����matcher����ƥ�䡣
*
* �����Ҫ�Ľ��
*
* @author xiaoqing.zhouxq
*
*/
public class SpringBasedDispatcherImpl implements SqlDispatcher {
/**
* ��Ҫע���sql ����������
*/
private SQLParser parser = null;
/**
* Zdal�ĸ��ڵ�
*/
ZdalRoot root;
private final Matcher matcher = new SpringBasedRuleMatcherImpl();
/**
* ������������Ͷ���
*/
public final static OutputHandlerConsist consist = new OutputHandlerConsist();
/**
* @see com.alipay.zdal.client.dispatcher.SqlDispatcher#getDBAndTables(java.lang.String, java.util.List)
*/
public DispatcherResult getDBAndTables(String sql, List<Object> args)
throws ZdalCheckedExcption {
DBType dbType = getDBType();
SqlParserResult sqlParserResult = parser.parse(sql, dbType);
// TODO: ������ң�Ҳ��������sql�����һ�б�����Ȼ��ȥ������
// �鿴�ĸ�����match�������һ����ʾ���������
// ����ж����ʾҪjoin��join������������ǿ���֧�ֵ�û��֧�ֵ�
String logicTableName = sqlParserResult.getTableName();
int index = logicTableName.indexOf(".");
if (index >= 0) {
logicTableName = logicTableName.substring(index + 1);
}
// ��root�������õ�����
LogicTableRule rule = root.getLogicTableMap(logicTableName);
if (rule == null) {
throw new IllegalArgumentException("δ���ҵ���Ӧ����,����:" + logicTableName);
}
boolean isAllowReverseOutput = rule.isAllowReverseOutput();
MatcherResult matcherResult = matcher.match(sqlParserResult.getComparativeMapChoicer(),
args, rule);
return getDispatcherResult(matcherResult, sqlParserResult, args, dbType, rule
.getUniqueColumns(), isAllowReverseOutput, true);
}
//TODO:�Ժ��Ǽ�һ��sql��״̬���ͱ�������sql��ִ�����ԣ������Ͳ������еط�����һ����
// private boolean validIsSingleDBandSingleTable(List<TargetDB> targetDB){
//
// }
/**
* ����ƥ�������������ո�TStatement�Ľ����ƴװ,��ͬ��matcher���Թ���
*
* @param matcherResult
* @return
*/
protected DispatcherResult getDispatcherResult(MatcherResult matcherResult,
SqlParserResult sqlParserResult,
List<Object> args, DBType dbType,
List<String> uniqueColumnSet,
boolean isAllowReverseOutput, boolean isSqlParser) {
DispatcherResultImp dispatcherResult = getTargetDatabaseMetaDataBydatabaseGroups(
matcherResult.getCalculationResult(), sqlParserResult, args, isAllowReverseOutput);
//��Ȼ�ж�sql�����������Ӧ�÷ŵ����������Ϊ����û��Ҫ�����˹����Ժ�ͷ���TargetDBList����ഫ��һ��
//�������һ�ξͿ�����
ControllerUtils.buildExecutePlan(dispatcherResult, matcherResult.getCalculationResult());
validGroupByFunction(sqlParserResult, dispatcherResult);
//TODO:reverseoutputҲ����ʹ������Ľ��
if (isSqlParser) {
//����sql parse��������������
ControllerUtils.buildReverseOutput(args, sqlParserResult, dispatcherResult.getMax(),
dispatcherResult.getSkip(), dispatcherResult, DBType.MYSQL.equals(dbType));
}
return dispatcherResult;
}
/**
* �����groupby��������ִ�мƻ���Ϊ���ⵥ����ޱ�����ޱ�
* ������ͨ��
* @param sqlParserResult
* @param dispatcherResult
*/
protected void validGroupByFunction(SqlParserResult sqlParserResult,
DispatcherResult dispatcherResult) {
List<OrderByEle> groupByElement = sqlParserResult.getGroupByEles();
if (groupByElement.size() != 0) {
if (dispatcherResult.getDatabaseExecutePlan() == EXECUTE_PLAN.MULTIPLE) {
throw new IllegalArgumentException("��������£�������ʹ��group by ����");
}
if (dispatcherResult.getTableExecutePlan() == EXECUTE_PLAN.MULTIPLE) {
throw new IllegalArgumentException("��������£�������ʹ��group by����");
}
}
}
protected DispatcherResultImp getTargetDatabaseMetaDataBydatabaseGroups(
List<TargetDB> targetDatabases,
SqlParserResult sqlParserResult,
List<Object> arguments,
boolean isAllowReverseOutput) {
// targetDatabase.set
DispatcherResultImp dispatcherResultImp = new DispatcherResultImp(sqlParserResult
.getTableName(), targetDatabases, isAllowReverseOutput, sqlParserResult
.getSkip(arguments), sqlParserResult.getMax(arguments), new OrderByMessagesImp(
sqlParserResult.getOrderByEles()), sqlParserResult.getGroupFuncType());
return dispatcherResultImp;
}
@SuppressWarnings("unchecked")
public DispatcherResult getDBAndTables(RouteCondition rc) {
String logicTableName = rc.getVirtualTableName();
List<String> uniqueColumns = Collections.emptyList();
SqlParserResult sqlParserResult = null;
if (rc instanceof RuleRouteCondition) {
//��Ҫģ��sqlparser�߹���� condition
sqlParserResult = ((RuleRouteCondition) rc).getSqlParserResult();
try {
LogicTableRule rule = root.getLogicTableMap(logicTableName);
uniqueColumns = rule.getUniqueColumns();
MatcherResult matcherResult = matcher.match(sqlParserResult
.getComparativeMapChoicer(), null, rule);
DispatcherResult result = getDispatcherResult(matcherResult, sqlParserResult,
Collections.emptyList(), null, rule.getUniqueColumns(), false, false);
//�����JoinCondition ��ôҪ��DispatcherResult�����join����������;
if (rc instanceof JoinCondition) {
result
.setVirtualJoinTableNames(((JoinCondition) rc).getVirtualJoinTableNames());
}
return result;
} catch (ZdalCheckedExcption e) {
throw new RuntimeException(e);
}
} else if (rc instanceof DBSelectorRouteCondition) {
final DBSelectorRouteCondition dBSelectorRouteCondition = (DBSelectorRouteCondition) rc;
List<TargetDB> targetDBs = new ArrayList<TargetDB>(1);
TargetDB targetDB = new TargetDB();
targetDB.setDbIndex(dBSelectorRouteCondition.getDBSelectorID());
Set<String> targetDBSet = new HashSet<String>();
targetDBSet.addAll(dBSelectorRouteCondition.getTableList());
targetDB.setTableNames(targetDBSet);
targetDBs.add(targetDB);
ComparativeMapChoicer choicer = new ComparativeMapChoicer() {
public Map<String, Comparative> getColumnsMap(List<Object> arguments,
Set<String> partnationSet) {
return Collections.emptyMap();
}
};
//����αװ��
sqlParserResult = new DummySqlParcerResult(choicer, logicTableName);
MatcherResult matcherResult = matcher.buildMatcherResult(Collections.EMPTY_MAP,
Collections.EMPTY_MAP, targetDBs);
return getDispatcherResult(matcherResult, sqlParserResult, Collections.emptyList(),
null, uniqueColumns, false, false);
} else {
throw new IllegalArgumentException("wrong RouteCondition type:"
+ rc.getClass().getName());
}
}
public Result getAllDatabasesAndTables(String logicTableName) {
LogicTable logicTable = root.getLogicTable((logicTableName.toLowerCase()));
if (logicTable == null) {
throw new IllegalArgumentException("������δ�ҵ�");
}
return new DatabaseAndTablesDispatcherResultImp(logicTable.getAllTargetDBList(),
logicTableName);
}
/**
* ������getter/setter
*/
public SQLParser getParser() {
return parser;
}
public void setParser(SQLParser parser) {
this.parser = parser;
}
public ZdalRoot getRoot() {
return root;
}
public void setRoot(ZdalRoot root) {
this.root = root;
}
public DBType getDBType() {
return root.getDBType();
}
}