mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improve sql-wall
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user