improved odps sql parser. support values datasource.

This commit is contained in:
wenshao
2017-02-23 21:01:48 +08:00
parent d84d1b81fe
commit 1ff403500f
10 changed files with 257 additions and 80 deletions
@@ -0,0 +1,42 @@
package com.alibaba.druid.sql.dialect.odps.ast;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.expr.SQLListExpr;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSourceImpl;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsObject;
import com.alibaba.druid.sql.dialect.odps.visitor.OdpsASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import java.util.ArrayList;
import java.util.List;
/**
* Created by wenshao on 23/02/2017.
*/
public class OdpsValuesTableSource extends SQLTableSourceImpl implements OdpsObject {
private List<SQLListExpr> values = new ArrayList<SQLListExpr>();
private List<SQLName> columns = new ArrayList<SQLName>();
@Override
protected void accept0(SQLASTVisitor visitor) {
accept0((OdpsASTVisitor) visitor);
}
public List<SQLListExpr> getValues() {
return values;
}
public List<SQLName> getColumns() {
return columns;
}
@Override
public void accept0(OdpsASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, values);
acceptChild(visitor, columns);
}
visitor.endVisit(this);
}
}
@@ -19,12 +19,14 @@ import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLLimit;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import com.alibaba.druid.sql.ast.SQLSetQuantifier;
import com.alibaba.druid.sql.ast.expr.SQLListExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsLateralViewTableSource;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsSelectQueryBlock;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsValuesTableSource;
import com.alibaba.druid.sql.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.SQLSelectParser;
import com.alibaba.druid.sql.parser.Token;
@@ -123,6 +125,41 @@ public class OdpsSelectParser extends SQLSelectParser {
return queryRest(queryBlock);
}
public SQLTableSource parseTableSource() {
if (lexer.token() == Token.VALUES) {
lexer.nextToken();
OdpsValuesTableSource tableSource = new OdpsValuesTableSource();
for (;;) {
accept(Token.LPAREN);
SQLListExpr listExpr = new SQLListExpr();
this.exprParser.exprList(listExpr.getItems(), listExpr);
accept(Token.RPAREN);
listExpr.setParent(tableSource);
tableSource.getValues().add(listExpr);
if (lexer.token() == Token.COMMA) {
lexer.nextToken();
continue;
}
break;
}
String alias = this.as();
tableSource.setAlias(alias);
accept(Token.LPAREN);
this.exprParser.names(tableSource.getColumns(), tableSource);
accept(Token.RPAREN);
return tableSource;
}
return super.parseTableSource();
}
protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) {
tableSource = super.parseTableSourceRest(tableSource);
@@ -15,24 +15,7 @@
*/
package com.alibaba.druid.sql.dialect.odps.visitor;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsAddStatisticStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsAnalyzeTableStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsCreateTableStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsDescStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsGrantStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsInsert;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsInsertStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsLateralViewTableSource;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsListStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsReadStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsRemoveStatisticStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsSelectQueryBlock;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsSetLabelStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowGrantsStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowPartitionsStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowStatisticStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsStatisticClause;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsUDTFSQLSelectItem;
import com.alibaba.druid.sql.dialect.odps.ast.*;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public interface OdpsASTVisitor extends SQLASTVisitor {
@@ -128,4 +111,8 @@ public interface OdpsASTVisitor extends SQLASTVisitor {
void endVisit(OdpsLateralViewTableSource x);
boolean visit(OdpsLateralViewTableSource x);
void endVisit(OdpsValuesTableSource x);
boolean visit(OdpsValuesTableSource x);
}
@@ -15,24 +15,7 @@
*/
package com.alibaba.druid.sql.dialect.odps.visitor;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsAddStatisticStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsAnalyzeTableStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsCreateTableStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsDescStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsGrantStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsInsert;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsInsertStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsLateralViewTableSource;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsListStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsReadStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsRemoveStatisticStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsSelectQueryBlock;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsSetLabelStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowGrantsStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowPartitionsStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowStatisticStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsStatisticClause;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsUDTFSQLSelectItem;
import com.alibaba.druid.sql.dialect.odps.ast.*;
import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter;
@@ -268,4 +251,13 @@ public class OdpsASTVisitorAdapter extends SQLASTVisitorAdapter implements OdpsA
return true;
}
@Override
public void endVisit(OdpsValuesTableSource x) {
}
@Override
public boolean visit(OdpsValuesTableSource x) {
return true;
}
}
@@ -29,24 +29,7 @@ import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource.JoinType;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsAddStatisticStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsAnalyzeTableStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsCreateTableStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsDescStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsGrantStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsInsert;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsInsertStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsLateralViewTableSource;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsListStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsReadStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsRemoveStatisticStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsSelectQueryBlock;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsSetLabelStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowGrantsStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowPartitionsStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowStatisticStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsStatisticClause;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsUDTFSQLSelectItem;
import com.alibaba.druid.sql.dialect.odps.ast.*;
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
import com.alibaba.druid.util.JdbcConstants;
@@ -911,4 +894,23 @@ public class OdpsOutputVisitor extends SQLASTOutputVisitor implements OdpsASTVis
return false;
}
@Override
public void endVisit(OdpsValuesTableSource x) {
}
@Override
public boolean visit(OdpsValuesTableSource x) {
print0(ucase ? "VALUES " : "values ");
printAndAccept(x.getValues(), ", ");
print(' ');
print0(x.getAlias());
print0(" (");
printAndAccept(x.getColumns(), ", ");
print(')');
return false;
}
}
@@ -18,24 +18,7 @@ package com.alibaba.druid.sql.dialect.odps.visitor;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsAddStatisticStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsAnalyzeTableStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsCreateTableStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsDescStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsGrantStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsInsert;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsInsertStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsLateralViewTableSource;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsListStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsReadStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsRemoveStatisticStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsSelectQueryBlock;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsSetLabelStatement;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowGrantsStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowPartitionsStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsShowStatisticStmt;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsStatisticClause;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsUDTFSQLSelectItem;
import com.alibaba.druid.sql.dialect.odps.ast.*;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
@@ -300,4 +283,19 @@ public class OdpsSchemaStatVisitor extends SchemaStatVisitor implements OdpsASTV
public boolean visit(OdpsLateralViewTableSource x) {
return true;
}
@Override
public void endVisit(OdpsValuesTableSource x) {
}
@Override
public boolean visit(OdpsValuesTableSource x) {
Map<String, String> aliasMap = getAliasMap();
if (aliasMap != null && x.getAlias() != null) {
putAliasMap(aliasMap, x.getAlias(), null);
addSubQuery(x.getAlias(), x);
}
return false;
}
}
@@ -54,6 +54,7 @@ import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlExpr;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsValuesTableSource;
import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleExpr;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitorAdapter;
import com.alibaba.druid.stat.TableStat;
@@ -859,6 +860,11 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
List<SQLSelectItem> selectList = null;
if (query instanceof SQLSelectQueryBlock) {
queryBlock = (SQLSelectQueryBlock) query;
if (queryBlock.getGroupBy() != null) {
return null;
}
selectList = queryBlock.getSelectList();
}
@@ -960,7 +966,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
return false;
}
Column column;
Column column = null;
if (currentTable != null) {
column = addColumn(currentTable, ident);
@@ -969,7 +975,22 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
}
x.putAttribute(ATTR_COLUMN, column);
} else {
column = handleUnkownColumn(ident);
boolean skip = false;
for (SQLObject parent = x.getParent();parent != null;parent = parent.getParent()) {
if (parent instanceof SQLSelectQueryBlock) {
SQLTableSource from = ((SQLSelectQueryBlock) parent).getFrom();
if (from instanceof OdpsValuesTableSource) {
skip = true;
break;
}
} else if (parent instanceof SQLSelectQuery) {
break;
}
}
if (!skip) {
column = handleUnkownColumn(ident);
}
if (column != null) {
x.putAttribute(ATTR_COLUMN, column);
}
@@ -0,0 +1,40 @@
/*
* 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.alter;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.parser.Token;
import junit.framework.TestCase;
import org.junit.Assert;
public class MySqlAlterTableAlterColumnTest extends TestCase {
public void test_alter_first() throws Exception {
String sql = "ALTER TABLE `cube_template` ADD `stat_report_json` VARCHAR(256) CHARSET utf8 COLLATE utf8_general_ci DEFAULT '' NOT NULL COMMENT '模板的统计报表json数组';";
MySqlStatementParser parser = new MySqlStatementParser(sql);
SQLStatement stmt = parser.parseStatementList().get(0);
parser.match(Token.EOF);
Assert.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));
Assert.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));
}
}
@@ -0,0 +1,58 @@
/*
* 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.odps;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
import com.alibaba.druid.util.JdbcConstants;
import junit.framework.TestCase;
import org.junit.Assert;
import java.util.List;
public class OdpsSelectTest21 extends TestCase {
public void test_select() throws Exception {
// 1095288847322
String sql = "select wm_concat(',', a) from values('abc', 1), (null, 2) t (a, i);";//
Assert.assertEquals("SELECT WM_CONCAT(',', a)\n" +
"FROM VALUES ('abc', 1), (NULL, 2) t (a, i);", SQLUtils.formatOdps(sql));
Assert.assertEquals("select wm_concat(',', a)\n" +
"from values ('abc', 1), (null, 2) t (a, i);", SQLUtils.formatOdps(sql, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION));
List<SQLStatement> statementList = SQLUtils.parseStatements(sql, JdbcConstants.ODPS);
SQLStatement stmt = statementList.get(0);
Assert.assertEquals(1, statementList.size());
SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.ODPS);
stmt.accept(visitor);
// System.out.println("Tables : " + visitor.getTables());
System.out.println("fields : " + visitor.getColumns());
// System.out.println("coditions : " + visitor.getConditions());
// System.out.println("orderBy : " + visitor.getOrderByColumns());
Assert.assertEquals(0, visitor.getTables().size());
Assert.assertEquals(0, visitor.getColumns().size());
Assert.assertEquals(0, visitor.getConditions().size());
// Assert.assertTrue(visitor.getColumns().contains(new Column("abc", "name")));
}
}
@@ -19,7 +19,7 @@ import java.util.Set;
public class SchemaStatTest_odps extends TestCase {
public void test_schemaStat() throws Exception {
File file = new File("/Users/wenshao/Downloads/odps_sql.txt");
File file = new File("/Users/wenshao/Downloads/odps_sql_1.txt");
String sql = FileUtils.readFileToString(file);
String dbType = JdbcConstants.ODPS;
@@ -42,10 +42,10 @@ public class SchemaStatTest_odps extends TestCase {
// System.out.println(statVisitor.getGroupByColumns()); // group by
System.out.println("relationships : " + statVisitor.getRelationships()); // group by
System.out.println(statVisitor.getConditions());
assertEquals(3, relationships.size());
Assert.assertEquals(21, statVisitor.getColumns().size());
Assert.assertEquals(20, statVisitor.getConditions().size());
assertEquals(1, statVisitor.getFunctions().size());
// assertEquals(3, relationships.size());
//
// Assert.assertEquals(21, statVisitor.getColumns().size());
// Assert.assertEquals(20, statVisitor.getConditions().size());
// assertEquals(1, statVisitor.getFunctions().size());
}
}