Skip to content

fix truncate parsing to capture multiple tables #2048

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
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
26 changes: 24 additions & 2 deletions src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
*/
package net.sf.jsqlparser.statement.truncate;

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

import java.util.List;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;
Expand All @@ -19,6 +22,7 @@ public class Truncate implements Statement {
boolean tableToken; // to support TRUNCATE without TABLE
boolean only; // to support TRUNCATE with ONLY
private Table table;
private List<Table> tables;

@Override
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
Expand All @@ -29,10 +33,18 @@ public Table getTable() {
return table;
}

public List<Table> getTables() {
return tables;
}

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

public void setTables(List<Table> tables) {
this.tables = tables;
}

public boolean getCascade() {
return cascade;
}
Expand All @@ -52,8 +64,13 @@ public String toString() {
sb.append(" ONLY");
}
sb.append(" ");
sb.append(table);

if (tables != null && !tables.isEmpty()) {
sb.append(tables.stream()
.map(Table::toString)
.collect(joining(", ")));
} else {
sb.append(table);
}
if (cascade) {
sb.append(" CASCADE");
}
Expand Down Expand Up @@ -86,6 +103,11 @@ public Truncate withTable(Table table) {
return this;
}

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

public Truncate withCascade(boolean cascade) {
this.setCascade(cascade);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
*/
package net.sf.jsqlparser.util.deparser;

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

import java.lang.reflect.InvocationTargetException;
import java.util.stream.Collectors;

import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Block;
import net.sf.jsqlparser.statement.Commit;
import net.sf.jsqlparser.statement.CreateFunctionalStatement;
Expand Down Expand Up @@ -180,8 +183,13 @@ public <S> StringBuilder visit(Truncate truncate, S context) {
buffer.append(" ONLY");
}
buffer.append(" ");
buffer.append(truncate.getTable());

if (truncate.getTables() != null && !truncate.getTables().isEmpty()) {
buffer.append(truncate.getTables().stream()
.map(Table::toString)
.collect(joining(", ")));
} else {
buffer.append(truncate.getTable());
}
if (truncate.getCascade()) {
buffer.append(" CASCADE");
}
Expand Down
23 changes: 18 additions & 5 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -6617,6 +6617,9 @@ Truncate Truncate():
{
Truncate truncate = new Truncate();
Table table;
List<Table> tables = new ArrayList<Table>();
boolean only = false;
boolean cascade = false;
}
{
/**
Expand All @@ -6627,14 +6630,24 @@ Truncate Truncate():
* [ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ]
*
*/
<K_TRUNCATE> [LOOKAHEAD(2) <K_TABLE> {truncate.setTableToken(true);}] [<K_ONLY> {truncate.setOnly(true);}]
table=Table() { truncate.setTable(table); truncate.setCascade(false); } [ <K_CASCADE> {truncate.setCascade(true);} ]
{
return truncate;
<K_TRUNCATE>
[LOOKAHEAD(2) <K_TABLE> {truncate.setTableToken(true);}]
[<K_ONLY> { only = true; }]
table=Table() { tables.add(table); } (LOOKAHEAD(2) "," table=Table() { tables.add(table); } )*
[<K_CASCADE> { cascade = true; }]
{
if (only && tables.size() > 1 ) {
throw new ParseException("Cannot TRUNCATE ONLY with multiple tables");
} else {
return truncate
.withTables(tables)
.withTable(table)
.withOnly(only)
.withCascade(cascade);
}
}
}


AlterExpression.ColumnDataType AlterExpressionColumnDataType():
{
String columnName = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2019 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.truncate;

import static net.sf.jsqlparser.test.TestUtils.assertDeparse;
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.StringReader;
import java.util.List;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.schema.Table;
import org.junit.jupiter.api.Test;

public class TruncateMultipleTablesTest {

private CCJSqlParserManager parserManager = new CCJSqlParserManager();

@Test
public void testTruncate2Tables() throws Exception {
String statement = "TRUncATE TABLE myschema.mytab, myschema2.mytab2";
Truncate truncate = (Truncate) parserManager.parse(new StringReader(statement));
assertEquals("myschema2", truncate.getTable().getSchemaName());
assertEquals("myschema2.mytab2", truncate.getTable().getFullyQualifiedName());
assertEquals(statement.toUpperCase(), truncate.toString().toUpperCase());
assertEquals("myschema.mytab", truncate.getTables().get(0).getFullyQualifiedName());
assertEquals("myschema2.mytab2", truncate.getTables().get(1).getFullyQualifiedName());

statement = "TRUncATE TABLE mytab, my2ndtab";
String toStringStatement = "TRUncATE TABLE mytab, my2ndtab";
truncate = (Truncate) parserManager.parse(new StringReader(statement));
assertEquals("my2ndtab", truncate.getTable().getName());
assertEquals(toStringStatement.toUpperCase(), truncate.toString().toUpperCase());
assertEquals("mytab", truncate.getTables().get(0).getFullyQualifiedName());
assertEquals("my2ndtab", truncate.getTables().get(1).getFullyQualifiedName());

statement = "TRUNCATE TABLE mytab, my2ndtab CASCADE";
truncate = (Truncate) parserManager.parse(new StringReader(statement));
assertNull(truncate.getTables().get(0).getSchemaName());
assertEquals("mytab", truncate.getTables().get(0).getFullyQualifiedName());
assertEquals("my2ndtab", truncate.getTables().get(1).getFullyQualifiedName());
assertTrue(truncate.getCascade());
assertEquals(statement, truncate.toString());
}

@Test
public void testTruncatePostgresqlWithoutTableNames() throws Exception {
String statement = "TRUncATE myschema.mytab, myschema2.mytab2";
Truncate truncate = (Truncate) parserManager.parse(new StringReader(statement));
assertEquals("myschema2", truncate.getTable().getSchemaName());
assertEquals("myschema2.mytab2", truncate.getTable().getFullyQualifiedName());
assertEquals(statement.toUpperCase(), truncate.toString().toUpperCase());
assertEquals("myschema.mytab", truncate.getTables().get(0).getFullyQualifiedName());
assertEquals("myschema2.mytab2", truncate.getTables().get(1).getFullyQualifiedName());

statement = "TRUncATE mytab, my2ndtab";
String toStringStatement = "TRUncATE mytab, my2ndtab";
truncate = (Truncate) parserManager.parse(new StringReader(statement));
assertEquals("my2ndtab", truncate.getTable().getName());
assertEquals(toStringStatement.toUpperCase(), truncate.toString().toUpperCase());
assertEquals("mytab", truncate.getTables().get(0).getFullyQualifiedName());
assertEquals("my2ndtab", truncate.getTables().get(1).getFullyQualifiedName());

statement = "TRUNCATE mytab, my2ndtab CASCADE";
truncate = (Truncate) parserManager.parse(new StringReader(statement));
assertNull(truncate.getTables().get(0).getSchemaName());
assertEquals("mytab", truncate.getTables().get(0).getFullyQualifiedName());
assertEquals("my2ndtab", truncate.getTables().get(1).getFullyQualifiedName());
assertTrue(truncate.getCascade());
assertEquals(statement, truncate.toString());
}

@Test
public void testTruncateDeparse() throws JSQLParserException {
String statement = "TRUNCATE TABLE foo, bar";
assertSqlCanBeParsedAndDeparsed(statement);
assertDeparse(new Truncate()
.withTables(List.of(new Table("foo"), new Table("bar")))
.withTableToken(true), statement);
}

@Test
public void testTruncateCascadeDeparse() throws JSQLParserException {
String statement = "TRUNCATE TABLE foo, bar CASCADE";
assertSqlCanBeParsedAndDeparsed(statement);
assertDeparse(new Truncate()
.withTables(List.of(new Table("foo"), new Table("bar")))
.withTableToken(true)
.withCascade(true), statement);
}

@Test
public void testTruncateDoesNotAllowOnlyWithMultipleTables() {
String statement = "TRUNCATE TABLE ONLY foo, bar";
assertThrows(JSQLParserException.class,
() -> parserManager.parse(new StringReader(statement)));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,37 @@ public void testTruncateDeparse() throws JSQLParserException {
String statement = "TRUNCATE TABLE foo";
assertSqlCanBeParsedAndDeparsed(statement);
assertDeparse(new Truncate()
.withTable(new Table("foo"))
.withTableToken(true), statement);
.withTable(new Table("foo"))
.withTableToken(true), statement);
}

@Test
public void testTruncateCascadeDeparse() throws JSQLParserException {
String statement = "TRUNCATE TABLE foo CASCADE";
assertSqlCanBeParsedAndDeparsed(statement);
assertDeparse(new Truncate()
.withTable(new Table("foo"))
.withTableToken(true)
.withCascade(true), statement);
.withTable(new Table("foo"))
.withTableToken(true)
.withCascade(true), statement);
}

@Test
public void testTruncateOnlyDeparse() throws JSQLParserException {
String statement = "TRUNCATE TABLE ONLY foo CASCADE";
String statement = "TRUNCATE TABLE ONLY foo";
assertSqlCanBeParsedAndDeparsed(statement);
assertDeparse(new Truncate()
.withTable(new Table("foo"))
.withCascade(true)
.withTableToken(true)
.withOnly(true), statement);
.withTable(new Table("foo"))
.withTableToken(true)
.withOnly(true), statement);
}

@Test
public void testTruncateOnlyAndCascadeDeparse() throws JSQLParserException {
String statement = "TRUNCATE ONLY foo CASCADE";
assertSqlCanBeParsedAndDeparsed(statement);
assertDeparse(new Truncate()
.withTable(new Table("foo"))
.withCascade(true)
.withOnly(true), statement);
}
}
Loading