diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java index 29fddfbff3..9a53f962e1 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java @@ -642,6 +642,7 @@ public class MySqlStatementParser extends SQLStatementParser { boolean full = false; if (lexer.token() == Token.FULL) { lexer.nextToken(); + full = true; } if (identifierEquals("PROCESSLIST")) { @@ -651,7 +652,7 @@ public class MySqlStatementParser extends SQLStatementParser { return stmt; } - if (identifierEquals("COLUMNS")) { + if (identifierEquals("COLUMNS") || identifierEquals("FIELDS")) { lexer.nextToken(); MySqlShowColumnsStatement stmt = parseShowColumns(); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java index 1d7a71db66..596e518992 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java @@ -422,7 +422,7 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS @Override public boolean visit(MySqlShowColumnsStatement x) { - return true; + return false; } @Override @@ -1283,7 +1283,7 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS public boolean visit(MySqlAlterTableImportTablespace x) { return false; } - + @Override public void endVisit(MySqlAlterTableImportTablespace x) { diff --git a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java index 11dc85cd5c..06296d5b10 100644 --- a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java +++ b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java @@ -186,7 +186,7 @@ public final class DruidStatManagerFacade { } @SuppressWarnings({ "rawtypes", "unchecked" }) - static Map mergWallStat(Map mapA, Map mapB) { + public static Map mergWallStat(Map mapA, Map mapB) { if (mapA.size() == 0) { return mapB; } diff --git a/src/main/java/com/alibaba/druid/wall/WallCheckResult.java b/src/main/java/com/alibaba/druid/wall/WallCheckResult.java index 0bde0dc64a..16e8fb2276 100644 --- a/src/main/java/com/alibaba/druid/wall/WallCheckResult.java +++ b/src/main/java/com/alibaba/druid/wall/WallCheckResult.java @@ -15,22 +15,51 @@ */ package com.alibaba.druid.wall; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; import com.alibaba.druid.sql.ast.SQLStatement; public class WallCheckResult { - private final List violations = new ArrayList(2); - private final List statementList = new ArrayList(2); + private final List statementList; + private final Map tableStats; + + private final List violations; + + private final Map functionStats; + + private final boolean syntaxError; public WallCheckResult(){ - + this(null); } - public WallCheckResult(Violation violation){ - this.violations.add(violation); + public WallCheckResult(WallSqlStat sqlStat){ + if (sqlStat != null) { + tableStats = sqlStat.getTableStats(); + violations = sqlStat.getViolations(); + functionStats = sqlStat.getFunctionStats(); + statementList = Collections.emptyList(); + syntaxError = sqlStat.isSyntaxError(); + } else { + tableStats = Collections.emptyMap(); + violations = Collections.emptyList(); + functionStats = Collections.emptyMap(); + statementList = Collections.emptyList(); + syntaxError = false; + } + } + + public WallCheckResult(List violations, Map tableStats, + Map functionStats, List statementList, + boolean syntaxError){ + this.tableStats = tableStats; + this.violations = violations; + this.functionStats = functionStats; + this.statementList = statementList; + this.syntaxError = syntaxError; } public List getViolations() { @@ -41,4 +70,16 @@ public class WallCheckResult { return statementList; } + + public Map getTableStats() { + return tableStats; + } + + public Map getFunctionStats() { + return functionStats; + } + + public boolean isSyntaxError() { + return syntaxError; + } } diff --git a/src/main/java/com/alibaba/druid/wall/WallFunctionStat.java b/src/main/java/com/alibaba/druid/wall/WallFunctionStat.java index 4f24a8953f..6b11d50961 100644 --- a/src/main/java/com/alibaba/druid/wall/WallFunctionStat.java +++ b/src/main/java/com/alibaba/druid/wall/WallFunctionStat.java @@ -15,6 +15,8 @@ */ package com.alibaba.druid.wall; +import java.util.Collections; +import java.util.Map; import java.util.concurrent.atomic.AtomicLongFieldUpdater; public class WallFunctionStat { @@ -39,4 +41,8 @@ public class WallFunctionStat { return "{\"invokeCount\":" + invokeCount + "}"; } + public Map toMap() { + return Collections.singletonMap("invokeCount", invokeCount); + } + } diff --git a/src/main/java/com/alibaba/druid/wall/WallProvider.java b/src/main/java/com/alibaba/druid/wall/WallProvider.java index aedbe294f9..57621f264b 100644 --- a/src/main/java/com/alibaba/druid/wall/WallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/WallProvider.java @@ -47,7 +47,7 @@ public abstract class WallProvider { private int MAX_SQL_LENGTH = 2048; // 1k - private int whiteSqlMaxSize = 10000; // 1k + private int whiteSqlMaxSize = 2000; // 1k private LRUCache blackList; @@ -103,6 +103,10 @@ public abstract class WallProvider { public WallTableStat getTableStat(String tableName) { String lowerCaseName = tableName.toLowerCase(); + if (lowerCaseName.startsWith("`") && lowerCaseName.endsWith("`")) { + lowerCaseName = lowerCaseName.substring(1, lowerCaseName.length() - 1); + } + return getTableStatWithLowerName(lowerCaseName); } @@ -224,7 +228,7 @@ public abstract class WallProvider { lock.writeLock().unlock(); } } - + public void clearBlackList() { lock.writeLock().lock(); try { @@ -371,25 +375,111 @@ public abstract class WallProvider { } WallContext.createIfNotExists(this.dbType); - WallCheckResult result = new WallCheckResult(); if (config.isDoPrivilegedAllow() && ispPivileged()) { - return result; + return new WallCheckResult(); } // first step, check whiteList + boolean mulltiTenant = config.getTenantTablePattern() != null && config.getTenantTablePattern().length() > 0; + if (!mulltiTenant) { + WallCheckResult checkResult = checkWhiteAndBlackList(sql); + if (checkResult != null) { + return checkResult; + } + } + + hardCheckCount.incrementAndGet(); + final List violations = new ArrayList(); + List statementList = new ArrayList(); + boolean syntaxError = false; + try { + SQLStatementParser parser = createParser(sql); + parser.getLexer().setCommentHandler(WallCommentHandler.instance); + + if (!config.isCommentAllow()) { + parser.getLexer().setAllowComment(false); // deny comment + } + + parser.parseStatementList(statementList); + + final Token lastToken = parser.getLexer().token(); + if (lastToken != Token.EOF) { + violations.add(new IllegalSQLObjectViolation("not terminal sql, token " + lastToken, sql)); + } + } catch (NotAllowCommentException e) { + violations.add(new SyntaxErrorViolation(e, sql)); + incrementCommentDeniedCount(); + } catch (ParserException e) { + syntaxErrrorCount.incrementAndGet(); + syntaxError = true; + if (config.isStrictSyntaxCheck()) { + violations.add(new SyntaxErrorViolation(e, sql)); + } + } catch (Exception e) { + violations.add(new SyntaxErrorViolation(e, sql)); + } + + if (statementList.size() > 1 && !config.isMultiStatementAllow()) { + violations.add(new IllegalSQLObjectViolation("multi-statement not allow", sql)); + } + + WallVisitor visitor = createWallVisitor(); + + if (statementList.size() > 0) { + SQLStatement stmt = statementList.get(0); + try { + stmt.accept(visitor); + } catch (ParserException e) { + violations.add(new SyntaxErrorViolation(e, sql)); + } + } + + if (visitor.getViolations().size() > 0) { + violations.addAll(visitor.getViolations()); + } + + WallSqlStat sqlStat = null; + if (violations.size() > 0) { + violationCount.incrementAndGet(); + + if (sql.length() < MAX_SQL_LENGTH) { + sqlStat = addBlackSql(sql, context.getTableStats(), context.getFunctionStats(), violations, syntaxError); + } + } else { + if (sql.length() < MAX_SQL_LENGTH) { + sqlStat = addWhiteSql(sql, context.getTableStats(), context.getFunctionStats(), syntaxError); + } + } + + Map tableStats = null; + Map functionStats = null; + if (context != null) { + tableStats = context.getTableStats(); + functionStats = context.getFunctionStats(); + recordStats(tableStats, functionStats); + } + + if (sqlStat != null) { + new WallCheckResult(sqlStat); + } + + return new WallCheckResult(violations, tableStats, functionStats, statementList, syntaxError); + } + + private WallCheckResult checkWhiteAndBlackList(String sql) { { WallSqlStat sqlStat = getWhiteSql(sql); if (sqlStat != null) { whiteListHitCount.incrementAndGet(); sqlStat.incrementAndGetExecuteCount(); - + if (sqlStat.isSyntaxError()) { syntaxErrrorCount.incrementAndGet(); } recordStats(sqlStat.getTableStats(), sqlStat.getFunctionStats()); - return result; + return new WallCheckResult(sqlStat); } } // check black list @@ -405,80 +495,12 @@ public abstract class WallProvider { sqlStat.incrementAndGetExecuteCount(); recordStats(sqlStat.getTableStats(), sqlStat.getFunctionStats()); - List blackViolations = sqlStat.getViolations(); - result.getViolations().addAll(blackViolations); - return result; + return new WallCheckResult(sqlStat); } } - hardCheckCount.incrementAndGet(); - boolean syntaxError = false; - try { - SQLStatementParser parser = createParser(sql); - parser.getLexer().setCommentHandler(WallCommentHandler.instance); - - if (!config.isCommentAllow()) { - parser.getLexer().setAllowComment(false); // deny comment - } - - parser.parseStatementList(result.getStatementList()); - - final Token lastToken = parser.getLexer().token(); - if (lastToken != Token.EOF) { - result.getViolations().add(new IllegalSQLObjectViolation("not terminal sql, token " + lastToken, sql)); - } - } catch (NotAllowCommentException e) { - result.getViolations().add(new SyntaxErrorViolation(e, sql)); - incrementCommentDeniedCount(); - } catch (ParserException e) { - syntaxErrrorCount.incrementAndGet(); - syntaxError = true; - if (config.isStrictSyntaxCheck()) { - result.getViolations().add(new SyntaxErrorViolation(e, sql)); - } - } catch (Exception e) { - result.getViolations().add(new SyntaxErrorViolation(e, sql)); - } - - if (result.getViolations().size() == 0 && result.getStatementList().size() > 1 - && !config.isMultiStatementAllow()) { - result.getViolations().add(new IllegalSQLObjectViolation("multi-statement not allow", sql)); - } - - WallVisitor visitor = createWallVisitor(); - - if (result.getStatementList().size() > 0) { - SQLStatement stmt = result.getStatementList().get(0); - try { - stmt.accept(visitor); - } catch (ParserException e) { - result.getViolations().add(new SyntaxErrorViolation(e, sql)); - } - } - - if (visitor.getViolations().size() > 0) { - result.getViolations().addAll(visitor.getViolations()); - } - - if (result.getViolations().size() > 0) { - violationCount.incrementAndGet(); - - if (sql.length() < MAX_SQL_LENGTH) { - addBlackSql(sql, context.getTableStats(), context.getFunctionStats(), result.getViolations(), - syntaxError); - } - } else { - if (sql.length() < MAX_SQL_LENGTH) { - addWhiteSql(sql, context.getTableStats(), context.getFunctionStats(), syntaxError); - } - } - - if (context != null) { - recordStats(context.getTableStats(), context.getFunctionStats()); - } - - return result; + return null; } void recordStats(Map tableStats, Map functionStats) { @@ -551,7 +573,7 @@ public abstract class WallProvider { public long getViolationCount() { return violationCount.get(); } - + public long getHardCheckCount() { return hardCheckCount.get(); } @@ -589,6 +611,7 @@ public abstract class WallProvider { Map info = new LinkedHashMap(); info.put("checkCount", this.getCheckCount()); + info.put("hardCheckCount", this.getHardCheckCount()); info.put("violationCount", this.getViolationCount()); info.put("blackListHitCount", this.getBlackListHitCount()); info.put("blackListSize", this.getBlackList().size()); @@ -597,25 +620,21 @@ public abstract class WallProvider { info.put("syntaxErrrorCount", this.getSyntaxErrorCount()); { - List> tables = new ArrayList>(); + Map> tables = new LinkedHashMap>(); for (Map.Entry entry : this.tableStats.entrySet()) { - Map stat = new LinkedHashMap(); - stat.put("name", entry.getKey()); - entry.getValue().toMap(stat); - tables.add(stat); + tables.put(entry.getKey(), entry.getValue().toMap()); } info.put("tables", tables); } { - List> functions = new ArrayList>(); + Map> functions = new LinkedHashMap>(); for (Map.Entry entry : this.functionStats.entrySet()) { - Map stat = new HashMap(); - stat.put("name", entry.getValue()); - stat.put("invokeCount", entry.getValue().getInvokeCount()); - functions.add(stat); + functions.put(entry.getKey(), entry.getValue().toMap()); } info.put("functions", functions); } + info.put("whiteList", this.getWhiteList()); + info.put("blackList", this.getBlackList()); return info; } } diff --git a/src/main/java/com/alibaba/druid/wall/WallSqlFunctionStat.java b/src/main/java/com/alibaba/druid/wall/WallSqlFunctionStat.java index 02754a0ac0..3d4af1985f 100644 --- a/src/main/java/com/alibaba/druid/wall/WallSqlFunctionStat.java +++ b/src/main/java/com/alibaba/druid/wall/WallSqlFunctionStat.java @@ -26,5 +26,8 @@ public class WallSqlFunctionStat { public void incrementInvokeCount() { this.invokeCount++; } - + + public void addInvokeCount(int value) { + this.invokeCount += value; + } } diff --git a/src/main/java/com/alibaba/druid/wall/WallSqlTableStat.java b/src/main/java/com/alibaba/druid/wall/WallSqlTableStat.java index 36e8ce1112..c2c929b68d 100644 --- a/src/main/java/com/alibaba/druid/wall/WallSqlTableStat.java +++ b/src/main/java/com/alibaba/druid/wall/WallSqlTableStat.java @@ -34,6 +34,10 @@ public class WallSqlTableStat { public void incrementSelectCount() { this.selectCount++; } + + public void addSelectCount(int value) { + this.selectCount += value; + } public int getSelectIntoCount() { return selectIntoCount; @@ -42,6 +46,10 @@ public class WallSqlTableStat { public void incrementSelectIntoCount() { this.selectIntoCount++; } + + public void addSelectIntoCount(int value) { + this.selectIntoCount += value; + } public int getInsertCount() { return insertCount; @@ -50,6 +58,10 @@ public class WallSqlTableStat { public void incrementInsertCount() { this.insertCount++; } + + public void addInsertCount(int value) { + this.insertCount += value; + } public int getUpdateCount() { return updateCount; @@ -59,6 +71,10 @@ public class WallSqlTableStat { this.updateCount++; } + public void addUpdateCount(int value) { + this.deleteCount += value; + } + public int getDeleteCount() { return deleteCount; } @@ -67,6 +83,10 @@ public class WallSqlTableStat { this.deleteCount++; } + public void addDeleteCount(int value) { + this.deleteCount += value; + } + public int getTruncateCount() { return truncateCount; } @@ -75,6 +95,10 @@ public class WallSqlTableStat { this.truncateCount++; } + public void addTruncateCount(int value) { + this.truncateCount += value; + } + public int getCreateCount() { return createCount; } @@ -83,6 +107,10 @@ public class WallSqlTableStat { this.createCount++; } + public void addCreateCount(int value) { + this.createCount += value; + } + public int getAlterCount() { return alterCount; } @@ -91,6 +119,10 @@ public class WallSqlTableStat { this.alterCount++; } + public void addAlterCount(int value) { + this.alterCount += value; + } + public int getDropCount() { return dropCount; } @@ -99,4 +131,7 @@ public class WallSqlTableStat { this.dropCount++; } + public void addDropCount(int value) { + this.dropCount += value; + } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallDescribteTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallDescribteTest.java index f65ee3ba25..db30dc7a26 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallDescribteTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallDescribteTest.java @@ -38,7 +38,7 @@ public class MySqlWallDescribteTest extends TestCase { public void test_not_allow() throws Exception { WallConfig config = new WallConfig(); - config.setVariantCheck(true); + config.setDescribeAllow(false); Assert.assertFalse(WallUtils.isValidateMySql("describe t", config)); } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_WhiteList.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_WhiteList.java index ee404dc669..77c6ce0b50 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_WhiteList.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallStatTest_WhiteList.java @@ -22,17 +22,17 @@ public class WallStatTest_WhiteList extends TestCase { public void testMySql() throws Exception { WallProvider provider = new MySqlWallProvider(); - for (int i = 0; i < 1001; ++i) { + for (int i = 0; i < 3001; ++i) { String sql = "select * from t where id = " + i; Assert.assertTrue(provider.checkValid(sql)); } WallTableStat tableStat = provider.getTableStat("t"); - Assert.assertEquals(1001, tableStat.getSelectCount()); + Assert.assertEquals(3001, tableStat.getSelectCount()); Assert.assertEquals(0, provider.getBlackListHitCount()); Assert.assertEquals(0, provider.getWhiteListHitCount()); - Assert.assertEquals(1000, provider.getWhiteList().size()); - Assert.assertEquals(1001, provider.getCheckCount()); + Assert.assertEquals(2000, provider.getWhiteList().size()); + Assert.assertEquals(3001, provider.getCheckCount()); } } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTestMysql.java b/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTestMysql.java index 54ae7e0cd0..82a3768684 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTestMysql.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTestMysql.java @@ -64,6 +64,6 @@ public class ConfigErrorTestMysql extends TestCase { Assert.assertEquals(0, LOG.getWarnCount()); dataSource.init(); - Assert.assertEquals(1, LOG.getWarnCount()); + Assert.assertEquals(0, LOG.getWarnCount()); } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DALParserTest.java b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DALParserTest.java index 4aa857d75e..bb0a005a1f 100755 --- a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DALParserTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DALParserTest.java @@ -18,9 +18,10 @@ */ package com.alibaba.druid.bvt.sql.cobar; -import junit.framework.Assert; import junit.framework.TestCase; +import org.junit.Assert; + import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.statement.SQLSetStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDescribeStatement;