/** * Alipay.com Inc. * Copyright (c) 2004-2012 All Rights Reserved. */ package com.alipay.zdal.parser; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import org.apache.log4j.Logger; import com.alipay.zdal.common.DBType; import com.alipay.zdal.parser.exceptions.SqlParserException; import com.alipay.zdal.parser.result.SqlParserResult; import com.alipay.zdal.parser.result.SqlParserResultFactory; import com.alipay.zdal.parser.sql.ast.SQLStatement; import com.alipay.zdal.parser.sql.dialect.mysql.parser.MySqlStatementParser; import com.alipay.zdal.parser.sql.dialect.mysql.visitor.MySqlOutputVisitor; import com.alipay.zdal.parser.sql.dialect.oracle.parser.OracleStatementParser; import com.alipay.zdal.parser.sql.dialect.oracle.visitor.OracleOutputVisitor; import com.alipay.zdal.parser.sql.visitor.SQLASTOutputVisitor; import com.alipay.zdal.parser.visitor.ZdalDB2SchemaStatVisitor; import com.alipay.zdal.parser.visitor.ZdalMySqlSchemaStatVisitor; import com.alipay.zdal.parser.visitor.ZdalOracleSchemaStatVisitor; import com.alipay.zdal.parser.visitor.ZdalSchemaStatVisitor; /** * SQL ��������ʵ���࣬��Ҫ�ǽ�SQL�������ŵ�cache�У� * ���cache���и���SQL,��ֱ�Ӵ�cache��ȡ���������parse * * * @author xiaoqing.zhouxq * @version $Id: SQLParserImp.java, v 0.1 2012-5-22 ����10:01:18 xiaoqing.zhouxq Exp $ */ public class DefaultSQLParser implements SQLParser { private static final Logger LOG = Logger.getLogger(DefaultSQLParser.class); private static final ParserCache GLOBALCACHE = ParserCache.instance(); public SqlParserResult parse(String sql, DBType dbType) { this.parseSQL(sql, dbType); ZdalSchemaStatVisitor visitor = getStatement(sql); try { if (visitor == null) { // ���ûȡ�������Է���sql����ʼ�� this.parseSQL(sql, dbType); visitor = getStatement(sql); } } catch (Exception e) { throw new SqlParserException("the sql = " + sql + " is not support yet " + e.getMessage()); } return SqlParserResultFactory.createSqlParserResult(visitor, dbType); } /** * ���Դ�cache��ȡ��sql,���δȡ�����������sql����ʼ���� * * �����Ƕ�γ�ʼ��������Ϊkeyһ�£�ͬһ��sql��������ʼ���Ժ�Ľ����һ�µ� * * ���п�����Ϊ������put��init֮ǰ������,������������� * @param sql */ public void parseSQL(String sql) { this.nestedParseSql(sql, DBType.MYSQL); } public void parseSQL(String sql, DBType dbType) { this.nestedParseSql(sql, dbType); } private void nestedParseSql(final String sql, final DBType dbType) { if (sql == null) { throw new SqlParserException("sql must not be null"); } //Ϊ�˷�ֹ����ظ���ʼ��������ʹ����future task��ȷ����ʼ��ֻ����һ�� FutureTask<ZdalSchemaStatVisitor> future = GLOBALCACHE.getFutureTask(sql); if (future == null) { Callable<ZdalSchemaStatVisitor> parserHandler = new Callable<ZdalSchemaStatVisitor>() { public ZdalSchemaStatVisitor call() throws Exception { final List<SQLStatement> parserResults = getSqlStatements(sql, dbType); if (parserResults == null || parserResults.isEmpty()) { LOG.error("ERROR ## the sql parser result is null,the sql = " + sql); return null; } if (parserResults.size() > 1) { LOG .warn("WARN ## after this sql parser,has more than one SQLStatement,the sql = " + sql); } SQLStatement statement = parserResults.get(0); ZdalSchemaStatVisitor visitor = null; if (dbType.isMysql()) { visitor = new ZdalMySqlSchemaStatVisitor(); statement.accept(visitor); } else if (dbType.isOracle()) { visitor = new ZdalOracleSchemaStatVisitor(); statement.accept(visitor); } else if (dbType.isDB2()) { visitor = new ZdalDB2SchemaStatVisitor(); statement.accept(visitor); } else { throw new IllegalArgumentException("ERROR ## dbType = " + dbType + " is not support"); } return visitor; } }; future = new FutureTask<ZdalSchemaStatVisitor>(parserHandler); future = GLOBALCACHE.setFutureTaskIfAbsent(sql, future); future.run(); } } /** * ���parse���������sql���. * @param parserResults * @return */ public String outputParsedSql(List<SQLStatement> parserResults, boolean isMysql) { StringBuilder out = new StringBuilder(); SQLASTOutputVisitor visitor = null; if (isMysql) { visitor = new MySqlOutputVisitor(out); } else { visitor = new OracleOutputVisitor(out); } for (SQLStatement stmt : parserResults) { stmt.accept(visitor); } return out.toString(); } /** * ͨ��parserģ�����sql���,����java�����ʾ��sql. * @param sql * @param isMysql * @return */ private List<SQLStatement> getSqlStatements(final String sql, final DBType dbType) { if (dbType.isMysql()) { MySqlStatementParser parser = new MySqlStatementParser(sql); return parser.parseStatementList(); } else if (dbType.isOracle()) { OracleStatementParser parser = new OracleStatementParser(sql); return parser.parseStatementList(); } else if (dbType.isDB2()) { OracleStatementParser parser = new OracleStatementParser(sql); return parser.parseStatementList(); } else { throw new IllegalArgumentException("ERROR ## dbType = " + dbType + " is not support"); } } /** * ����SQL��ȡ��Ӧ��javaSQL���� * @param sql * @return java SQL ���� ���cache��û���򷵻ؿ� */ private ZdalSchemaStatVisitor getStatement(String sql) { try { FutureTask<ZdalSchemaStatVisitor> future = GLOBALCACHE.getFutureTask(sql); if (future == null) { return null; } else { return future.get(); } } catch (Exception e) { throw new SqlParserException("ERROR ## get sqlparser result from cache has an error:", e); } } }