diff --git a/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java b/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java new file mode 100644 index 000000000..98421e2bb --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java @@ -0,0 +1,63 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2021 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +/* + * Copyright (C) 2021 JSQLParser. + * + * This library is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; either version + * 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.schema.Column; + +import java.util.Objects; + +/** + * + * @author are + */ +public class ConnectByPriorOperator extends ASTNodeAccessImpl implements Expression { + private final Column column; + + public ConnectByPriorOperator(Column column) { + this.column = Objects.requireNonNull(column, + "The COLUMN of the ConnectByPrior Operator must not be null"); + } + + public Column getColumn() { + return column; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append("PRIOR ").append(column); + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} \ No newline at end of file diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java index e02ff0262..a6a0992b0 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java @@ -557,6 +557,12 @@ default void visit(ConnectByRootOperator connectByRootOperator) { this.visit(connectByRootOperator, null); } + T visit(ConnectByPriorOperator connectByPriorOperator, S context); + + default void visit(ConnectByPriorOperator connectByPriorOperator) { + this.visit(connectByPriorOperator, null); + } + T visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, S context); default void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) { diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java index 5a4b34345..6a54e3851 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java @@ -703,6 +703,11 @@ public T visit(ConnectByRootOperator connectByRootOperator, S context) { return connectByRootOperator.getColumn().accept(this, context); } + @Override + public T visit(ConnectByPriorOperator connectByPriorOperator, S context) { + return connectByPriorOperator.getColumn().accept(this, context); + } + @Override public T visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, S context) { return oracleNamedFunctionParameter.getExpression().accept(this, context); diff --git a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java index f6ff7e7aa..9e9fa8b05 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java +++ b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java @@ -56,6 +56,7 @@ public class ParserKeywordsUtils { {"CHECK", RESTRICTED_SQL2016}, {"CONNECT", RESTRICTED_ALIAS}, {"CONNECT_BY_ROOT", RESTRICTED_JSQLPARSER}, + {"PRIOR", RESTRICTED_JSQLPARSER}, {"CONSTRAINT", RESTRICTED_SQL2016}, {"CREATE", RESTRICTED_ALIAS}, {"CROSS", RESTRICTED_SQL2016}, diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 1e0f93968..ee4601e75 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -20,6 +20,7 @@ import net.sf.jsqlparser.expression.CastExpression; import net.sf.jsqlparser.expression.CollateExpression; import net.sf.jsqlparser.expression.ConnectByRootOperator; +import net.sf.jsqlparser.expression.ConnectByPriorOperator; import net.sf.jsqlparser.expression.DateTimeLiteralExpression; import net.sf.jsqlparser.expression.DateValue; import net.sf.jsqlparser.expression.DoubleValue; @@ -1722,6 +1723,12 @@ public Void visit(ConnectByRootOperator connectByRootOperator, S context) { return null; } + @Override + public Void visit(ConnectByPriorOperator connectByPriorOperator, S context) { + connectByPriorOperator.getColumn().accept(this, context); + return null; + } + @Override public Void visit(IfElseStatement ifElseStatement, S context) { ifElseStatement.getIfStatement().accept(this, context); diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index 2575b642f..3b0e7281e 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -20,6 +20,7 @@ import net.sf.jsqlparser.expression.CastExpression; import net.sf.jsqlparser.expression.CollateExpression; import net.sf.jsqlparser.expression.ConnectByRootOperator; +import net.sf.jsqlparser.expression.ConnectByPriorOperator; import net.sf.jsqlparser.expression.DateTimeLiteralExpression; import net.sf.jsqlparser.expression.DateValue; import net.sf.jsqlparser.expression.DoubleValue; @@ -1583,6 +1584,13 @@ public StringBuilder visit(ConnectByRootOperator connectByRootOperator, S co return buffer; } + @Override + public StringBuilder visit(ConnectByPriorOperator connectByPriorOperator, S context) { + buffer.append("PRIOR "); + connectByPriorOperator.getColumn().accept(this, context); + return buffer; + } + @Override public StringBuilder visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, S context) { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java index 5278c3010..8c3a36066 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java @@ -19,6 +19,7 @@ import net.sf.jsqlparser.expression.CastExpression; import net.sf.jsqlparser.expression.CollateExpression; import net.sf.jsqlparser.expression.ConnectByRootOperator; +import net.sf.jsqlparser.expression.ConnectByPriorOperator; import net.sf.jsqlparser.expression.DateTimeLiteralExpression; import net.sf.jsqlparser.expression.DateValue; import net.sf.jsqlparser.expression.DoubleValue; @@ -1014,6 +1015,12 @@ public Void visit(ConnectByRootOperator connectByRootOperator, S context) { return null; } + @Override + public Void visit(ConnectByPriorOperator connectByPriorOperator, S context) { + connectByPriorOperator.getColumn().accept(this, context); + return null; + } + @Override public Void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, S context) { oracleNamedFunctionParameter.getExpression().accept(this, context); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 61b4fc125..5809e4987 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -2749,6 +2749,8 @@ SelectItem SelectItem() #SelectItem: ( expression = AllColumns() | + expression = ConnectByPriorOperator() + | LOOKAHEAD(AllTableColumns()) expression = AllTableColumns() | LOOKAHEAD( 3 ) expression = XorExpression() @@ -4899,6 +4901,17 @@ ConnectByRootOperator ConnectByRootOperator() #ConnectByRootOperator: { } } +ConnectByPriorOperator ConnectByPriorOperator() #ConnectByPriorOperator: { + Column column; +} +{ + column = Column() + { + return new ConnectByPriorOperator(column); + } +} + + NextValExpression NextValExpression() : { ObjectNames data = null; Token token; diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by08.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by08.sql new file mode 100644 index 000000000..ca64e160e --- /dev/null +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by08.sql @@ -0,0 +1,15 @@ +--- +-- #%L +-- JSQLParser library +-- %% +-- Copyright (C) 2004 - 2019 JSQLParser +-- %% +-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0 +-- #L% +--- +select t.*, connect_by_root t.id as root_id +from test t +start with t.id = 1 +connect by prior t.id = t.parent_id +order siblings by t.some_text +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Oct 2, 2024, 8:11:58 PM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by09.sql new file mode 100644 index 000000000..e29c601d6 --- /dev/null +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by09.sql @@ -0,0 +1,15 @@ +--- +-- #%L +-- JSQLParser library +-- %% +-- Copyright (C) 2004 - 2019 JSQLParser +-- %% +-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0 +-- #L% +--- +select t.*, prior t.id parent_id +from test t +start with t.id = 1 +connect by prior t.id = t.parent_id +order siblings by t.some_text +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Oct 2, 2024, 8:14:31 PM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by10.sql new file mode 100644 index 000000000..f0001cf44 --- /dev/null +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by10.sql @@ -0,0 +1,15 @@ +--- +-- #%L +-- JSQLParser library +-- %% +-- Copyright (C) 2004 - 2019 JSQLParser +-- %% +-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0 +-- #L% +--- +select t.*, prior t.id as parent_id +from test t +start with t.id = 1 +connect by prior t.id = t.parent_id +order siblings by t.some_text +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Oct 2, 2024, 8:14:33 PM \ No newline at end of file