diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/expr/MySqlOutFileExpr.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/expr/MySqlOutFileExpr.java index ff2f12b444..485a41fd7c 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/expr/MySqlOutFileExpr.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/expr/MySqlOutFileExpr.java @@ -25,7 +25,7 @@ public class MySqlOutFileExpr extends MySqlObjectImpl implements SQLExpr { private SQLExpr file; private String charset; - private SQLLiteralExpr columnsTerminatedBy; + private SQLExpr columnsTerminatedBy; private boolean columnsEnclosedOptionally = false; private SQLLiteralExpr columnsEnclosedBy; private SQLLiteralExpr columnsEscaped; @@ -66,11 +66,11 @@ public class MySqlOutFileExpr extends MySqlObjectImpl implements SQLExpr { this.charset = charset; } - public SQLLiteralExpr getColumnsTerminatedBy() { + public SQLExpr getColumnsTerminatedBy() { return columnsTerminatedBy; } - public void setColumnsTerminatedBy(SQLLiteralExpr columnsTerminatedBy) { + public void setColumnsTerminatedBy(SQLExpr columnsTerminatedBy) { this.columnsTerminatedBy = columnsTerminatedBy; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java index c002413543..55b4681669 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java @@ -328,7 +328,7 @@ public class MySqlSelectParser extends SQLSelectParser { lexer.nextToken(); accept(Token.BY); } - outFile.setColumnsTerminatedBy((SQLLiteralExpr) expr()); + outFile.setColumnsTerminatedBy(expr()); if (identifierEquals("OPTIONALLY")) { lexer.nextToken(); 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 50fcbf53e2..54431f30ab 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 @@ -250,6 +250,9 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS @Override public boolean visit(MySqlKey x) { + for (SQLObject item : x.getColumns()) { + item.accept(this); + } return false; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/odps/ast/OdpsValuesTableSource.java b/src/main/java/com/alibaba/druid/sql/dialect/odps/ast/OdpsValuesTableSource.java index 86311cbc06..f774168031 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/odps/ast/OdpsValuesTableSource.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/odps/ast/OdpsValuesTableSource.java @@ -1,3 +1,18 @@ +/* + * 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.sql.dialect.odps.ast; import com.alibaba.druid.sql.ast.SQLName; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java index af530adfab..87c3059cb5 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java @@ -236,7 +236,6 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS print0(ucase ? "DELETE " : "delete "); SQLTableSource tableSource = x.getTableSource(); - if (x.getHints().size() > 0) { printAndAccept(x.getHints(), ", "); print(' '); diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java index b9db7ab5bb..7f2c9c29ef 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -996,6 +996,13 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { } } if (column != null) { + SQLObject parent = x.getParent(); + if (parent instanceof SQLPrimaryKey) { + column.setPrimaryKey(true); + } else if (parent instanceof SQLUnique) { + column.setUnique(true); + } + setColumn(x, column); } return false; @@ -1440,6 +1447,14 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { column.setDataType(x.getDataType().getName()); } + for (SQLColumnConstraint item : x.getConstraints()) { + if (item instanceof SQLPrimaryKey) { + column.setPrimaryKey(true); + } else if (item instanceof SQLUnique) { + column.setUnique(true); + } + } + return false; } diff --git a/src/main/java/com/alibaba/druid/stat/TableStat.java b/src/main/java/com/alibaba/druid/stat/TableStat.java index 9ed81a614f..43de7e5730 100644 --- a/src/main/java/com/alibaba/druid/stat/TableStat.java +++ b/src/main/java/com/alibaba/druid/stat/TableStat.java @@ -405,6 +405,9 @@ public class TableStat { private boolean having; private boolean join; + private boolean primaryKey; // for ddl + private boolean unique; // + private Map attributes = new HashMap(); private transient String fullName; @@ -484,6 +487,22 @@ public class TableStat { this.having = having; } + public boolean isPrimaryKey() { + return primaryKey; + } + + public void setPrimaryKey(boolean primaryKey) { + this.primaryKey = primaryKey; + } + + public boolean isUnique() { + return unique; + } + + public void setUnique(boolean unique) { + this.unique = unique; + } + public String getName() { return name; } diff --git a/src/main/java/com/alibaba/druid/util/MySqlUtils.java b/src/main/java/com/alibaba/druid/util/MySqlUtils.java index 66e61376ea..f540c2bd62 100644 --- a/src/main/java/com/alibaba/druid/util/MySqlUtils.java +++ b/src/main/java/com/alibaba/druid/util/MySqlUtils.java @@ -42,7 +42,8 @@ public class MySqlUtils { static Constructor MysqlXAConnectionConstructor = null; public static XAConnection createXAConnection(Driver driver, Connection physicalConn) throws SQLException { - if (driver.getMajorVersion() == 5) { + final int major = driver.getMajorVersion(); + if (major == 5) { if (utilClass == null && !utilClassError) { try { utilClass = Class.forName("com.mysql.jdbc.Util"); diff --git a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java index 6e4c403c20..f8b3a18cb7 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java @@ -1650,6 +1650,10 @@ public class WallVisitorUtils { return; } + if (isTopFromDenySchema(visitor, x)) { + return; + } + boolean isShow = x.getParent() instanceof MySqlShowGrantsStatement; if (isShow) { return; @@ -1699,6 +1703,7 @@ public class WallVisitorUtils { if (!(x.getParent() instanceof SQLSelectItem)) { return false; } + SQLSelectItem item = (SQLSelectItem) x.getParent(); if (!(item.getParent() instanceof SQLSelectQueryBlock)) { @@ -1725,6 +1730,51 @@ public class WallVisitorUtils { return stmt.getParent() == null; } + private static boolean isTopFromDenySchema(WallVisitor visitor, SQLMethodInvokeExpr x) { + SQLObject parent = x.getParent(); + for (;; ) { + if (parent instanceof SQLExpr || parent instanceof Item || parent instanceof SQLSelectItem) { + parent = parent.getParent(); + } else { + break; + } + } + + if (parent instanceof SQLSelectQueryBlock) { + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) parent; + if (!(queryBlock.getParent() instanceof SQLSelect)) { + return false; + } + + SQLSelect select = (SQLSelect) queryBlock.getParent(); + + if (!(select.getParent() instanceof SQLSelectStatement)) { + return false; + } + + SQLSelectStatement stmt = (SQLSelectStatement) select.getParent(); + + if (stmt.getParent() != null) { + return false; + } + + SQLTableSource from = queryBlock.getFrom(); + if (from instanceof SQLExprTableSource) { + SQLExpr fromExpr = ((SQLExprTableSource) from).getExpr(); + if (fromExpr instanceof SQLName) { + String fromTableName = fromExpr.toString(); + return visitor.isDenyTable(fromTableName); + } + } + + return false; + } + + + + return false; + } + private static boolean checkSchema(WallVisitor visitor, SQLExpr x) { final WallTopStatementContext topStatementContext = wallTopStatementContextLocal.get(); if (topStatementContext != null && (topStatementContext.fromSysSchema || topStatementContext.fromSysTable)) { diff --git a/src/main/resources/META-INF/druid/wall/postgres/deny-table.txt b/src/main/resources/META-INF/druid/wall/postgres/deny-table.txt new file mode 100644 index 0000000000..27839ffb14 --- /dev/null +++ b/src/main/resources/META-INF/druid/wall/postgres/deny-table.txt @@ -0,0 +1 @@ +pg_database \ No newline at end of file diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/pg/PGWallTest1.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/pg/PGWallTest1.java new file mode 100644 index 0000000000..6408e00191 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/pg/PGWallTest1.java @@ -0,0 +1,34 @@ +/* + * 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.filter.wall.pg; + +import com.alibaba.druid.wall.WallUtils; +import junit.framework.TestCase; +import org.junit.Assert; + +/** + * SQLServerWallTest + * + * @author RaymondXiu + * @version 1.0, 2012-3-18 + * @see + */ +public class PGWallTest1 extends TestCase { + public void test_wall() throws Exception { + Assert.assertTrue(WallUtils.isValidatePostgres(// + "select pg_encoding_to_char(encoding) from pg_database where datname = current_database()")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/visitor/MySqlSchemaStatVisitorTest_pk_0.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/visitor/MySqlSchemaStatVisitorTest_pk_0.java new file mode 100644 index 0000000000..788fa3bbcd --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/visitor/MySqlSchemaStatVisitorTest_pk_0.java @@ -0,0 +1,107 @@ +/* + * 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.visitor; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; +import com.alibaba.druid.sql.ast.statement.SQLTableElement; +import com.alibaba.druid.sql.ast.statement.SQLUnique; +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 junit.framework.TestCase; +import org.junit.Assert; + +import java.util.List; + +public class MySqlSchemaStatVisitorTest_pk_0 extends TestCase { + + public void test_0() throws Exception { + String sql ="CREATE TABLE `m_dt` (\n" + + " `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n" + + " `gmt_create` datetime NOT NULL COMMENT '创建时间',\n" + + " `gmt_modified` datetime NOT NULL COMMENT '修改时间',\n" + + " `instance_id` int(11) NOT NULL COMMENT '实例id',\n" + + " `schema_name` varchar(128) NOT NULL COMMENT '数据库schema名称',\n" + + " `state` tinyint(4) NOT NULL DEFAULT '0' COMMENT ' x dd ',\n" + + " `busi_user` varchar(64) DEFAULT NULL COMMENT 'JDBC业务用户',\n" + + " `bzp` varchar(128) DEFAULT NULL COMMENT 'bcp',\n" + + " `ecd` varchar(32) DEFAULT NULL COMMENT 'xxx',\n" + + " `last_sync_time` datetime DEFAULT NULL COMMENT '最后同步时间',\n" + + " `catalog_name` varchar(128) NOT NULL COMMENT '物理库名称',\n" + + " `search_name` varchar(256) NOT NULL COMMENT '用于搜索,区分不同数据库的不同字段信息',\n" + + " `db_type` tinyint(4) NOT NULL COMMENT '数据库类型,和meta_instance表一致',\n" + + " `et` varchar(32) NOT NULL DEFAULT '' COMMENT 'et',\n" + + " `ae` varchar(32) DEFAULT NULL COMMENT 'ae',\n" + + " PRIMARY KEY (`id`),\n" + + " UNIQUE KEY `uk_instanceid_schemaname` (`instance_id`,`catalog_name`,`schema_name`),\n" + + " KEY `idx_schema_name` (`schema_name`),\n" + + " KEY `idx_instance_id_state` (`instance_id`,`id`,`state`),\n" + + " KEY `idx_search_name` (`search_name`(255))\n" + + ") ENGINE=InnoDB AUTO_INCREMENT=408695 DEFAULT CHARSET=utf8 COMMENT='数据库表信息'"; + +// sql = "select columnName from table1 where id in (select id from table3 where name = ?)"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLCreateTableStatement stmt = (SQLCreateTableStatement) statementList.get(0); + + Assert.assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + System.out.println(sql); + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + + Assert.assertEquals(1, visitor.getTables().size()); + Assert.assertEquals(true, visitor.containsTable("m_dt")); + + Assert.assertEquals(15, visitor.getColumns().size()); + + { + TableStat.Column column = visitor.getColumn("m_dt", "id"); + assertNotNull(column); + assertTrue(column.isPrimaryKey()); + } + { + TableStat.Column column = visitor.getColumn("m_dt", "schema_name"); + assertNotNull(column); + assertTrue(column.isUnique()); + } + { + TableStat.Column column = visitor.getColumn("m_dt", "instance_id"); + assertNotNull(column); + assertTrue(column.isUnique()); + } + + for (SQLTableElement element : stmt.getTableElementList()) { + if (element instanceof SQLUnique) { + SQLName name = ((SQLUnique) element).getName(); + if (name != null) { + String uniqueName = name.toString(); + } + } + } + // Assert.assertEquals(true, visitor.getFields().contains(new + // Column("users", "id"))); + // Assert.assertEquals(true, visitor.getFields().contains(new + // Column("users", "name"))); + + } + +}