improve sql-wall

This commit is contained in:
wenshao
2013-08-25 23:36:18 +08:00
parent e10c681671
commit b05671447c
25 changed files with 497 additions and 53 deletions
@@ -32,6 +32,7 @@ import com.alibaba.druid.sql.ast.expr.SQLNumberExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLAssignItem;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.dialect.db2.visitor.DB2ParameterizedOutputVisitor;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlParameterizedOutputVisitor;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleParameterizedOutputVisitor;
@@ -158,6 +159,7 @@ public class ParameterizedOutputVisitorUtils {
|| parent instanceof SQLColumnDefinition //
|| parent instanceof SQLServerTop //
|| parent instanceof SQLAssignItem //
|| parent instanceof SQLSelectOrderByItem //
) {
return false;
}
@@ -555,7 +555,7 @@ public class SQLEvalVisitorUtils {
char ch = (char) intValue;
x.putAttribute(EVAL_VALUE, Character.toString(ch));
}
} else if ("CURRENT_USER".equals(methodName)) {
} else if ("current_user".equals(methodName)) {
x.putAttribute(EVAL_VALUE, "CURRENT_USER");
}
return false;
@@ -213,6 +213,15 @@ public class JSONWriter {
write("\\\\");
} else if (c == '\t') {
write("\\t");
} else if (c < 16) {
write("\\u000");
write(Integer.toHexString(c));
} else if (c < 32) {
write("\\u00");
write(Integer.toHexString(c));
} else if (c >= 0x7f && c <= 0xA0) {
write("\\u00");
write(Integer.toHexString(c));
} else {
write(c);
}
@@ -129,7 +129,7 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
} else {
throw new IllegalStateException("dbType not support : " + dbType + ", url " + dataSource.getUrl());
}
provider.setName(dataSource.getName());
this.inited = true;
@@ -364,6 +364,9 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
setSqlStatAttribute(statement);
}
return firstResult;
} catch (SQLException ex) {
incrementExecuteErrorCount();
throw ex;
} finally {
if (originalContext != null) {
WallContext.setContext(originalContext);
@@ -385,6 +388,9 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
setSqlStatAttribute(statement);
}
return firstResult;
} catch (SQLException ex) {
incrementExecuteErrorCount();
throw ex;
} finally {
WallContext.clearContext();
}
@@ -404,6 +410,9 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
setSqlStatAttribute(statement);
}
return firstResult;
} catch (SQLException ex) {
incrementExecuteErrorCount();
throw ex;
} finally {
WallContext.clearContext();
}
@@ -423,6 +432,9 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
setSqlStatAttribute(statement);
}
return firstResult;
} catch (SQLException ex) {
incrementExecuteErrorCount();
throw ex;
} finally {
WallContext.clearContext();
}
@@ -443,6 +455,9 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
}
return updateCounts;
} catch (SQLException ex) {
incrementExecuteErrorCount();
throw ex;
} finally {
WallContext.clearContext();
}
@@ -455,6 +470,9 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
try {
sql = check(sql);
return chain.statement_executeQuery(statement, sql);
} catch (SQLException ex) {
incrementExecuteErrorCount();
throw ex;
} finally {
WallContext.clearContext();
}
@@ -468,6 +486,9 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
int updateCount = chain.statement_executeUpdate(statement, sql);
statExecuteUpdate(updateCount);
return updateCount;
} catch (SQLException ex) {
incrementExecuteErrorCount();
throw ex;
} finally {
WallContext.clearContext();
}
@@ -482,6 +503,9 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
int updateCount = chain.statement_executeUpdate(statement, sql, autoGeneratedKeys);
statExecuteUpdate(updateCount);
return updateCount;
} catch (SQLException ex) {
incrementExecuteErrorCount();
throw ex;
} finally {
WallContext.clearContext();
}
@@ -496,6 +520,9 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
int updateCount = chain.statement_executeUpdate(statement, sql, columnIndexes);
statExecuteUpdate(updateCount);
return updateCount;
} catch (SQLException ex) {
incrementExecuteErrorCount();
throw ex;
} finally {
WallContext.clearContext();
}
@@ -520,6 +547,9 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
int updateCount = chain.statement_executeUpdate(statement, sql, columnNames);
statExecuteUpdate(updateCount);
return updateCount;
} catch (SQLException ex) {
incrementExecuteErrorCount();
throw ex;
} finally {
WallContext.clearContext();
}
@@ -527,33 +557,48 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
@Override
public boolean preparedStatement_execute(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
boolean firstResult = chain.preparedStatement_execute(statement);
try {
boolean firstResult = chain.preparedStatement_execute(statement);
if (!firstResult) {
WallSqlStat sqlStat = (WallSqlStat) statement.getAttribute(ATTR_SQL_STAT);
int updateCount = statement.getUpdateCount();
if (sqlStat != null) {
provider.addUpdateCount(sqlStat, updateCount);
if (!firstResult) {
WallSqlStat sqlStat = (WallSqlStat) statement.getAttribute(ATTR_SQL_STAT);
int updateCount = statement.getUpdateCount();
if (sqlStat != null) {
provider.addUpdateCount(sqlStat, updateCount);
}
}
}
return firstResult;
return firstResult;
} catch (SQLException ex) {
incrementExecuteErrorCount(statement);
throw ex;
}
}
@Override
public ResultSetProxy preparedStatement_executeQuery(FilterChain chain, PreparedStatementProxy statement)
throws SQLException {
return chain.preparedStatement_executeQuery(statement);
try {
return chain.preparedStatement_executeQuery(statement);
} catch (SQLException ex) {
incrementExecuteErrorCount(statement);
throw ex;
}
}
@Override
public int preparedStatement_executeUpdate(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
int updateCount = chain.preparedStatement_executeUpdate(statement);
WallSqlStat sqlStat = (WallSqlStat) statement.getAttribute(ATTR_SQL_STAT);
if (sqlStat != null) {
provider.addUpdateCount(sqlStat, updateCount);
try {
int updateCount = chain.preparedStatement_executeUpdate(statement);
WallSqlStat sqlStat = (WallSqlStat) statement.getAttribute(ATTR_SQL_STAT);
if (sqlStat != null) {
provider.addUpdateCount(sqlStat, updateCount);
}
return updateCount;
} catch (SQLException ex) {
incrementExecuteErrorCount(statement);
throw ex;
}
return updateCount;
}
public void setSqlStatAttribute(StatementProxy stmt) {
@@ -585,6 +630,27 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
provider.addUpdateCount(sqlStat, updateCount);
}
}
public void incrementExecuteErrorCount(PreparedStatementProxy statement) {
WallSqlStat sqlStat = (WallSqlStat) statement.getAttribute(ATTR_SQL_STAT);
if (sqlStat != null) {
sqlStat.incrementAndGetExecuteErrorCount();
}
}
public void incrementExecuteErrorCount() {
WallContext context = WallContext.current();
if (context == null) {
return;
}
WallSqlStat sqlStat = context.getSqlStat();
if (sqlStat == null) {
return;
}
sqlStat.incrementAndGetExecuteErrorCount();
}
public String check(String sql) throws SQLException {
WallCheckResult checkResult = provider.check(sql);
@@ -64,7 +64,7 @@ public abstract class WallProvider {
private LRUCache<String, WallSqlStat> blackList;
private LRUCache<String, WallSqlStat> blackMergedList;
private int blackSqlMaxSize = 100; // 1k
private int blackSqlMaxSize = 200; // 1k
protected final WallConfig config;
@@ -25,15 +25,19 @@ import java.util.concurrent.atomic.AtomicLongFieldUpdater;
public class WallSqlStat {
private volatile long executeCount;
private volatile long executeErrorCount;
private volatile long fetchRowCount;
private volatile long updateCount;
final static AtomicLongFieldUpdater<WallSqlStat> executeCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
"executeCount");
final static AtomicLongFieldUpdater<WallSqlStat> fetchRowCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
"fetchRowCount");
final static AtomicLongFieldUpdater<WallSqlStat> updateCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
"updateCount");
final static AtomicLongFieldUpdater<WallSqlStat> executeCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
"executeCount");
final static AtomicLongFieldUpdater<WallSqlStat> executeErrorCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
"executeErrorCount");
final static AtomicLongFieldUpdater<WallSqlStat> fetchRowCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
"fetchRowCount");
final static AtomicLongFieldUpdater<WallSqlStat> updateCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
"updateCount");
private final Map<String, WallSqlTableStat> tableStats;
private final List<Violation> violations;
@@ -79,12 +83,16 @@ public class WallSqlStat {
return executeCountUpdater.incrementAndGet(this);
}
public long incrementAndGetExecuteErrorCount() {
return executeErrorCountUpdater.incrementAndGet(this);
}
public long getExecuteCount() {
return executeCount;
}
public long incrementAndGetFetchRowCount() {
return fetchRowCountUpdater.incrementAndGet(this);
public long getExecuteErrorCount() {
return executeErrorCount;
}
public long addAndFetchRowCount(long delta) {
@@ -123,6 +131,7 @@ public class WallSqlStat {
final WallSqlStatValue statValue = new WallSqlStatValue();
statValue.setExecuteCount(get(this, executeCountUpdater, reset));
statValue.setExecuteErrorCount(get(this, executeErrorCountUpdater, reset));
statValue.setFetchRowCount(get(this, fetchRowCountUpdater, reset));
statValue.setUpdateCount(get(this, updateCountUpdater, reset));
statValue.setSyntaxError(this.syntaxError);
@@ -38,6 +38,9 @@ public class WallSqlStatValue {
@MField(aggregate = AggregateType.Sum)
private long executeCount;
@MField(aggregate = AggregateType.Sum)
private long executeErrorCount;
@MField(aggregate = AggregateType.Sum)
private long fetchRowCount;
@@ -118,6 +121,14 @@ public class WallSqlStatValue {
this.violationMessage = violationMessage;
}
public long getExecuteErrorCount() {
return executeErrorCount;
}
public void setExecuteErrorCount(long executeErrorCount) {
this.executeErrorCount = executeErrorCount;
}
public Map<String, Object> toMap() {
Map<String, Object> sqlStatMap = new LinkedHashMap<String, Object>();
sqlStatMap.put("sql", sql);
@@ -125,6 +136,10 @@ public class WallSqlStatValue {
sqlStatMap.put("sample", sqlSample);
}
sqlStatMap.put("executeCount", getExecuteCount());
if (executeErrorCount > 0) {
sqlStatMap.put("executeErrorCount", executeErrorCount);
}
if (fetchRowCount > 0) {
sqlStatMap.put("fetchRowCount", fetchRowCount);
@@ -15,6 +15,8 @@
*/
package com.alibaba.druid.wall.spi;
import static com.alibaba.druid.sql.visitor.SQLEvalVisitor.EVAL_VALUE;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -211,6 +213,10 @@ public class WallVisitorUtils {
SQLExpr where = x.getWhere();
if (where != null) {
if (queryBlockFromIsNull(visitor, x, false)) {
addViolation(visitor, ErrorCode.EmptyQueryHasCondition, "empty select has condition", x);
}
where.setParent(x);
checkCondition(visitor, x.getWhere());
@@ -641,6 +647,10 @@ public class WallVisitorUtils {
SQLExpr right = x.getRight();
Object leftResult = getValue(visitor, left);
Object rightResult = getValue(visitor, right);
if (x.getOperator() == SQLBinaryOperator.Like && leftResult instanceof String && leftResult.equals(rightResult)) {
addViolation(visitor, ErrorCode.DoubleConstCondition, "same const like", x);
}
if (x.getOperator() == SQLBinaryOperator.Like || x.getOperator() == SQLBinaryOperator.NotLike) {
WallContext context = WallContext.current();
@@ -652,8 +662,14 @@ public class WallVisitorUtils {
}
if (x.getOperator() == SQLBinaryOperator.BooleanAnd) {
if (Boolean.FALSE == leftResult || Boolean.FALSE == rightResult) {
return false;
if (rightResult != null && x.getLeft() instanceof SQLBinaryOpExpr) {
SQLBinaryOpExpr leftBinaryOpExpr = (SQLBinaryOpExpr) x.getLeft();
if (leftBinaryOpExpr.getOperator() == SQLBinaryOperator.BooleanAnd) {
Object leftRightVal = getValue(leftBinaryOpExpr.getRight());
if (leftRightVal != null) {
addViolation(visitor, ErrorCode.DoubleConstCondition, "double const condition", x);
}
}
}
if (leftResult == Boolean.TRUE) {
@@ -680,6 +696,10 @@ public class WallVisitorUtils {
if (Boolean.TRUE == leftResult && Boolean.TRUE == rightResult) {
return true;
}
if (Boolean.FALSE == leftResult || Boolean.FALSE == rightResult) {
return false;
}
}
String dbType = null;
@@ -944,6 +964,10 @@ public class WallVisitorUtils {
}
public static Object getValue(WallVisitor visitor, SQLExpr x) {
if (x != null && x.getAttributes().containsKey(EVAL_VALUE)) {
return x.getAttribute(EVAL_VALUE);
}
if (x instanceof SQLBinaryOpExpr) {
return getValue(visitor, (SQLBinaryOpExpr) x);
}
@@ -978,17 +1002,17 @@ public class WallVisitorUtils {
}
if (x instanceof SQLMethodInvokeExpr //
|| x instanceof SQLBetweenExpr //
|| x instanceof SQLInListExpr //
|| x instanceof SQLUnaryExpr //
) {
|| x instanceof SQLBetweenExpr //
|| x instanceof SQLInListExpr //
|| x instanceof SQLUnaryExpr //
) {
String dbType = null;
if (visitor != null) {
dbType = visitor.getDbType();
}
return SQLEvalVisitorUtils.eval(dbType, x, Collections.emptyList(), false);
}
return null;
}
@@ -1495,6 +1519,10 @@ public class WallVisitorUtils {
}
public static boolean queryBlockFromIsNull(WallVisitor visitor, SQLSelectQuery query) {
return queryBlockFromIsNull(visitor, query, true);
}
public static boolean queryBlockFromIsNull(WallVisitor visitor, SQLSelectQuery query, boolean checkSelectConst) {
if (query instanceof SQLSelectQueryBlock) {
SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query;
SQLTableSource from = queryBlock.getFrom();
@@ -1526,15 +1554,17 @@ public class WallVisitorUtils {
}
}
boolean allIsConst = true;
for (SQLSelectItem item : queryBlock.getSelectList()) {
if (getValue(visitor, item.getExpr()) == null) {
allIsConst = false;
break;
if (checkSelectConst) {
boolean allIsConst = true;
for (SQLSelectItem item : queryBlock.getSelectList()) {
if (getValue(visitor, item.getExpr()) == null) {
allIsConst = false;
break;
}
}
if (allIsConst) {
return true;
}
}
if (allIsConst) {
return true;
}
}
@@ -60,6 +60,9 @@ public interface ErrorCode {
public final static int BITWISE = 2103;
public final static int NONE_CONDITION = 2104;
public final static int LIKE_NUMBER = 2105;
public final static int EmptyQueryHasCondition = 2106;
public final static int DoubleConstCondition = 2107;
public final static int SameConstLike = 2108;
public final static int NOT_PARAMETERIZED = 2200;
public final static int MULTI_TENANT = 2201;