Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class CreateTable implements Statement {
private ColDataType ofType;
private boolean selectParenthesis;
private boolean useAsKeyword = true;
private Boolean withData;
private boolean ifNotExists = false;
private boolean orReplace = false;
private TablePartitioning partitioning;
Expand Down Expand Up @@ -204,6 +205,15 @@ public void setUseAsKeyword(boolean useAsKeyword) {
this.useAsKeyword = useAsKeyword;
}

/** Returns null for omission, true for WITH DATA, and false for WITH NO DATA. */
public Boolean getWithData() {
return withData;
}

public void setWithData(Boolean withData) {
this.withData = withData;
}

public StringBuilder appendSelectTo(StringBuilder builder,
java.util.function.Consumer<Select> selectRenderer) {
if (select != null) {
Expand All @@ -215,6 +225,9 @@ public StringBuilder appendSelectTo(StringBuilder builder,
if (selectParenthesis) {
builder.append(")");
}
if (withData != null) {
builder.append(withData ? " WITH DATA" : " WITH NO DATA");
}
}
return builder;
}
Expand Down
15 changes: 13 additions & 2 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -14968,6 +14968,7 @@ CreateTable CreateTable(boolean isUsingOrReplace):
Table partitionOfTable = null;
PartitionBound partitionBound = null;
ColDataType ofType = null;
boolean withData;
}
{
{ createTable.setOrReplace(isUsingOrReplace);}
Expand Down Expand Up @@ -15021,6 +15022,8 @@ CreateTable CreateTable(boolean isUsingOrReplace):
[ <K_AS> { createTable.setUseAsKeyword(true); } ]
( LOOKAHEAD(<K_TABLE>) select=TableStatement() | select=Select() )
{ createTable.setSelect(select, false); }
[ LOOKAHEAD(2) <K_WITH> withData=DataPopulation()
{ createTable.setWithData(withData); } ]
]
[
<K_LIKE> ( LOOKAHEAD("(" Table() ")") "(" likeTable=Table() { createTable.setLikeTable(likeTable, true); } ")"
Expand Down Expand Up @@ -15611,7 +15614,7 @@ CreateView CreateView(boolean isUsingOrReplace):
List<Index.Option> storageParameters = null;
List<ViewOption> viewOptions = new ArrayList<ViewOption>();
ViewOption viewOption = null;
boolean withData = true;
boolean withData;
}
{
{ createView.setOrReplace(isUsingOrReplace);}
Expand Down Expand Up @@ -15666,7 +15669,7 @@ CreateView CreateView(boolean isUsingOrReplace):
}
}
|
[ <K_NO> { withData = false; } ] <K_DATA> { createView.setWithData(withData); }
withData=DataPopulation() { createView.setWithData(withData); }
)
]
{ createView.validateOptions(); return createView; }
Expand All @@ -15684,6 +15687,14 @@ ViewOption PostgreSqlViewOption():
{ return new ViewOption(name, value, useEquals); }
}

/** Shared WITH [NO] DATA tail for table and materialized-view query sources. */
boolean DataPopulation():
{ boolean withData = true; }
{
[ <K_NO> { withData = false; } ] <K_DATA>
{ return withData; }
}

List<String> CreateViewTailComment():
{
Token tk = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*-
* #%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.create;

import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.create.view.CreateView;
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
import net.sf.jsqlparser.util.deparser.SelectDeParser;
import net.sf.jsqlparser.util.deparser.StatementDeParser;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class CreateTableDataPopulationTest {
@ParameterizedTest
@ValueSource(strings = {"SELECT id FROM source", "TABLE source", "VALUES (1), (2)",
"(SELECT id FROM source)", "WITH c AS (SELECT 1 AS id) SELECT id FROM c",
"SELECT id FROM source UNION ALL SELECT id FROM other ORDER BY id LIMIT 4"})
void preservesDataChoiceForQuerySources(String query) throws JSQLParserException {
for (String suffix : new String[] {"", " WITH DATA", " WITH NO DATA"}) {
CreateTable table = parse("CREATE TABLE t AS " + query + suffix);
assertEquals(suffix.isEmpty() ? null : !suffix.contains("NO"), table.getWithData());
roundTrip(table);
}
}

@Test
void sharesOutputAndKeepsCustomQueryVisitor() throws JSQLParserException {
CreateTable table =
parse("CREATE TEMP TABLE t (id) ON COMMIT DROP AS SELECT 7 WITH NO DATA");
table.setWithData(true);
assertTrue(table.toString().endsWith("WITH DATA"));
ExpressionDeParser expression = new ExpressionDeParser() {
@Override
public <S> StringBuilder visit(LongValue value, S context) {
return getBuilder().append(value.getValue() + 100);
}
};
StringBuilder out = new StringBuilder();
table.accept(new StatementDeParser(expression, new SelectDeParser(), out));
assertTrue(out.toString().endsWith("SELECT 107 WITH DATA"));
assertTrue(table.toString().contains("SELECT 7"));
table.setWithData(null);
assertFalse(table.toString().contains("WITH DATA"));
roundTrip(table);
}

@Test
void retainsMaterializedViewTailAndStatementBoundaries() throws JSQLParserException {
CreateView view = (CreateView) CCJSqlParserUtil.parse(
"CREATE MATERIALIZED VIEW v AS SELECT 1 WITH NO DATA");
assertEquals(Boolean.FALSE, view.getWithData());
assertEquals(2, CCJSqlParserUtil.parseStatements(
"CREATE TABLE t AS SELECT 1 WITH NO DATA; SELECT 2").size());
for (String sql : List.of("CREATE TABLE t AS SELECT 1 WITH NO",
"CREATE TABLE t AS SELECT 1 WITH DATA WITH NO DATA",
"SELECT 1 WITH NO DATA")) {
assertThrows(JSQLParserException.class, () -> CCJSqlParserUtil.parse(sql));
}
}

private static CreateTable parse(String sql) throws JSQLParserException {
return (CreateTable) CCJSqlParserUtil.parse(sql, p -> p.withDialect(Dialect.POSTGRESQL));
}

private static void roundTrip(CreateTable table) throws JSQLParserException {
StringBuilder out = new StringBuilder();
table.accept(new StatementDeParser(out));
assertEquals(table.toString(), out.toString());
assertEquals(table.getWithData(), parse(out.toString()).getWithData());
assertEquals(out.toString(), parse(out.toString()).toString());
}
}
Loading