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 7ed3d913ea..1255bd1de1 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 @@ -63,6 +63,8 @@ public enum SQLBinaryOperator { POSIX_Regular_Match_Insensitive("~*", 110), POSIX_Regular_Not_Match("!~", 110), POSIX_Regular_Not_Match_POSIX_Regular_Match_Insensitive("!~*", 110), + Array_Contains("@>", 110), + Array_ContainedBy("<@", 110), RLike("RLIKE", 110), NotRLike("NOT RLIKE", 110), @@ -82,7 +84,9 @@ public enum SQLBinaryOperator { BooleanAnd("AND", 140), BooleanXor("XOR", 150), BooleanOr("OR", 160), - Assignment(":=", 169) + Assignment(":=", 169), + + PG_And("&&", 140), ; public static int getPriority(SQLBinaryOperator operator) { 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 9a1b6fec21..d1eb4a4343 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -608,6 +608,9 @@ private final void scanOperator() { } else if (ch == '<') { scanChar(); token = Token.LTLT; + } else if (ch == '@') { + scanChar(); + token = Token.LT_MONKEYS_AT; } else { token = Token.LT; } @@ -1003,7 +1006,8 @@ public void scanVariable() { bufPos = 1; char ch; - if (charAt(pos + 1) == '@') { + final char c1 = charAt(pos + 1); + if (c1 == '@') { if (JdbcConstants.POSTGRESQL.equalsIgnoreCase(dbType)) { pos += 2; token = Token.MONKEYS_AT_AT; @@ -1013,7 +1017,12 @@ public void scanVariable() { ch = charAt(++pos); bufPos++; - } else if (charAt(pos + 1) == '{') { + } else if (c1 == '>' && JdbcConstants.POSTGRESQL.equalsIgnoreCase(dbType)) { + pos += 2; + token = Token.MONKEYS_AT_GT; + this.ch = charAt(++pos); + return; + } else if (c1 == '{') { pos++; bufPos++; 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 e2bcc73d5c..8d37b7fcdc 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -1299,7 +1299,8 @@ public SQLExpr and() { public SQLExpr andRest(SQLExpr expr) { for (;;) { - if (lexer.token() == Token.AND || lexer.token() == Token.AMPAMP) { + Token token = lexer.token(); + if (token == Token.AND || token == Token.AMPAMP) { if (lexer.isKeepComments() && lexer.hasComment()) { expr.addAfterComment(lexer.readAndResetComments()); } @@ -1308,7 +1309,11 @@ public SQLExpr andRest(SQLExpr expr) { SQLExpr rightExp = relational(); - expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanAnd, rightExp, getDbType()); + SQLBinaryOperator operator = token == Token.AMPAMP && JdbcConstants.POSTGRESQL.equals(getDbType()) ? + SQLBinaryOperator.PG_And + : SQLBinaryOperator.BooleanAnd; + + expr = new SQLBinaryOpExpr(expr, operator, rightExp, getDbType()); } else { break; } @@ -1451,6 +1456,20 @@ public SQLExpr relationalRest(SQLExpr expr) { rightExp = relationalRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.AT_AT, rightExp, getDbType()); + } else if (lexer.token() == Token.MONKEYS_AT_GT) { + lexer.nextToken(); + rightExp = equality(); + + rightExp = relationalRest(rightExp); + + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Array_Contains, rightExp, getDbType()); + } else if (lexer.token() == Token.LT_MONKEYS_AT) { + lexer.nextToken(); + rightExp = equality(); + + rightExp = relationalRest(rightExp); + + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Array_ContainedBy, rightExp, getDbType()); } else if (lexer.token() == (Token.NOT)) { lexer.nextToken(); expr = notRationalRest(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 174b3598de..0a01ba326b 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Token.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Token.java @@ -335,7 +335,9 @@ public enum Token { MONKEYS_AT_AT("@@"), POUND("#"), POUNDGT("#>"), - POUNDGTGT("#>>") + POUNDGTGT("#>>"), + MONKEYS_AT_GT("@>"), + LT_MONKEYS_AT("<@"), ; public final String name; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest38.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest38.java new file mode 100644 index 0000000000..386c1fcb5c --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest38.java @@ -0,0 +1,52 @@ +/* + * 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 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; +import org.junit.Assert; + +import java.util.List; + +public class PGSelectTest38 extends PGTest { + + public void test_0() throws Exception { + String sql = "select '{1,2,3}'::int[] && '{1,2,3}'::int[]"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT '{1,2,3}'::int[] && '{1,2,3}'::int[]", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select '{1,2,3}'::int[] && '{1,2,3}'::int[]", 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(0, visitor.getTables().size()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest39.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest39.java new file mode 100644 index 0000000000..70c6276065 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest39.java @@ -0,0 +1,52 @@ +/* + * 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 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; +import org.junit.Assert; + +import java.util.List; + +public class PGSelectTest39 extends PGTest { + + public void test_0() throws Exception { + String sql = "select '{1,2,3}'::int[] @> '{1,2,3}'::int[]"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT '{1,2,3}'::int[] @> '{1,2,3}'::int[]", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select '{1,2,3}'::int[] @> '{1,2,3}'::int[]", 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(0, visitor.getTables().size()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest40.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest40.java new file mode 100644 index 0000000000..283eb01372 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest40.java @@ -0,0 +1,52 @@ +/* + * 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 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; +import org.junit.Assert; + +import java.util.List; + +public class PGSelectTest40 extends PGTest { + + public void test_0() throws Exception { + String sql = "select '{1,2,3}'::int[] <@ '{1,2,3}'::int[]"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT '{1,2,3}'::int[] <@ '{1,2,3}'::int[]", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select '{1,2,3}'::int[] <@ '{1,2,3}'::int[]", 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(0, visitor.getTables().size()); + } +}