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
91 changes: 91 additions & 0 deletions src/main/java/net/sf/jsqlparser/schema/TableReference.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*-
* #%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.schema;

import java.io.Serializable;

/** A relation target with optional PostgreSQL inheritance scope, shared by LOCK and TRUNCATE. */
public class TableReference implements Serializable {
private Table table;
private boolean only;
private boolean includeDescendants;
private boolean parenthesized;

public TableReference(Table table) {
this.table = table;
}

public Table getTable() {
return table;
}

public void setTable(Table table) {
this.table = table;
}

public boolean isOnly() {
return only;
}

public void setOnly(boolean only) {
this.only = only;
if (only) {
includeDescendants = false;
} else {
parenthesized = false;
}
}

public boolean isIncludeDescendants() {
return includeDescendants;
}

public void setIncludeDescendants(boolean includeDescendants) {
this.includeDescendants = includeDescendants;
if (includeDescendants) {
only = false;
parenthesized = false;
}
}

public boolean isParenthesized() {
return parenthesized;
}

public void setParenthesized(boolean parenthesized) {
this.parenthesized = parenthesized;
if (parenthesized) {
only = true;
includeDescendants = false;
}
}

public StringBuilder appendTo(StringBuilder builder) {
if (only) {
builder.append("ONLY ");
}
if (parenthesized) {
builder.append('(');
}
builder.append(table.getFullyQualifiedName());
if (parenthesized) {
builder.append(')');
}
if (includeDescendants) {
builder.append(" *");
}
return builder;
}

@Override
public String toString() {
return appendTo(new StringBuilder()).toString();
}
}
28 changes: 7 additions & 21 deletions src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,34 +34,20 @@ public enum Scope {
DEFAULT, ONLY, INCLUDING_DESCENDANTS
}

