From 022c0fe6202d68949002e7473f59496d2d5a5a3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=93=81?= Date: Wed, 29 Jun 2016 16:40:06 +0800 Subject: [PATCH] sql parser support postgresql json operator --- .../druid/sql/ast/expr/SQLBinaryOperator.java | 5 ++ .../dialect/postgresql/parser/PGLexer.java | 12 +++- .../com/alibaba/druid/sql/parser/Lexer.java | 12 +++- .../druid/sql/parser/SQLExprParser.java | 23 +++++++- .../com/alibaba/druid/sql/parser/Token.java | 6 +- .../bvt/sql/postgresql/PGSelectTest26.java | 55 +++++++++++++++++++ .../bvt/sql/postgresql/PGSelectTest27.java | 55 +++++++++++++++++++ .../bvt/sql/postgresql/PGSelectTest28.java | 55 +++++++++++++++++++ .../bvt/sql/postgresql/PGSelectTest29.java | 55 +++++++++++++++++++ 9 files changed, 274 insertions(+), 4 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest26.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest27.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest28.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest29.java diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java index 51f931b432..1fdacb30f4 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java @@ -33,6 +33,11 @@ public enum SQLBinaryOperator { Add("+", 70), Subtract("-", 70), + SubGt("->", 20), + SubGtGt("->>", 20), + PoundGt("#>", 20), + PoundGtGt("#>>", 20), + LeftShift("<<", 80), RightShift(">>", 80), diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java index 78e42b9c39..dc96ab3d8e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java @@ -165,7 +165,17 @@ public class PGLexer extends Lexer { } public void scanSharp() { - token = Token.POUND; scanChar(); + if (ch == '>') { + scanChar(); + if (ch == '>') { + scanChar(); + token = Token.POUNDGTGT; + } else { + token = Token.POUNDGT; + } + } else { + token = Token.POUND; + } } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java index 7b86ea77f0..a9638f4421 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -510,7 +510,17 @@ public class Lexer { break; case '-': scanChar(); - token = Token.SUB; + if (ch == '>') { + scanChar(); + if (ch == '>') { + scanChar(); + token = Token.SUBGTGT; + } else { + token = Token.SUBGT; + } + } else { + token = Token.SUB; + } break; case '*': scanChar(); diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index ebb55270c7..0d1035f45b 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -152,11 +152,32 @@ public class SQLExprParser extends SQLParser { } public SQLExpr bitXorRest(SQLExpr expr) { - if (lexer.token() == Token.CARET) { + Token token = lexer.token; + if (token == Token.CARET) { lexer.nextToken(); SQLExpr rightExp = primary(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BitwiseXor, rightExp, getDbType()); expr = bitXorRest(expr); + } else if (token == Token.SUBGT) { + lexer.nextToken(); + SQLExpr rightExp = primary(); + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SubGt, rightExp, getDbType()); + expr = bitXorRest(expr); + } else if (token == Token.SUBGTGT) { + lexer.nextToken(); + SQLExpr rightExp = primary(); + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SubGtGt, rightExp, getDbType()); + expr = bitXorRest(expr); + } else if (token == Token.POUNDGT) { + lexer.nextToken(); + SQLExpr rightExp = primary(); + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.PoundGt, rightExp, getDbType()); + expr = bitXorRest(expr); + } else if (token == Token.POUNDGTGT) { + lexer.nextToken(); + SQLExpr rightExp = primary(); + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.PoundGtGt, rightExp, getDbType()); + expr = bitXorRest(expr); } return expr; diff --git a/src/main/java/com/alibaba/druid/sql/parser/Token.java b/src/main/java/com/alibaba/druid/sql/parser/Token.java index 71157df09a..fc1ece5ddc 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Token.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Token.java @@ -315,6 +315,8 @@ public enum Token { BARSLASH("|/"), PLUS("+"), SUB("-"), + SUBGT("->"), + SUBGTGT("->>"), STAR("*"), SLASH("/"), AMP("&"), @@ -324,7 +326,9 @@ public enum Token { LTLT("<<"), GTGT(">>"), MONKEYS_AT("@"), - POUND("#") + POUND("#"), + POUNDGT("#>"), + POUNDGTGT("#>>") ; public final String name; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest26.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest26.java new file mode 100644 index 0000000000..86aed0078f --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest26.java @@ -0,0 +1,55 @@ +/* + * 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.postgresql; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGSchemaStatVisitor; + +public class PGSelectTest26 extends PGTest { + + public void test_0() throws Exception { + String sql = "select '[{\"a\":\"foo\"},{\"b\":\"bar\"},{\"c\":\"baz\"}]'::json->2 from dual"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT '[{\"a\":\"foo\"},{\"b\":\"bar\"},{\"c\":\"baz\"}]'::json -> 2" + + "\nFROM dual", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select '[{\"a\":\"foo\"},{\"b\":\"bar\"},{\"c\":\"baz\"}]'::json -> 2" + + "\nfrom dual", SQLUtils.toPGString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + + Assert.assertEquals(1, statementList.size()); + + PGSchemaStatVisitor visitor = new PGSchemaStatVisitor(); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); + + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(1, visitor.getTables().size()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest27.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest27.java new file mode 100644 index 0000000000..1ddb0ef180 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest27.java @@ -0,0 +1,55 @@ +/* + * 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.postgresql; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGSchemaStatVisitor; + +public class PGSelectTest27 extends PGTest { + + public void test_0() throws Exception { + String sql = "select '[{\"a\":\"foo\"},{\"b\":\"bar\"},{\"c\":\"baz\"}]'::json->>2 from dual"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT '[{\"a\":\"foo\"},{\"b\":\"bar\"},{\"c\":\"baz\"}]'::json ->> 2" + + "\nFROM dual", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select '[{\"a\":\"foo\"},{\"b\":\"bar\"},{\"c\":\"baz\"}]'::json ->> 2" + + "\nfrom dual", SQLUtils.toPGString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + + Assert.assertEquals(1, statementList.size()); + + PGSchemaStatVisitor visitor = new PGSchemaStatVisitor(); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); + + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(1, visitor.getTables().size()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest28.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest28.java new file mode 100644 index 0000000000..4aceac1065 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest28.java @@ -0,0 +1,55 @@ +/* + * 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.postgresql; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGSchemaStatVisitor; + +public class PGSelectTest28 extends PGTest { + + public void test_0() throws Exception { + String sql = "select '{\"a\": {\"b\":{\"c\": \"foo\"}}}'::json #> '{a,b}' from dual"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT '{\"a\": {\"b\":{\"c\": \"foo\"}}}'::json #> '{a,b}'" + + "\nFROM dual", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select '{\"a\": {\"b\":{\"c\": \"foo\"}}}'::json #> '{a,b}'" + + "\nfrom dual", SQLUtils.toPGString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + + Assert.assertEquals(1, statementList.size()); + + PGSchemaStatVisitor visitor = new PGSchemaStatVisitor(); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); + + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(1, visitor.getTables().size()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest29.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest29.java new file mode 100644 index 0000000000..65213d6433 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest29.java @@ -0,0 +1,55 @@ +/* + * 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.postgresql; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.PGTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGSchemaStatVisitor; + +public class PGSelectTest29 extends PGTest { + + public void test_0() throws Exception { + String sql = "select '{\"a\": {\"b\":{\"c\": \"foo\"}}}'::json #>> '{a,b}' from dual"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT '{\"a\": {\"b\":{\"c\": \"foo\"}}}'::json #>> '{a,b}'" + + "\nFROM dual", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select '{\"a\": {\"b\":{\"c\": \"foo\"}}}'::json #>> '{a,b}'" + + "\nfrom dual", SQLUtils.toPGString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + + Assert.assertEquals(1, statementList.size()); + + PGSchemaStatVisitor visitor = new PGSchemaStatVisitor(); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); + + Assert.assertEquals(0, visitor.getColumns().size()); + Assert.assertEquals(1, visitor.getTables().size()); + } +}