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 32572b498b..7ed3d913ea 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 @@ -59,6 +59,10 @@ public enum SQLBinaryOperator { NotILike("NOT ILIKE", 110), AT_AT("@@", 110), // postgresql textsearch SIMILAR_TO("SIMILAR TO", 110), + POSIX_Regular_Match("~", 110), + POSIX_Regular_Match_Insensitive("~*", 110), + POSIX_Regular_Not_Match("!~", 110), + POSIX_Regular_Not_Match_POSIX_Regular_Match_Insensitive("!~*", 110), RLike("RLIKE", 110), NotRLike("NOT RLIKE", 110), 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 93425c35a3..9a1b6fec21 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -626,6 +626,14 @@ public class Lexer { } else if (ch == '!') { scanChar(); token = Token.BANGBANG; // postsql + } else if (ch == '~') { + scanChar(); + if (ch == '*') { + scanChar(); + token = Token.BANG_TILDE_STAR; // postsql + } else { + token = Token.BANG_TILDE; // postsql + } } else { token = Token.BANG; } @@ -636,7 +644,12 @@ public class Lexer { break; case '~': scanChar(); - token = Token.TILDE; + if (ch == '*') { + scanChar(); + token = Token.TILDE_STAR; + } else { + token = Token.TILDE; + } break; default: throw new ParserException("TODO"); 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 551a53866a..457f45343a 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -1492,16 +1492,49 @@ public class SQLExprParser extends SQLParser { } } else if (lexer.token() == Token.IN) { expr = inRest(expr); - } else if (JdbcConstants.POSTGRESQL.equals(lexer.dbType) - && identifierEquals("SIMILAR")) { - lexer.nextToken(); - accept(Token.TO); + } else if (JdbcConstants.POSTGRESQL.equals(lexer.dbType)) { + if (identifierEquals("SIMILAR")) { + lexer.nextToken(); + accept(Token.TO); - rightExp = equality(); + rightExp = equality(); - rightExp = relationalRest(rightExp); + rightExp = relationalRest(rightExp); - expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SIMILAR_TO, rightExp, getDbType()); + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SIMILAR_TO, rightExp, getDbType()); + } else if (lexer.token() == Token.TILDE) { + lexer.nextToken(); + + rightExp = equality(); + + rightExp = relationalRest(rightExp); + + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Match, rightExp, getDbType()); + } else if (lexer.token() == Token.TILDE_STAR) { + lexer.nextToken(); + + rightExp = equality(); + + rightExp = relationalRest(rightExp); + + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Match_Insensitive, rightExp, getDbType()); + } else if (lexer.token() == Token.BANG_TILDE) { + lexer.nextToken(); + + rightExp = equality(); + + rightExp = relationalRest(rightExp); + + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Not_Match, rightExp, getDbType()); + } else if (lexer.token() == Token.BANG_TILDE_STAR) { + lexer.nextToken(); + + rightExp = equality(); + + rightExp = relationalRest(rightExp); + + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Not_Match_POSIX_Regular_Match_Insensitive, rightExp, getDbType()); + } } 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 cacf0a46c9..174b3598de 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Token.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Token.java @@ -299,7 +299,10 @@ public enum Token { LT("<"), BANG("!"), BANGBANG("!!"), - TILDE("~"), + BANG_TILDE("!~"), + BANG_TILDE_STAR("!~*"), + TILDE("~"), + TILDE_STAR("~*"), QUES("?"), COLON(":"), COLONCOLON(":"), diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest33.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest33.java new file mode 100644 index 0000000000..37b13d246b --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest33.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 PGSelectTest33 extends PGTest { + + public void test_0() throws Exception { + String sql = "select 'thomas' ~ '.*thomas.*'"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT 'thomas' ~ '.*thomas.*'", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select 'thomas' ~ '.*thomas.*'", 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/PGSelectTest34.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest34.java new file mode 100644 index 0000000000..c67dc6c10c --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest34.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 PGSelectTest34 extends PGTest { + + public void test_0() throws Exception { + String sql = "select 'thomas' ~* '.*thomas.*'"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT 'thomas' ~* '.*thomas.*'", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select 'thomas' ~* '.*thomas.*'", 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/PGSelectTest35.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest35.java new file mode 100644 index 0000000000..85fbba32d3 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest35.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 PGSelectTest35 extends PGTest { + + public void test_0() throws Exception { + String sql = "select 'thomas' !~ '.*thomas.*'"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT 'thomas' !~ '.*thomas.*'", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select 'thomas' !~ '.*thomas.*'", 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/PGSelectTest36.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest36.java new file mode 100644 index 0000000000..f3456fd884 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/PGSelectTest36.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 PGSelectTest36 extends PGTest { + + public void test_0() throws Exception { + String sql = "select 'thomas' !~* '.*thomas.*'"; + + PGSQLStatementParser parser = new PGSQLStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertEquals("SELECT 'thomas' !~* '.*thomas.*'", SQLUtils.toPGString(stmt)); + + Assert.assertEquals("select 'thomas' !~* '.*thomas.*'", 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()); + } +}