improved mysql parser, support more create view syntax.

This commit is contained in:
wenshao
2017-02-11 19:20:39 +08:00
parent 427c16d955
commit 1f3c5467eb
5 changed files with 194 additions and 51 deletions
@@ -33,6 +33,10 @@ public class SQLCreateViewStatement extends SQLStatementImpl implements SQLDDLSt
protected SQLSelect subQuery;
protected boolean ifNotExists = false;
protected String algorithm;
protected SQLName definer;
protected String sqlSecurity;
protected final List<Column> columns = new ArrayList<Column>();
private Level with;
@@ -109,6 +113,33 @@ public class SQLCreateViewStatement extends SQLStatementImpl implements SQLDDLSt
this.comment = comment;
}
public String getAlgorithm() {
return algorithm;
}
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
public SQLName getDefiner() {
return definer;
}
public void setDefiner(SQLName definer) {
if (definer != null) {
definer.setParent(this);
}
this.definer = definer;
}
public String getSqlSecurity() {
return sqlSecurity;
}
public void setSqlSecurity(String sqlSecurity) {
this.sqlSecurity = sqlSecurity;
}
public void output(StringBuffer buf) {
buf.append("CREATE VIEW ");
this.name.output(buf);
@@ -37,55 +37,8 @@ import com.alibaba.druid.sql.ast.expr.SQLLiteralExpr;
import com.alibaba.druid.sql.ast.expr.SQLNCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLAlterDatabaseStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddConstraint;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddIndex;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAnalyzePartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableCheckPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableCoalescePartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableConvertCharSet;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableConstraint;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableKeys;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDiscardPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropConstraint;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropForeignKey;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropIndex;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropKey;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropPrimaryKey;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableEnableConstraint;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableEnableKeys;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableImportPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableOptimizePartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableReOrganizePartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableRebuildPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableRepairPartition;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableTruncatePartition;
import com.alibaba.druid.sql.ast.statement.SQLBlockStatement;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCreateDatabaseStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLIfStatement;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause;
import com.alibaba.druid.sql.ast.statement.SQLLoopStatement;
import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLSetStatement;
import com.alibaba.druid.sql.ast.statement.SQLShowTablesStatement;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUnique;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.MysqlForeignKey;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.ConditionValue;
import com.alibaba.druid.sql.dialect.mysql.ast.clause.ConditionValue.ConditionType;
@@ -179,7 +132,6 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowTableStatusSta
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowTriggersStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowVariantsStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowWarningsStatement;
import com.alibaba.druid.sql.ast.statement.SQLStartTransactionStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUnlockTablesStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MysqlDeallocatePrepareStatement;
@@ -376,7 +328,8 @@ public class MySqlStatementParser extends SQLStatementParser {
return parseCreateUser();
}
if (lexer.token() == Token.VIEW) {
if (lexer.token() == Token.VIEW
|| identifierEquals("ALGORITHM")) {
if (replace) {
lexer.reset(markBp, markChar, Token.CREATE);
}
@@ -398,7 +351,7 @@ public class MySqlStatementParser extends SQLStatementParser {
return parseCreateProcedure();
}
throw new ParserException("TODO " + lexer.token());
throw new ParserException("TODO " + lexer.info());
}
public SQLStatement parseCreateIndex(boolean acceptCreate) {
@@ -1927,6 +1927,30 @@ public class SQLStatementParser extends SQLParser {
createView.setOrReplace(true);
}
if (identifierEquals("ALGORITHM")) {
lexer.nextToken();
accept(Token.EQ);
String algorithm = lexer.stringVal();
createView.setAlgorithm(algorithm);
lexer.nextToken();
}
if (identifierEquals("DEFINER")) {
lexer.nextToken();
accept(Token.EQ);
SQLName definer = this.exprParser.name();
createView.setDefiner(definer);
lexer.nextToken();
}
if (identifierEquals("SQL")) {
lexer.nextToken();
acceptIdentifier("SECURITY");
String sqlSecurity = lexer.stringVal();
createView.setSqlSecurity(sqlSecurity);
lexer.nextToken();
}
this.accept(Token.VIEW);
if (lexer.token() == Token.IF || identifierEquals("IF")) {
@@ -2053,6 +2053,31 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet
if (x.isOrReplace()) {
print0(ucase ? "OR REPLACE " : "or replace ");
}
incrementIndent();
String algorithm = x.getAlgorithm();
if (algorithm != null && algorithm.length() > 0) {
print0(ucase ? "ALGORITHM = " : "algorithm = ");
print0(algorithm);
println();
}
SQLName definer = x.getDefiner();
if (definer != null) {
print0(ucase ? "DEFINER = " : "definer = ");
definer.accept(this);
println();
}
String sqlSecurity = x.getSqlSecurity();
if (sqlSecurity != null && sqlSecurity.length() > 0) {
print0(ucase ? "SQL SECURITY = " : "sql security = ");
print0(sqlSecurity);
println();
}
decrementIndent();
print0(ucase ? "VIEW " : "view ");
if (x.isIfNotExists()) {
@@ -0,0 +1,110 @@
/*
* Copyright 1999-2101 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.druid.bvt.sql.mysql.create;
import com.alibaba.druid.sql.MysqlTest;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateViewStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.stat.TableStat.Column;
import org.junit.Assert;
import java.util.List;
public class MySqlCreateViewTest1 extends MysqlTest {
public void test_0() throws Exception {
String sql = "CREATE ALGORITHM=UNDEFINED DEFINER=root@localhost SQL SECURITY DEFINER VIEW view_audit_enroll AS " +
"SELECT a.enroll_id AS 'enrollId', case when ((SELECT audit FROM actvty_audit WHERE enroll_id = a.enroll_id AND rankjurisdiction = 1) > 0) then \"县站已审核\" else NULL end AS 'countyAudit', case when ((SELECT audit FROM actvty_audit WHERE enroll_id = a.enroll_id AND rankjurisdiction = 2) > 0) then \"市馆已审核\" else NULL end AS 'cityAudit', case when ((SELECT audit FROM actvty_audit WHERE enroll_id = a.enroll_id AND rankjurisdiction = 3) > 0) then \"省馆已审核\" else NULL end AS 'provinceAudit' FROM actvty_audit a GROUP BY a.enroll_id";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLCreateViewStatement stmt = (SQLCreateViewStatement) statementList.get(0);
// print(statementList);
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
stmt.accept(visitor);
Assert.assertEquals("CREATE ALGORITHM = UNDEFINED\n" +
"\tDEFINER = root\n" +
"\tSQL SECURITY = DEFINER\n" +
"\tVIEW view_audit_enroll\n" +
"AS\n" +
"SELECT a.enroll_id AS 'enrollId', CASE WHEN (\n" +
"\t\tSELECT audit\n" +
"\t\tFROM actvty_audit\n" +
"\t\tWHERE enroll_id = a.enroll_id\n" +
"\t\t\tAND rankjurisdiction = 1\n" +
"\t\t) > 0 THEN '县站已审核' ELSE NULL END AS 'countyAudit', CASE WHEN (\n" +
"\t\tSELECT audit\n" +
"\t\tFROM actvty_audit\n" +
"\t\tWHERE enroll_id = a.enroll_id\n" +
"\t\t\tAND rankjurisdiction = 2\n" +
"\t\t) > 0 THEN '市馆已审核' ELSE NULL END AS 'cityAudit', CASE WHEN (\n" +
"\t\tSELECT audit\n" +
"\t\tFROM actvty_audit\n" +
"\t\tWHERE enroll_id = a.enroll_id\n" +
"\t\t\tAND rankjurisdiction = 3\n" +
"\t\t) > 0 THEN '省馆已审核' ELSE NULL END AS 'provinceAudit'\n" +
"FROM actvty_audit a\n" +
"GROUP BY a.enroll_id", //
SQLUtils.toMySqlString(stmt));
Assert.assertEquals("create algorithm = UNDEFINED\n" +
"\tdefiner = root\n" +
"\tsql security = DEFINER\n" +
"\tview view_audit_enroll\n" +
"as\n" +
"select a.enroll_id as 'enrollId', case when (\n" +
"\t\tselect audit\n" +
"\t\tfrom actvty_audit\n" +
"\t\twhere enroll_id = a.enroll_id\n" +
"\t\t\tand rankjurisdiction = 1\n" +
"\t\t) > 0 then '县站已审核' else null end as 'countyAudit', case when (\n" +
"\t\tselect audit\n" +
"\t\tfrom actvty_audit\n" +
"\t\twhere enroll_id = a.enroll_id\n" +
"\t\t\tand rankjurisdiction = 2\n" +
"\t\t) > 0 then '市馆已审核' else null end as 'cityAudit', case when (\n" +
"\t\tselect audit\n" +
"\t\tfrom actvty_audit\n" +
"\t\twhere enroll_id = a.enroll_id\n" +
"\t\t\tand rankjurisdiction = 3\n" +
"\t\t) > 0 then '省馆已审核' else null end as 'provinceAudit'\n" +
"from actvty_audit a\n" +
"group by a.enroll_id", //
SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION));
// System.out.println("Tables : " + visitor.getTables());
// System.out.println("fields : " + visitor.getColumns());
// System.out.println("coditions : " + visitor.getConditions());
// System.out.println("orderBy : " + visitor.getOrderByColumns());
Assert.assertEquals(1, visitor.getTables().size());
Assert.assertEquals(3, visitor.getColumns().size());
Assert.assertEquals(2, visitor.getConditions().size());
Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("actvty_audit")));
Assert.assertTrue(visitor.getColumns().contains(new Column("actvty_audit", "audit")));
Assert.assertTrue(visitor.getColumns().contains(new Column("actvty_audit", "enroll_id")));
}
}