mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improved mysql parser. for issue #2340
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.mysql.ast;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLName;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
|
||||
import com.alibaba.druid.sql.ast.statement.SQLTableConstraint;
|
||||
@@ -31,6 +32,8 @@ public class MySqlKey extends SQLUnique implements SQLUniqueConstraint, SQLTable
|
||||
|
||||
private boolean hasConstaint;
|
||||
|
||||
private SQLExpr keyBlockSize;
|
||||
|
||||
public MySqlKey(){
|
||||
dbType = JdbcConstants.MYSQL;
|
||||
}
|
||||
@@ -71,6 +74,9 @@ public class MySqlKey extends SQLUnique implements SQLUniqueConstraint, SQLTable
|
||||
super.cloneTo(x);
|
||||
x.indexType = indexType;
|
||||
x.hasConstaint = hasConstaint;
|
||||
if (keyBlockSize != null) {
|
||||
this.setKeyBlockSize(keyBlockSize.clone());
|
||||
}
|
||||
}
|
||||
|
||||
public MySqlKey clone() {
|
||||
@@ -78,4 +84,15 @@ public class MySqlKey extends SQLUnique implements SQLUniqueConstraint, SQLTable
|
||||
cloneTo(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
public SQLExpr getKeyBlockSize() {
|
||||
return keyBlockSize;
|
||||
}
|
||||
|
||||
public void setKeyBlockSize(SQLExpr x) {
|
||||
if (x != null) {
|
||||
x.setParent(this);
|
||||
}
|
||||
this.keyBlockSize = x;
|
||||
}
|
||||
}
|
||||
|
||||
+63
-1
@@ -115,6 +115,57 @@ public class MySqlCreateTableParser extends SQLCreateTableParser {
|
||||
stmt.getTableElementList().add(fulltextKey);
|
||||
if (lexer.token() == Token.RPAREN) {
|
||||
break;
|
||||
} else if (lexer.token() == Token.COMMA) {
|
||||
lexer.nextToken();
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
lexer.reset(mark);
|
||||
}
|
||||
} else if (lexer.identifierEquals(FnvHash.Constants.SPATIAL)) {
|
||||
Lexer.SavePoint mark = lexer.mark();
|
||||
lexer.nextToken();
|
||||
if (lexer.token() == Token.INDEX) {
|
||||
lexer.nextToken();
|
||||
MySqlTableIndex idx = new MySqlTableIndex();
|
||||
idx.setIndexType("SPATIAL");
|
||||
|
||||
if (lexer.token() == Token.IDENTIFIER) {
|
||||
if (!"USING".equalsIgnoreCase(lexer.stringVal())) {
|
||||
idx.setName(this.exprParser.name());
|
||||
}
|
||||
}
|
||||
|
||||
if (lexer.identifierEquals("USING")) {
|
||||
lexer.nextToken();
|
||||
idx.setIndexType(lexer.stringVal());
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
accept(Token.LPAREN);
|
||||
for (;;) {
|
||||
idx.addColumn(this.exprParser.parseSelectOrderByItem());
|
||||
if (!(lexer.token() == (Token.COMMA))) {
|
||||
break;
|
||||
} else {
|
||||
lexer.nextToken();
|
||||
}
|
||||
}
|
||||
accept(Token.RPAREN);
|
||||
|
||||
if (lexer.identifierEquals("USING")) {
|
||||
lexer.nextToken();
|
||||
idx.setIndexType(lexer.stringVal());
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
stmt.getTableElementList().add(idx);
|
||||
|
||||
if (lexer.token() == Token.RPAREN) {
|
||||
break;
|
||||
} else if (lexer.token() == Token.COMMA) {
|
||||
lexer.nextToken();
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
lexer.reset(mark);
|
||||
@@ -461,11 +512,22 @@ public class MySqlCreateTableParser extends SQLCreateTableParser {
|
||||
|
||||
if (lexer.identifierEquals("ENCRYPTION")) {
|
||||
lexer.nextToken();
|
||||
accept(Token.EQ);
|
||||
if (lexer.token() == Token.EQ) {
|
||||
lexer.nextToken();
|
||||
}
|
||||
stmt.getTableOptions().put("ENCRYPTION", this.exprParser.expr());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lexer.identifierEquals(FnvHash.Constants.COMPRESSION)) {
|
||||
lexer.nextToken();
|
||||
if (lexer.token() == Token.EQ) {
|
||||
lexer.nextToken();
|
||||
}
|
||||
stmt.getTableOptions().put("COMPRESSION", this.exprParser.expr());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lexer.token() == Token.PARTITION) {
|
||||
lexer.nextToken();
|
||||
accept(Token.BY);
|
||||
|
||||
@@ -795,6 +795,15 @@ public class MySqlExprParser extends SQLExprParser {
|
||||
lexer.nextToken();
|
||||
}
|
||||
|
||||
if (lexer.identifierEquals(FnvHash.Constants.KEY_BLOCK_SIZE)) {
|
||||
lexer.nextToken();
|
||||
if (lexer.token() == Token.EQ) {
|
||||
lexer.nextToken();
|
||||
}
|
||||
SQLExpr value = this.primary();
|
||||
unique.setKeyBlockSize(value);
|
||||
}
|
||||
|
||||
return unique;
|
||||
}
|
||||
|
||||
|
||||
@@ -399,8 +399,13 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
|
||||
public boolean visit(MySqlTableIndex x) {
|
||||
String indexType = x.getIndexType();
|
||||
|
||||
boolean indexTypePrinted = false;
|
||||
if ("FULLTEXT".equalsIgnoreCase(indexType)) {
|
||||
print0(ucase ? "FULLTEXT " : "fulltext ");
|
||||
indexTypePrinted = true;
|
||||
} else if ("SPATIAL".equalsIgnoreCase(indexType)) {
|
||||
print0(ucase ? "SPATIAL " : "spatial ");
|
||||
indexTypePrinted = true;
|
||||
}
|
||||
|
||||
print0(ucase ? "INDEX" : "index");
|
||||
@@ -409,7 +414,7 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
|
||||
x.getName().accept(this);
|
||||
}
|
||||
|
||||
if (indexType != null && !"FULLTEXT".equalsIgnoreCase(indexType)) {
|
||||
if (indexType != null && !indexTypePrinted) {
|
||||
print0(ucase ? " USING " : " using ");
|
||||
print0(indexType);
|
||||
}
|
||||
@@ -2720,7 +2725,6 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
|
||||
|
||||
if (x.getIndexType() != null) {
|
||||
print0(ucase ? " USING " : " using ");
|
||||
;
|
||||
print0(x.getIndexType());
|
||||
}
|
||||
|
||||
@@ -2728,6 +2732,12 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
|
||||
printAndAccept(x.getColumns(), ", ");
|
||||
print(')');
|
||||
|
||||
SQLExpr keyBlockSize = x.getKeyBlockSize();
|
||||
if (keyBlockSize != null) {
|
||||
print0(ucase ? " KEY_BLOCK_SIZE = " : " key_block_size = ");
|
||||
keyBlockSize.accept(this);
|
||||
}
|
||||
|
||||
SQLExpr comment = x.getComment();
|
||||
if (comment != null) {
|
||||
print0(" COMMENT ");
|
||||
|
||||
@@ -633,7 +633,10 @@ public final class FnvHash {
|
||||
|
||||
long TBLPROPERTIES = fnv1a_64_lower("TBLPROPERTIES");
|
||||
long FULLTEXT = fnv1a_64_lower("FULLTEXT");
|
||||
long SPATIAL = fnv1a_64_lower("SPATIAL");
|
||||
long NO = fnv1a_64_lower("NO");
|
||||
long PATH = fnv1a_64_lower("PATH");
|
||||
long COMPRESSION = fnv1a_64_lower("COMPRESSION");
|
||||
long KEY_BLOCK_SIZE = fnv1a_64_lower("KEY_BLOCK_SIZE");
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,10 +31,10 @@ public class MySqlAlterTableAlterColumnTest extends TestCase {
|
||||
parser.match(Token.EOF);
|
||||
|
||||
assertEquals("ALTER TABLE `cube_template`\n" +
|
||||
"\tADD COLUMN `stat_report_json` VARCHAR(256) CHARSET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '模板的统计报表json数组';", SQLUtils.toMySqlString(stmt));
|
||||
"\tADD COLUMN `stat_report_json` VARCHAR(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '模板的统计报表json数组';", SQLUtils.toMySqlString(stmt));
|
||||
|
||||
assertEquals("alter table `cube_template`\n" +
|
||||
"\tadd column `stat_report_json` VARCHAR(256) charset utf8 COLLATE utf8_general_ci not null default '' comment '模板的统计报表json数组';", SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION));
|
||||
"\tadd column `stat_report_json` VARCHAR(256) character set utf8 collate utf8_general_ci not null default '' comment '模板的统计报表json数组';", SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.alibaba.druid.bvt.sql.mysql.createTable;
|
||||
|
||||
import com.alibaba.druid.sql.MysqlTest;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MySqlCreateTableTest100 extends MysqlTest {
|
||||
|
||||
public void test_0() throws Exception {
|
||||
String sql = "CREATE TABLE IF NOT EXISTS ttable\n" +
|
||||
"(\n" +
|
||||
"`id` BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
|
||||
"`queue_id` varchar(20) NOT NULL DEFAULT '-1',\n" +
|
||||
"`status` TINYINT(4) NOT NULL DEFAULT '1',\n" +
|
||||
"`geometry` geometry not null,\n" +
|
||||
"CONSTRAINT PRIMARY KEY (`id`),\n" +
|
||||
"CONSTRAINT UNIQUE KEY `uk_queue_id` USING BTREE (`queue_id`) KEY_BLOCK_SIZE=10,\n" +
|
||||
"FULLTEXT KEY `ft_status` (`queue_id`),\n" +
|
||||
"spatial index `spatial` (`geometry`),\n" +
|
||||
"CONSTRAINT FOREIGN KEY `fk_test`(`queue_id`) REFERENCES `test`(`id`)\n" +
|
||||
") ENGINE=INNODB";
|
||||
|
||||
MySqlStatementParser parser = new MySqlStatementParser(sql);
|
||||
List<SQLStatement> statementList = parser.parseStatementList();
|
||||
MySqlCreateTableStatement stmt = (MySqlCreateTableStatement)statementList.get(0);
|
||||
|
||||
assertEquals(1, statementList.size());
|
||||
assertEquals(9, stmt.getTableElementList().size());
|
||||
|
||||
assertEquals("CREATE TABLE IF NOT EXISTS ttable (\n" +
|
||||
"\t`id` BIGINT(20) NOT NULL AUTO_INCREMENT,\n" +
|
||||
"\t`queue_id` varchar(20) NOT NULL DEFAULT '-1',\n" +
|
||||
"\t`status` TINYINT(4) NOT NULL DEFAULT '1',\n" +
|
||||
"\t`geometry` geometry NOT NULL,\n" +
|
||||
"\tPRIMARY KEY (`id`),\n" +
|
||||
"\tCONSTRAINT `uk_queue_id` UNIQUE `uk_queue_id` USING BTREE (`queue_id`) KEY_BLOCK_SIZE = 10,\n" +
|
||||
"\tKEY `ft_status` USING FULLTEXT (`queue_id`),\n" +
|
||||
"\tSPATIAL INDEX `spatial`(`geometry`),\n" +
|
||||
"\tCONSTRAINT FOREIGN KEY `fk_test` (`queue_id`) REFERENCES `test` (`id`)\n" +
|
||||
") ENGINE = INNODB", stmt.toString());
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -40,14 +40,14 @@ public class MySqlCreateTableTest60 extends MysqlTest {
|
||||
String output = SQLUtils.toMySqlString(stmt);
|
||||
Assert.assertEquals("CREATE TABLE t10 ("
|
||||
+ "\n\tpk int PRIMARY KEY AUTO_INCREMENT,"
|
||||
+ "\n\tf1 varchar(65500) CHARSET latin1 "
|
||||
+ "\n\tf1 varchar(65500) CHARACTER SET latin1"
|
||||
+ "\n)", output);
|
||||
}
|
||||
{
|
||||
String output = SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION);
|
||||
Assert.assertEquals("create table t10 ("
|
||||
+ "\n\tpk int primary key auto_increment,"
|
||||
+ "\n\tf1 varchar(65500) charset latin1 "
|
||||
+ "\n\tf1 varchar(65500) character set latin1"
|
||||
+ "\n)", output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.alibaba.druid.bvt.sql.mysql.createTable;
|
||||
|
||||
import com.alibaba.druid.sql.MysqlTest;
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MySqlCreateTableTest99 extends MysqlTest {
|
||||
|
||||
public void test_0() throws Exception {
|
||||
String sql = "CREATE TABLE IF NOT EXISTS srcTable\n" +
|
||||
"(\n" +
|
||||
" `id` BIGINT(20) NOT NULL,\n" +
|
||||
" `queue_id` BIGINT(20) NOT NULL DEFAULT '-1',\n" +
|
||||
" `status` TINYINT(4) NOT NULL DEFAULT '1',\n" +
|
||||
" PRIMARY KEY (`id`)\n" +
|
||||
") ENGINE=INNODB AUTO_INCREMENT 10 AVG_ROW_LENGTH 10 DEFAULT CHARACTER SET=utf8 DEFAULT COLLATE = utf8_general_ci\n" +
|
||||
"CHECKSUM=0 COMPRESSION='NONE' CONNECTION = 'connect_string' DELAY_KEY_WRITE = 0 ENCRYPTION 'N' INSERT_METHOD FIRST\n" +
|
||||
"MAX_ROWS 1000 MIN_ROWS=10 PACK_KEYS DEFAULT PASSWORD '12345678' STATS_AUTO_RECALC 0 STATS_PERSISTENT 0 \n" +
|
||||
"STATS_SAMPLE_PAGES 10";
|
||||
|
||||
// System.out.println(sql);
|
||||
|
||||
MySqlStatementParser parser = new MySqlStatementParser(sql);
|
||||
List<SQLStatement> statementList = parser.parseStatementList();
|
||||
MySqlCreateTableStatement stmt = (MySqlCreateTableStatement)statementList.get(0);
|
||||
|
||||
assertEquals(1, statementList.size());
|
||||
assertEquals(4, stmt.getTableElementList().size());
|
||||
|
||||
assertEquals("CREATE TABLE IF NOT EXISTS srcTable (\n" +
|
||||
"\t`id` BIGINT(20) NOT NULL,\n" +
|
||||
"\t`queue_id` BIGINT(20) NOT NULL DEFAULT '-1',\n" +
|
||||
"\t`status` TINYINT(4) NOT NULL DEFAULT '1',\n" +
|
||||
"\tPRIMARY KEY (`id`)\n" +
|
||||
") ENGINE = INNODB AUTO_INCREMENT = 10 AVG_ROW_LENGTH = 10 CHARACTER SET = utf8 COLLATE = utf8_general_ci CHECKSUM = 0 COMPRESSION = 'NONE' CONNECTION = 'connect_string' DELAY_KEY_WRITE = 0 ENCRYPTION = 'N' INSERT_METHOD = FIRST MAX_ROWS = 1000 MIN_ROWS = 10 PACK_KEYS = DEFAULT PASSWORD = '12345678' STATS_AUTO_RECALC = 0 STATS_PERSISTENT = 0 STATS_SAMPLE_PAGES = 10", stmt.toString());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user