Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ public <S> T visit(SetOperationList setOpList, S context) {
*/
@Override
public <S> T visit(WithItem<?> withItem, S context) {
if (withItem.getCycleClause() != null) {
withItem.getCycleClause().accept(expressionVisitor, context);
}
ParenthesedStatement body = withItem.getParenthesedStatement();

// ParenthesedSelect is a Select and stays on the select path
Expand Down
129 changes: 129 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/select/WithCycleClause.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2026 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.select;

import java.io.Serializable;
import java.util.function.Consumer;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.schema.Column;

/** Cycle detection metadata for a recursive common table expression. */
public class WithCycleClause implements Serializable {
private ExpressionList<Column> cycleColumns;
private String markColumnName;
private Expression markValue;
private Expression markDefault;
private String pathColumnName;

public ExpressionList<Column> getCycleColumns() {
return cycleColumns;
}

public void setCycleColumns(ExpressionList<Column> cycleColumns) {
this.cycleColumns = cycleColumns;
}

public WithCycleClause withCycleColumns(ExpressionList<Column> cycleColumns) {
setCycleColumns(cycleColumns);
return this;
}

public String getMarkColumnName() {
return markColumnName;
}

public void setMarkColumnName(String markColumnName) {
this.markColumnName = markColumnName;
}

public WithCycleClause withMarkColumnName(String markColumnName) {
setMarkColumnName(markColumnName);
return this;
}

public Expression getMarkValue() {
return markValue;
}

public void setMarkValue(Expression markValue) {
this.markValue = markValue;
}

public WithCycleClause withMarkValue(Expression markValue) {
setMarkValue(markValue);
return this;
}

public Expression getMarkDefault() {
return markDefault;
}

public void setMarkDefault(Expression markDefault) {
this.markDefault = markDefault;
}

public WithCycleClause withMarkDefault(Expression markDefault) {
setMarkDefault(markDefault);
return this;
}

public String getPathColumnName() {
return pathColumnName;
}

public void setPathColumnName(String pathColumnName) {
this.pathColumnName = pathColumnName;
}

public WithCycleClause withPathColumnName(String pathColumnName) {
setPathColumnName(pathColumnName);
return this;
}

public <S> void accept(ExpressionVisitor<?> visitor, S context) {
if (cycleColumns != null) {
cycleColumns.forEach(column -> column.accept(visitor, context));
}
if (markValue != null) {
markValue.accept(visitor, context);
}
if (markDefault != null) {
markDefault.accept(visitor, context);
}
}

public StringBuilder appendTo(StringBuilder builder, Consumer<Expression> expressionPrinter) {
builder.append("CYCLE ");
if (cycleColumns != null) {
for (int i = 0; i < cycleColumns.size(); i++) {
if (i > 0) {
builder.append(", ");
}
expressionPrinter.accept(cycleColumns.get(i));
}
}
builder.append(" SET ").append(markColumnName);
if (markValue != null) {
builder.append(" TO ");
expressionPrinter.accept(markValue);
builder.append(" DEFAULT ");
expressionPrinter.accept(markDefault);
}
return builder.append(" USING ").append(pathColumnName);
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
return appendTo(builder, expression -> builder.append(expression)).toString();
}
}
34 changes: 31 additions & 3 deletions src/main/java/net/sf/jsqlparser/statement/select/WithItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
*/
package net.sf.jsqlparser.statement.select;

import java.util.function.Consumer;
import net.sf.jsqlparser.expression.Expression;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -28,6 +31,7 @@ public class WithItem<K extends ParenthesedStatement> implements Serializable {
private List<SelectItem<?>> withItemList;
private WithFunctionDeclaration withFunctionDeclaration;
private WithSearchClause searchClause;
private WithCycleClause cycleClause;
private boolean recursive = false;
private boolean usingNot = false;
private boolean materialized = false;
Expand Down Expand Up @@ -149,6 +153,32 @@ public WithItem<K> withSearchClause(WithSearchClause searchClause) {
return this;
}

public WithCycleClause getCycleClause() {
return cycleClause;
}

public void setCycleClause(WithCycleClause cycleClause) {
this.cycleClause = cycleClause;
}

public WithItem<K> withCycleClause(WithCycleClause cycleClause) {
setCycleClause(cycleClause);
return this;
}

public StringBuilder appendRecursiveClausesTo(StringBuilder builder,
Consumer<Expression> expressionPrinter) {
if (searchClause != null) {
builder.append(" ");
searchClause.appendTo(builder, expressionPrinter);
}
if (cycleClause != null) {
builder.append(" ");
cycleClause.appendTo(builder, expressionPrinter);
}
return builder;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
Expand All @@ -174,9 +204,7 @@ public String toString() {
: "MATERIALIZED ");
}
builder.append(statement);
if (searchClause != null) {
builder.append(" ").append(searchClause);
}
appendRecursiveClausesTo(builder, expression -> builder.append(expression));
}
return builder.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
*/
package net.sf.jsqlparser.statement.select;

import java.util.function.Consumer;
import net.sf.jsqlparser.expression.Expression;

import java.io.Serializable;
import java.util.Collection;

Expand Down Expand Up @@ -86,15 +89,23 @@ public WithSearchClause withSequenceColumnName(String sequenceColumnName) {
return this;
}

public StringBuilder appendTo(StringBuilder builder,
Consumer<Expression> expressionPrinter) {
builder.append("SEARCH ").append(searchOrder).append(" FIRST BY ");
if (searchColumns != null) {
for (int i = 0; i < searchColumns.size(); i++) {
if (i > 0) {
builder.append(", ");
}
expressionPrinter.accept(searchColumns.get(i));
}
}
return builder.append(" SET ").append(sequenceColumnName);
}

@Override
public String toString() {
return new StringBuilder()
.append("SEARCH ")
.append(searchOrder)
.append(" FIRST BY ")
.append(Select.getStringList(searchColumns))
.append(" SET ")
.append(sequenceColumnName)
.toString();
StringBuilder builder = new StringBuilder();
return appendTo(builder, expression -> builder.append(expression)).toString();
}
}
3 changes: 3 additions & 0 deletions src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,9 @@ public <S> Void visit(WithItem<?> withItem, S context) {
if (withItem.getAlias() != null) {
otherItemNames.add(withItem.getAlias().getName());
}
if (withItem.getCycleClause() != null) {
withItem.getCycleClause().accept(this, context);
}
// dispatch any ParenthesedStatement payload (Select, Delete, Update, Insert)
withItem.accept((StatementVisitor<?>) this, context);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -902,9 +902,8 @@ public <S> StringBuilder visit(WithItem<?> withItem, S context) {
StatementDeParser statementDeParser =
new StatementDeParser((ExpressionDeParser) expressionVisitor, this, builder);
statementDeParser.deParse(withItem.getParenthesedStatement());
if (withItem.getSearchClause() != null) {
builder.append(" ").append(withItem.getSearchClause());
}
withItem.appendRecursiveClausesTo(builder,
expression -> expression.accept(expressionVisitor, context));
} else {
builder.append(withItem.getWithFunctionDeclaration().toString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,9 @@ public <S> Void visit(WithItem<?> withItem, S context) {
if (isNotEmpty(withItem.getWithItemList())) {
withItem.getWithItemList().forEach(wi -> wi.accept(this, context));
}
if (withItem.getCycleClause() != null) {
withItem.getCycleClause().accept(getValidator(ExpressionValidator.class), context);
}
withItem.getSelect().accept((SelectVisitor<?>) this, context);
return null;
}
Expand Down
20 changes: 20 additions & 0 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -6279,6 +6279,7 @@ WithItem<?> WithItem() #WithItem:
WithFunctionDeclaration withFunctionDeclaration = null;
ParenthesedStatement statement = null;
WithSearchClause withSearchClause = null;
WithCycleClause withCycleClause = null;
WithItem<?> withItem;
}
{
Expand Down Expand Up @@ -6312,6 +6313,7 @@ WithItem<?> WithItem() #WithItem:
)
)
[ withSearchClause = WithSearchClause() { withItem.setSearchClause(withSearchClause); } ]
[ withCycleClause = WithCycleClause() { withItem.setCycleClause(withCycleClause); } ]
{
return withItem;
}
Expand Down Expand Up @@ -6342,6 +6344,24 @@ WithSearchClause WithSearchClause() #WithSearchClause:
}
}

WithCycleClause WithCycleClause() #WithCycleClause:
{
WithCycleClause cycle = new WithCycleClause();
ExpressionList<Column> columns = new ExpressionList<Column>();
String name;
Expression value;
}
{
<K_CYCLE>
name=RelObjectName() { columns.add(new Column(name)); }
( "," name=RelObjectName() { columns.add(new Column(name)); } )*
<K_SET> name=RelObjectName() { cycle.setMarkColumnName(name); }
[ <K_TO> value=Expression() { cycle.setMarkValue(value); }
<K_DEFAULT> value=Expression() { cycle.setMarkDefault(value); } ]
<K_USING> name=RelObjectName() { cycle.setPathColumnName(name); }
{ return cycle.withCycleColumns(columns); }
}

WithFunctionDeclaration WithFunctionDeclaration() #WithFunctionDeclaration:
{
String functionName;
Expand Down
Loading
Loading