public static class Target {
private Table table;
private Scope scope = Scope.DEFAULT;

public static class Target extends net.sf.jsqlparser.schema.TableReference {
public Target(Table table) {
this.table = table;
}

public Table getTable() {
return table;
}

public void setTable(Table table) {
this.table = table;
super(table);
}

public Scope getScope() {
return scope;
return isOnly() ? Scope.ONLY
: isIncludeDescendants() ? Scope.INCLUDING_DESCENDANTS : Scope.DEFAULT;
}

public void setScope(Scope scope) {
this.scope = Objects.requireNonNull(scope);
}

@Override
public String toString() {
return (scope == Scope.ONLY ? "ONLY " : "") + table.getFullyQualifiedName()
+ (scope == Scope.INCLUDING_DESCENDANTS ? " *" : "");
Objects.requireNonNull(scope);
setOnly(scope == Scope.ONLY);
setIncludeDescendants(scope == Scope.INCLUDING_DESCENDANTS);
}
}

Expand Down
179 changes: 126 additions & 53 deletions src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,113 +9,186 @@
*/
package net.sf.jsqlparser.statement.truncate;

import static java.util.stream.Collectors.joining;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.schema.TableReference;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;

public class Truncate implements Statement {
public enum IdentityOption {
RESTART, CONTINUE
}
public enum DropBehavior {
CASCADE, RESTRICT
}

boolean cascade; // to support TRUNCATE TABLE ... CASCADE
boolean tableToken; // to support TRUNCATE without TABLE
boolean only; // to support TRUNCATE with ONLY
private Table table;
private List<Table> tables;
private boolean tableToken;
private boolean only;
private final List<TableReference> targets = new ArrayList<>();
private IdentityOption identityOption;
private DropBehavior dropBehavior;

@Override
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
return statementVisitor.visit(this, context);
}

public Table getTable() {
return table;
public List<TableReference> getTargets() {
return targets;
}

public List<Table> getTables() {
return tables;
public void setTargets(List<TableReference> references) {
List<TableReference> replacement = new ArrayList<>(references);
targets.clear();
targets.addAll(replacement);
}

/** Preserves the legacy parser's singular accessor for the last target. */
public Table getTable() {
return targets.isEmpty() ? null : targets.get(targets.size() - 1).getTable();
}

public void setTable(Table table) {
this.table = table;
if (targets.isEmpty()) {
TableReference target = new TableReference(table);
target.setOnly(only);
targets.add(target);
} else {
targets.get(targets.size() - 1).setTable(table);
}
}

/** Mutable table projection; replacing a table preserves its target's inheritance scope. */
public List<Table> getTables() {
return new AbstractList<Table>() {
@Override
public Table get(int index) {
return targets.get(index).getTable();
}

@Override
public int size() {
return targets.size();
}

@Override
public Table set(int index, Table table) {
Table previous = get(index);
targets.get(index).setTable(table);
return previous;
}

@Override
public void add(int index, Table table) {
targets.add(index, new TableReference(table));
}

@Override
public Table remove(int index) {
return targets.remove(index).getTable();
}
};
}

public void setTables(List<Table> tables) {
this.tables = tables;
List<Table> replacement = tables == null ? new ArrayList<>() : new ArrayList<>(tables);
boolean firstOnly = isOnly();
targets.clear();
replacement.forEach(table -> targets.add(new TableReference(table)));
setOnly(firstOnly);
}

public boolean getCascade() {
return cascade;
public IdentityOption getIdentityOption() {
return identityOption;
}

public void setCascade(boolean c) {
cascade = c;
public void setIdentityOption(IdentityOption option) {
identityOption = option;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("TRUNCATE");
if (tableToken) {
sb.append(" TABLE");
}
if (only) {
sb.append(" ONLY");
}
sb.append(" ");
if (tables != null && !tables.isEmpty()) {
sb.append(tables.stream()
.map(Table::toString)
.collect(joining(", ")));
} else {
sb.append(table);
}
if (cascade) {
sb.append(" CASCADE");
}
return sb.toString();
public DropBehavior getDropBehavior() {
return dropBehavior;
}

public void setDropBehavior(DropBehavior behavior) {
dropBehavior = behavior;
}

public boolean getCascade() {
return dropBehavior == DropBehavior.CASCADE;
}

public void setCascade(boolean cascade) {
dropBehavior = cascade ? DropBehavior.CASCADE : null;
}

public boolean isTableToken() {
return tableToken;
}

public void setTableToken(boolean hasTable) {
this.tableToken = hasTable;
public void setTableToken(boolean tableToken) {
this.tableToken = tableToken;
}

/** Legacy ONLY accessor describes the first target. */
public boolean isOnly() {
return only;
return targets.isEmpty() ? only : targets.get(0).isOnly();
}

public void setOnly(boolean only) {
this.only = only;
if (!targets.isEmpty()) {
targets.get(0).setOnly(only);
}
}

public Truncate withTableToken(boolean hasTableToken) {
this.setTableToken(hasTableToken);
public StringBuilder appendTo(StringBuilder builder) {
builder.append(tableToken ? "TRUNCATE TABLE " : "TRUNCATE ");
for (int i = 0; i < targets.size(); i++) {
if (i > 0) {
builder.append(", ");
}
targets.get(i).appendTo(builder);
}
if (identityOption != null) {
builder.append(' ').append(identityOption).append(" IDENTITY");
}
if (dropBehavior != null) {
builder.append(' ').append(dropBehavior);
}
return builder;
}

@Override
public String toString() {
return appendTo(new StringBuilder()).toString();
}

public Truncate withTableToken(boolean value) {
setTableToken(value);
return this;
}

public Truncate withTable(Table table) {
this.setTable(table);
public Truncate withTable(Table value) {
setTable(value);
return this;
}

public Truncate withTables(List<Table> tables) {
this.setTables(tables);
public Truncate withTables(List<Table> value) {
setTables(value);
return this;
}

public Truncate withCascade(boolean cascade) {
this.setCascade(cascade);
public Truncate withCascade(boolean value) {
setCascade(value);
return this;
}

public Truncate withOnly(boolean only) {
this.setOnly(only);
public Truncate withOnly(boolean value) {
setOnly(value);
return this;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -1612,7 +1612,7 @@ public void visit(Drop drop) {

@Override
public <S> Void visit(Truncate truncate, S context) {
visit(truncate.getTable(), context);
truncate.getTables().forEach(table -> visit(table, context));
return null;
}

Expand Down
Loading
Loading