diff --git a/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java b/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java index 5d654c4edb..b361788214 100644 --- a/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java +++ b/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java @@ -21,9 +21,8 @@ import java.sql.Clob; import java.sql.NClob; import java.sql.SQLException; import java.sql.Savepoint; -import java.util.ArrayList; import java.util.Date; -import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; @@ -40,6 +39,7 @@ import com.alibaba.druid.logging.LogFactory; import com.alibaba.druid.proxy.jdbc.CallableStatementProxy; import com.alibaba.druid.proxy.jdbc.ConnectionProxy; import com.alibaba.druid.proxy.jdbc.DataSourceProxy; +import com.alibaba.druid.proxy.jdbc.JdbcParameter; import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy; import com.alibaba.druid.proxy.jdbc.ResultSetProxy; import com.alibaba.druid.proxy.jdbc.StatementProxy; @@ -406,29 +406,32 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean { long millis = nanoSpan / (1000 * 1000); if (millis >= slowSqlMillis) { - List lastSlowParameters = new ArrayList(); - for (Object value : statement.getParameters().values()) { + Map parameters = statement.getParameters(); + String[] lastSlowParameters = new String[parameters.size()]; + int index = 0; + for (JdbcParameter parameter : statement.getParameters().values()) { + Object value = parameter.getValue(); if (value == null) { - lastSlowParameters.add("null"); + lastSlowParameters[index] = "null"; } else if (value instanceof String) { - lastSlowParameters.add("'" + value.toString() + "'"); + lastSlowParameters[index] = "'" + value.toString() + "'"; } else if (value instanceof Number) { - lastSlowParameters.add(value.toString()); + lastSlowParameters[index] = value.toString(); } else if (value instanceof java.util.Date) { java.util.Date date = (java.util.Date) value; - lastSlowParameters.add(date.getClass().getSimpleName() + "(" + date.getTime() + ")"); + lastSlowParameters[index] = date.getClass().getSimpleName() + "(" + date.getTime() + ")"; } else if (value instanceof Boolean) { - lastSlowParameters.add(value.toString()); + lastSlowParameters[index] = value.toString(); } else if (value instanceof InputStream) { - lastSlowParameters.add(""); + lastSlowParameters[index] = ""; } else if (value instanceof Clob) { - lastSlowParameters.add(""); + lastSlowParameters[index] = ""; } else if (value instanceof NClob) { - lastSlowParameters.add(""); + lastSlowParameters[index] = ""; } else if (value instanceof Blob) { - lastSlowParameters.add(""); + lastSlowParameters[index] = ""; } else { - lastSlowParameters.add("<" + value.getClass() + ">"); + lastSlowParameters[index] = "<" + value.getClass() + ">"; } } sqlStat.setLastSlowParameters(lastSlowParameters); diff --git a/src/main/java/com/alibaba/druid/filter/wall/WallUtils.java b/src/main/java/com/alibaba/druid/filter/wall/WallUtils.java index e2ad2254e2..22e2e3df38 100644 --- a/src/main/java/com/alibaba/druid/filter/wall/WallUtils.java +++ b/src/main/java/com/alibaba/druid/filter/wall/WallUtils.java @@ -9,9 +9,19 @@ public class WallUtils { MySqlWallProvider provider = new MySqlWallProvider(); return provider.check(sql, false); } - + + public static boolean isValidateMySql(String sql, WallConfig config) { + MySqlWallProvider provider = new MySqlWallProvider(config); + return provider.check(sql, false); + } + public static boolean isValidateOracle(String sql) { OracleWallProvider provider = new OracleWallProvider(); return provider.check(sql, false); } + + public static boolean isValidateOracle(String sql, WallConfig config) { + OracleWallProvider provider = new OracleWallProvider(config); + return provider.check(sql, false); + } } diff --git a/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallVisitor.java b/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallVisitor.java index 3679b89d6b..16511794f9 100644 --- a/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallVisitor.java +++ b/src/main/java/com/alibaba/druid/filter/wall/spi/MySqlWallVisitor.java @@ -89,23 +89,13 @@ public class MySqlWallVisitor extends MySqlASTVisitorAdapter implements WallVisi @Override public boolean visit(SQLDeleteStatement x) { - if (!config.isDeleteAllow()) { - this.getViolations().add(new IllegalSQLObjectViolation(this.toSQL(x))); - return false; - } - - WallVisitorUtils.checkDeleteCondition(this, x.getWhere()); + WallVisitorUtils.checkDelete(this, x); return true; } @Override public boolean visit(SQLUpdateStatement x) { - if (!config.isUpdateAllow()) { - this.getViolations().add(new IllegalSQLObjectViolation(this.toSQL(x))); - return false; - } - - WallVisitorUtils.checkUpdateCondition(this, x.getWhere()); + WallVisitorUtils.checkUpdate(this, x); return true; } diff --git a/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallVisitor.java b/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallVisitor.java index 88941430b3..e8d3400e58 100644 --- a/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallVisitor.java +++ b/src/main/java/com/alibaba/druid/filter/wall/spi/OracleWallVisitor.java @@ -200,12 +200,7 @@ public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVi @Override public boolean visit(SQLDeleteStatement x) { - if (!config.isDeleteAllow()) { - this.getViolations().add(new IllegalSQLObjectViolation(this.toSQL(x))); - return false; - } - - WallVisitorUtils.checkDeleteCondition(this, x.getWhere()); + WallVisitorUtils.checkDelete(this, x); return true; } @@ -216,12 +211,7 @@ public class OracleWallVisitor extends OracleASTVIsitorAdapter implements WallVi @Override public boolean visit(SQLUpdateStatement x) { - if (!config.isUpdateAllow()) { - this.getViolations().add(new IllegalSQLObjectViolation(this.toSQL(x))); - return false; - } - - WallVisitorUtils.checkUpdateCondition(this, x.getWhere()); + WallVisitorUtils.checkUpdate(this, x); return true; } diff --git a/src/main/java/com/alibaba/druid/filter/wall/spi/WallVisitorUtils.java b/src/main/java/com/alibaba/druid/filter/wall/spi/WallVisitorUtils.java index 3b062c3064..ddfd28c06d 100644 --- a/src/main/java/com/alibaba/druid/filter/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/filter/wall/spi/WallVisitorUtils.java @@ -29,6 +29,7 @@ import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumericLiteralExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; +import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectItem; @@ -36,6 +37,7 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource; import com.alibaba.druid.sql.ast.statement.SQLTableSource; +import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlBooleanExpr; import com.alibaba.druid.util.JdbcUtils; @@ -92,8 +94,9 @@ public class WallVisitorUtils { } } - public static void checkDeleteCondition(WallVisitor visitor, SQLExpr x) { - if (x == null) { + public static void checkDelete(WallVisitor visitor, SQLDeleteStatement x) { + if (!visitor.getConfig().isDeleteAllow()) { + visitor.getViolations().add(new IllegalSQLObjectViolation(visitor.toSQL(x))); return; } @@ -101,22 +104,23 @@ public class WallVisitorUtils { return; } - if (Boolean.TRUE == getValue(x)) { - visitor.getViolations().add(new IllegalSQLObjectViolation(SQLUtils.toSQLString(x))); + if (x.getWhere() == null || Boolean.TRUE == getValue(x.getWhere())) { + visitor.getViolations().add(new IllegalSQLObjectViolation(visitor.toSQL(x))); } } - public static void checkUpdateCondition(WallVisitor visitor, SQLExpr x) { - if (x == null) { + public static void checkUpdate(WallVisitor visitor, SQLUpdateStatement x) { + if (!visitor.getConfig().isUpdateAllow()) { + visitor.getViolations().add(new IllegalSQLObjectViolation(visitor.toSQL(x))); return; } - + if (!visitor.getConfig().isUpdateWhereAlayTrueCheck()) { return; } - if (Boolean.TRUE == getValue(x)) { - visitor.getViolations().add(new IllegalSQLObjectViolation(SQLUtils.toSQLString(x))); + if (x.getWhere() == null || Boolean.TRUE == getValue(x.getWhere())) { + visitor.getViolations().add(new IllegalSQLObjectViolation(visitor.toSQL(x))); } } @@ -395,11 +399,11 @@ public class WallVisitorUtils { visitor.getViolations().add(new IllegalSQLObjectViolation(visitor.toSQL(x))); } } - + if (!visitor.getConfig().isFunctionCheck()) { return; } - + String methodName = x.getMethodName(); if (visitor.getConfig().isPermitFunction(methodName.toLowerCase())) { diff --git a/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java b/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java index a607527784..4992699ba7 100644 --- a/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java +++ b/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java @@ -17,7 +17,6 @@ package com.alibaba.druid.stat; import java.util.Date; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; @@ -65,7 +64,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean { private final AtomicLong inTransactionCount = new AtomicLong(); - private List lastSlowParameters; + private String[] lastSlowParameters; private final Histogram histogram = new Histogram(new long[] { // // @@ -78,11 +77,11 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean { this.sql = sql; } - public List getLastSlowParameters() { + public String[] getLastSlowParameters() { return lastSlowParameters; } - public void setLastSlowParameters(List lastSlowParameters) { + public void setLastSlowParameters(String[] lastSlowParameters) { this.lastSlowParameters = lastSlowParameters; } @@ -391,7 +390,8 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean { SimpleType.STRING, // // 25 - - new ArrayType(SimpleType.LONG, true) // + new ArrayType(SimpleType.LONG, true), // + new ArrayType(SimpleType.STRING, true), // }; String[] indexNames = { @@ -431,7 +431,9 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean { "URL", // // 25 - - "Histogram" // + "Histogram", // + "LastSlowParameters" + // }; String[] indexDescriptions = indexNames; COMPOSITE_TYPE = new CompositeType("SqlStatistic", "Sql Statistic", indexNames, indexDescriptions, indexTypes); @@ -446,6 +448,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean { public Map getData() throws JMException { Map map = new HashMap(); + // 0 - 4 map.put("ID", id); map.put("DataSource", dataSource); map.put("SQL", sql); @@ -487,6 +490,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean { map.put("InTransactionCount", getInTransactionCount()); map.put("Histogram", this.histogram.toArray()); + map.put("LastSlowParameters", lastSlowParameters); return map; } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDeleteTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDeleteTest.java new file mode 100644 index 0000000000..db6a36a2d3 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDeleteTest.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallConfig; +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,检测 + * @author wenshao + * + */ +public class WallDeleteTest extends TestCase { + private String sql = "DELETE FROM T WHERE F1 = ?"; + + private WallConfig config = new WallConfig(); + + protected void setUp() throws Exception { + config.setDeleteAllow(false); + } + + public void testMySql() throws Exception { + Assert.assertFalse(WallUtils.isValidateMySql(sql, config)); + } + + public void testORACLE() throws Exception { + + Assert.assertFalse(WallUtils.isValidateOracle(sql, config)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDeleteWhereTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDeleteWhereTest.java index 93d8973b12..163c15e758 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDeleteWhereTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDeleteWhereTest.java @@ -7,7 +7,7 @@ import org.junit.Assert; import com.alibaba.druid.filter.wall.WallUtils; /** - * 这个场景,检测可疑的Having条件 + * * @author wenshao * */ diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDeleteWhereTest1.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDeleteWhereTest1.java new file mode 100644 index 0000000000..597a952f56 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallDeleteWhereTest1.java @@ -0,0 +1,24 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,检测可疑的Having条件 + * @author wenshao + * + */ +public class WallDeleteWhereTest1 extends TestCase { + private String sql = "DELETE FROM T"; + + public void testMySql() throws Exception { + Assert.assertFalse(WallUtils.isValidateMySql(sql)); + } + + public void testORACLE() throws Exception { + Assert.assertFalse(WallUtils.isValidateOracle(sql)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallInsertTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallInsertTest.java new file mode 100644 index 0000000000..46e01809fe --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallInsertTest.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallConfig; +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,检测 + * @author wenshao + * + */ +public class WallInsertTest extends TestCase { + private String sql = "INSERT INTO T (F1, F2) VALUES (1, 2)"; + + private WallConfig config = new WallConfig(); + + protected void setUp() throws Exception { + config.setInsertAllow(false); + } + + public void testMySql() throws Exception { + Assert.assertFalse(WallUtils.isValidateMySql(sql, config)); + } + + public void testORACLE() throws Exception { + + Assert.assertFalse(WallUtils.isValidateOracle(sql, config)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallInsertTest2.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallInsertTest2.java new file mode 100644 index 0000000000..cf2b97f2af --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallInsertTest2.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallConfig; +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,检测 + * @author wenshao + * + */ +public class WallInsertTest2 extends TestCase { + private String sql = "INSERT INTO T (F1, F2) VALUES (1, 2)"; + + private WallConfig config = new WallConfig(); + + protected void setUp() throws Exception { + config.setInsertAllow(true); + } + + public void testMySql() throws Exception { + Assert.assertTrue(WallUtils.isValidateMySql(sql, config)); + } + + public void testORACLE() throws Exception { + + Assert.assertTrue(WallUtils.isValidateOracle(sql, config)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest4.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest4.java index c8fd2fbdd7..02abcffe1e 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest4.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallSelectWhereTest4.java @@ -7,7 +7,7 @@ import org.junit.Assert; import com.alibaba.druid.filter.wall.WallUtils; /** - * 这个场景,检测可疑的Having条件 + * 这个场景,检测可疑的Where条件 * @author wenshao * */ diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest.java new file mode 100644 index 0000000000..7df4c5d5e0 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallConfig; +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,检测 + * @author wenshao + * + */ +public class WallUpdateTest extends TestCase { + private String sql = "UPDATE T_USER SET FNAME = ? WHERE FID = ?"; + + private WallConfig config = new WallConfig(); + + protected void setUp() throws Exception { + config.setDeleteAllow(false); + } + + public void testMySql() throws Exception { + Assert.assertTrue(WallUtils.isValidateMySql(sql, config)); + } + + public void testORACLE() throws Exception { + + Assert.assertTrue(WallUtils.isValidateOracle(sql, config)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest1.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest1.java new file mode 100644 index 0000000000..1f38a72fa4 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest1.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallConfig; +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,检测 + * @author wenshao + * + */ +public class WallUpdateTest1 extends TestCase { + private String sql = "UPDATE T_USER SET FNAME = ? WHERE FID = ?"; + + private WallConfig config = new WallConfig(); + + protected void setUp() throws Exception { + config.setUpdateAllow(false); + } + + public void testMySql() throws Exception { + Assert.assertFalse(WallUtils.isValidateMySql(sql, config)); + } + + public void testORACLE() throws Exception { + + Assert.assertFalse(WallUtils.isValidateOracle(sql, config)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest2.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest2.java new file mode 100644 index 0000000000..8e8a91f48c --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest2.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallConfig; +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,检测 + * @author wenshao + * + */ +public class WallUpdateTest2 extends TestCase { + private String sql = "UPDATE T_USER SET FNAME = ?"; + + private WallConfig config = new WallConfig(); + + protected void setUp() throws Exception { + config.setUpdateAllow(true); + } + + public void testMySql() throws Exception { + Assert.assertFalse(WallUtils.isValidateMySql(sql, config)); + } + + public void testORACLE() throws Exception { + + Assert.assertFalse(WallUtils.isValidateOracle(sql, config)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest3.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest3.java new file mode 100644 index 0000000000..373d86bb33 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest3.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallConfig; +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,检测 + * @author wenshao + * + */ +public class WallUpdateTest3 extends TestCase { + private String sql = "UPDATE T_USER SET FNAME = ? WHERE 1 = 1"; + + private WallConfig config = new WallConfig(); + + protected void setUp() throws Exception { + config.setUpdateAllow(true); + } + + public void testMySql() throws Exception { + Assert.assertFalse(WallUtils.isValidateMySql(sql, config)); + } + + public void testORACLE() throws Exception { + + Assert.assertFalse(WallUtils.isValidateOracle(sql, config)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest4.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest4.java new file mode 100644 index 0000000000..262d3a6beb --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/WallUpdateTest4.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.filter.wall.WallConfig; +import com.alibaba.druid.filter.wall.WallUtils; + +/** + * 这个场景,检测 + * @author wenshao + * + */ +public class WallUpdateTest4 extends TestCase { + private String sql = "UPDATE T_USER SET FNAME = ? WHERE FID = ? OR 1 = 1"; + + private WallConfig config = new WallConfig(); + + protected void setUp() throws Exception { + config.setUpdateAllow(true); + } + + public void testMySql() throws Exception { + Assert.assertFalse(WallUtils.isValidateMySql(sql, config)); + } + + public void testORACLE() throws Exception { + + Assert.assertFalse(WallUtils.isValidateOracle(sql, config)); + } +}