mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
odps sql parser support qualify clause
This commit is contained in:
@@ -46,6 +46,7 @@ public class SQLSelectQueryBlock extends SQLSelectQueryBase implements SQLReplac
|
||||
|
||||
protected SQLSelectGroupByClause groupBy;
|
||||
protected List<SQLWindow> windows;
|
||||
protected SQLExpr qualify;
|
||||
protected SQLOrderBy orderBy;
|
||||
protected boolean forUpdate;
|
||||
protected boolean noWait;
|
||||
@@ -113,6 +114,17 @@ public class SQLSelectQueryBlock extends SQLSelectQueryBase implements SQLReplac
|
||||
this.windows.add(x);
|
||||
}
|
||||
|
||||
public SQLExpr getQualify() {
|
||||
return qualify;
|
||||
}
|
||||
|
||||
public void setQualify(SQLExpr x) {
|
||||
if (x != null) {
|
||||
x.setParent(this);
|
||||
}
|
||||
this.qualify = x;
|
||||
}
|
||||
|
||||
public SQLExpr getWhere() {
|
||||
return this.where;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ public class OdpsLexer extends Lexer {
|
||||
map.put("RLIKE", Token.RLIKE);
|
||||
map.put("DIV", Token.DIV);
|
||||
map.put("LATERAL", Token.LATERAL);
|
||||
map.put("QUALIFY", Token.QUALIFY);
|
||||
map.put(";", Token.SEMI);
|
||||
|
||||
DEFAULT_ODPS_KEYWORDS = new Keywords(map);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.alibaba.druid.sql.dialect.odps.parser;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLExpr;
|
||||
import com.alibaba.druid.sql.ast.SQLLimit;
|
||||
import com.alibaba.druid.sql.ast.SQLObject;
|
||||
import com.alibaba.druid.sql.ast.SQLSetQuantifier;
|
||||
@@ -161,11 +162,17 @@ public class OdpsSelectParser extends SQLSelectParser {
|
||||
parseGroupBy(queryBlock);
|
||||
}
|
||||
|
||||
parseGroupBy(queryBlock);
|
||||
|
||||
if (lexer.identifierEquals(FnvHash.Constants.WINDOW)) {
|
||||
parseWindow(queryBlock);
|
||||
}
|
||||
|
||||
parseGroupBy(queryBlock);
|
||||
if (lexer.token() == Token.QUALIFY) {
|
||||
lexer.nextToken();
|
||||
SQLExpr qualify = this.exprParser.expr();
|
||||
queryBlock.setQualify(qualify);
|
||||
}
|
||||
|
||||
queryBlock.setOrderBy(this.exprParser.parseOrderBy());
|
||||
queryBlock.setZOrderBy(this.exprParser.parseZOrderBy());
|
||||
|
||||
@@ -473,6 +473,13 @@ public class OdpsOutputVisitor extends HiveOutputVisitor implements OdpsASTVisit
|
||||
printAndAccept(windows, ", ");
|
||||
}
|
||||
|
||||
SQLExpr qualify = x.getQualify();
|
||||
if (qualify != null) {
|
||||
println();
|
||||
print0(ucase ? "QUALIFY " : "qualify ");
|
||||
qualify.accept(this);
|
||||
}
|
||||
|
||||
if (x.getOrderBy() != null) {
|
||||
println();
|
||||
x.getOrderBy().accept(this);
|
||||
|
||||
@@ -974,6 +974,7 @@ public final class FnvHash {
|
||||
long RETURNS = fnv1a_64_lower("RETURNS");
|
||||
long ROWTYPE = fnv1a_64_lower("ROWTYPE");
|
||||
long WINDOW = fnv1a_64_lower("WINDOW");
|
||||
long QUALIFY = fnv1a_64_lower("QUALIFY");
|
||||
long MULTIVALUE = fnv1a_64_lower("MULTIVALUE");
|
||||
long OPTIONALLY = fnv1a_64_lower("OPTIONALLY");
|
||||
long ENCLOSED = fnv1a_64_lower("ENCLOSED");
|
||||
|
||||
@@ -70,7 +70,7 @@ public class TestUtil {
|
||||
try (Reader reader = new InputStreamReader(
|
||||
contextClassLoader
|
||||
.getResourceAsStream(path), "UTF-8")
|
||||
){
|
||||
) {
|
||||
return Utils.read(reader);
|
||||
} catch (IOException ignored) {
|
||||
return null;
|
||||
|
||||
@@ -15,37 +15,29 @@
|
||||
*/
|
||||
package com.alibaba.druid.bvt.sql.odps;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
|
||||
import com.alibaba.druid.TestUtil;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLStatement;
|
||||
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.odps.parser.OdpsStatementParser;
|
||||
import com.alibaba.druid.sql.dialect.odps.visitor.OdpsSchemaStatVisitor;
|
||||
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
|
||||
import com.alibaba.druid.util.JdbcUtils;
|
||||
import com.alibaba.druid.util.Utils;
|
||||
|
||||
public class OdpsResourceTest extends TestCase {
|
||||
public void test_0() throws Exception {
|
||||
exec_test("bvt/parser/odps-0.sql");
|
||||
exec_test("bvt/parser/odps-0.txt");
|
||||
}
|
||||
|
||||
public void test_9() throws Exception {
|
||||
exec_test("bvt/parser/odps-9.txt");
|
||||
}
|
||||
|
||||
public void exec_test(String resource) throws Exception {
|
||||
// System.out.println(resource);
|
||||
InputStream is = null;
|
||||
|
||||
is = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
|
||||
Reader reader = new InputStreamReader(is, "UTF-8");
|
||||
String input = Utils.read(reader);
|
||||
JdbcUtils.close(reader);
|
||||
String input = TestUtil.getResource(resource);
|
||||
String[] items = input.split("---------------------------");
|
||||
String sql = items[0].trim();
|
||||
String expect = null;
|
||||
@@ -63,29 +55,9 @@ public class OdpsResourceTest extends TestCase {
|
||||
SchemaStatVisitor visitor = new OdpsSchemaStatVisitor();
|
||||
stmt.accept(visitor);
|
||||
|
||||
// System.out.println(sql);
|
||||
// System.out.println("Tables : " + visitor.getTables());
|
||||
// System.out.println("fields : " + visitor.getColumns());
|
||||
//
|
||||
// System.out.println();
|
||||
// System.out.println("---------------------------");
|
||||
// System.out.println(SQLUtils.toOdpsString(stmt));
|
||||
if (expect != null) {
|
||||
String result = stmt.toString();
|
||||
assertEquals(expect, result);
|
||||
}
|
||||
}
|
||||
|
||||
void mergValidate(String sql, String expect) {
|
||||
MySqlStatementParser parser = new MySqlStatementParser(sql);
|
||||
List<SQLStatement> statementList = parser.parseStatementList();
|
||||
SQLStatement statemen = statementList.get(0);
|
||||
|
||||
Assert.assertEquals(1, statementList.size());
|
||||
|
||||
StringBuilder out = new StringBuilder();
|
||||
MySqlOutputVisitor visitor = new MySqlOutputVisitor(out, true);
|
||||
statemen.accept(visitor);
|
||||
|
||||
System.out.println(out.toString());
|
||||
|
||||
Assert.assertEquals(expect, out.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import com.alibaba.druid.util.Utils;
|
||||
|
||||
public class OdpsFileTest extends TestCase {
|
||||
public void test_0() throws Exception {
|
||||
exec_test("bvt/parser/odps-0.sql");
|
||||
exec_test("bvt/parser/odps-0.txt");
|
||||
}
|
||||
|
||||
public void exec_test(String resource) throws Exception {
|
||||
|
||||
+14
-12
@@ -10,15 +10,17 @@ create table tt_xx
|
||||
) comment 'xx comment xxx' partitioned by (pt string comment '按天分区字段', seg string comment '时间跨度')
|
||||
;
|
||||
---------------------------
|
||||
create table tt_xx
|
||||
(
|
||||
f1 string,
|
||||
f2 string comment 'xxx',
|
||||
f3 string comment 'xxx',
|
||||
gmt_first datetime comment '首次时间',
|
||||
gmt_last datetime comment '末次时间',
|
||||
pv_cnt bigint comment 'PV数量',
|
||||
pv_day_cnt bigint comment 'PV天数'
|
||||
) comment 'xx comment xxx'
|
||||
partitioned by (pt string comment '按天分区字段', seg string comment '时间跨度')
|
||||
;
|
||||
CREATE TABLE tt_xx (
|
||||
f1 STRING,
|
||||
f2 STRING COMMENT 'xxx',
|
||||
f3 STRING COMMENT 'xxx',
|
||||
gmt_first DATETIME COMMENT '首次时间',
|
||||
gmt_last DATETIME COMMENT '末次时间',
|
||||
pv_cnt BIGINT COMMENT 'PV数量',
|
||||
pv_day_cnt BIGINT COMMENT 'PV天数'
|
||||
)
|
||||
COMMENT 'xx comment xxx'
|
||||
PARTITIONED BY (
|
||||
pt STRING COMMENT '按天分区字段',
|
||||
seg STRING COMMENT '时间跨度'
|
||||
);
|
||||
@@ -0,0 +1,8 @@
|
||||
select i, p, o
|
||||
from qt
|
||||
qualify row_number() over (partition by p order by o) = 1
|
||||
;
|
||||
---------------------------
|
||||
SELECT i, p, o
|
||||
FROM qt
|
||||
QUALIFY row_number() OVER (PARTITION BY p ORDER BY o) = 1;
|
||||
Reference in New Issue
Block a user