diff --git a/src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java b/src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java
index 4388f3ddd..58442d38e 100644
--- a/src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java
+++ b/src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java
@@ -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;
@@ -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
tables;
@Override
public T accept(StatementVisitor statementVisitor, S context) {
@@ -29,10 +33,18 @@ public Table getTable() {
return table;
}
+ public List getTables() {
+ return tables;
+ }
+
public void setTable(Table table) {
this.table = table;
}
+ public void setTables(List tables) {
+ this.tables = tables;
+ }
+
public boolean getCascade() {
return cascade;
}
@@ -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");
}
@@ -86,6 +103,11 @@ public Truncate withTable(Table table) {
return this;
}
+ public Truncate withTables(List tables) {
+ this.setTables(tables);
+ return this;
+ }
+
public Truncate withCascade(boolean cascade) {
this.setCascade(cascade);
return this;
diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java
index 30cf27f79..47ecd643d 100644
--- a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java
+++ b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java
@@ -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;
@@ -180,8 +183,13 @@ public 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");
}
diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
index a9f977dd9..d0e868446 100644
--- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
+++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
@@ -6617,6 +6617,9 @@ Truncate Truncate():
{
Truncate truncate = new Truncate();
Table table;
+ List tables = new ArrayList();
+ boolean only = false;
+ boolean cascade = false;
}
{
/**
@@ -6627,14 +6630,24 @@ Truncate Truncate():
* [ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ]
*
*/
- [LOOKAHEAD(2) {truncate.setTableToken(true);}] [ {truncate.setOnly(true);}]
- table=Table() { truncate.setTable(table); truncate.setCascade(false); } [ {truncate.setCascade(true);} ]
- {
- return truncate;
+
+ [LOOKAHEAD(2) {truncate.setTableToken(true);}]
+ [ { only = true; }]
+ table=Table() { tables.add(table); } (LOOKAHEAD(2) "," table=Table() { tables.add(table); } )*
+ [ { 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;
diff --git a/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateMultipleTablesTest.java b/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateMultipleTablesTest.java
new file mode 100644
index 000000000..18894c8ca
--- /dev/null
+++ b/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateMultipleTablesTest.java
@@ -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)));
+ }
+
+}
diff --git a/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateTest.java b/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateTest.java
index 036aa64ad..5d8db40f6 100644
--- a/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateTest.java
+++ b/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateTest.java
@@ -71,8 +71,8 @@ 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
@@ -80,19 +80,28 @@ 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);
}
}