Merge pull request #1050 from wenshao/master

odps sql parser support lateral view & bug fixed for issue 1049
This commit is contained in:
wenshao
2016-01-16 13:42:17 +08:00
9 changed files with 228 additions and 3 deletions
@@ -0,0 +1,59 @@
package com.alibaba.druid.sql.dialect.odps.ast;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSourceImpl;
import com.alibaba.druid.sql.dialect.odps.visitor.OdpsASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class OdpsLateralViewTableSource extends SQLTableSourceImpl {
private SQLTableSource tableSource;
private SQLMethodInvokeExpr method;
private List<SQLName> columns = new ArrayList<SQLName>(2);
@Override
protected void accept0(SQLASTVisitor visitor) {
accept0((OdpsASTVisitor) visitor);
}
protected void accept0(OdpsASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, tableSource);
acceptChild(visitor, method);
acceptChild(visitor, columns);
}
visitor.endVisit(this);
}
public SQLTableSource getTableSource() {
return tableSource;
}
public void setTableSource(SQLTableSource tableSource) {
this.tableSource = tableSource;
}
public SQLMethodInvokeExpr getMethod() {
return method;
}
public void setMethod(SQLMethodInvokeExpr method) {
this.method = method;
}
public List<SQLName> getColumns() {
return columns;
}
public void setColumns(List<SQLName> columns) {
this.columns = columns;
}
}
@@ -18,8 +18,11 @@ package com.alibaba.druid.sql.dialect.odps.parser;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import com.alibaba.druid.sql.ast.SQLSetQuantifier;
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.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.SQLSelectParser;
@@ -121,5 +124,39 @@ public class OdpsSelectParser extends SQLSelectParser {
return queryRest(queryBlock);
}
protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) {
tableSource = super.parseTableSourceRest(tableSource);
if ("LATERAL".equalsIgnoreCase(tableSource.getAlias()) && lexer.token() == Token.VIEW) {
return parseLateralView(tableSource);
}
if (identifierEquals("LATERAL")) {
lexer.nextToken();
return parseLateralView(tableSource);
}
return tableSource;
}
protected SQLTableSource parseLateralView(SQLTableSource tableSource) {
accept(Token.VIEW);
tableSource.setAlias(null);
OdpsLateralViewTableSource lateralViewTabSrc = new OdpsLateralViewTableSource();
lateralViewTabSrc.setTableSource(tableSource);
SQLMethodInvokeExpr udtf = (SQLMethodInvokeExpr) this.exprParser.expr();
lateralViewTabSrc.setMethod(udtf);
String alias = as();
lateralViewTabSrc.setAlias(alias);
accept(Token.AS);
this.exprParser.names(lateralViewTabSrc.getColumns());
return parseTableSourceRest(lateralViewTabSrc);
}
}
@@ -22,6 +22,7 @@ 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;
@@ -123,4 +124,8 @@ public interface OdpsASTVisitor extends SQLASTVisitor {
void endVisit(OdpsDescStmt x);
boolean visit(OdpsDescStmt x);
void endVisit(OdpsLateralViewTableSource x);
boolean visit(OdpsLateralViewTableSource x);
}
@@ -22,6 +22,7 @@ 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;
@@ -256,5 +257,15 @@ public class OdpsASTVisitorAdapter extends SQLASTVisitorAdapter implements OdpsA
public boolean visit(OdpsDescStmt x) {
return true;
}
@Override
public void endVisit(OdpsLateralViewTableSource x) {
}
@Override
public boolean visit(OdpsLateralViewTableSource x) {
return true;
}
}
@@ -41,6 +41,7 @@ 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;
@@ -847,4 +848,24 @@ public class OdpsOutputVisitor extends SQLASTOutputVisitor implements OdpsASTVis
}
return false;
}
@Override
public void endVisit(OdpsLateralViewTableSource x) {
}
@Override
public boolean visit(OdpsLateralViewTableSource x) {
x.getTableSource().accept(this);
incrementIndent();
println();
print0(ucase ? "LATERAL VIEW " : "lateral view ");
x.getMethod().accept(this);
print(' ');
print0(x.getAlias());
print0(ucase ? " AS " : " as ");
printAndAccept(x.getColumns(), ", ");
decrementIndent();
return false;
}
}
@@ -25,6 +25,7 @@ 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;
@@ -261,4 +262,14 @@ public class OdpsSchemaStatVisitor extends SchemaStatVisitor implements OdpsASTV
public boolean visit(OdpsDescStmt x) {
return true;
}
@Override
public void endVisit(OdpsLateralViewTableSource x) {
}
@Override
public boolean visit(OdpsLateralViewTableSource x) {
return true;
}
}
@@ -389,10 +389,9 @@ public class SQLExprParser extends SQLParser {
SQLExpr notTarget = expr();
accept(Token.RPAREN);
notTarget = exprRest(notTarget);
notTarget = relationalRest(notTarget);
sqlExpr = new SQLNotExpr(notTarget);
return primaryRest(sqlExpr);
} else {
SQLExpr restExpr = relational();
@@ -0,0 +1,65 @@
/*
* 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;
import java.util.List;
import org.junit.Assert;
import com.alibaba.druid.sql.MysqlTest;
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.dialect.mysql.visitor.MySqlSchemaStatVisitor;
public class MySqlSelectTest_24 extends MysqlTest {
public void test_0() throws Exception {
String sql = "select * from company where id=1 and not (name='e') and addr='a'";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
print(statementList);
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
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(1, visitor.getTables().size());
Assert.assertEquals(4, visitor.getColumns().size());
Assert.assertEquals(3, visitor.getConditions().size());
Assert.assertEquals(0, visitor.getOrderByColumns().size());
String output = SQLUtils.toMySqlString(stmt);
Assert.assertEquals("SELECT *"
+ "\nFROM company"
+ "\nWHERE id = 1"
+ "\n\tAND NOT name = 'e'"
+ "\n\tAND addr = 'a'", //
output);
}
}
@@ -0,0 +1,17 @@
package com.alibaba.druid.bvt.sql.odps;
import org.junit.Assert;
import com.alibaba.druid.sql.SQLUtils;
import junit.framework.TestCase;
public class OdpsFormatCommentTest28 extends TestCase {
public void test_drop_function() throws Exception {
String sql = "SELECT pageid, adid FROM pageAds LATERAL VIEW explode(adid_list) adTable AS adid;";
Assert.assertEquals("SELECT pageid"
+ "\n\t, adid"
+ "\nFROM pageAds"
+ "\n\tLATERAL VIEW EXPLODE(adid_list) adTable AS adid;", SQLUtils.formatOdps(sql));
}
}